• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts {
2    const enum SignatureFlags {
3        None = 0,
4        Yield = 1 << 0,
5        Await = 1 << 1,
6        Type  = 1 << 2,
7        IgnoreMissingOpenBrace = 1 << 4,
8        JSDoc = 1 << 5,
9    }
10
11    const enum SpeculationKind {
12        TryParse,
13        Lookahead,
14        Reparse
15    }
16
17    let NodeConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
18    let TokenConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
19    let IdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
20    let PrivateIdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
21    let SourceFileConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
22
23    /**
24     * NOTE: You should not use this, it is only exported to support `createNode` in `~/src/deprecatedCompat/deprecations.ts`.
25     */
26    /* @internal */
27    export const parseBaseNodeFactory: BaseNodeFactory = {
28        createBaseSourceFileNode: kind => new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, -1, -1),
29        createBaseIdentifierNode: kind => new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, -1, -1),
30        createBasePrivateIdentifierNode: kind => new (PrivateIdentifierConstructor || (PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor()))(kind, -1, -1),
31        createBaseTokenNode: kind => new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, -1, -1),
32        createBaseNode: kind => new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, -1, -1),
33    };
34
35    /* @internal */
36    export const parseNodeFactory = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules, parseBaseNodeFactory);
37
38    function visitNode<T>(cbNode: (node: Node) => T, node: Node | undefined): T | undefined {
39        return node && cbNode(node);
40    }
41
42    function visitNodes<T>(cbNode: (node: Node) => T, cbNodes: ((node: NodeArray<Node>) => T | undefined) | undefined, nodes: NodeArray<Node> | undefined): T | undefined {
43        if (nodes) {
44            if (cbNodes) {
45                return cbNodes(nodes);
46            }
47            for (const node of nodes) {
48                const result = cbNode(node);
49                if (result) {
50                    return result;
51                }
52            }
53        }
54    }
55
56    /*@internal*/
57    export function isJSDocLikeText(text: string, start: number) {
58        return text.charCodeAt(start + 1) === CharacterCodes.asterisk &&
59            text.charCodeAt(start + 2) === CharacterCodes.asterisk &&
60            text.charCodeAt(start + 3) !== CharacterCodes.slash;
61    }
62
63    /*@internal*/
64    export function isFileProbablyExternalModule(sourceFile: SourceFile) {
65        // Try to use the first top-level import/export when available, then
66        // fall back to looking for an 'import.meta' somewhere in the tree if necessary.
67        return forEach(sourceFile.statements, isAnExternalModuleIndicatorNode) ||
68            getImportMetaIfNecessary(sourceFile);
69    }
70
71    function isAnExternalModuleIndicatorNode(node: Node) {
72        return canHaveModifiers(node) && hasModifierOfKind(node, SyntaxKind.ExportKeyword)
73            || isImportEqualsDeclaration(node) && isExternalModuleReference(node.moduleReference)
74            || isImportDeclaration(node)
75            || isExportAssignment(node)
76            || isExportDeclaration(node) ? node : undefined;
77    }
78
79    function getImportMetaIfNecessary(sourceFile: SourceFile) {
80        return sourceFile.flags & NodeFlags.PossiblyContainsImportMeta ?
81            walkTreeForImportMeta(sourceFile) :
82            undefined;
83    }
84
85    function walkTreeForImportMeta(node: Node): Node | undefined {
86        return isImportMeta(node) ? node : forEachChild(node, walkTreeForImportMeta);
87    }
88
89    /** Do not use hasModifier inside the parser; it relies on parent pointers. Use this instead. */
90    function hasModifierOfKind(node: HasModifiers, kind: SyntaxKind) {
91        return some(node.modifiers, m => m.kind === kind);
92    }
93
94    function isImportMeta(node: Node): boolean {
95        return isMetaProperty(node) && node.keywordToken === SyntaxKind.ImportKeyword && node.name.escapedText === "meta";
96    }
97
98    type ForEachChildFunction<TNode> = <T>(node: TNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined) => T | undefined;
99    type ForEachChildTable = { [TNode in ForEachChildNodes as TNode["kind"]]: ForEachChildFunction<TNode> };
100    const forEachChildTable: ForEachChildTable = {
101        [SyntaxKind.QualifiedName]: function forEachChildInQualifiedName<T>(node: QualifiedName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
102            return visitNode(cbNode, node.left) ||
103                visitNode(cbNode, node.right);
104        },
105        [SyntaxKind.TypeParameter]: function forEachChildInTypeParameter<T>(node: TypeParameterDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
106            return visitNodes(cbNode, cbNodes, node.modifiers) ||
107                visitNode(cbNode, node.name) ||
108                visitNode(cbNode, node.constraint) ||
109                visitNode(cbNode, node.default) ||
110                visitNode(cbNode, node.expression);
111        },
112        [SyntaxKind.ShorthandPropertyAssignment]: function forEachChildInShorthandPropertyAssignment<T>(node: ShorthandPropertyAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
113            return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
114                visitNodes(cbNode, cbNodes, node.modifiers) ||
115                visitNode(cbNode, node.name) ||
116                visitNode(cbNode, node.questionToken) ||
117                visitNode(cbNode, node.exclamationToken) ||
118                visitNode(cbNode, node.equalsToken) ||
119                visitNode(cbNode, node.objectAssignmentInitializer);
120        },
121        [SyntaxKind.SpreadAssignment]: function forEachChildInSpreadAssignment<T>(node: SpreadAssignment, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
122            return visitNode(cbNode, node.expression);
123        },
124        [SyntaxKind.Parameter]: function forEachChildInParameter<T>(node: ParameterDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
125            return visitNodes(cbNode, cbNodes, node.modifiers) ||
126                visitNode(cbNode, node.dotDotDotToken) ||
127                visitNode(cbNode, node.name) ||
128                visitNode(cbNode, node.questionToken) ||
129                visitNode(cbNode, node.type) ||
130                visitNode(cbNode, node.initializer);
131        },
132        [SyntaxKind.PropertyDeclaration]: function forEachChildInPropertyDeclaration<T>(node: PropertyDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
133            return visitNodes(cbNode, cbNodes, node.modifiers) ||
134                visitNode(cbNode, node.name) ||
135                visitNode(cbNode, node.questionToken) ||
136                visitNode(cbNode, node.exclamationToken) ||
137                visitNode(cbNode, node.type) ||
138                visitNode(cbNode, node.initializer);
139        },
140        [SyntaxKind.PropertySignature]: function forEachChildInPropertySignature<T>(node: PropertySignature, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
141            return visitNodes(cbNode, cbNodes, node.modifiers) ||
142                visitNode(cbNode, node.name) ||
143                visitNode(cbNode, node.questionToken) ||
144                visitNode(cbNode, node.type) ||
145                visitNode(cbNode, node.initializer);
146        },
147        [SyntaxKind.PropertyAssignment]: function forEachChildInPropertyAssignment<T>(node: PropertyAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
148            return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
149                visitNodes(cbNode, cbNodes, node.modifiers) ||
150                visitNode(cbNode, node.name) ||
151                visitNode(cbNode, node.questionToken) ||
152                visitNode(cbNode, node.exclamationToken) ||
153                visitNode(cbNode, node.initializer);
154        },
155        [SyntaxKind.VariableDeclaration]: function forEachChildInVariableDeclaration<T>(node: VariableDeclaration, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
156            return visitNode(cbNode, node.name) ||
157                visitNode(cbNode, node.exclamationToken) ||
158                visitNode(cbNode, node.type) ||
159                visitNode(cbNode, node.initializer);
160        },
161        [SyntaxKind.BindingElement]: function forEachChildInBindingElement<T>(node: BindingElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
162            return visitNode(cbNode, node.dotDotDotToken) ||
163                visitNode(cbNode, node.propertyName) ||
164                visitNode(cbNode, node.name) ||
165                visitNode(cbNode, node.initializer);
166        },
167        [SyntaxKind.IndexSignature]: function forEachChildInIndexSignature<T>(node: IndexSignatureDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
168            return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
169                visitNodes(cbNode, cbNodes, node.modifiers) ||
170                visitNodes(cbNode, cbNodes, node.typeParameters) ||
171                visitNodes(cbNode, cbNodes, node.parameters) ||
172                visitNode(cbNode, node.type);
173        },
174        [SyntaxKind.ConstructorType]: function forEachChildInConstructorType<T>(node: ConstructorTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
175            return visitNodes(cbNode, cbNodes, node.modifiers) ||
176                visitNodes(cbNode, cbNodes, node.typeParameters) ||
177                visitNodes(cbNode, cbNodes, node.parameters) ||
178                visitNode(cbNode, node.type);
179        },
180        [SyntaxKind.FunctionType]: function forEachChildInFunctionType<T>(node: FunctionTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
181            return visitNodes(cbNode, cbNodes, node.modifiers) ||
182                visitNodes(cbNode, cbNodes, node.typeParameters) ||
183                visitNodes(cbNode, cbNodes, node.parameters) ||
184                visitNode(cbNode, node.type);
185        },
186        [SyntaxKind.CallSignature]: forEachChildInCallOrConstructSignature,
187        [SyntaxKind.ConstructSignature]: forEachChildInCallOrConstructSignature,
188        [SyntaxKind.EtsComponentExpression]: function forEachChildInEtsComponentExpression<T>(node: EtsComponentExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
189            return visitNode(cbNode, node.expression) ||
190              visitNodes(cbNode, cbNodes, node.arguments) ||
191              visitNode(cbNode, node.body);
192        },
193        [SyntaxKind.MethodDeclaration]: function forEachChildInMethodDeclaration<T>(node: MethodDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
194            return visitNodes(cbNode, cbNodes, node.modifiers) ||
195                visitNode(cbNode, node.asteriskToken) ||
196                visitNode(cbNode, node.name) ||
197                visitNode(cbNode, node.questionToken) ||
198                visitNode(cbNode, node.exclamationToken) ||
199                visitNodes(cbNode, cbNodes, node.typeParameters) ||
200                visitNodes(cbNode, cbNodes, node.parameters) ||
201                visitNode(cbNode, node.type) ||
202                visitNode(cbNode, node.body);
203        },
204        [SyntaxKind.MethodSignature]: function forEachChildInMethodSignature<T>(node: MethodSignature, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
205            return visitNodes(cbNode, cbNodes, node.modifiers) ||
206                visitNode(cbNode, node.name) ||
207                visitNode(cbNode, node.questionToken) ||
208                visitNodes(cbNode, cbNodes, node.typeParameters) ||
209                visitNodes(cbNode, cbNodes, node.parameters) ||
210                visitNode(cbNode, node.type);
211        },
212        [SyntaxKind.Constructor]: function forEachChildInConstructor<T>(node: ConstructorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
213            return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
214                visitNodes(cbNode, cbNodes, node.modifiers) ||
215                visitNode(cbNode, node.name) ||
216                visitNodes(cbNode, cbNodes, node.typeParameters) ||
217                visitNodes(cbNode, cbNodes, node.parameters) ||
218                visitNode(cbNode, node.type) ||
219                visitNode(cbNode, node.body);
220        },
221        [SyntaxKind.GetAccessor]: function forEachChildInGetAccessor<T>(node: GetAccessorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
222            return visitNodes(cbNode, cbNodes, node.modifiers) ||
223                visitNode(cbNode, node.name) ||
224                visitNodes(cbNode, cbNodes, node.typeParameters) ||
225                visitNodes(cbNode, cbNodes, node.parameters) ||
226                visitNode(cbNode, node.type) ||
227                visitNode(cbNode, node.body);
228        },
229        [SyntaxKind.SetAccessor]: function forEachChildInSetAccessor<T>(node: SetAccessorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
230            return visitNodes(cbNode, cbNodes, node.modifiers) ||
231                visitNode(cbNode, node.name) ||
232                visitNodes(cbNode, cbNodes, node.typeParameters) ||
233                visitNodes(cbNode, cbNodes, node.parameters) ||
234                visitNode(cbNode, node.type) ||
235                visitNode(cbNode, node.body);
236        },
237        [SyntaxKind.FunctionDeclaration]: function forEachChildInFunctionDeclaration<T>(node: FunctionDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
238            return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
239                visitNodes(cbNode, cbNodes, node.modifiers) ||
240                visitNode(cbNode, node.asteriskToken) ||
241                visitNode(cbNode, node.name) ||
242                visitNodes(cbNode, cbNodes, node.typeParameters) ||
243                visitNodes(cbNode, cbNodes, node.parameters) ||
244                visitNode(cbNode, node.type) ||
245                visitNode(cbNode, node.body);
246        },
247        [SyntaxKind.FunctionExpression]: function forEachChildInFunctionExpression<T>(node: FunctionExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
248            return visitNodes(cbNode, cbNodes, node.modifiers) ||
249                visitNode(cbNode, node.asteriskToken) ||
250                visitNode(cbNode, node.name) ||
251                visitNodes(cbNode, cbNodes, node.typeParameters) ||
252                visitNodes(cbNode, cbNodes, node.parameters) ||
253                visitNode(cbNode, node.type) ||
254                visitNode(cbNode, node.body);
255        },
256        [SyntaxKind.ArrowFunction]: function forEachChildInArrowFunction<T>(node: ArrowFunction, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
257            return visitNodes(cbNode, cbNodes, node.modifiers) ||
258                visitNodes(cbNode, cbNodes, node.typeParameters) ||
259                visitNodes(cbNode, cbNodes, node.parameters) ||
260                visitNode(cbNode, node.type) ||
261                visitNode(cbNode, node.equalsGreaterThanToken) ||
262                visitNode(cbNode, node.body);
263        },
264        [SyntaxKind.ClassStaticBlockDeclaration]: function forEachChildInClassStaticBlockDeclaration<T>(node: ClassStaticBlockDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
265            return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
266                visitNodes(cbNode, cbNodes, node.modifiers) ||
267                visitNode(cbNode, node.body);
268        },
269        [SyntaxKind.TypeReference]: function forEachChildInTypeReference<T>(node: TypeReferenceNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
270            return visitNode(cbNode, node.typeName) ||
271                visitNodes(cbNode, cbNodes, node.typeArguments);
272        },
273        [SyntaxKind.TypePredicate]: function forEachChildInTypePredicate<T>(node: TypePredicateNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
274            return visitNode(cbNode, node.assertsModifier) ||
275                visitNode(cbNode, node.parameterName) ||
276                visitNode(cbNode, node.type);
277        },
278        [SyntaxKind.TypeQuery]: function forEachChildInTypeQuery<T>(node: TypeQueryNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
279            return visitNode(cbNode, node.exprName) ||
280                visitNodes(cbNode, cbNodes, node.typeArguments);
281        },
282        [SyntaxKind.TypeLiteral]: function forEachChildInTypeLiteral<T>(node: TypeLiteralNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
283            return visitNodes(cbNode, cbNodes, node.members);
284        },
285        [SyntaxKind.ArrayType]: function forEachChildInArrayType<T>(node: ArrayTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
286            return visitNode(cbNode, node.elementType);
287        },
288        [SyntaxKind.TupleType]: function forEachChildInTupleType<T>(node: TupleTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
289            return visitNodes(cbNode, cbNodes, node.elements);
290        },
291        [SyntaxKind.UnionType]: forEachChildInUnionOrIntersectionType,
292        [SyntaxKind.IntersectionType]: forEachChildInUnionOrIntersectionType,
293        [SyntaxKind.ConditionalType]: function forEachChildInConditionalType<T>(node: ConditionalTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
294            return visitNode(cbNode, node.checkType) ||
295                visitNode(cbNode, node.extendsType) ||
296                visitNode(cbNode, node.trueType) ||
297                visitNode(cbNode, node.falseType);
298        },
299        [SyntaxKind.InferType]: function forEachChildInInferType<T>(node: InferTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
300            return visitNode(cbNode, node.typeParameter);
301        },
302        [SyntaxKind.ImportType]: function forEachChildInImportType<T>(node: ImportTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
303            return visitNode(cbNode, node.argument) ||
304                visitNode(cbNode, node.assertions) ||
305                visitNode(cbNode, node.qualifier) ||
306                visitNodes(cbNode, cbNodes, node.typeArguments);
307        },
308        [SyntaxKind.ImportTypeAssertionContainer]: function forEachChildInImportTypeAssertionContainer<T>(node: ImportTypeAssertionContainer, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
309            return visitNode(cbNode, node.assertClause);
310        },
311        [SyntaxKind.ParenthesizedType]: forEachChildInParenthesizedTypeOrTypeOperator,
312        [SyntaxKind.TypeOperator]: forEachChildInParenthesizedTypeOrTypeOperator,
313        [SyntaxKind.IndexedAccessType]: function forEachChildInIndexedAccessType<T>(node: IndexedAccessTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
314            return visitNode(cbNode, node.objectType) ||
315                visitNode(cbNode, node.indexType);
316        },
317        [SyntaxKind.MappedType]: function forEachChildInMappedType<T>(node: MappedTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
318            return visitNode(cbNode, node.readonlyToken) ||
319                visitNode(cbNode, node.typeParameter) ||
320                visitNode(cbNode, node.nameType) ||
321                visitNode(cbNode, node.questionToken) ||
322                visitNode(cbNode, node.type) ||
323                visitNodes(cbNode, cbNodes, node.members);
324        },
325        [SyntaxKind.LiteralType]: function forEachChildInLiteralType<T>(node: LiteralTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
326            return visitNode(cbNode, node.literal);
327        },
328        [SyntaxKind.NamedTupleMember]: function forEachChildInNamedTupleMember<T>(node: NamedTupleMember, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
329            return visitNode(cbNode, node.dotDotDotToken) ||
330                visitNode(cbNode, node.name) ||
331                visitNode(cbNode, node.questionToken) ||
332                visitNode(cbNode, node.type);
333        },
334        [SyntaxKind.ObjectBindingPattern]: forEachChildInObjectOrArrayBindingPattern,
335        [SyntaxKind.ArrayBindingPattern]: forEachChildInObjectOrArrayBindingPattern,
336        [SyntaxKind.ArrayLiteralExpression]: function forEachChildInArrayLiteralExpression<T>(node: ArrayLiteralExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
337            return visitNodes(cbNode, cbNodes, node.elements);
338        },
339        [SyntaxKind.ObjectLiteralExpression]: function forEachChildInObjectLiteralExpression<T>(node: ObjectLiteralExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
340            return visitNodes(cbNode, cbNodes, node.properties);
341        },
342        [SyntaxKind.PropertyAccessExpression]: function forEachChildInPropertyAccessExpression<T>(node: PropertyAccessExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
343            return visitNode(cbNode, node.expression) ||
344                visitNode(cbNode, node.questionDotToken) ||
345                visitNode(cbNode, node.name);
346        },
347        [SyntaxKind.ElementAccessExpression]: function forEachChildInElementAccessExpression<T>(node: ElementAccessExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
348            return visitNode(cbNode, node.expression) ||
349                visitNode(cbNode, node.questionDotToken) ||
350                visitNode(cbNode, node.argumentExpression);
351        },
352        [SyntaxKind.CallExpression]: forEachChildInCallOrNewExpression,
353        [SyntaxKind.NewExpression]: forEachChildInCallOrNewExpression,
354        [SyntaxKind.TaggedTemplateExpression]: function forEachChildInTaggedTemplateExpression<T>(node: TaggedTemplateExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
355            return visitNode(cbNode, node.tag) ||
356                visitNode(cbNode, node.questionDotToken) ||
357                visitNodes(cbNode, cbNodes, node.typeArguments) ||
358                visitNode(cbNode, node.template);
359        },
360        [SyntaxKind.TypeAssertionExpression]: function forEachChildInTypeAssertionExpression<T>(node: TypeAssertion, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
361            return visitNode(cbNode, node.type) ||
362                visitNode(cbNode, node.expression);
363        },
364        [SyntaxKind.ParenthesizedExpression]: function forEachChildInParenthesizedExpression<T>(node: ParenthesizedExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
365            return visitNode(cbNode, node.expression);
366        },
367        [SyntaxKind.DeleteExpression]: function forEachChildInDeleteExpression<T>(node: DeleteExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
368            return visitNode(cbNode, node.expression);
369        },
370        [SyntaxKind.TypeOfExpression]: function forEachChildInTypeOfExpression<T>(node: TypeOfExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
371            return visitNode(cbNode, node.expression);
372        },
373        [SyntaxKind.VoidExpression]: function forEachChildInVoidExpression<T>(node: VoidExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
374            return visitNode(cbNode, node.expression);
375        },
376        [SyntaxKind.PrefixUnaryExpression]: function forEachChildInPrefixUnaryExpression<T>(node: PrefixUnaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
377            return visitNode(cbNode, node.operand);
378        },
379        [SyntaxKind.YieldExpression]: function forEachChildInYieldExpression<T>(node: YieldExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
380            return visitNode(cbNode, node.asteriskToken) ||
381                visitNode(cbNode, node.expression);
382        },
383        [SyntaxKind.AwaitExpression]: function forEachChildInAwaitExpression<T>(node: AwaitExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
384            return visitNode(cbNode, node.expression);
385        },
386        [SyntaxKind.PostfixUnaryExpression]: function forEachChildInPostfixUnaryExpression<T>(node: PostfixUnaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
387            return visitNode(cbNode, node.operand);
388        },
389        [SyntaxKind.BinaryExpression]: function forEachChildInBinaryExpression<T>(node: BinaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
390            return visitNode(cbNode, node.left) ||
391                visitNode(cbNode, node.operatorToken) ||
392                visitNode(cbNode, node.right);
393        },
394        [SyntaxKind.AsExpression]: function forEachChildInAsExpression<T>(node: AsExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
395            return visitNode(cbNode, node.expression) ||
396                visitNode(cbNode, node.type);
397        },
398        [SyntaxKind.NonNullExpression]: function forEachChildInNonNullExpression<T>(node: NonNullExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
399            return visitNode(cbNode, node.expression);
400        },
401        [SyntaxKind.SatisfiesExpression]: function forEachChildInSatisfiesExpression<T>(node: SatisfiesExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
402            return visitNode(cbNode, node.expression) || visitNode(cbNode, node.type);
403        },
404        [SyntaxKind.MetaProperty]: function forEachChildInMetaProperty<T>(node: MetaProperty, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
405            return visitNode(cbNode, node.name);
406        },
407        [SyntaxKind.ConditionalExpression]: function forEachChildInConditionalExpression<T>(node: ConditionalExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
408            return visitNode(cbNode, node.condition) ||
409                visitNode(cbNode, node.questionToken) ||
410                visitNode(cbNode, node.whenTrue) ||
411                visitNode(cbNode, node.colonToken) ||
412                visitNode(cbNode, node.whenFalse);
413        },
414        [SyntaxKind.SpreadElement]: function forEachChildInSpreadElement<T>(node: SpreadElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
415            return visitNode(cbNode, node.expression);
416        },
417        [SyntaxKind.Block]: forEachChildInBlock,
418        [SyntaxKind.ModuleBlock]: forEachChildInBlock,
419        [SyntaxKind.SourceFile]: function forEachChildInSourceFile<T>(node: SourceFile, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
420            return visitNodes(cbNode, cbNodes, node.statements) ||
421                visitNode(cbNode, node.endOfFileToken);
422        },
423        [SyntaxKind.VariableStatement]: function forEachChildInVariableStatement<T>(node: VariableStatement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
424            return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
425                visitNodes(cbNode, cbNodes, node.modifiers) ||
426                visitNode(cbNode, node.declarationList);
427        },
428        [SyntaxKind.VariableDeclarationList]: function forEachChildInVariableDeclarationList<T>(node: VariableDeclarationList, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
429            return visitNodes(cbNode, cbNodes, node.declarations);
430        },
431        [SyntaxKind.ExpressionStatement]: function forEachChildInExpressionStatement<T>(node: ExpressionStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
432            return visitNode(cbNode, node.expression);
433        },
434        [SyntaxKind.IfStatement]: function forEachChildInIfStatement<T>(node: IfStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
435            return visitNode(cbNode, node.expression) ||
436                visitNode(cbNode, node.thenStatement) ||
437                visitNode(cbNode, node.elseStatement);
438        },
439        [SyntaxKind.DoStatement]: function forEachChildInDoStatement<T>(node: DoStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
440            return visitNode(cbNode, node.statement) ||
441                visitNode(cbNode, node.expression);
442        },
443        [SyntaxKind.WhileStatement]: function forEachChildInWhileStatement<T>(node: WhileStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
444            return visitNode(cbNode, node.expression) ||
445                visitNode(cbNode, node.statement);
446        },
447        [SyntaxKind.ForStatement]: function forEachChildInForStatement<T>(node: ForStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
448            return visitNode(cbNode, node.initializer) ||
449                visitNode(cbNode, node.condition) ||
450                visitNode(cbNode, node.incrementor) ||
451                visitNode(cbNode, node.statement);
452        },
453        [SyntaxKind.ForInStatement]: function forEachChildInForInStatement<T>(node: ForInStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
454            return visitNode(cbNode, node.initializer) ||
455                visitNode(cbNode, node.expression) ||
456                visitNode(cbNode, node.statement);
457        },
458        [SyntaxKind.ForOfStatement]: function forEachChildInForOfStatement<T>(node: ForOfStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
459            return visitNode(cbNode, node.awaitModifier) ||
460                visitNode(cbNode, node.initializer) ||
461                visitNode(cbNode, node.expression) ||
462                visitNode(cbNode, node.statement);
463        },
464        [SyntaxKind.ContinueStatement]: forEachChildInContinueOrBreakStatement,
465        [SyntaxKind.BreakStatement]: forEachChildInContinueOrBreakStatement,
466        [SyntaxKind.ReturnStatement]: function forEachChildInReturnStatement<T>(node: ReturnStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
467            return visitNode(cbNode, node.expression);
468        },
469        [SyntaxKind.WithStatement]: function forEachChildInWithStatement<T>(node: WithStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
470            return visitNode(cbNode, node.expression) ||
471                visitNode(cbNode, node.statement);
472        },
473        [SyntaxKind.SwitchStatement]: function forEachChildInSwitchStatement<T>(node: SwitchStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
474            return visitNode(cbNode, node.expression) ||
475                visitNode(cbNode, node.caseBlock);
476        },
477        [SyntaxKind.CaseBlock]: function forEachChildInCaseBlock<T>(node: CaseBlock, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
478            return visitNodes(cbNode, cbNodes, node.clauses);
479        },
480        [SyntaxKind.CaseClause]: function forEachChildInCaseClause<T>(node: CaseClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
481            return visitNode(cbNode, node.expression) ||
482                visitNodes(cbNode, cbNodes, node.statements);
483        },
484        [SyntaxKind.DefaultClause]: function forEachChildInDefaultClause<T>(node: DefaultClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
485            return visitNodes(cbNode, cbNodes, node.statements);
486        },
487        [SyntaxKind.LabeledStatement]: function forEachChildInLabeledStatement<T>(node: LabeledStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
488            return visitNode(cbNode, node.label) ||
489                visitNode(cbNode, node.statement);
490        },
491        [SyntaxKind.ThrowStatement]: function forEachChildInThrowStatement<T>(node: ThrowStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
492            return visitNode(cbNode, node.expression);
493        },
494        [SyntaxKind.TryStatement]: function forEachChildInTryStatement<T>(node: TryStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
495            return visitNode(cbNode, node.tryBlock) ||
496                visitNode(cbNode, node.catchClause) ||
497                visitNode(cbNode, node.finallyBlock);
498        },
499        [SyntaxKind.CatchClause]: function forEachChildInCatchClause<T>(node: CatchClause, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
500            return visitNode(cbNode, node.variableDeclaration) ||
501                visitNode(cbNode, node.block);
502        },
503        [SyntaxKind.Decorator]: function forEachChildInDecorator<T>(node: Decorator, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
504            return visitNode(cbNode, node.expression);
505        },
506        [SyntaxKind.ClassDeclaration]: forEachChildInClassDeclarationOrExpression,
507        [SyntaxKind.ClassExpression]: forEachChildInClassDeclarationOrExpression,
508        [SyntaxKind.StructDeclaration]: forEachChildInClassDeclarationOrExpression,
509        [SyntaxKind.InterfaceDeclaration]: function forEachChildInInterfaceDeclaration<T>(node: InterfaceDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
510            return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
511                visitNodes(cbNode, cbNodes, node.modifiers) ||
512                visitNode(cbNode, node.name) ||
513                visitNodes(cbNode, cbNodes, node.typeParameters) ||
514                visitNodes(cbNode, cbNodes, node.heritageClauses) ||
515                visitNodes(cbNode, cbNodes, node.members);
516        },
517        [SyntaxKind.TypeAliasDeclaration]: function forEachChildInTypeAliasDeclaration<T>(node: TypeAliasDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
518            return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
519                visitNodes(cbNode, cbNodes, node.modifiers) ||
520                visitNode(cbNode, node.name) ||
521                visitNodes(cbNode, cbNodes, node.typeParameters) ||
522                visitNode(cbNode, node.type);
523        },
524        [SyntaxKind.EnumDeclaration]: function forEachChildInEnumDeclaration<T>(node: EnumDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
525            return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
526                visitNodes(cbNode, cbNodes, node.modifiers) ||
527                visitNode(cbNode, node.name) ||
528                visitNodes(cbNode, cbNodes, node.members);
529        },
530        [SyntaxKind.EnumMember]: function forEachChildInEnumMember<T>(node: EnumMember, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
531            return visitNode(cbNode, node.name) ||
532                visitNode(cbNode, node.initializer);
533        },
534        [SyntaxKind.ModuleDeclaration]: function forEachChildInModuleDeclaration<T>(node: ModuleDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
535            return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
536                visitNodes(cbNode, cbNodes, node.modifiers) ||
537                visitNode(cbNode, node.name) ||
538                visitNode(cbNode, node.body);
539        },
540        [SyntaxKind.ImportEqualsDeclaration]: function forEachChildInImportEqualsDeclaration<T>(node: ImportEqualsDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
541            return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
542                visitNodes(cbNode, cbNodes, node.modifiers) ||
543                visitNode(cbNode, node.name) ||
544                visitNode(cbNode, node.moduleReference);
545        },
546        [SyntaxKind.ImportDeclaration]: function forEachChildInImportDeclaration<T>(node: ImportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
547            return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
548                visitNodes(cbNode, cbNodes, node.modifiers) ||
549                visitNode(cbNode, node.importClause) ||
550                visitNode(cbNode, node.moduleSpecifier) ||
551                visitNode(cbNode, node.assertClause);
552        },
553        [SyntaxKind.ImportClause]: function forEachChildInImportClause<T>(node: ImportClause, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
554            return visitNode(cbNode, node.name) ||
555                visitNode(cbNode, node.namedBindings);
556        },
557        [SyntaxKind.AssertClause]: function forEachChildInAssertClause<T>(node: AssertClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
558            return visitNodes(cbNode, cbNodes, node.elements);
559        },
560        [SyntaxKind.AssertEntry]: function forEachChildInAssertEntry<T>(node: AssertEntry, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
561            return visitNode(cbNode, node.name) ||
562                visitNode(cbNode, node.value);
563        },
564        [SyntaxKind.NamespaceExportDeclaration]: function forEachChildInNamespaceExportDeclaration<T>(node: NamespaceExportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
565            return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
566                visitNode(cbNode, node.name);
567        },
568        [SyntaxKind.NamespaceImport]: function forEachChildInNamespaceImport<T>(node: NamespaceImport, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
569            return visitNode(cbNode, node.name);
570        },
571        [SyntaxKind.NamespaceExport]: function forEachChildInNamespaceExport<T>(node: NamespaceExport, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
572            return visitNode(cbNode, node.name);
573        },
574        [SyntaxKind.NamedImports]: forEachChildInNamedImportsOrExports,
575        [SyntaxKind.NamedExports]: forEachChildInNamedImportsOrExports,
576        [SyntaxKind.ExportDeclaration]: function forEachChildInExportDeclaration<T>(node: ExportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
577            return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
578                visitNodes(cbNode, cbNodes, node.modifiers) ||
579                visitNode(cbNode, node.exportClause) ||
580                visitNode(cbNode, node.moduleSpecifier) ||
581                visitNode(cbNode, node.assertClause);
582        },
583        [SyntaxKind.ImportSpecifier]: forEachChildInImportOrExportSpecifier,
584        [SyntaxKind.ExportSpecifier]: forEachChildInImportOrExportSpecifier,
585        [SyntaxKind.ExportAssignment]: function forEachChildInExportAssignment<T>(node: ExportAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
586            return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
587                visitNodes(cbNode, cbNodes, node.modifiers) ||
588                visitNode(cbNode, node.expression);
589        },
590        [SyntaxKind.TemplateExpression]: function forEachChildInTemplateExpression<T>(node: TemplateExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
591            return visitNode(cbNode, node.head) ||
592                visitNodes(cbNode, cbNodes, node.templateSpans);
593        },
594        [SyntaxKind.TemplateSpan]: function forEachChildInTemplateSpan<T>(node: TemplateSpan, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
595            return visitNode(cbNode, node.expression) ||
596                visitNode(cbNode, node.literal);
597        },
598        [SyntaxKind.TemplateLiteralType]: function forEachChildInTemplateLiteralType<T>(node: TemplateLiteralTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
599            return visitNode(cbNode, node.head) ||
600                visitNodes(cbNode, cbNodes, node.templateSpans);
601        },
602        [SyntaxKind.TemplateLiteralTypeSpan]: function forEachChildInTemplateLiteralTypeSpan<T>(node: TemplateLiteralTypeSpan, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
603            return visitNode(cbNode, node.type) ||
604                visitNode(cbNode, node.literal);
605        },
606        [SyntaxKind.ComputedPropertyName]: function forEachChildInComputedPropertyName<T>(node: ComputedPropertyName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
607            return visitNode(cbNode, node.expression);
608        },
609        [SyntaxKind.HeritageClause]: function forEachChildInHeritageClause<T>(node: HeritageClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
610            return visitNodes(cbNode, cbNodes, node.types);
611        },
612        [SyntaxKind.ExpressionWithTypeArguments]: function forEachChildInExpressionWithTypeArguments<T>(node: ExpressionWithTypeArguments, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
613            return visitNode(cbNode, node.expression) ||
614                visitNodes(cbNode, cbNodes, node.typeArguments);
615        },
616        [SyntaxKind.ExternalModuleReference]: function forEachChildInExternalModuleReference<T>(node: ExternalModuleReference, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
617            return visitNode(cbNode, node.expression);
618        },
619        [SyntaxKind.MissingDeclaration]: function forEachChildInMissingDeclaration<T>(node: MissingDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
620            return visitNodes(cbNode, cbNodes, node.illegalDecorators) ||
621                visitNodes(cbNode, cbNodes, node.modifiers);
622        },
623        [SyntaxKind.CommaListExpression]: function forEachChildInCommaListExpression<T>(node: CommaListExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
624            return visitNodes(cbNode, cbNodes, node.elements);
625        },
626        [SyntaxKind.JsxElement]: function forEachChildInJsxElement<T>(node: JsxElement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
627            return visitNode(cbNode, node.openingElement) ||
628                visitNodes(cbNode, cbNodes, node.children) ||
629                visitNode(cbNode, node.closingElement);
630        },
631        [SyntaxKind.JsxFragment]: function forEachChildInJsxFragment<T>(node: JsxFragment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
632            return visitNode(cbNode, node.openingFragment) ||
633                visitNodes(cbNode, cbNodes, node.children) ||
634                visitNode(cbNode, node.closingFragment);
635        },
636        [SyntaxKind.JsxSelfClosingElement]: forEachChildInJsxOpeningOrSelfClosingElement,
637        [SyntaxKind.JsxOpeningElement]: forEachChildInJsxOpeningOrSelfClosingElement,
638        [SyntaxKind.JsxAttributes]: function forEachChildInJsxAttributes<T>(node: JsxAttributes, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
639            return visitNodes(cbNode, cbNodes, node.properties);
640        },
641        [SyntaxKind.JsxAttribute]: function forEachChildInJsxAttribute<T>(node: JsxAttribute, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
642            return visitNode(cbNode, node.name) ||
643                visitNode(cbNode, node.initializer);
644        },
645        [SyntaxKind.JsxSpreadAttribute]: function forEachChildInJsxSpreadAttribute<T>(node: JsxSpreadAttribute, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
646            return visitNode(cbNode, node.expression);
647        },
648        [SyntaxKind.JsxExpression]: function forEachChildInJsxExpression<T>(node: JsxExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
649            return visitNode(cbNode, node.dotDotDotToken) ||
650                visitNode(cbNode, node.expression);
651        },
652        [SyntaxKind.JsxClosingElement]: function forEachChildInJsxClosingElement<T>(node: JsxClosingElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
653            return visitNode(cbNode, node.tagName);
654        },
655        [SyntaxKind.OptionalType]: forEachChildInOptionalRestOrJSDocParameterModifier,
656        [SyntaxKind.RestType]: forEachChildInOptionalRestOrJSDocParameterModifier,
657        [SyntaxKind.JSDocTypeExpression]: forEachChildInOptionalRestOrJSDocParameterModifier,
658        [SyntaxKind.JSDocNonNullableType]: forEachChildInOptionalRestOrJSDocParameterModifier,
659        [SyntaxKind.JSDocNullableType]: forEachChildInOptionalRestOrJSDocParameterModifier,
660        [SyntaxKind.JSDocOptionalType]: forEachChildInOptionalRestOrJSDocParameterModifier,
661        [SyntaxKind.JSDocVariadicType]: forEachChildInOptionalRestOrJSDocParameterModifier,
662        [SyntaxKind.JSDocFunctionType]: function forEachChildInJSDocFunctionType<T>(node: JSDocFunctionType, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
663            return visitNodes(cbNode, cbNodes, node.parameters) ||
664                visitNode(cbNode, node.type);
665        },
666        [SyntaxKind.JSDoc]: function forEachChildInJSDoc<T>(node: JSDoc, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
667            return (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment))
668                || visitNodes(cbNode, cbNodes, node.tags);
669        },
670        [SyntaxKind.JSDocSeeTag]: function forEachChildInJSDocSeeTag<T>(node: JSDocSeeTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
671            return visitNode(cbNode, node.tagName) ||
672                visitNode(cbNode, node.name) ||
673                (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
674        },
675        [SyntaxKind.JSDocNameReference]: function forEachChildInJSDocNameReference<T>(node: JSDocNameReference, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
676            return visitNode(cbNode, node.name);
677        },
678        [SyntaxKind.JSDocMemberName]: function forEachChildInJSDocMemberName<T>(node: JSDocMemberName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
679            return visitNode(cbNode, node.left) ||
680                visitNode(cbNode, node.right);
681        },
682        [SyntaxKind.JSDocParameterTag]: forEachChildInJSDocParameterOrPropertyTag,
683        [SyntaxKind.JSDocPropertyTag]: forEachChildInJSDocParameterOrPropertyTag,
684        [SyntaxKind.JSDocAuthorTag]: function forEachChildInJSDocAuthorTag<T>(node: JSDocAuthorTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
685            return visitNode(cbNode, node.tagName) ||
686                (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
687        },
688        [SyntaxKind.JSDocImplementsTag]: function forEachChildInJSDocImplementsTag<T>(node: JSDocImplementsTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
689            return visitNode(cbNode, node.tagName) ||
690                visitNode(cbNode, node.class) ||
691                (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
692        },
693        [SyntaxKind.JSDocAugmentsTag]: function forEachChildInJSDocAugmentsTag<T>(node: JSDocAugmentsTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
694            return visitNode(cbNode, node.tagName) ||
695                visitNode(cbNode, node.class) ||
696                (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
697        },
698        [SyntaxKind.JSDocTemplateTag]: function forEachChildInJSDocTemplateTag<T>(node: JSDocTemplateTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
699            return visitNode(cbNode, node.tagName) ||
700                visitNode(cbNode, node.constraint) ||
701                visitNodes(cbNode, cbNodes, node.typeParameters) ||
702                (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
703        },
704        [SyntaxKind.JSDocTypedefTag]: function forEachChildInJSDocTypedefTag<T>(node: JSDocTypedefTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
705            return visitNode(cbNode, node.tagName) ||
706                (node.typeExpression &&
707                    node.typeExpression.kind === SyntaxKind.JSDocTypeExpression
708                    ? visitNode(cbNode, node.typeExpression) ||
709                    visitNode(cbNode, node.fullName) ||
710                    (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment))
711                    : visitNode(cbNode, node.fullName) ||
712                    visitNode(cbNode, node.typeExpression) ||
713                    (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)));
714        },
715        [SyntaxKind.JSDocCallbackTag]: function forEachChildInJSDocCallbackTag<T>(node: JSDocCallbackTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
716            return visitNode(cbNode, node.tagName) ||
717                visitNode(cbNode, node.fullName) ||
718                visitNode(cbNode, node.typeExpression) ||
719                (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
720        },
721        [SyntaxKind.JSDocReturnTag]: forEachChildInJSDocReturnTag,
722        [SyntaxKind.JSDocTypeTag]: forEachChildInJSDocReturnTag,
723        [SyntaxKind.JSDocThisTag]: forEachChildInJSDocReturnTag,
724        [SyntaxKind.JSDocEnumTag]: forEachChildInJSDocReturnTag,
725        [SyntaxKind.JSDocSignature]: function forEachChildInJSDocSignature<T>(node: JSDocSignature, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
726            return forEach(node.typeParameters, cbNode) ||
727                forEach(node.parameters, cbNode) ||
728                visitNode(cbNode, node.type);
729        },
730        [SyntaxKind.JSDocLink]: forEachChildInJSDocLinkCodeOrPlain,
731        [SyntaxKind.JSDocLinkCode]: forEachChildInJSDocLinkCodeOrPlain,
732        [SyntaxKind.JSDocLinkPlain]: forEachChildInJSDocLinkCodeOrPlain,
733        [SyntaxKind.JSDocTypeLiteral]: function forEachChildInJSDocTypeLiteral<T>(node: JSDocTypeLiteral, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
734            return forEach(node.jsDocPropertyTags, cbNode);
735        },
736        [SyntaxKind.JSDocTag]: forEachChildInJSDocTag,
737        [SyntaxKind.JSDocClassTag]: forEachChildInJSDocTag,
738        [SyntaxKind.JSDocPublicTag]: forEachChildInJSDocTag,
739        [SyntaxKind.JSDocPrivateTag]: forEachChildInJSDocTag,
740        [SyntaxKind.JSDocProtectedTag]: forEachChildInJSDocTag,
741        [SyntaxKind.JSDocReadonlyTag]: forEachChildInJSDocTag,
742        [SyntaxKind.JSDocDeprecatedTag]: forEachChildInJSDocTag,
743        [SyntaxKind.JSDocOverrideTag]: forEachChildInJSDocTag,
744        [SyntaxKind.PartiallyEmittedExpression]: forEachChildInPartiallyEmittedExpression,
745    };
746
747    // shared
748
749    function forEachChildInCallOrConstructSignature<T>(node: CallSignatureDeclaration | ConstructSignatureDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
750        return visitNodes(cbNode, cbNodes, node.typeParameters) ||
751            visitNodes(cbNode, cbNodes, node.parameters) ||
752            visitNode(cbNode, node.type);
753    }
754
755    function forEachChildInUnionOrIntersectionType<T>(node: UnionTypeNode | IntersectionTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
756        return visitNodes(cbNode, cbNodes, node.types);
757    }
758
759    function forEachChildInParenthesizedTypeOrTypeOperator<T>(node: ParenthesizedTypeNode | TypeOperatorNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
760        return visitNode(cbNode, node.type);
761    }
762
763    function forEachChildInObjectOrArrayBindingPattern<T>(node: BindingPattern, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
764        return visitNodes(cbNode, cbNodes, node.elements);
765    }
766
767    function forEachChildInCallOrNewExpression<T>(node: CallExpression | NewExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
768        return visitNode(cbNode, node.expression) ||
769            // TODO: should we separate these branches out?
770            visitNode(cbNode, (node as CallExpression).questionDotToken) ||
771            visitNodes(cbNode, cbNodes, node.typeArguments) ||
772            visitNodes(cbNode, cbNodes, node.arguments);
773    }
774
775    function forEachChildInBlock<T>(node: Block | ModuleBlock, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
776        return visitNodes(cbNode, cbNodes, node.statements);
777    }
778
779    function forEachChildInContinueOrBreakStatement<T>(node: ContinueStatement | BreakStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
780        return visitNode(cbNode, node.label);
781    }
782
783    function forEachChildInClassDeclarationOrExpression<T>(node: ClassDeclaration | ClassExpression | StructDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
784        return visitNodes(cbNode, cbNodes, node.modifiers) ||
785            visitNode(cbNode, node.name) ||
786            visitNodes(cbNode, cbNodes, node.typeParameters) ||
787            visitNodes(cbNode, cbNodes, node.heritageClauses) ||
788            visitNodes(cbNode, cbNodes, node.members);
789    }
790
791    function forEachChildInNamedImportsOrExports<T>(node: NamedImports | NamedExports, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
792        return visitNodes(cbNode, cbNodes, node.elements);
793    }
794
795    function forEachChildInImportOrExportSpecifier<T>(node: ImportSpecifier | ExportSpecifier, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
796        return visitNode(cbNode, node.propertyName) ||
797            visitNode(cbNode, node.name);
798    }
799
800    function forEachChildInJsxOpeningOrSelfClosingElement<T>(node: JsxOpeningLikeElement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
801        return visitNode(cbNode, node.tagName) ||
802            visitNodes(cbNode, cbNodes, node.typeArguments) ||
803            visitNode(cbNode, node.attributes);
804    }
805
806    function forEachChildInOptionalRestOrJSDocParameterModifier<T>(node: OptionalTypeNode | RestTypeNode | JSDocTypeExpression | JSDocNullableType | JSDocNonNullableType | JSDocOptionalType | JSDocVariadicType, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
807        return visitNode(cbNode, node.type);
808    }
809
810    function forEachChildInJSDocParameterOrPropertyTag<T>(node: JSDocParameterTag | JSDocPropertyTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
811        return visitNode(cbNode, node.tagName) ||
812            (node.isNameFirst
813                ? visitNode(cbNode, node.name) || visitNode(cbNode, node.typeExpression)
814                : visitNode(cbNode, node.typeExpression) || visitNode(cbNode, node.name)) ||
815            (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
816    }
817
818    function forEachChildInJSDocReturnTag<T>(node: JSDocReturnTag | JSDocTypeTag | JSDocThisTag | JSDocEnumTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
819        return visitNode(cbNode, node.tagName) ||
820            visitNode(cbNode, node.typeExpression) ||
821            (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
822    }
823
824    function forEachChildInJSDocLinkCodeOrPlain<T>(node: JSDocLink | JSDocLinkCode | JSDocLinkPlain, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
825        return visitNode(cbNode, node.name);
826    }
827
828    function forEachChildInJSDocTag<T>(node: JSDocUnknownTag | JSDocClassTag | JSDocPublicTag | JSDocPrivateTag | JSDocProtectedTag | JSDocReadonlyTag | JSDocDeprecatedTag | JSDocOverrideTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
829        return visitNode(cbNode, node.tagName)
830            || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment));
831    }
832
833    function forEachChildInPartiallyEmittedExpression<T>(node: PartiallyEmittedExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
834        return visitNode(cbNode, node.expression);
835    }
836
837    /**
838     * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes
839     * stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise,
840     * embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns
841     * a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned.
842     *
843     * @param node a given node to visit its children
844     * @param cbNode a callback to be invoked for all child nodes
845     * @param cbNodes a callback to be invoked for embedded array
846     *
847     * @remarks `forEachChild` must visit the children of a node in the order
848     * that they appear in the source code. The language service depends on this property to locate nodes by position.
849     */
850    export function forEachChild<T>(node: Node, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
851        if (node === undefined || node.kind <= SyntaxKind.LastToken) {
852            return;
853        }
854        const fn = (forEachChildTable as Record<SyntaxKind, ForEachChildFunction<any>>)[node.kind];
855        return fn === undefined ? undefined : fn(node, cbNode, cbNodes);
856    }
857
858    /** @internal */
859    /**
860     * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes
861     * stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; additionally,
862     * unlike `forEachChild`, embedded arrays are flattened and the 'cbNode' callback is invoked for each element.
863     *  If a callback returns a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned.
864     *
865     * @param node a given node to visit its children
866     * @param cbNode a callback to be invoked for all child nodes
867     * @param cbNodes a callback to be invoked for embedded array
868     *
869     * @remarks Unlike `forEachChild`, `forEachChildRecursively` handles recursively invoking the traversal on each child node found,
870     * and while doing so, handles traversing the structure without relying on the callstack to encode the tree structure.
871     */
872    export function forEachChildRecursively<T>(rootNode: Node, cbNode: (node: Node, parent: Node) => T | "skip" | undefined, cbNodes?: (nodes: NodeArray<Node>, parent: Node) => T | "skip" | undefined): T | undefined {
873        const queue: (Node | NodeArray<Node>)[] = gatherPossibleChildren(rootNode);
874        const parents: Node[] = []; // tracks parent references for elements in queue
875        while (parents.length < queue.length) {
876            parents.push(rootNode);
877        }
878        while (queue.length !== 0) {
879            const current = queue.pop()!;
880            const parent = parents.pop()!;
881            if (isArray(current)) {
882                if (cbNodes) {
883                    const res = cbNodes(current, parent);
884                    if (res) {
885                        if (res === "skip") continue;
886                        return res;
887                    }
888                }
889                for (let i = current.length - 1; i >= 0; --i) {
890                    queue.push(current[i]);
891                    parents.push(parent);
892                }
893            }
894            else {
895                const res = cbNode(current, parent);
896                if (res) {
897                    if (res === "skip") continue;
898                    return res;
899                }
900                if (current.kind >= SyntaxKind.FirstNode) {
901                    // add children in reverse order to the queue, so popping gives the first child
902                    for (const child of gatherPossibleChildren(current)) {
903                        queue.push(child);
904                        parents.push(current);
905                    }
906                }
907            }
908        }
909    }
910
911    function gatherPossibleChildren(node: Node) {
912        const children: (Node | NodeArray<Node>)[] = [];
913        forEachChild(node, addWorkItem, addWorkItem); // By using a stack above and `unshift` here, we emulate a depth-first preorder traversal
914        return children;
915
916        function addWorkItem(n: Node | NodeArray<Node>) {
917            children.unshift(n);
918        }
919    }
920
921    export interface CreateSourceFileOptions {
922        languageVersion: ScriptTarget;
923        /**
924         * Controls the format the file is detected as - this can be derived from only the path
925         * and files on disk, but needs to be done with a module resolution cache in scope to be performant.
926         * This is usually `undefined` for compilations that do not have `moduleResolution` values of `node16` or `nodenext`.
927         */
928        impliedNodeFormat?: ModuleKind.ESNext | ModuleKind.CommonJS;
929        /**
930         * Controls how module-y-ness is set for the given file. Usually the result of calling
931         * `getSetExternalModuleIndicator` on a valid `CompilerOptions` object. If not present, the default
932         * check specified by `isFileProbablyExternalModule` will be used to set the field.
933         */
934        setExternalModuleIndicator?: (file: SourceFile) => void;
935        /*@internal*/ packageJsonLocations?: readonly string[];
936        /*@internal*/ packageJsonScope?: PackageJsonInfo;
937    }
938
939    function setExternalModuleIndicator(sourceFile: SourceFile) {
940        sourceFile.externalModuleIndicator = isFileProbablyExternalModule(sourceFile);
941    }
942
943    let sourceFileCompilerOptions: CompilerOptions;
944    export function createSourceFile(fileName: string, sourceText: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, setParentNodes = false, scriptKind?: ScriptKind, options?: CompilerOptions): SourceFile {
945        tracing?.push(tracing.Phase.Parse, "createSourceFile", { path: fileName }, /*separateBeginAndEnd*/ true);
946        performance.mark("beforeParse");
947        let result: SourceFile;
948        sourceFileCompilerOptions = options ?? defaultInitCompilerOptions;
949        perfLogger.logStartParseSourceFile(fileName);
950        const {
951            languageVersion,
952            setExternalModuleIndicator: overrideSetExternalModuleIndicator,
953            impliedNodeFormat: format
954        } = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions : ({ languageVersion: languageVersionOrOptions } as CreateSourceFileOptions);
955        if (languageVersion === ScriptTarget.JSON) {
956            result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, ScriptKind.JSON, noop);
957        }
958        else {
959            const setIndicator = format === undefined ? overrideSetExternalModuleIndicator : (file: SourceFile) => {
960                file.impliedNodeFormat = format;
961                return (overrideSetExternalModuleIndicator || setExternalModuleIndicator)(file);
962            };
963            result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind, setIndicator);
964        }
965        perfLogger.logStopParseSourceFile();
966
967        performance.mark("afterParse");
968        performance.measure("Parse", "beforeParse", "afterParse");
969        tracing?.pop();
970        return result;
971    }
972
973    export function parseIsolatedEntityName(text: string, languageVersion: ScriptTarget): EntityName | undefined {
974        return Parser.parseIsolatedEntityName(text, languageVersion);
975    }
976
977    /**
978     * Parse json text into SyntaxTree and return node and parse errors if any
979     * @param fileName
980     * @param sourceText
981     */
982    export function parseJsonText(fileName: string, sourceText: string): JsonSourceFile {
983        return Parser.parseJsonText(fileName, sourceText);
984    }
985
986    // See also `isExternalOrCommonJsModule` in utilities.ts
987    export function isExternalModule(file: SourceFile): boolean {
988        return file.externalModuleIndicator !== undefined;
989    }
990
991    // Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter
992    // indicates what changed between the 'text' that this SourceFile has and the 'newText'.
993    // The SourceFile will be created with the compiler attempting to reuse as many nodes from
994    // this file as possible.
995    //
996    // Note: this function mutates nodes from this SourceFile. That means any existing nodes
997    // from this SourceFile that are being held onto may change as a result (including
998    // becoming detached from any SourceFile).  It is recommended that this SourceFile not
999    // be used once 'update' is called on it.
1000    export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks = false, option?: CompilerOptions): SourceFile {
1001        sourceFileCompilerOptions = option ?? defaultInitCompilerOptions;
1002        const newSourceFile = IncrementalParser.updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks);
1003        // 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.
1004        // We will manually port the flag to the new source file.
1005        (newSourceFile as Mutable<SourceFile>).flags |= (sourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags);
1006        return newSourceFile;
1007    }
1008
1009    /* @internal */
1010    export function parseIsolatedJSDocComment(content: string, start?: number, length?: number) {
1011        const result = Parser.JSDocParser.parseIsolatedJSDocComment(content, start, length);
1012        if (result && result.jsDoc) {
1013            // because the jsDocComment was parsed out of the source file, it might
1014            // not be covered by the fixupParentReferences.
1015            Parser.fixupParentReferences(result.jsDoc);
1016        }
1017
1018        return result;
1019    }
1020
1021    /* @internal */
1022    // Exposed only for testing.
1023    export function parseJSDocTypeExpressionForTests(content: string, start?: number, length?: number) {
1024        return Parser.JSDocParser.parseJSDocTypeExpressionForTests(content, start, length);
1025    }
1026
1027    // Implement the parser as a singleton module.  We do this for perf reasons because creating
1028    // parser instances can actually be expensive enough to impact us on projects with many source
1029    // files.
1030    namespace Parser {
1031        // Share a single scanner across all calls to parse a source file.  This helps speed things
1032        // up by avoiding the cost of creating/compiling scanners over and over again.
1033        const scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ true);
1034
1035        const disallowInAndDecoratorContext = NodeFlags.DisallowInContext | NodeFlags.DecoratorContext;
1036
1037        // capture constructors in 'initializeState' to avoid null checks
1038        let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
1039        let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
1040        let IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
1041        let PrivateIdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
1042        let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
1043
1044        function countNode(node: Node) {
1045            nodeCount++;
1046            return node;
1047        }
1048
1049        // Rather than using `createBaseNodeFactory` here, we establish a `BaseNodeFactory` that closes over the
1050        // constructors above, which are reset each time `initializeState` is called.
1051        const baseNodeFactory: BaseNodeFactory = {
1052            createBaseSourceFileNode: kind => countNode(new SourceFileConstructor(kind, /*pos*/ 0, /*end*/ 0)),
1053            createBaseIdentifierNode: kind => countNode(new IdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0)),
1054            createBasePrivateIdentifierNode: kind => countNode(new PrivateIdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0)),
1055            createBaseTokenNode: kind => countNode(new TokenConstructor(kind, /*pos*/ 0, /*end*/ 0)),
1056            createBaseNode: kind => countNode(new NodeConstructor(kind, /*pos*/ 0, /*end*/ 0))
1057        };
1058
1059        const factory = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules | NodeFactoryFlags.NoNodeConverters | NodeFactoryFlags.NoOriginalNode, baseNodeFactory);
1060
1061        let fileName: string;
1062        let sourceFlags: NodeFlags;
1063        let sourceText: string;
1064        let languageVersion: ScriptTarget;
1065        let scriptKind: ScriptKind;
1066        let languageVariant: LanguageVariant;
1067        let parseDiagnostics: DiagnosticWithDetachedLocation[];
1068        let jsDocDiagnostics: DiagnosticWithDetachedLocation[];
1069        let syntaxCursor: IncrementalParser.SyntaxCursor | undefined;
1070
1071        let currentToken: SyntaxKind;
1072        let nodeCount: number;
1073        let identifiers: ESMap<string, string>;
1074        let privateIdentifiers: ESMap<string, string>;
1075        let identifierCount: number;
1076
1077        let parsingContext: ParsingContext;
1078
1079        let notParenthesizedArrow: Set<number> | undefined;
1080
1081        // Flags that dictate what parsing context we're in.  For example:
1082        // Whether or not we are in strict parsing mode.  All that changes in strict parsing mode is
1083        // that some tokens that would be considered identifiers may be considered keywords.
1084        //
1085        // When adding more parser context flags, consider which is the more common case that the
1086        // flag will be in.  This should be the 'false' state for that flag.  The reason for this is
1087        // that we don't store data in our nodes unless the value is in the *non-default* state.  So,
1088        // for example, more often than code 'allows-in' (or doesn't 'disallow-in').  We opt for
1089        // 'disallow-in' set to 'false'.  Otherwise, if we had 'allowsIn' set to 'true', then almost
1090        // all nodes would need extra state on them to store this info.
1091        //
1092        // Note: 'allowIn' and 'allowYield' track 1:1 with the [in] and [yield] concepts in the ES6
1093        // grammar specification.
1094        //
1095        // An important thing about these context concepts.  By default they are effectively inherited
1096        // while parsing through every grammar production.  i.e. if you don't change them, then when
1097        // you parse a sub-production, it will have the same context values as the parent production.
1098        // This is great most of the time.  After all, consider all the 'expression' grammar productions
1099        // and how nearly all of them pass along the 'in' and 'yield' context values:
1100        //
1101        // EqualityExpression[In, Yield] :
1102        //      RelationalExpression[?In, ?Yield]
1103        //      EqualityExpression[?In, ?Yield] == RelationalExpression[?In, ?Yield]
1104        //      EqualityExpression[?In, ?Yield] != RelationalExpression[?In, ?Yield]
1105        //      EqualityExpression[?In, ?Yield] === RelationalExpression[?In, ?Yield]
1106        //      EqualityExpression[?In, ?Yield] !== RelationalExpression[?In, ?Yield]
1107        //
1108        // Where you have to be careful is then understanding what the points are in the grammar
1109        // where the values are *not* passed along.  For example:
1110        //
1111        // SingleNameBinding[Yield,GeneratorParameter]
1112        //      [+GeneratorParameter]BindingIdentifier[Yield] Initializer[In]opt
1113        //      [~GeneratorParameter]BindingIdentifier[?Yield]Initializer[In, ?Yield]opt
1114        //
1115        // Here this is saying that if the GeneratorParameter context flag is set, that we should
1116        // explicitly set the 'yield' context flag to false before calling into the BindingIdentifier
1117        // and we should explicitly unset the 'yield' context flag before calling into the Initializer.
1118        // production.  Conversely, if the GeneratorParameter context flag is not set, then we
1119        // should leave the 'yield' context flag alone.
1120        //
1121        // Getting this all correct is tricky and requires careful reading of the grammar to
1122        // understand when these values should be changed versus when they should be inherited.
1123        //
1124        // Note: it should not be necessary to save/restore these flags during speculative/lookahead
1125        // parsing.  These context flags are naturally stored and restored through normal recursive
1126        // descent parsing and unwinding.
1127        let contextFlags: NodeFlags;
1128
1129        let etsFlags: EtsFlags;
1130
1131        // Indicates whether we are currently parsing top-level statements.
1132        let topLevel = true;
1133
1134        // Whether or not we've had a parse error since creating the last AST node.  If we have
1135        // encountered an error, it will be stored on the next AST node we create.  Parse errors
1136        // can be broken down into three categories:
1137        //
1138        // 1) An error that occurred during scanning.  For example, an unterminated literal, or a
1139        //    character that was completely not understood.
1140        //
1141        // 2) A token was expected, but was not present.  This type of error is commonly produced
1142        //    by the 'parseExpected' function.
1143        //
1144        // 3) A token was present that no parsing function was able to consume.  This type of error
1145        //    only occurs in the 'abortParsingListOrMoveToNextToken' function when the parser
1146        //    decides to skip the token.
1147        //
1148        // In all of these cases, we want to mark the next node as having had an error before it.
1149        // With this mark, we can know in incremental settings if this node can be reused, or if
1150        // we have to reparse it.  If we don't keep this information around, we may just reuse the
1151        // node.  in that event we would then not produce the same errors as we did before, causing
1152        // significant confusion problems.
1153        //
1154        // Note: it is necessary that this value be saved/restored during speculative/lookahead
1155        // parsing.  During lookahead parsing, we will often create a node.  That node will have
1156        // this value attached, and then this value will be set back to 'false'.  If we decide to
1157        // rewind, we must get back to the same value we had prior to the lookahead.
1158        //
1159        // Note: any errors at the end of the file that do not precede a regular node, should get
1160        // attached to the EOF token.
1161        let parseErrorBeforeNextFinishedNode = false;
1162
1163        let extendEtsComponentDeclaration: { name: string, type: string, instance: string } | undefined;
1164
1165        let stylesEtsComponentDeclaration: { name: string, type: string, instance: string } | undefined;
1166
1167        // A map to record file scope '@styles' function name
1168        const fileStylesComponents = new Map<string, SyntaxKind>();
1169
1170        let currentStructName: string | undefined;
1171
1172        let stateStylesRootNode: string | undefined;
1173
1174        // A map to record struct scope '@styles' method name
1175        const structStylesComponents = new Map<string, { structName: string, kind: SyntaxKind }>();
1176
1177        export function parseSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, syntaxCursor: IncrementalParser.SyntaxCursor | undefined, setParentNodes = false, scriptKind?: ScriptKind, setExternalModuleIndicatorOverride?: (file: SourceFile) => void): SourceFile {
1178            scriptKind = ensureScriptKind(fileName, scriptKind);
1179            if (scriptKind === ScriptKind.JSON) {
1180                const result = parseJsonText(fileName, sourceText, languageVersion, syntaxCursor, setParentNodes);
1181                convertToObjectWorker(result, result.statements[0]?.expression, result.parseDiagnostics, /*returnValue*/ false, /*knownRootOptions*/ undefined, /*jsonConversionNotifier*/ undefined);
1182                result.referencedFiles = emptyArray;
1183                result.typeReferenceDirectives = emptyArray;
1184                result.libReferenceDirectives = emptyArray;
1185                result.amdDependencies = emptyArray;
1186                result.hasNoDefaultLib = false;
1187                result.pragmas = emptyMap as ReadonlyPragmaMap;
1188                return result;
1189            }
1190
1191            initializeState(fileName, sourceText, languageVersion, syntaxCursor, scriptKind);
1192
1193            const result = parseSourceFileWorker(languageVersion, setParentNodes, scriptKind, setExternalModuleIndicatorOverride || setExternalModuleIndicator);
1194
1195            clearState();
1196
1197            return result;
1198        }
1199
1200        export function parseIsolatedEntityName(content: string, languageVersion: ScriptTarget): EntityName | undefined {
1201            // Choice of `isDeclarationFile` should be arbitrary
1202            initializeState("", content, languageVersion, /*syntaxCursor*/ undefined, ScriptKind.JS);
1203            // Prime the scanner.
1204            nextToken();
1205            const entityName = parseEntityName(/*allowReservedWords*/ true);
1206            const isInvalid = token() === SyntaxKind.EndOfFileToken && !parseDiagnostics.length;
1207            clearState();
1208            return isInvalid ? entityName : undefined;
1209        }
1210
1211        export function parseJsonText(fileName: string, sourceText: string, languageVersion: ScriptTarget = ScriptTarget.ES2015, syntaxCursor?: IncrementalParser.SyntaxCursor, setParentNodes = false): JsonSourceFile {
1212            initializeState(fileName, sourceText, languageVersion, syntaxCursor, ScriptKind.JSON);
1213            sourceFlags = contextFlags;
1214
1215            // Prime the scanner.
1216            nextToken();
1217            const pos = getNodePos();
1218            let statements, endOfFileToken;
1219            if (token() === SyntaxKind.EndOfFileToken) {
1220                statements = createNodeArray([], pos, pos);
1221                endOfFileToken = parseTokenNode<EndOfFileToken>();
1222            }
1223            else {
1224                // Loop and synthesize an ArrayLiteralExpression if there are more than
1225                // one top-level expressions to ensure all input text is consumed.
1226                let expressions: Expression[] | Expression | undefined;
1227                while (token() !== SyntaxKind.EndOfFileToken) {
1228                    let expression;
1229                    switch (token()) {
1230                        case SyntaxKind.OpenBracketToken:
1231                            expression = parseArrayLiteralExpression();
1232                            break;
1233                        case SyntaxKind.TrueKeyword:
1234                        case SyntaxKind.FalseKeyword:
1235                        case SyntaxKind.NullKeyword:
1236                            expression = parseTokenNode<BooleanLiteral | NullLiteral>();
1237                            break;
1238                        case SyntaxKind.MinusToken:
1239                            if (lookAhead(() => nextToken() === SyntaxKind.NumericLiteral && nextToken() !== SyntaxKind.ColonToken)) {
1240                                expression = parsePrefixUnaryExpression() as JsonMinusNumericLiteral;
1241                            }
1242                            else {
1243                                expression = parseObjectLiteralExpression();
1244                            }
1245                            break;
1246                        case SyntaxKind.NumericLiteral:
1247                        case SyntaxKind.StringLiteral:
1248                            if (lookAhead(() => nextToken() !== SyntaxKind.ColonToken)) {
1249                                expression = parseLiteralNode() as StringLiteral | NumericLiteral;
1250                                break;
1251                            }
1252                            // falls through
1253                        default:
1254                            expression = parseObjectLiteralExpression();
1255                            break;
1256                    }
1257
1258                    // Error recovery: collect multiple top-level expressions
1259                    if (expressions && isArray(expressions)) {
1260                        expressions.push(expression);
1261                    }
1262                    else if (expressions) {
1263                        expressions = [expressions, expression];
1264                    }
1265                    else {
1266                        expressions = expression;
1267                        if (token() !== SyntaxKind.EndOfFileToken) {
1268                            parseErrorAtCurrentToken(Diagnostics.Unexpected_token);
1269                        }
1270                    }
1271                }
1272
1273                const expression = isArray(expressions) ? finishNode(factory.createArrayLiteralExpression(expressions), pos) : Debug.checkDefined(expressions);
1274                const statement = factory.createExpressionStatement(expression) as JsonObjectExpressionStatement;
1275                finishNode(statement, pos);
1276                statements = createNodeArray([statement], pos);
1277                endOfFileToken = parseExpectedToken(SyntaxKind.EndOfFileToken, Diagnostics.Unexpected_token);
1278            }
1279
1280            // Set source file so that errors will be reported with this file name
1281            const sourceFile = createSourceFile(fileName, ScriptTarget.ES2015, ScriptKind.JSON, /*isDeclaration*/ false, statements, endOfFileToken, sourceFlags, noop);
1282
1283            if (setParentNodes) {
1284                fixupParentReferences(sourceFile);
1285            }
1286
1287            sourceFile.nodeCount = nodeCount;
1288            sourceFile.identifierCount = identifierCount;
1289            sourceFile.identifiers = identifiers;
1290            sourceFile.parseDiagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile);
1291            if (jsDocDiagnostics) {
1292                sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile);
1293            }
1294
1295            const result = sourceFile as JsonSourceFile;
1296            clearState();
1297            return result;
1298        }
1299
1300        function initializeState(_fileName: string, _sourceText: string, _languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor | undefined, _scriptKind: ScriptKind) {
1301            NodeConstructor = objectAllocator.getNodeConstructor();
1302            TokenConstructor = objectAllocator.getTokenConstructor();
1303            IdentifierConstructor = objectAllocator.getIdentifierConstructor();
1304            PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor();
1305            SourceFileConstructor = objectAllocator.getSourceFileConstructor();
1306
1307            fileName = normalizePath(_fileName);
1308            sourceText = _sourceText;
1309            languageVersion = _languageVersion;
1310            syntaxCursor = _syntaxCursor;
1311            scriptKind = _scriptKind;
1312            languageVariant = getLanguageVariant(_scriptKind);
1313
1314            parseDiagnostics = [];
1315            parsingContext = 0;
1316            identifiers = new Map<string, string>();
1317            privateIdentifiers = new Map<string, string>();
1318            identifierCount = 0;
1319            nodeCount = 0;
1320            sourceFlags = 0;
1321            topLevel = true;
1322
1323            switch (scriptKind) {
1324                case ScriptKind.JS:
1325                case ScriptKind.JSX:
1326                    contextFlags = NodeFlags.JavaScriptFile;
1327                    break;
1328                case ScriptKind.JSON:
1329                    contextFlags = NodeFlags.JavaScriptFile | NodeFlags.JsonFile;
1330                    break;
1331                case ScriptKind.ETS:
1332                    contextFlags = NodeFlags.EtsContext;
1333                    break;
1334                default:
1335                    contextFlags = NodeFlags.None;
1336                    break;
1337            }
1338            if (fileName.endsWith(Extension.Ets)) {
1339                contextFlags = NodeFlags.EtsContext;
1340            }
1341            parseErrorBeforeNextFinishedNode = false;
1342
1343            // Initialize and prime the scanner before parsing the source elements.
1344            scanner.setText(sourceText);
1345            scanner.setOnError(scanError);
1346            scanner.setScriptTarget(languageVersion);
1347            scanner.setLanguageVariant(languageVariant);
1348            scanner.setEtsContext(inEtsContext());
1349        }
1350
1351        function clearState() {
1352            // Clear out the text the scanner is pointing at, so it doesn't keep anything alive unnecessarily.
1353            scanner.clearCommentDirectives();
1354            scanner.setText("");
1355            scanner.setOnError(undefined);
1356            scanner.setEtsContext(false);
1357            // Clear any data.  We don't want to accidentally hold onto it for too long.
1358            sourceText = undefined!;
1359            languageVersion = undefined!;
1360            syntaxCursor = undefined;
1361            scriptKind = undefined!;
1362            languageVariant = undefined!;
1363            sourceFlags = 0;
1364            parseDiagnostics = undefined!;
1365            jsDocDiagnostics = undefined!;
1366            parsingContext = 0;
1367            identifiers = undefined!;
1368            notParenthesizedArrow = undefined;
1369            topLevel = true;
1370            extendEtsComponentDeclaration = undefined;
1371            stylesEtsComponentDeclaration = undefined;
1372            stateStylesRootNode = undefined;
1373            fileStylesComponents.clear();
1374            structStylesComponents.clear();
1375        }
1376
1377        function parseSourceFileWorker(languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind, setExternalModuleIndicator: (file: SourceFile) => void): SourceFile {
1378            const isDeclarationFile = isDeclarationFileName(fileName);
1379            if (isDeclarationFile) {
1380                contextFlags |= NodeFlags.Ambient;
1381            }
1382
1383            sourceFlags = contextFlags;
1384
1385            // Prime the scanner.
1386            nextToken();
1387
1388            const statements = parseList(ParsingContext.SourceElements, parseStatement);
1389            Debug.assert(token() === SyntaxKind.EndOfFileToken);
1390            const endOfFileToken = addJSDocComment(parseTokenNode<EndOfFileToken>());
1391
1392            const sourceFile = createSourceFile(fileName, languageVersion, scriptKind, isDeclarationFile, statements, endOfFileToken, sourceFlags, setExternalModuleIndicator);
1393
1394            // 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
1395            processCommentPragmas(sourceFile as {} as PragmaContext, sourceText);
1396            processPragmasIntoFields(sourceFile as {} as PragmaContext, reportPragmaDiagnostic);
1397
1398            sourceFile.commentDirectives = scanner.getCommentDirectives();
1399            sourceFile.nodeCount = nodeCount;
1400            sourceFile.identifierCount = identifierCount;
1401            sourceFile.identifiers = identifiers;
1402            sourceFile.parseDiagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile);
1403            if (jsDocDiagnostics) {
1404                sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile);
1405            }
1406
1407            if (setParentNodes) {
1408                fixupParentReferences(sourceFile);
1409            }
1410
1411            return sourceFile;
1412
1413            function reportPragmaDiagnostic(pos: number, end: number, diagnostic: DiagnosticMessage) {
1414                parseDiagnostics.push(createDetachedDiagnostic(fileName, pos, end, diagnostic));
1415            }
1416        }
1417
1418        function withJSDoc<T extends HasJSDoc>(node: T, hasJSDoc: boolean): T {
1419            return hasJSDoc ? addJSDocComment(node) : node;
1420        }
1421
1422        let hasDeprecatedTag = false;
1423        function addJSDocComment<T extends HasJSDoc>(node: T): T {
1424            Debug.assert(!node.jsDoc); // Should only be called once per node
1425            const jsDoc = mapDefined(getJSDocCommentRanges(node, sourceText), comment => JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos));
1426            if (jsDoc.length) node.jsDoc = jsDoc;
1427            if (hasDeprecatedTag) {
1428                hasDeprecatedTag = false;
1429                (node as Mutable<T>).flags |= NodeFlags.Deprecated;
1430            }
1431            return node;
1432        }
1433
1434        function reparseTopLevelAwait(sourceFile: SourceFile) {
1435            const savedSyntaxCursor = syntaxCursor;
1436            const baseSyntaxCursor = IncrementalParser.createSyntaxCursor(sourceFile);
1437            syntaxCursor = { currentNode };
1438
1439            const statements: Statement[] = [];
1440            const savedParseDiagnostics = parseDiagnostics;
1441
1442            parseDiagnostics = [];
1443
1444            let pos = 0;
1445            let start = findNextStatementWithAwait(sourceFile.statements, 0);
1446            while (start !== -1) {
1447                // append all statements between pos and start
1448                const prevStatement = sourceFile.statements[pos];
1449                const nextStatement = sourceFile.statements[start];
1450                addRange(statements, sourceFile.statements, pos, start);
1451                pos = findNextStatementWithoutAwait(sourceFile.statements, start);
1452
1453                // append all diagnostics associated with the copied range
1454                const diagnosticStart = findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= prevStatement.pos);
1455                const diagnosticEnd = diagnosticStart >= 0 ? findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= nextStatement.pos, diagnosticStart) : -1;
1456                if (diagnosticStart >= 0) {
1457                    addRange(parseDiagnostics, savedParseDiagnostics, diagnosticStart, diagnosticEnd >= 0 ? diagnosticEnd : undefined);
1458                }
1459
1460                // reparse all statements between start and pos. We skip existing diagnostics for the same range and allow the parser to generate new ones.
1461                speculationHelper(() => {
1462                    const savedContextFlags = contextFlags;
1463                    contextFlags |= NodeFlags.AwaitContext;
1464                    scanner.setTextPos(nextStatement.pos);
1465                    nextToken();
1466
1467                    while (token() !== SyntaxKind.EndOfFileToken) {
1468                        const startPos = scanner.getStartPos();
1469                        const statement = parseListElement(ParsingContext.SourceElements, parseStatement);
1470                        statements.push(statement);
1471                        if (startPos === scanner.getStartPos()) {
1472                            nextToken();
1473                        }
1474
1475                        if (pos >= 0) {
1476                            const nonAwaitStatement = sourceFile.statements[pos];
1477                            if (statement.end === nonAwaitStatement.pos) {
1478                                // done reparsing this section
1479                                break;
1480                            }
1481                            if (statement.end > nonAwaitStatement.pos) {
1482                                // we ate into the next statement, so we must reparse it.
1483                                pos = findNextStatementWithoutAwait(sourceFile.statements, pos + 1);
1484                            }
1485                        }
1486                    }
1487
1488                    contextFlags = savedContextFlags;
1489                }, SpeculationKind.Reparse);
1490
1491                // find the next statement containing an `await`
1492                start = pos >= 0 ? findNextStatementWithAwait(sourceFile.statements, pos) : -1;
1493            }
1494
1495            // append all statements between pos and the end of the list
1496            if (pos >= 0) {
1497                const prevStatement = sourceFile.statements[pos];
1498                addRange(statements, sourceFile.statements, pos);
1499
1500                // append all diagnostics associated with the copied range
1501                const diagnosticStart = findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= prevStatement.pos);
1502                if (diagnosticStart >= 0) {
1503                    addRange(parseDiagnostics, savedParseDiagnostics, diagnosticStart);
1504                }
1505            }
1506
1507            syntaxCursor = savedSyntaxCursor;
1508            return factory.updateSourceFile(sourceFile, setTextRange(factory.createNodeArray(statements), sourceFile.statements));
1509
1510            function containsPossibleTopLevelAwait(node: Node) {
1511                return !(node.flags & NodeFlags.AwaitContext)
1512                    && !!(node.transformFlags & TransformFlags.ContainsPossibleTopLevelAwait);
1513            }
1514
1515            function findNextStatementWithAwait(statements: NodeArray<Statement>, start: number) {
1516                for (let i = start; i < statements.length; i++) {
1517                    if (containsPossibleTopLevelAwait(statements[i])) {
1518                        return i;
1519                    }
1520                }
1521                return -1;
1522            }
1523
1524            function findNextStatementWithoutAwait(statements: NodeArray<Statement>, start: number) {
1525                for (let i = start; i < statements.length; i++) {
1526                    if (!containsPossibleTopLevelAwait(statements[i])) {
1527                        return i;
1528                    }
1529                }
1530                return -1;
1531            }
1532
1533            function currentNode(position: number) {
1534                const node = baseSyntaxCursor.currentNode(position);
1535                if (topLevel && node && containsPossibleTopLevelAwait(node)) {
1536                    node.intersectsChange = true;
1537                }
1538                return node;
1539            }
1540
1541        }
1542
1543        export function fixupParentReferences(rootNode: Node) {
1544            // normally parent references are set during binding. However, for clients that only need
1545            // a syntax tree, and no semantic features, then the binding process is an unnecessary
1546            // overhead.  This functions allows us to set all the parents, without all the expense of
1547            // binding.
1548            setParentRecursive(rootNode, /*incremental*/ true);
1549        }
1550
1551        function createSourceFile(
1552            fileName: string,
1553            languageVersion: ScriptTarget,
1554            scriptKind: ScriptKind,
1555            isDeclarationFile: boolean,
1556            statements: readonly Statement[],
1557            endOfFileToken: EndOfFileToken,
1558            flags: NodeFlags,
1559            setExternalModuleIndicator: (sourceFile: SourceFile) => void): SourceFile {
1560            // code from createNode is inlined here so createNode won't have to deal with special case of creating source files
1561            // this is quite rare comparing to other nodes and createNode should be as fast as possible
1562            let sourceFile = factory.createSourceFile(statements, endOfFileToken, flags);
1563            setTextRangePosWidth(sourceFile, 0, sourceText.length);
1564            setFields(sourceFile);
1565
1566            // If we parsed this as an external module, it may contain top-level await
1567            if (!isDeclarationFile && isExternalModule(sourceFile) && sourceFile.transformFlags & TransformFlags.ContainsPossibleTopLevelAwait) {
1568                sourceFile = reparseTopLevelAwait(sourceFile);
1569                setFields(sourceFile);
1570            }
1571
1572            return sourceFile;
1573
1574            function setFields(sourceFile: SourceFile) {
1575                sourceFile.text = sourceText;
1576                sourceFile.bindDiagnostics = [];
1577                sourceFile.bindSuggestionDiagnostics = undefined;
1578                sourceFile.languageVersion = languageVersion;
1579                sourceFile.fileName = fileName;
1580                sourceFile.languageVariant = getLanguageVariant(scriptKind);
1581                sourceFile.isDeclarationFile = isDeclarationFile;
1582                sourceFile.scriptKind = scriptKind;
1583
1584                setExternalModuleIndicator(sourceFile);
1585                sourceFile.setExternalModuleIndicator = setExternalModuleIndicator;
1586            }
1587        }
1588
1589        function setContextFlag(val: boolean, flag: NodeFlags) {
1590            if (val) {
1591                contextFlags |= flag;
1592            }
1593            else {
1594                contextFlags &= ~flag;
1595            }
1596        }
1597
1598        function setEtsFlag(val: boolean, flag: EtsFlags) {
1599            if (val) {
1600                etsFlags |= flag;
1601            }
1602            else {
1603                etsFlags &= ~flag;
1604            }
1605        }
1606
1607        function setDisallowInContext(val: boolean) {
1608            setContextFlag(val, NodeFlags.DisallowInContext);
1609        }
1610
1611        function setYieldContext(val: boolean) {
1612            setContextFlag(val, NodeFlags.YieldContext);
1613        }
1614
1615        function setDecoratorContext(val: boolean) {
1616            setContextFlag(val, NodeFlags.DecoratorContext);
1617        }
1618
1619        function setAwaitContext(val: boolean) {
1620            setContextFlag(val, NodeFlags.AwaitContext);
1621        }
1622
1623        function setStructContext(val: boolean) {
1624            setEtsFlag(val, EtsFlags.StructContext);
1625        }
1626
1627        function setEtsComponentsContext(val: boolean) {
1628            setEtsFlag(val, EtsFlags.EtsComponentsContext);
1629        }
1630
1631        function setEtsNewExpressionContext(val: boolean) {
1632            setEtsFlag(val, EtsFlags.EtsNewExpressionContext);
1633        }
1634
1635        function setEtsExtendComponentsContext(val: boolean) {
1636            setEtsFlag(val, EtsFlags.EtsExtendComponentsContext);
1637        }
1638
1639        function setEtsStylesComponentsContext(val: boolean) {
1640            setEtsFlag(val, EtsFlags.EtsStylesComponentsContext);
1641        }
1642
1643        function setEtsBuildContext(val: boolean) {
1644            setEtsFlag(val, EtsFlags.EtsBuildContext);
1645        }
1646
1647        function setEtsBuilderContext(val: boolean) {
1648            setEtsFlag(val, EtsFlags.EtsBuilderContext);
1649        }
1650
1651        function setEtsStateStylesContext(val: boolean) {
1652            setEtsFlag(val, EtsFlags.EtsStateStylesContext);
1653        }
1654
1655        function doOutsideOfContext<T>(context: NodeFlags, func: () => T): T {
1656            // contextFlagsToClear will contain only the context flags that are
1657            // currently set that we need to temporarily clear
1658            // We don't just blindly reset to the previous flags to ensure
1659            // that we do not mutate cached flags for the incremental
1660            // parser (ThisNodeHasError, ThisNodeOrAnySubNodesHasError, and
1661            // HasAggregatedChildData).
1662            const contextFlagsToClear = context & contextFlags;
1663            if (contextFlagsToClear) {
1664                // clear the requested context flags
1665                setContextFlag(/*val*/ false, contextFlagsToClear);
1666                const result = func();
1667                // restore the context flags we just cleared
1668                setContextFlag(/*val*/ true, contextFlagsToClear);
1669                return result;
1670            }
1671
1672            // no need to do anything special as we are not in any of the requested contexts
1673            return func();
1674        }
1675
1676        function doInsideOfContext<T>(context: NodeFlags, func: () => T): T {
1677            // contextFlagsToSet will contain only the context flags that
1678            // are not currently set that we need to temporarily enable.
1679            // We don't just blindly reset to the previous flags to ensure
1680            // that we do not mutate cached flags for the incremental
1681            // parser (ThisNodeHasError, ThisNodeOrAnySubNodesHasError, and
1682            // HasAggregatedChildData).
1683            const contextFlagsToSet = context & ~contextFlags;
1684            if (contextFlagsToSet) {
1685                // set the requested context flags
1686                setContextFlag(/*val*/ true, contextFlagsToSet);
1687                const result = func();
1688                // reset the context flags we just set
1689                setContextFlag(/*val*/ false, contextFlagsToSet);
1690                return result;
1691            }
1692
1693            // no need to do anything special as we are already in all of the requested contexts
1694            return func();
1695        }
1696
1697        function allowInAnd<T>(func: () => T): T {
1698            return doOutsideOfContext(NodeFlags.DisallowInContext, func);
1699        }
1700
1701        function disallowInAnd<T>(func: () => T): T {
1702            return doInsideOfContext(NodeFlags.DisallowInContext, func);
1703        }
1704
1705        function allowConditionalTypesAnd<T>(func: () => T): T {
1706            return doOutsideOfContext(NodeFlags.DisallowConditionalTypesContext, func);
1707        }
1708
1709        function disallowConditionalTypesAnd<T>(func: () => T): T {
1710            return doInsideOfContext(NodeFlags.DisallowConditionalTypesContext, func);
1711        }
1712
1713        function doInYieldContext<T>(func: () => T): T {
1714            return doInsideOfContext(NodeFlags.YieldContext, func);
1715        }
1716
1717        function doInDecoratorContext<T>(func: () => T): T {
1718            // setting Ets Extend Components
1719            const extendDecorator = sourceFileCompilerOptions.ets?.extend?.decorator ?? "Extend";
1720            if (token() === SyntaxKind.Identifier && scanner.getTokenText() === extendDecorator) {
1721                setEtsFlag(true, EtsFlags.EtsExtendComponentsContext);
1722            }
1723            // setting Ets Styles Components
1724            const stylesDecorator = sourceFileCompilerOptions.ets?.styles?.decorator ?? "Styles";
1725            if (token() === SyntaxKind.Identifier && scanner.getTokenText() === stylesDecorator) {
1726                setEtsFlag(true, EtsFlags.EtsStylesComponentsContext);
1727            }
1728            return doInsideOfContext(NodeFlags.DecoratorContext, func);
1729        }
1730
1731        function doInAwaitContext<T>(func: () => T): T {
1732            return doInsideOfContext(NodeFlags.AwaitContext, func);
1733        }
1734
1735        function doOutsideOfAwaitContext<T>(func: () => T): T {
1736            return doOutsideOfContext(NodeFlags.AwaitContext, func);
1737        }
1738
1739        function doInYieldAndAwaitContext<T>(func: () => T): T {
1740            return doInsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext, func);
1741        }
1742
1743        function doOutsideOfYieldAndAwaitContext<T>(func: () => T): T {
1744            return doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext, func);
1745        }
1746
1747        function inContext(flags: NodeFlags) {
1748            return (contextFlags & flags) !== 0;
1749        }
1750
1751        function inEtsFlagsContext(flags: EtsFlags) {
1752            return (etsFlags & flags) !== 0;
1753        }
1754
1755        function inYieldContext() {
1756            return inContext(NodeFlags.YieldContext);
1757        }
1758
1759        function inDisallowInContext() {
1760            return inContext(NodeFlags.DisallowInContext);
1761        }
1762
1763        function inDisallowConditionalTypesContext() {
1764            return inContext(NodeFlags.DisallowConditionalTypesContext);
1765        }
1766
1767        function inDecoratorContext() {
1768            return inContext(NodeFlags.DecoratorContext);
1769        }
1770
1771        function inAwaitContext() {
1772            return inContext(NodeFlags.AwaitContext);
1773        }
1774
1775        function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined {
1776            return parseErrorAt(scanner.getTokenPos(), scanner.getTextPos(), message, arg0);
1777        }
1778
1779        function inEtsContext() {
1780            return inContext(NodeFlags.EtsContext);
1781        }
1782
1783        function inStructContext() {
1784            return inEtsContext() && inEtsFlagsContext(EtsFlags.StructContext);
1785        }
1786
1787        function inEtsComponentsContext() {
1788            return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsComponentsContext);
1789        }
1790
1791        function inEtsNewExpressionContext() {
1792            return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsNewExpressionContext);
1793        }
1794
1795        function inEtsExtendComponentsContext() {
1796            return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsExtendComponentsContext);
1797        }
1798
1799        function inEtsStylesComponentsContext() {
1800            return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsStylesComponentsContext);
1801        }
1802
1803        function inBuildContext() {
1804            return inEtsContext() && inStructContext() && inEtsFlagsContext(EtsFlags.EtsBuildContext);
1805        }
1806
1807        function inBuilderContext() {
1808            return inEtsContext() && inEtsFlagsContext(EtsFlags.EtsBuilderContext);
1809        }
1810
1811        function inEtsStateStylesContext() {
1812            return inEtsContext() && inStructContext() && inEtsFlagsContext(EtsFlags.EtsStateStylesContext);
1813        }
1814
1815        function parseErrorAtPosition(start: number, length: number, message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined {
1816            // Don't report another error if it would just be at the same position as the last error.
1817            const lastError = lastOrUndefined(parseDiagnostics);
1818            let result: DiagnosticWithDetachedLocation | undefined;
1819            if (!lastError || start !== lastError.start) {
1820                result = createDetachedDiagnostic(fileName, start, length, message, arg0);
1821                parseDiagnostics.push(result);
1822            }
1823
1824            // Mark that we've encountered an error.  We'll set an appropriate bit on the next
1825            // node we finish so that it can't be reused incrementally.
1826            parseErrorBeforeNextFinishedNode = true;
1827            return result;
1828        }
1829
1830        function parseErrorAt(start: number, end: number, message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined {
1831            return parseErrorAtPosition(start, end - start, message, arg0);
1832        }
1833
1834        function parseErrorAtRange(range: TextRange, message: DiagnosticMessage, arg0?: any): void {
1835            parseErrorAt(range.pos, range.end, message, arg0);
1836        }
1837
1838        function scanError(message: DiagnosticMessage, length: number): void {
1839            parseErrorAtPosition(scanner.getTextPos(), length, message);
1840        }
1841
1842        function getNodePos(): number {
1843            return scanner.getStartPos();
1844        }
1845
1846        function hasPrecedingJSDocComment() {
1847            return scanner.hasPrecedingJSDocComment();
1848        }
1849
1850        // Use this function to access the current token instead of reading the currentToken
1851        // variable. Since function results aren't narrowed in control flow analysis, this ensures
1852        // that the type checker doesn't make wrong assumptions about the type of the current
1853        // token (e.g. a call to nextToken() changes the current token but the checker doesn't
1854        // reason about this side effect).  Mainstream VMs inline simple functions like this, so
1855        // there is no performance penalty.
1856        function token(): SyntaxKind {
1857            return currentToken;
1858        }
1859
1860        function nextTokenWithoutCheck() {
1861            return currentToken = scanner.scan();
1862        }
1863
1864        function nextTokenAnd<T>(func: () => T): T {
1865            nextToken();
1866            return func();
1867        }
1868
1869        function nextToken(): SyntaxKind {
1870            // if the keyword had an escape
1871            if (isKeyword(currentToken) && (scanner.hasUnicodeEscape() || scanner.hasExtendedUnicodeEscape())) {
1872                // issue a parse error for the escape
1873                parseErrorAt(scanner.getTokenPos(), scanner.getTextPos(), Diagnostics.Keywords_cannot_contain_escape_characters);
1874            }
1875            return nextTokenWithoutCheck();
1876        }
1877
1878        function nextTokenJSDoc(): JSDocSyntaxKind {
1879            return currentToken = scanner.scanJsDocToken();
1880        }
1881
1882        function reScanGreaterToken(): SyntaxKind {
1883            return currentToken = scanner.reScanGreaterToken();
1884        }
1885
1886        function reScanSlashToken(): SyntaxKind {
1887            return currentToken = scanner.reScanSlashToken();
1888        }
1889
1890        function reScanTemplateToken(isTaggedTemplate: boolean): SyntaxKind {
1891            return currentToken = scanner.reScanTemplateToken(isTaggedTemplate);
1892        }
1893
1894        function reScanTemplateHeadOrNoSubstitutionTemplate(): SyntaxKind {
1895            return currentToken = scanner.reScanTemplateHeadOrNoSubstitutionTemplate();
1896        }
1897
1898        function reScanLessThanToken(): SyntaxKind {
1899            return currentToken = scanner.reScanLessThanToken();
1900        }
1901
1902        function reScanHashToken(): SyntaxKind {
1903            return currentToken = scanner.reScanHashToken();
1904        }
1905
1906        function scanJsxIdentifier(): SyntaxKind {
1907            return currentToken = scanner.scanJsxIdentifier();
1908        }
1909
1910        function scanJsxText(): SyntaxKind {
1911            return currentToken = scanner.scanJsxToken();
1912        }
1913
1914        function scanJsxAttributeValue(): SyntaxKind {
1915            return currentToken = scanner.scanJsxAttributeValue();
1916        }
1917
1918        function speculationHelper<T>(callback: () => T, speculationKind: SpeculationKind): T {
1919            // Keep track of the state we'll need to rollback to if lookahead fails (or if the
1920            // caller asked us to always reset our state).
1921            const saveToken = currentToken;
1922            const saveParseDiagnosticsLength = parseDiagnostics.length;
1923            const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode;
1924
1925            // Note: it is not actually necessary to save/restore the context flags here.  That's
1926            // because the saving/restoring of these flags happens naturally through the recursive
1927            // descent nature of our parser.  However, we still store this here just so we can
1928            // assert that invariant holds.
1929            const saveContextFlags = contextFlags;
1930
1931            // If we're only looking ahead, then tell the scanner to only lookahead as well.
1932            // Otherwise, if we're actually speculatively parsing, then tell the scanner to do the
1933            // same.
1934            const result = speculationKind !== SpeculationKind.TryParse
1935                ? scanner.lookAhead(callback)
1936                : scanner.tryScan(callback);
1937
1938            Debug.assert(saveContextFlags === contextFlags);
1939
1940            // If our callback returned something 'falsy' or we're just looking ahead,
1941            // then unconditionally restore us to where we were.
1942            if (!result || speculationKind !== SpeculationKind.TryParse) {
1943                currentToken = saveToken;
1944                if (speculationKind !== SpeculationKind.Reparse) {
1945                    parseDiagnostics.length = saveParseDiagnosticsLength;
1946                }
1947                parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode;
1948            }
1949
1950            return result;
1951        }
1952
1953        /** Invokes the provided callback then unconditionally restores the parser to the state it
1954         * was in immediately prior to invoking the callback.  The result of invoking the callback
1955         * is returned from this function.
1956         */
1957        function lookAhead<T>(callback: () => T): T {
1958            return speculationHelper(callback, SpeculationKind.Lookahead);
1959        }
1960
1961        /** Invokes the provided callback.  If the callback returns something falsy, then it restores
1962         * the parser to the state it was in immediately prior to invoking the callback.  If the
1963         * callback returns something truthy, then the parser state is not rolled back.  The result
1964         * of invoking the callback is returned from this function.
1965         */
1966        function tryParse<T>(callback: () => T): T {
1967            return speculationHelper(callback, SpeculationKind.TryParse);
1968        }
1969
1970        function isBindingIdentifier(): boolean {
1971            if (token() === SyntaxKind.Identifier) {
1972                return true;
1973            }
1974
1975            // `let await`/`let yield` in [Yield] or [Await] are allowed here and disallowed in the binder.
1976            return token() > SyntaxKind.LastReservedWord;
1977        }
1978
1979        // Ignore strict mode flag because we will report an error in type checker instead.
1980        function isIdentifier(): boolean {
1981            if (token() === SyntaxKind.Identifier) {
1982                return true;
1983            }
1984
1985            // If we have a 'yield' keyword, and we're in the [yield] context, then 'yield' is
1986            // considered a keyword and is not an identifier.
1987            if (token() === SyntaxKind.YieldKeyword && inYieldContext()) {
1988                return false;
1989            }
1990
1991            // If we have a 'await' keyword, and we're in the [Await] context, then 'await' is
1992            // considered a keyword and is not an identifier.
1993            if (token() === SyntaxKind.AwaitKeyword && inAwaitContext()) {
1994                return false;
1995            }
1996
1997            return token() > SyntaxKind.LastReservedWord;
1998        }
1999
2000        function parseExpected(kind: SyntaxKind, diagnosticMessage?: DiagnosticMessage, shouldAdvance = true): boolean {
2001            if (token() === kind) {
2002                if (shouldAdvance) {
2003                    nextToken();
2004                }
2005                return true;
2006            }
2007
2008            if (token() !== kind && stateStylesRootNode && inEtsStateStylesContext()) {
2009                return true;
2010            }
2011
2012            // Report specific message if provided with one.  Otherwise, report generic fallback message.
2013            if (diagnosticMessage) {
2014                parseErrorAtCurrentToken(diagnosticMessage);
2015            }
2016            else {
2017                parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind));
2018            }
2019            return false;
2020        }
2021
2022        const viableKeywordSuggestions = Object.keys(textToKeywordObj).filter(keyword => keyword.length > 2);
2023
2024        /**
2025         * Provides a better error message than the generic "';' expected" if possible for
2026         * known common variants of a missing semicolon, such as from a mispelled names.
2027         *
2028         * @param node Node preceding the expected semicolon location.
2029         */
2030        function parseErrorForMissingSemicolonAfter(node: Expression | PropertyName): void {
2031            // Tagged template literals are sometimes used in places where only simple strings are allowed, i.e.:
2032            //   module `M1` {
2033            //   ^^^^^^^^^^^ This block is parsed as a template literal like module`M1`.
2034            if (isTaggedTemplateExpression(node)) {
2035                parseErrorAt(skipTrivia(sourceText, node.template.pos), node.template.end, Diagnostics.Module_declaration_names_may_only_use_or_quoted_strings);
2036                return;
2037            }
2038
2039            // Otherwise, if this isn't a well-known keyword-like identifier, give the generic fallback message.
2040            const expressionText = ts.isIdentifier(node) ? idText(node) : undefined;
2041            if (!expressionText || !isIdentifierText(expressionText, languageVersion)) {
2042                parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.SemicolonToken));
2043                return;
2044            }
2045
2046            const pos = skipTrivia(sourceText, node.pos);
2047
2048            // Some known keywords are likely signs of syntax being used improperly.
2049            switch (expressionText) {
2050                case "const":
2051                case "let":
2052                case "var":
2053                    parseErrorAt(pos, node.end, Diagnostics.Variable_declaration_not_allowed_at_this_location);
2054                    return;
2055
2056                case "declare":
2057                    // If a declared node failed to parse, it would have emitted a diagnostic already.
2058                    return;
2059
2060                case "interface":
2061                    parseErrorForInvalidName(Diagnostics.Interface_name_cannot_be_0, Diagnostics.Interface_must_be_given_a_name, SyntaxKind.OpenBraceToken);
2062                    return;
2063
2064                case "is":
2065                    parseErrorAt(pos, scanner.getTextPos(), Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods);
2066                    return;
2067
2068                case "module":
2069                case "namespace":
2070                    parseErrorForInvalidName(Diagnostics.Namespace_name_cannot_be_0, Diagnostics.Namespace_must_be_given_a_name, SyntaxKind.OpenBraceToken);
2071                    return;
2072
2073                case "type":
2074                    parseErrorForInvalidName(Diagnostics.Type_alias_name_cannot_be_0, Diagnostics.Type_alias_must_be_given_a_name, SyntaxKind.EqualsToken);
2075                    return;
2076            }
2077
2078            // The user alternatively might have misspelled or forgotten to add a space after a common keyword.
2079            const suggestion = getSpellingSuggestion(expressionText, viableKeywordSuggestions, n => n) ?? getSpaceSuggestion(expressionText);
2080            if (suggestion) {
2081                parseErrorAt(pos, node.end, Diagnostics.Unknown_keyword_or_identifier_Did_you_mean_0, suggestion);
2082                return;
2083            }
2084
2085            // Unknown tokens are handled with their own errors in the scanner
2086            if (token() === SyntaxKind.Unknown) {
2087                return;
2088            }
2089
2090            // Otherwise, we know this some kind of unknown word, not just a missing expected semicolon.
2091            parseErrorAt(pos, node.end, Diagnostics.Unexpected_keyword_or_identifier);
2092        }
2093
2094        /**
2095         * Reports a diagnostic error for the current token being an invalid name.
2096         *
2097         * @param blankDiagnostic Diagnostic to report for the case of the name being blank (matched tokenIfBlankName).
2098         * @param nameDiagnostic Diagnostic to report for all other cases.
2099         * @param tokenIfBlankName Current token if the name was invalid for being blank (not provided / skipped).
2100         */
2101        function parseErrorForInvalidName(nameDiagnostic: DiagnosticMessage, blankDiagnostic: DiagnosticMessage, tokenIfBlankName: SyntaxKind) {
2102            if (token() === tokenIfBlankName) {
2103                parseErrorAtCurrentToken(blankDiagnostic);
2104            }
2105            else {
2106                parseErrorAtCurrentToken(nameDiagnostic, scanner.getTokenValue());
2107            }
2108        }
2109
2110        function getSpaceSuggestion(expressionText: string) {
2111            for (const keyword of viableKeywordSuggestions) {
2112                if (expressionText.length > keyword.length + 2 && startsWith(expressionText, keyword)) {
2113                    return `${keyword} ${expressionText.slice(keyword.length)}`;
2114                }
2115            }
2116
2117            return undefined;
2118        }
2119
2120        function parseSemicolonAfterPropertyName(name: PropertyName, type: TypeNode | undefined, initializer: Expression | undefined) {
2121            if (token() === SyntaxKind.AtToken && !scanner.hasPrecedingLineBreak()) {
2122                parseErrorAtCurrentToken(Diagnostics.Decorators_must_precede_the_name_and_all_keywords_of_property_declarations);
2123                return;
2124            }
2125
2126            if (token() === SyntaxKind.OpenParenToken) {
2127                parseErrorAtCurrentToken(Diagnostics.Cannot_start_a_function_call_in_a_type_annotation);
2128                nextToken();
2129                return;
2130            }
2131
2132            if (type && !canParseSemicolon()) {
2133                if (initializer) {
2134                    parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.SemicolonToken));
2135                }
2136                else {
2137                    parseErrorAtCurrentToken(Diagnostics.Expected_for_property_initializer);
2138                }
2139                return;
2140            }
2141
2142            if (tryParseSemicolon()) {
2143                return;
2144            }
2145
2146            if (initializer) {
2147                parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.SemicolonToken));
2148                return;
2149            }
2150
2151            parseErrorForMissingSemicolonAfter(name);
2152        }
2153
2154        function parseExpectedJSDoc(kind: JSDocSyntaxKind) {
2155            if (token() === kind) {
2156                nextTokenJSDoc();
2157                return true;
2158            }
2159            parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind));
2160            return false;
2161        }
2162
2163        function parseExpectedMatchingBrackets(openKind: SyntaxKind, closeKind: SyntaxKind, openParsed: boolean, openPosition: number) {
2164            if (token() === closeKind) {
2165                nextToken();
2166                return;
2167            }
2168            const lastError = parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(closeKind));
2169            if (!openParsed) {
2170                return;
2171            }
2172            if (lastError) {
2173                addRelatedInfo(
2174                    lastError,
2175                    createDetachedDiagnostic(fileName, openPosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, tokenToString(openKind), tokenToString(closeKind))
2176                );
2177            }
2178        }
2179
2180        function parseOptional(t: SyntaxKind): boolean {
2181            if (token() === t) {
2182                nextToken();
2183                return true;
2184            }
2185            return false;
2186        }
2187
2188        function parseOptionalToken<TKind extends SyntaxKind>(t: TKind): Token<TKind>;
2189        function parseOptionalToken(t: SyntaxKind): Node | undefined {
2190            if (token() === t) {
2191                return parseTokenNode();
2192            }
2193            return undefined;
2194        }
2195
2196        function parseOptionalTokenJSDoc<TKind extends JSDocSyntaxKind>(t: TKind): Token<TKind>;
2197        function parseOptionalTokenJSDoc(t: JSDocSyntaxKind): Node | undefined {
2198            if (token() === t) {
2199                return parseTokenNodeJSDoc();
2200            }
2201            return undefined;
2202        }
2203
2204        function parseExpectedToken<TKind extends SyntaxKind>(t: TKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Token<TKind>;
2205        function parseExpectedToken(t: SyntaxKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Node {
2206            return parseOptionalToken(t) ||
2207                createMissingNode(t, /*reportAtCurrentPosition*/ false, diagnosticMessage || Diagnostics._0_expected, arg0 || tokenToString(t));
2208        }
2209
2210        function parseExpectedTokenJSDoc<TKind extends JSDocSyntaxKind>(t: TKind): Token<TKind>;
2211        function parseExpectedTokenJSDoc(t: JSDocSyntaxKind): Node {
2212            return parseOptionalTokenJSDoc(t) ||
2213                createMissingNode(t, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(t));
2214        }
2215
2216        function parseTokenNode<T extends Node>(): T {
2217            const pos = getNodePos();
2218            const kind = token();
2219            nextToken();
2220            return finishNode(factory.createToken(kind), pos) as T;
2221        }
2222
2223        function parseTokenNodeJSDoc<T extends Node>(): T {
2224            const pos = getNodePos();
2225            const kind = token();
2226            nextTokenJSDoc();
2227            return finishNode(factory.createToken(kind), pos) as T;
2228        }
2229
2230        function canParseSemicolon() {
2231            // If there's a real semicolon, then we can always parse it out.
2232            if (token() === SyntaxKind.SemicolonToken) {
2233                return true;
2234            }
2235
2236            // We can parse out an optional semicolon in ASI cases in the following cases.
2237            return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.EndOfFileToken || scanner.hasPrecedingLineBreak();
2238        }
2239
2240        function tryParseSemicolon() {
2241            if (!canParseSemicolon()) {
2242                return false;
2243            }
2244
2245            if (token() === SyntaxKind.SemicolonToken) {
2246                // consume the semicolon if it was explicitly provided.
2247                nextToken();
2248            }
2249
2250            return true;
2251        }
2252
2253        function parseSemicolon(): boolean {
2254            return tryParseSemicolon() || parseExpected(SyntaxKind.SemicolonToken);
2255        }
2256
2257        function createNodeArray<T extends Node>(elements: T[], pos: number, end?: number, hasTrailingComma?: boolean): NodeArray<T> {
2258            const array = factory.createNodeArray(elements, hasTrailingComma);
2259            setTextRangePosEnd(array, pos, end ?? scanner.getStartPos());
2260            return array;
2261        }
2262
2263        function finishNode<T extends Node>(node: T, pos: number, end?: number, virtual?: boolean): T {
2264            setTextRangePosEnd(node, pos, end ?? scanner.getStartPos());
2265            if (contextFlags) {
2266                (node as Mutable<T>).flags |= contextFlags;
2267            }
2268
2269            // Keep track on the node if we encountered an error while parsing it.  If we did, then
2270            // we cannot reuse the node incrementally.  Once we've marked this node, clear out the
2271            // flag so that we don't mark any subsequent nodes.
2272            if (parseErrorBeforeNextFinishedNode) {
2273                parseErrorBeforeNextFinishedNode = false;
2274                (node as Mutable<T>).flags |= NodeFlags.ThisNodeHasError;
2275            }
2276
2277            if (virtual) {
2278                node.virtual = true;
2279            }
2280
2281            return node;
2282        }
2283
2284        function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: false, diagnosticMessage?: DiagnosticMessage, arg0?: any): T;
2285        function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): T;
2286        function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): T {
2287            if (reportAtCurrentPosition) {
2288                parseErrorAtPosition(scanner.getStartPos(), 0, diagnosticMessage, arg0);
2289            }
2290            else if (diagnosticMessage) {
2291                parseErrorAtCurrentToken(diagnosticMessage, arg0);
2292            }
2293
2294            const pos = getNodePos();
2295            const result =
2296                kind === SyntaxKind.Identifier ? factory.createIdentifier("", /*typeArguments*/ undefined, /*originalKeywordKind*/ undefined) :
2297                isTemplateLiteralKind(kind) ? factory.createTemplateLiteralLikeNode(kind, "", "", /*templateFlags*/ undefined) :
2298                kind === SyntaxKind.NumericLiteral ? factory.createNumericLiteral("", /*numericLiteralFlags*/ undefined) :
2299                kind === SyntaxKind.StringLiteral ? factory.createStringLiteral("", /*isSingleQuote*/ undefined) :
2300                kind === SyntaxKind.MissingDeclaration ? factory.createMissingDeclaration() :
2301                factory.createToken(kind);
2302            return finishNode(result, pos) as T;
2303        }
2304
2305        function internIdentifier(text: string): string {
2306            let identifier = identifiers.get(text);
2307            if (identifier === undefined) {
2308                identifiers.set(text, identifier = text);
2309            }
2310            return identifier;
2311        }
2312
2313        // An identifier that starts with two underscores has an extra underscore character prepended to it to avoid issues
2314        // with magic property names like '__proto__'. The 'identifiers' object is used to share a single string instance for
2315        // each identifier in order to reduce memory consumption.
2316        function createIdentifier(isIdentifier: boolean, diagnosticMessage?: DiagnosticMessage, privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier {
2317            if (isIdentifier) {
2318                identifierCount++;
2319                const pos = getNodePos();
2320                // Store original token kind if it is not just an Identifier so we can report appropriate error later in type checker
2321                const originalKeywordKind = token();
2322                const text = internIdentifier(scanner.getTokenValue());
2323                const hasExtendedUnicodeEscape = scanner.hasExtendedUnicodeEscape();
2324                nextTokenWithoutCheck();
2325                return finishNode(factory.createIdentifier(text, /*typeArguments*/ undefined, originalKeywordKind, hasExtendedUnicodeEscape), pos);
2326            }
2327
2328            if (token() === SyntaxKind.PrivateIdentifier) {
2329                parseErrorAtCurrentToken(privateIdentifierDiagnosticMessage || Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies);
2330                return createIdentifier(/*isIdentifier*/ true);
2331            }
2332
2333            if (token() === SyntaxKind.Unknown && scanner.tryScan(() => scanner.reScanInvalidIdentifier() === SyntaxKind.Identifier)) {
2334                // Scanner has already recorded an 'Invalid character' error, so no need to add another from the parser.
2335                return createIdentifier(/*isIdentifier*/ true);
2336            }
2337
2338            if (stateStylesRootNode && inEtsStateStylesContext() && token() === SyntaxKind.DotToken) {
2339                identifierCount++;
2340                const pos = getNodePos();
2341                return finishVirtualNode(
2342                    factory.createIdentifier(`${stateStylesRootNode}Instance`, /*typeArguments*/ undefined, SyntaxKind.Identifier),
2343                    pos,
2344                    pos
2345                );
2346            }
2347
2348            identifierCount++;
2349            // Only for end of file because the error gets reported incorrectly on embedded script tags.
2350            const reportAtCurrentPosition = token() === SyntaxKind.EndOfFileToken;
2351
2352            const isReservedWord = scanner.isReservedWord();
2353            const msgArg = scanner.getTokenText();
2354
2355            const defaultMessage = isReservedWord ?
2356                Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here :
2357                Diagnostics.Identifier_expected;
2358
2359            return createMissingNode<Identifier>(SyntaxKind.Identifier, reportAtCurrentPosition, diagnosticMessage || defaultMessage, msgArg);
2360        }
2361
2362        function parseBindingIdentifier(privateIdentifierDiagnosticMessage?: DiagnosticMessage) {
2363            return createIdentifier(isBindingIdentifier(), /*diagnosticMessage*/ undefined, privateIdentifierDiagnosticMessage);
2364        }
2365
2366        function parseIdentifier(diagnosticMessage?: DiagnosticMessage, privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier {
2367            return createIdentifier(isIdentifier(), diagnosticMessage, privateIdentifierDiagnosticMessage);
2368        }
2369
2370        function parseEtsIdentifier(pos: number): Identifier {
2371            identifierCount++;
2372            const text = internIdentifier(stylesEtsComponentDeclaration!.type);
2373            return finishVirtualNode(factory.createIdentifier(text), pos, pos);
2374        }
2375
2376        function parseIdentifierName(diagnosticMessage?: DiagnosticMessage): Identifier {
2377            return createIdentifier(tokenIsIdentifierOrKeyword(token()), diagnosticMessage);
2378        }
2379
2380        function isLiteralPropertyName(): boolean {
2381            return tokenIsIdentifierOrKeyword(token()) ||
2382                token() === SyntaxKind.StringLiteral ||
2383                token() === SyntaxKind.NumericLiteral;
2384        }
2385
2386        function isAssertionKey(): boolean {
2387            return tokenIsIdentifierOrKeyword(token()) ||
2388                token() === SyntaxKind.StringLiteral;
2389        }
2390
2391        function parsePropertyNameWorker(allowComputedPropertyNames: boolean): PropertyName {
2392            if (token() === SyntaxKind.StringLiteral || token() === SyntaxKind.NumericLiteral) {
2393                const node = parseLiteralNode() as StringLiteral | NumericLiteral;
2394                node.text = internIdentifier(node.text);
2395                return node;
2396            }
2397            if (allowComputedPropertyNames && token() === SyntaxKind.OpenBracketToken) {
2398                return parseComputedPropertyName();
2399            }
2400            if (token() === SyntaxKind.PrivateIdentifier) {
2401                return parsePrivateIdentifier();
2402            }
2403            return parseIdentifierName();
2404        }
2405
2406        function parsePropertyName(): PropertyName {
2407            return parsePropertyNameWorker(/*allowComputedPropertyNames*/ true);
2408        }
2409
2410        function parseComputedPropertyName(): ComputedPropertyName {
2411            // PropertyName [Yield]:
2412            //      LiteralPropertyName
2413            //      ComputedPropertyName[?Yield]
2414            const pos = getNodePos();
2415            parseExpected(SyntaxKind.OpenBracketToken);
2416            // We parse any expression (including a comma expression). But the grammar
2417            // says that only an assignment expression is allowed, so the grammar checker
2418            // will error if it sees a comma expression.
2419            const expression = allowInAnd(parseExpression);
2420            parseExpected(SyntaxKind.CloseBracketToken);
2421            return finishNode(factory.createComputedPropertyName(expression), pos);
2422        }
2423
2424        function internPrivateIdentifier(text: string): string {
2425            let privateIdentifier = privateIdentifiers.get(text);
2426            if (privateIdentifier === undefined) {
2427                privateIdentifiers.set(text, privateIdentifier = text);
2428            }
2429            return privateIdentifier;
2430        }
2431
2432        function parsePrivateIdentifier(): PrivateIdentifier {
2433            const pos = getNodePos();
2434            const node = factory.createPrivateIdentifier(internPrivateIdentifier(scanner.getTokenValue()));
2435            nextToken();
2436            return finishNode(node, pos);
2437        }
2438
2439        function parseContextualModifier(t: SyntaxKind): boolean {
2440            return token() === t && tryParse(nextTokenCanFollowModifier);
2441        }
2442
2443        function nextTokenIsOnSameLineAndCanFollowModifier() {
2444            nextToken();
2445            if (scanner.hasPrecedingLineBreak()) {
2446                return false;
2447            }
2448            return canFollowModifier();
2449        }
2450
2451        function nextTokenCanFollowModifier() {
2452            switch (token()) {
2453                case SyntaxKind.ConstKeyword:
2454                    // 'const' is only a modifier if followed by 'enum'.
2455                    return nextToken() === SyntaxKind.EnumKeyword;
2456                case SyntaxKind.ExportKeyword:
2457                    nextToken();
2458                    if (token() === SyntaxKind.DefaultKeyword) {
2459                        return lookAhead(nextTokenCanFollowDefaultKeyword);
2460                    }
2461                    if (token() === SyntaxKind.TypeKeyword) {
2462                        return lookAhead(nextTokenCanFollowExportModifier);
2463                    }
2464                    return canFollowExportModifier();
2465                case SyntaxKind.DefaultKeyword:
2466                    return nextTokenCanFollowDefaultKeyword();
2467                case SyntaxKind.AccessorKeyword:
2468                case SyntaxKind.StaticKeyword:
2469                case SyntaxKind.GetKeyword:
2470                case SyntaxKind.SetKeyword:
2471                    nextToken();
2472                    return canFollowModifier();
2473                default:
2474                    return nextTokenIsOnSameLineAndCanFollowModifier();
2475            }
2476        }
2477
2478        function canFollowExportModifier(): boolean {
2479            return token() !== SyntaxKind.AsteriskToken
2480                && token() !== SyntaxKind.AsKeyword
2481                && token() !== SyntaxKind.OpenBraceToken
2482                && canFollowModifier();
2483        }
2484
2485        function nextTokenCanFollowExportModifier(): boolean {
2486            nextToken();
2487            return canFollowExportModifier();
2488        }
2489
2490        function parseAnyContextualModifier(): boolean {
2491            return isModifierKind(token()) && tryParse(nextTokenCanFollowModifier);
2492        }
2493
2494        function canFollowModifier(): boolean {
2495            return token() === SyntaxKind.OpenBracketToken
2496                || token() === SyntaxKind.OpenBraceToken
2497                || token() === SyntaxKind.AsteriskToken
2498                || token() === SyntaxKind.DotDotDotToken
2499                || isLiteralPropertyName();
2500        }
2501
2502        function nextTokenCanFollowDefaultKeyword(): boolean {
2503            nextToken();
2504            return token() === SyntaxKind.ClassKeyword || (inEtsContext() && token() === SyntaxKind.StructKeyword) ||
2505                token() === SyntaxKind.FunctionKeyword || token() === SyntaxKind.InterfaceKeyword ||
2506                (token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsClassKeywordOnSameLine)) ||
2507                (token() === SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsFunctionKeywordOnSameLine));
2508        }
2509
2510        // True if positioned at the start of a list element
2511        function isListElement(parsingContext: ParsingContext, inErrorRecovery: boolean): boolean {
2512            const node = currentNode(parsingContext);
2513            if (node) {
2514                return true;
2515            }
2516
2517            switch (parsingContext) {
2518                case ParsingContext.SourceElements:
2519                case ParsingContext.BlockStatements:
2520                case ParsingContext.SwitchClauseStatements:
2521                    // If we're in error recovery, then we don't want to treat ';' as an empty statement.
2522                    // The problem is that ';' can show up in far too many contexts, and if we see one
2523                    // and assume it's a statement, then we may bail out inappropriately from whatever
2524                    // we're parsing.  For example, if we have a semicolon in the middle of a class, then
2525                    // we really don't want to assume the class is over and we're on a statement in the
2526                    // outer module.  We just want to consume and move on.
2527                    return !(token() === SyntaxKind.SemicolonToken && inErrorRecovery) && isStartOfStatement();
2528                case ParsingContext.SwitchClauses:
2529                    return token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword;
2530                case ParsingContext.TypeMembers:
2531                    return lookAhead(isTypeMemberStart);
2532                case ParsingContext.ClassMembers:
2533                    // We allow semicolons as class elements (as specified by ES6) as long as we're
2534                    // not in error recovery.  If we're in error recovery, we don't want an errant
2535                    // semicolon to be treated as a class member (since they're almost always used
2536                    // for statements.
2537                    return lookAhead(isClassMemberStart) || (token() === SyntaxKind.SemicolonToken && !inErrorRecovery);
2538                case ParsingContext.EnumMembers:
2539                    // Include open bracket computed properties. This technically also lets in indexers,
2540                    // which would be a candidate for improved error reporting.
2541                    return token() === SyntaxKind.OpenBracketToken || isLiteralPropertyName();
2542                case ParsingContext.ObjectLiteralMembers:
2543                    switch (token()) {
2544                        case SyntaxKind.OpenBracketToken:
2545                        case SyntaxKind.AsteriskToken:
2546                        case SyntaxKind.DotDotDotToken:
2547                        case SyntaxKind.DotToken: // Not an object literal member, but don't want to close the object (see `tests/cases/fourslash/completionsDotInObjectLiteral.ts`)
2548                            return true;
2549                        default:
2550                            return isLiteralPropertyName();
2551                    }
2552                case ParsingContext.RestProperties:
2553                    return isLiteralPropertyName();
2554                case ParsingContext.ObjectBindingElements:
2555                    return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName();
2556                case ParsingContext.AssertEntries:
2557                    return isAssertionKey();
2558                case ParsingContext.HeritageClauseElement:
2559                    // If we see `{ ... }` then only consume it as an expression if it is followed by `,` or `{`
2560                    // That way we won't consume the body of a class in its heritage clause.
2561                    if (token() === SyntaxKind.OpenBraceToken) {
2562                        return lookAhead(isValidHeritageClauseObjectLiteral);
2563                    }
2564
2565                    if (!inErrorRecovery) {
2566                        return isStartOfLeftHandSideExpression() && !isHeritageClauseExtendsOrImplementsKeyword();
2567                    }
2568                    else {
2569                        // If we're in error recovery we tighten up what we're willing to match.
2570                        // That way we don't treat something like "this" as a valid heritage clause
2571                        // element during recovery.
2572                        return isIdentifier() && !isHeritageClauseExtendsOrImplementsKeyword();
2573                    }
2574                case ParsingContext.VariableDeclarations:
2575                    return isBindingIdentifierOrPrivateIdentifierOrPattern();
2576                case ParsingContext.ArrayBindingElements:
2577                    return token() === SyntaxKind.CommaToken || token() === SyntaxKind.DotDotDotToken || isBindingIdentifierOrPrivateIdentifierOrPattern();
2578                case ParsingContext.TypeParameters:
2579                    return token() === SyntaxKind.InKeyword || isIdentifier();
2580                case ParsingContext.ArrayLiteralMembers:
2581                    switch (token()) {
2582                        case SyntaxKind.CommaToken:
2583                        case SyntaxKind.DotToken: // Not an array literal member, but don't want to close the array (see `tests/cases/fourslash/completionsDotInArrayLiteralInObjectLiteral.ts`)
2584                            return true;
2585                    }
2586                    // falls through
2587                case ParsingContext.ArgumentExpressions:
2588                    return token() === SyntaxKind.DotDotDotToken || isStartOfExpression();
2589                case ParsingContext.Parameters:
2590                    return isStartOfParameter(/*isJSDocParameter*/ false);
2591                case ParsingContext.JSDocParameters:
2592                    return isStartOfParameter(/*isJSDocParameter*/ true);
2593                case ParsingContext.TypeArguments:
2594                case ParsingContext.TupleElementTypes:
2595                    return token() === SyntaxKind.CommaToken || isStartOfType();
2596                case ParsingContext.HeritageClauses:
2597                    return isHeritageClause();
2598                case ParsingContext.ImportOrExportSpecifiers:
2599                    return tokenIsIdentifierOrKeyword(token());
2600                case ParsingContext.JsxAttributes:
2601                    return tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.OpenBraceToken;
2602                case ParsingContext.JsxChildren:
2603                    return true;
2604            }
2605
2606            return Debug.fail("Non-exhaustive case in 'isListElement'.");
2607        }
2608
2609        function isValidHeritageClauseObjectLiteral() {
2610            Debug.assert(token() === SyntaxKind.OpenBraceToken);
2611            if (nextToken() === SyntaxKind.CloseBraceToken) {
2612                // if we see "extends {}" then only treat the {} as what we're extending (and not
2613                // the class body) if we have:
2614                //
2615                //      extends {} {
2616                //      extends {},
2617                //      extends {} extends
2618                //      extends {} implements
2619
2620                const next = nextToken();
2621                return next === SyntaxKind.CommaToken || next === SyntaxKind.OpenBraceToken || next === SyntaxKind.ExtendsKeyword || next === SyntaxKind.ImplementsKeyword;
2622            }
2623
2624            return true;
2625        }
2626
2627        function nextTokenIsIdentifier() {
2628            nextToken();
2629            return isIdentifier();
2630        }
2631
2632        function nextTokenIsIdentifierOrKeyword() {
2633            nextToken();
2634            return tokenIsIdentifierOrKeyword(token());
2635        }
2636
2637        function nextTokenIsIdentifierOrKeywordOrGreaterThan() {
2638            nextToken();
2639            return tokenIsIdentifierOrKeywordOrGreaterThan(token());
2640        }
2641
2642        function isHeritageClauseExtendsOrImplementsKeyword(): boolean {
2643            if (token() === SyntaxKind.ImplementsKeyword ||
2644                token() === SyntaxKind.ExtendsKeyword) {
2645
2646                return lookAhead(nextTokenIsStartOfExpression);
2647            }
2648
2649            return false;
2650        }
2651
2652        function nextTokenIsStartOfExpression() {
2653            nextToken();
2654            return isStartOfExpression();
2655        }
2656
2657        function nextTokenIsStartOfType() {
2658            nextToken();
2659            return isStartOfType();
2660        }
2661
2662        // True if positioned at a list terminator
2663        function isListTerminator(kind: ParsingContext): boolean {
2664            if (token() === SyntaxKind.EndOfFileToken) {
2665                // Being at the end of the file ends all lists.
2666                return true;
2667            }
2668
2669            switch (kind) {
2670                case ParsingContext.BlockStatements:
2671                case ParsingContext.SwitchClauses:
2672                case ParsingContext.TypeMembers:
2673                case ParsingContext.ClassMembers:
2674                case ParsingContext.EnumMembers:
2675                case ParsingContext.ObjectLiteralMembers:
2676                case ParsingContext.ObjectBindingElements:
2677                case ParsingContext.ImportOrExportSpecifiers:
2678                case ParsingContext.AssertEntries:
2679                    return token() === SyntaxKind.CloseBraceToken;
2680                case ParsingContext.SwitchClauseStatements:
2681                    return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword;
2682                case ParsingContext.HeritageClauseElement:
2683                    return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword;
2684                case ParsingContext.VariableDeclarations:
2685                    return isVariableDeclaratorListTerminator();
2686                case ParsingContext.TypeParameters:
2687                    // Tokens other than '>' are here for better error recovery
2688                    return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword;
2689                case ParsingContext.ArgumentExpressions:
2690                    // Tokens other than ')' are here for better error recovery
2691                    return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.SemicolonToken;
2692                case ParsingContext.ArrayLiteralMembers:
2693                case ParsingContext.TupleElementTypes:
2694                case ParsingContext.ArrayBindingElements:
2695                    return token() === SyntaxKind.CloseBracketToken;
2696                case ParsingContext.JSDocParameters:
2697                case ParsingContext.Parameters:
2698                case ParsingContext.RestProperties:
2699                    // Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery
2700                    return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.CloseBracketToken /*|| token === SyntaxKind.OpenBraceToken*/;
2701                case ParsingContext.TypeArguments:
2702                    // All other tokens should cause the type-argument to terminate except comma token
2703                    return token() !== SyntaxKind.CommaToken;
2704                case ParsingContext.HeritageClauses:
2705                    return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.CloseBraceToken;
2706                case ParsingContext.JsxAttributes:
2707                    return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.SlashToken;
2708                case ParsingContext.JsxChildren:
2709                    return token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsSlash);
2710                default:
2711                    return false;
2712            }
2713        }
2714
2715        function isVariableDeclaratorListTerminator(): boolean {
2716            // If we can consume a semicolon (either explicitly, or with ASI), then consider us done
2717            // with parsing the list of variable declarators.
2718            if (canParseSemicolon()) {
2719                return true;
2720            }
2721
2722            // in the case where we're parsing the variable declarator of a 'for-in' statement, we
2723            // are done if we see an 'in' keyword in front of us. Same with for-of
2724            if (isInOrOfKeyword(token())) {
2725                return true;
2726            }
2727
2728            // ERROR RECOVERY TWEAK:
2729            // For better error recovery, if we see an '=>' then we just stop immediately.  We've got an
2730            // arrow function here and it's going to be very unlikely that we'll resynchronize and get
2731            // another variable declaration.
2732            if (token() === SyntaxKind.EqualsGreaterThanToken) {
2733                return true;
2734            }
2735
2736            // Keep trying to parse out variable declarators.
2737            return false;
2738        }
2739
2740        // True if positioned at element or terminator of the current list or any enclosing list
2741        function isInSomeParsingContext(): boolean {
2742            for (let kind = 0; kind < ParsingContext.Count; kind++) {
2743                if (parsingContext & (1 << kind)) {
2744                    if (isListElement(kind, /*inErrorRecovery*/ true) || isListTerminator(kind)) {
2745                        return true;
2746                    }
2747                }
2748            }
2749
2750            return false;
2751        }
2752
2753        // Parses a list of elements
2754        function parseList<T extends Node>(kind: ParsingContext, parseElement: () => T): NodeArray<T> {
2755            const saveParsingContext = parsingContext;
2756            parsingContext |= 1 << kind;
2757            const list = [];
2758            const listPos = getNodePos();
2759
2760            while (!isListTerminator(kind)) {
2761                if (isListElement(kind, /*inErrorRecovery*/ false)) {
2762                    list.push(parseListElement(kind, parseElement));
2763
2764                    continue;
2765                }
2766
2767                if (abortParsingListOrMoveToNextToken(kind)) {
2768                    break;
2769                }
2770            }
2771
2772            parsingContext = saveParsingContext;
2773            return createNodeArray(list, listPos);
2774        }
2775
2776        function parseListElement<T extends Node | undefined>(parsingContext: ParsingContext, parseElement: () => T): T {
2777            const node = currentNode(parsingContext);
2778            if (node) {
2779                return consumeNode(node) as T;
2780            }
2781
2782            return parseElement();
2783        }
2784
2785        function currentNode(parsingContext: ParsingContext, pos?: number): Node | undefined {
2786            // If we don't have a cursor or the parsing context isn't reusable, there's nothing to reuse.
2787            //
2788            // If there is an outstanding parse error that we've encountered, but not attached to
2789            // some node, then we cannot get a node from the old source tree.  This is because we
2790            // want to mark the next node we encounter as being unusable.
2791            //
2792            // Note: This may be too conservative.  Perhaps we could reuse the node and set the bit
2793            // on it (or its leftmost child) as having the error.  For now though, being conservative
2794            // is nice and likely won't ever affect perf.
2795            if (!syntaxCursor || !isReusableParsingContext(parsingContext) || parseErrorBeforeNextFinishedNode) {
2796                return undefined;
2797            }
2798
2799            const node = syntaxCursor.currentNode(pos ?? scanner.getStartPos());
2800
2801            // Can't reuse a missing node.
2802            // Can't reuse a node that intersected the change range.
2803            // Can't reuse a node that contains a parse error.  This is necessary so that we
2804            // produce the same set of errors again.
2805            if (nodeIsMissing(node) || node.intersectsChange || containsParseError(node)) {
2806                return undefined;
2807            }
2808
2809            // We can only reuse a node if it was parsed under the same strict mode that we're
2810            // currently in.  i.e. if we originally parsed a node in non-strict mode, but then
2811            // the user added 'using strict' at the top of the file, then we can't use that node
2812            // again as the presence of strict mode may cause us to parse the tokens in the file
2813            // differently.
2814            //
2815            // Note: we *can* reuse tokens when the strict mode changes.  That's because tokens
2816            // are unaffected by strict mode.  It's just the parser will decide what to do with it
2817            // differently depending on what mode it is in.
2818            //
2819            // This also applies to all our other context flags as well.
2820            const nodeContextFlags = node.flags & NodeFlags.ContextFlags;
2821            if (nodeContextFlags !== contextFlags) {
2822                return undefined;
2823            }
2824
2825            // Ok, we have a node that looks like it could be reused.  Now verify that it is valid
2826            // in the current list parsing context that we're currently at.
2827            if (!canReuseNode(node, parsingContext)) {
2828                return undefined;
2829            }
2830
2831            if ((node as JSDocContainer).jsDocCache) {
2832                // jsDocCache may include tags from parent nodes, which might have been modified.
2833                (node as JSDocContainer).jsDocCache = undefined;
2834            }
2835
2836            return node;
2837        }
2838
2839        function consumeNode(node: Node) {
2840            // Move the scanner so it is after the node we just consumed.
2841            scanner.setTextPos(node.end);
2842            nextToken();
2843            return node;
2844        }
2845
2846        function isReusableParsingContext(parsingContext: ParsingContext): boolean {
2847            switch (parsingContext) {
2848                case ParsingContext.ClassMembers:
2849                case ParsingContext.SwitchClauses:
2850                case ParsingContext.SourceElements:
2851                case ParsingContext.BlockStatements:
2852                case ParsingContext.SwitchClauseStatements:
2853                case ParsingContext.EnumMembers:
2854                case ParsingContext.TypeMembers:
2855                case ParsingContext.VariableDeclarations:
2856                case ParsingContext.JSDocParameters:
2857                case ParsingContext.Parameters:
2858                    return true;
2859            }
2860            return false;
2861        }
2862
2863        function canReuseNode(node: Node, parsingContext: ParsingContext): boolean {
2864            switch (parsingContext) {
2865                case ParsingContext.ClassMembers:
2866                    return isReusableClassMember(node);
2867
2868                case ParsingContext.SwitchClauses:
2869                    return isReusableSwitchClause(node);
2870
2871                case ParsingContext.SourceElements:
2872                case ParsingContext.BlockStatements:
2873                case ParsingContext.SwitchClauseStatements:
2874                    return isReusableStatement(node);
2875
2876                case ParsingContext.EnumMembers:
2877                    return isReusableEnumMember(node);
2878
2879                case ParsingContext.TypeMembers:
2880                    return isReusableTypeMember(node);
2881
2882                case ParsingContext.VariableDeclarations:
2883                    return isReusableVariableDeclaration(node);
2884
2885                case ParsingContext.JSDocParameters:
2886                case ParsingContext.Parameters:
2887                    return isReusableParameter(node);
2888
2889                // Any other lists we do not care about reusing nodes in.  But feel free to add if
2890                // you can do so safely.  Danger areas involve nodes that may involve speculative
2891                // parsing.  If speculative parsing is involved with the node, then the range the
2892                // parser reached while looking ahead might be in the edited range (see the example
2893                // in canReuseVariableDeclaratorNode for a good case of this).
2894
2895                // case ParsingContext.HeritageClauses:
2896                // This would probably be safe to reuse.  There is no speculative parsing with
2897                // heritage clauses.
2898
2899                // case ParsingContext.TypeParameters:
2900                // This would probably be safe to reuse.  There is no speculative parsing with
2901                // type parameters.  Note that that's because type *parameters* only occur in
2902                // unambiguous *type* contexts.  While type *arguments* occur in very ambiguous
2903                // *expression* contexts.
2904
2905                // case ParsingContext.TupleElementTypes:
2906                // This would probably be safe to reuse.  There is no speculative parsing with
2907                // tuple types.
2908
2909                // Technically, type argument list types are probably safe to reuse.  While
2910                // speculative parsing is involved with them (since type argument lists are only
2911                // produced from speculative parsing a < as a type argument list), we only have
2912                // the types because speculative parsing succeeded.  Thus, the lookahead never
2913                // went past the end of the list and rewound.
2914                // case ParsingContext.TypeArguments:
2915
2916                // Note: these are almost certainly not safe to ever reuse.  Expressions commonly
2917                // need a large amount of lookahead, and we should not reuse them as they may
2918                // have actually intersected the edit.
2919                // case ParsingContext.ArgumentExpressions:
2920
2921                // This is not safe to reuse for the same reason as the 'AssignmentExpression'
2922                // cases.  i.e. a property assignment may end with an expression, and thus might
2923                // have lookahead far beyond it's old node.
2924                // case ParsingContext.ObjectLiteralMembers:
2925
2926                // This is probably not safe to reuse.  There can be speculative parsing with
2927                // type names in a heritage clause.  There can be generic names in the type
2928                // name list, and there can be left hand side expressions (which can have type
2929                // arguments.)
2930                // case ParsingContext.HeritageClauseElement:
2931
2932                // Perhaps safe to reuse, but it's unlikely we'd see more than a dozen attributes
2933                // on any given element. Same for children.
2934                // case ParsingContext.JsxAttributes:
2935                // case ParsingContext.JsxChildren:
2936
2937            }
2938
2939            return false;
2940        }
2941
2942        function isReusableClassMember(node: Node) {
2943            if (node) {
2944                switch (node.kind) {
2945                    case SyntaxKind.Constructor:
2946                    case SyntaxKind.IndexSignature:
2947                    case SyntaxKind.GetAccessor:
2948                    case SyntaxKind.SetAccessor:
2949                    case SyntaxKind.SemicolonClassElement:
2950                        return true;
2951                    case SyntaxKind.PropertyDeclaration:
2952                        return !inStructContext();
2953                    case SyntaxKind.MethodDeclaration:
2954                        // Method declarations are not necessarily reusable.  An object-literal
2955                        // may have a method calls "constructor(...)" and we must reparse that
2956                        // into an actual .ConstructorDeclaration.
2957                        const methodDeclaration = node as MethodDeclaration;
2958                        const nameIsConstructor = methodDeclaration.name.kind === SyntaxKind.Identifier &&
2959                            methodDeclaration.name.originalKeywordKind === SyntaxKind.ConstructorKeyword;
2960
2961                        return !nameIsConstructor;
2962                }
2963            }
2964
2965            return false;
2966        }
2967
2968        function isReusableSwitchClause(node: Node) {
2969            if (node) {
2970                switch (node.kind) {
2971                    case SyntaxKind.CaseClause:
2972                    case SyntaxKind.DefaultClause:
2973                        return true;
2974                }
2975            }
2976
2977            return false;
2978        }
2979
2980        function isReusableStatement(node: Node) {
2981            if (node) {
2982                switch (node.kind) {
2983                    case SyntaxKind.FunctionDeclaration:
2984                    case SyntaxKind.VariableStatement:
2985                    case SyntaxKind.Block:
2986                    case SyntaxKind.IfStatement:
2987                    case SyntaxKind.ExpressionStatement:
2988                    case SyntaxKind.ThrowStatement:
2989                    case SyntaxKind.ReturnStatement:
2990                    case SyntaxKind.SwitchStatement:
2991                    case SyntaxKind.BreakStatement:
2992                    case SyntaxKind.ContinueStatement:
2993                    case SyntaxKind.ForInStatement:
2994                    case SyntaxKind.ForOfStatement:
2995                    case SyntaxKind.ForStatement:
2996                    case SyntaxKind.WhileStatement:
2997                    case SyntaxKind.WithStatement:
2998                    case SyntaxKind.EmptyStatement:
2999                    case SyntaxKind.TryStatement:
3000                    case SyntaxKind.LabeledStatement:
3001                    case SyntaxKind.DoStatement:
3002                    case SyntaxKind.DebuggerStatement:
3003                    case SyntaxKind.ImportDeclaration:
3004                    case SyntaxKind.ImportEqualsDeclaration:
3005                    case SyntaxKind.ExportDeclaration:
3006                    case SyntaxKind.ExportAssignment:
3007                    case SyntaxKind.ModuleDeclaration:
3008                    case SyntaxKind.ClassDeclaration:
3009                    case SyntaxKind.StructDeclaration:
3010                    case SyntaxKind.InterfaceDeclaration:
3011                    case SyntaxKind.EnumDeclaration:
3012                    case SyntaxKind.TypeAliasDeclaration:
3013                        return true;
3014                }
3015            }
3016
3017            return false;
3018        }
3019
3020        function isReusableEnumMember(node: Node) {
3021            return node.kind === SyntaxKind.EnumMember;
3022        }
3023
3024        function isReusableTypeMember(node: Node) {
3025            if (node) {
3026                switch (node.kind) {
3027                    case SyntaxKind.ConstructSignature:
3028                    case SyntaxKind.MethodSignature:
3029                    case SyntaxKind.IndexSignature:
3030                    case SyntaxKind.PropertySignature:
3031                    case SyntaxKind.CallSignature:
3032                        return true;
3033                }
3034            }
3035
3036            return false;
3037        }
3038
3039        function isReusableVariableDeclaration(node: Node) {
3040            if (node.kind !== SyntaxKind.VariableDeclaration) {
3041                return false;
3042            }
3043
3044            // Very subtle incremental parsing bug.  Consider the following code:
3045            //
3046            //      let v = new List < A, B
3047            //
3048            // This is actually legal code.  It's a list of variable declarators "v = new List<A"
3049            // on one side and "B" on the other. If you then change that to:
3050            //
3051            //      let v = new List < A, B >()
3052            //
3053            // then we have a problem.  "v = new List<A" doesn't intersect the change range, so we
3054            // start reparsing at "B" and we completely fail to handle this properly.
3055            //
3056            // In order to prevent this, we do not allow a variable declarator to be reused if it
3057            // has an initializer.
3058            const variableDeclarator = node as VariableDeclaration;
3059            return variableDeclarator.initializer === undefined;
3060        }
3061
3062        function isReusableParameter(node: Node) {
3063            if (node.kind !== SyntaxKind.Parameter) {
3064                return false;
3065            }
3066
3067            // See the comment in isReusableVariableDeclaration for why we do this.
3068            const parameter = node as ParameterDeclaration;
3069            return parameter.initializer === undefined;
3070        }
3071
3072        // Returns true if we should abort parsing.
3073        function abortParsingListOrMoveToNextToken(kind: ParsingContext) {
3074            parsingContextErrors(kind);
3075            if (isInSomeParsingContext()) {
3076                return true;
3077            }
3078
3079            nextToken();
3080            return false;
3081        }
3082
3083        function parsingContextErrors(context: ParsingContext) {
3084            switch (context) {
3085                case ParsingContext.SourceElements:
3086                    return token() === SyntaxKind.DefaultKeyword
3087                        ? parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.ExportKeyword))
3088                        : parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected);
3089                case ParsingContext.BlockStatements: return parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected);
3090                case ParsingContext.SwitchClauses: return parseErrorAtCurrentToken(Diagnostics.case_or_default_expected);
3091                case ParsingContext.SwitchClauseStatements: return parseErrorAtCurrentToken(Diagnostics.Statement_expected);
3092                case ParsingContext.RestProperties: // fallthrough
3093                case ParsingContext.TypeMembers: return parseErrorAtCurrentToken(Diagnostics.Property_or_signature_expected);
3094                case ParsingContext.ClassMembers: return parseErrorAtCurrentToken(Diagnostics.Unexpected_token_A_constructor_method_accessor_or_property_was_expected);
3095                case ParsingContext.EnumMembers: return parseErrorAtCurrentToken(Diagnostics.Enum_member_expected);
3096                case ParsingContext.HeritageClauseElement: return parseErrorAtCurrentToken(Diagnostics.Expression_expected);
3097                case ParsingContext.VariableDeclarations:
3098                    return isKeyword(token())
3099                        ? parseErrorAtCurrentToken(Diagnostics._0_is_not_allowed_as_a_variable_declaration_name, tokenToString(token()))
3100                        : parseErrorAtCurrentToken(Diagnostics.Variable_declaration_expected);
3101                case ParsingContext.ObjectBindingElements: return parseErrorAtCurrentToken(Diagnostics.Property_destructuring_pattern_expected);
3102                case ParsingContext.ArrayBindingElements: return parseErrorAtCurrentToken(Diagnostics.Array_element_destructuring_pattern_expected);
3103                case ParsingContext.ArgumentExpressions: return parseErrorAtCurrentToken(Diagnostics.Argument_expression_expected);
3104                case ParsingContext.ObjectLiteralMembers: return parseErrorAtCurrentToken(Diagnostics.Property_assignment_expected);
3105                case ParsingContext.ArrayLiteralMembers: return parseErrorAtCurrentToken(Diagnostics.Expression_or_comma_expected);
3106                case ParsingContext.JSDocParameters: return parseErrorAtCurrentToken(Diagnostics.Parameter_declaration_expected);
3107                case ParsingContext.Parameters:
3108                    return isKeyword(token())
3109                        ? parseErrorAtCurrentToken(Diagnostics._0_is_not_allowed_as_a_parameter_name, tokenToString(token()))
3110                        : parseErrorAtCurrentToken(Diagnostics.Parameter_declaration_expected);
3111                case ParsingContext.TypeParameters: return parseErrorAtCurrentToken(Diagnostics.Type_parameter_declaration_expected);
3112                case ParsingContext.TypeArguments: return parseErrorAtCurrentToken(Diagnostics.Type_argument_expected);
3113                case ParsingContext.TupleElementTypes: return parseErrorAtCurrentToken(Diagnostics.Type_expected);
3114                case ParsingContext.HeritageClauses: return parseErrorAtCurrentToken(Diagnostics.Unexpected_token_expected);
3115                case ParsingContext.ImportOrExportSpecifiers: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected);
3116                case ParsingContext.JsxAttributes: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected);
3117                case ParsingContext.JsxChildren: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected);
3118                case ParsingContext.AssertEntries: return parseErrorAtCurrentToken(Diagnostics.Identifier_or_string_literal_expected); // AssertionKey.
3119                case ParsingContext.Count: return Debug.fail("ParsingContext.Count used as a context"); // Not a real context, only a marker.
3120                default: Debug.assertNever(context);
3121            }
3122        }
3123
3124        // Parses a comma-delimited list of elements
3125        function parseDelimitedList<T extends Node>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<T>;
3126        function parseDelimitedList<T extends Node | undefined>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<NonNullable<T>> | undefined;
3127        function parseDelimitedList<T extends Node | undefined>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<NonNullable<T>> | undefined {
3128            const saveParsingContext = parsingContext;
3129            parsingContext |= 1 << kind;
3130            const list: NonNullable<T>[] = [];
3131            const listPos = getNodePos();
3132
3133            let commaStart = -1; // Meaning the previous token was not a comma
3134            while (true) {
3135                if (isListElement(kind, /*inErrorRecovery*/ false)) {
3136                    const startPos = scanner.getStartPos();
3137                    const result = parseListElement(kind, parseElement);
3138                    if (!result) {
3139                        parsingContext = saveParsingContext;
3140                        return undefined;
3141                    }
3142                    list.push(result);
3143                    commaStart = scanner.getTokenPos();
3144
3145                    if (parseOptional(SyntaxKind.CommaToken)) {
3146                        // No need to check for a zero length node since we know we parsed a comma
3147                        continue;
3148                    }
3149
3150                    commaStart = -1; // Back to the state where the last token was not a comma
3151                    if (isListTerminator(kind)) {
3152                        break;
3153                    }
3154
3155                    // We didn't get a comma, and the list wasn't terminated, explicitly parse
3156                    // out a comma so we give a good error message.
3157                    parseExpected(SyntaxKind.CommaToken, getExpectedCommaDiagnostic(kind));
3158
3159                    // If the token was a semicolon, and the caller allows that, then skip it and
3160                    // continue.  This ensures we get back on track and don't result in tons of
3161                    // parse errors.  For example, this can happen when people do things like use
3162                    // a semicolon to delimit object literal members.   Note: we'll have already
3163                    // reported an error when we called parseExpected above.
3164                    if (considerSemicolonAsDelimiter && token() === SyntaxKind.SemicolonToken && !scanner.hasPrecedingLineBreak()) {
3165                        nextToken();
3166                    }
3167                    if (startPos === scanner.getStartPos()) {
3168                        // What we're parsing isn't actually remotely recognizable as a element and we've consumed no tokens whatsoever
3169                        // Consume a token to advance the parser in some way and avoid an infinite loop
3170                        // This can happen when we're speculatively parsing parenthesized expressions which we think may be arrow functions,
3171                        // or when a modifier keyword which is disallowed as a parameter name (ie, `static` in strict mode) is supplied
3172                        nextToken();
3173                    }
3174                    continue;
3175                }
3176
3177                if (isListTerminator(kind)) {
3178                    break;
3179                }
3180
3181                if (abortParsingListOrMoveToNextToken(kind)) {
3182                    break;
3183                }
3184            }
3185
3186            parsingContext = saveParsingContext;
3187            // Recording the trailing comma is deliberately done after the previous
3188            // loop, and not just if we see a list terminator. This is because the list
3189            // may have ended incorrectly, but it is still important to know if there
3190            // was a trailing comma.
3191            // Check if the last token was a comma.
3192            // Always preserve a trailing comma by marking it on the NodeArray
3193            return createNodeArray(list, listPos, /*end*/ undefined, commaStart >= 0);
3194        }
3195
3196        function getExpectedCommaDiagnostic(kind: ParsingContext) {
3197            return kind === ParsingContext.EnumMembers ? Diagnostics.An_enum_member_name_must_be_followed_by_a_or : undefined;
3198        }
3199
3200        interface MissingList<T extends Node> extends NodeArray<T> {
3201            isMissingList: true;
3202        }
3203
3204        function createMissingList<T extends Node>(): MissingList<T> {
3205            const list = createNodeArray<T>([], getNodePos()) as MissingList<T>;
3206            list.isMissingList = true;
3207            return list;
3208        }
3209
3210        function isMissingList(arr: NodeArray<Node>): boolean {
3211            return !!(arr as MissingList<Node>).isMissingList;
3212        }
3213
3214        function parseBracketedList<T extends Node>(kind: ParsingContext, parseElement: () => T, open: SyntaxKind, close: SyntaxKind): NodeArray<T> {
3215            if (parseExpected(open)) {
3216                const result = parseDelimitedList(kind, parseElement);
3217                parseExpected(close);
3218                return result;
3219            }
3220
3221            return createMissingList<T>();
3222        }
3223
3224        function parseEntityName(allowReservedWords: boolean, diagnosticMessage?: DiagnosticMessage): EntityName {
3225            const pos = getNodePos();
3226            let entity: EntityName = allowReservedWords ? parseIdentifierName(diagnosticMessage) : parseIdentifier(diagnosticMessage);
3227            let dotPos = getNodePos();
3228            while (parseOptional(SyntaxKind.DotToken)) {
3229                if (token() === SyntaxKind.LessThanToken) {
3230                    // the entity is part of a JSDoc-style generic, so record the trailing dot for later error reporting
3231                    entity.jsdocDotPos = dotPos;
3232                    break;
3233                }
3234                dotPos = getNodePos();
3235                entity = finishNode(
3236                    factory.createQualifiedName(
3237                        entity,
3238                        parseRightSideOfDot(allowReservedWords, /* allowPrivateIdentifiers */ false) as Identifier
3239                    ),
3240                    pos
3241                );
3242            }
3243            return entity;
3244        }
3245
3246        function createQualifiedName(entity: EntityName, name: Identifier): QualifiedName {
3247            return finishNode(factory.createQualifiedName(entity, name), entity.pos);
3248        }
3249
3250        function parseRightSideOfDot(allowIdentifierNames: boolean, allowPrivateIdentifiers: boolean): Identifier | PrivateIdentifier {
3251            // Technically a keyword is valid here as all identifiers and keywords are identifier names.
3252            // However, often we'll encounter this in error situations when the identifier or keyword
3253            // is actually starting another valid construct.
3254            //
3255            // So, we check for the following specific case:
3256            //
3257            //      name.
3258            //      identifierOrKeyword identifierNameOrKeyword
3259            //
3260            // Note: the newlines are important here.  For example, if that above code
3261            // were rewritten into:
3262            //
3263            //      name.identifierOrKeyword
3264            //      identifierNameOrKeyword
3265            //
3266            // Then we would consider it valid.  That's because ASI would take effect and
3267            // the code would be implicitly: "name.identifierOrKeyword; identifierNameOrKeyword".
3268            // In the first case though, ASI will not take effect because there is not a
3269            // line terminator after the identifier or keyword.
3270            if (scanner.hasPrecedingLineBreak() && tokenIsIdentifierOrKeyword(token())) {
3271                const matchesPattern = lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine);
3272
3273                if (matchesPattern) {
3274                    // Report that we need an identifier.  However, report it right after the dot,
3275                    // and not on the next token.  This is because the next token might actually
3276                    // be an identifier and the error would be quite confusing.
3277                    return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected);
3278                }
3279            }
3280
3281            if (token() === SyntaxKind.PrivateIdentifier) {
3282                const node = parsePrivateIdentifier();
3283                return allowPrivateIdentifiers ? node : createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected);
3284            }
3285
3286            return allowIdentifierNames ? parseIdentifierName() : parseIdentifier();
3287        }
3288
3289        function parseTemplateSpans(isTaggedTemplate: boolean) {
3290            const pos = getNodePos();
3291            const list = [];
3292            let node: TemplateSpan;
3293            do {
3294                node = parseTemplateSpan(isTaggedTemplate);
3295                list.push(node);
3296            }
3297            while (node.literal.kind === SyntaxKind.TemplateMiddle);
3298            return createNodeArray(list, pos);
3299        }
3300
3301        function parseTemplateExpression(isTaggedTemplate: boolean): TemplateExpression {
3302            const pos = getNodePos();
3303            return finishNode(
3304                factory.createTemplateExpression(
3305                    parseTemplateHead(isTaggedTemplate),
3306                    parseTemplateSpans(isTaggedTemplate)
3307                ),
3308                pos
3309            );
3310        }
3311
3312        function parseTemplateType(): TemplateLiteralTypeNode {
3313            const pos = getNodePos();
3314            return finishNode(
3315                factory.createTemplateLiteralType(
3316                    parseTemplateHead(/*isTaggedTemplate*/ false),
3317                    parseTemplateTypeSpans()
3318                ),
3319                pos
3320            );
3321        }
3322
3323        function parseTemplateTypeSpans() {
3324            const pos = getNodePos();
3325            const list = [];
3326            let node: TemplateLiteralTypeSpan;
3327            do {
3328                node = parseTemplateTypeSpan();
3329                list.push(node);
3330            }
3331            while (node.literal.kind === SyntaxKind.TemplateMiddle);
3332            return createNodeArray(list, pos);
3333        }
3334
3335        function parseTemplateTypeSpan(): TemplateLiteralTypeSpan {
3336            const pos = getNodePos();
3337            return finishNode(
3338                factory.createTemplateLiteralTypeSpan(
3339                    parseType(),
3340                    parseLiteralOfTemplateSpan(/*isTaggedTemplate*/ false)
3341                ),
3342                pos
3343            );
3344        }
3345
3346        function parseLiteralOfTemplateSpan(isTaggedTemplate: boolean) {
3347            if (token() === SyntaxKind.CloseBraceToken) {
3348                reScanTemplateToken(isTaggedTemplate);
3349                return parseTemplateMiddleOrTemplateTail();
3350            }
3351            else {
3352                // TODO(rbuckton): Do we need to call `parseExpectedToken` or can we just call `createMissingNode` directly?
3353                return parseExpectedToken(SyntaxKind.TemplateTail, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken)) as TemplateTail;
3354            }
3355        }
3356
3357        function parseTemplateSpan(isTaggedTemplate: boolean): TemplateSpan {
3358            const pos = getNodePos();
3359            return finishNode(
3360                factory.createTemplateSpan(
3361                    allowInAnd(parseExpression),
3362                    parseLiteralOfTemplateSpan(isTaggedTemplate)
3363                ),
3364                pos
3365            );
3366        }
3367
3368        function parseLiteralNode(): LiteralExpression {
3369            return parseLiteralLikeNode(token()) as LiteralExpression;
3370        }
3371
3372        function parseTemplateHead(isTaggedTemplate: boolean): TemplateHead {
3373            if (isTaggedTemplate) {
3374                reScanTemplateHeadOrNoSubstitutionTemplate();
3375            }
3376            const fragment = parseLiteralLikeNode(token());
3377            Debug.assert(fragment.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind");
3378            return fragment as TemplateHead;
3379        }
3380
3381        function parseTemplateMiddleOrTemplateTail(): TemplateMiddle | TemplateTail {
3382            const fragment = parseLiteralLikeNode(token());
3383            Debug.assert(fragment.kind === SyntaxKind.TemplateMiddle || fragment.kind === SyntaxKind.TemplateTail, "Template fragment has wrong token kind");
3384            return fragment as TemplateMiddle | TemplateTail;
3385        }
3386
3387        function getTemplateLiteralRawText(kind: TemplateLiteralToken["kind"]) {
3388            const isLast = kind === SyntaxKind.NoSubstitutionTemplateLiteral || kind === SyntaxKind.TemplateTail;
3389            const tokenText = scanner.getTokenText();
3390            return tokenText.substring(1, tokenText.length - (scanner.isUnterminated() ? 0 : isLast ? 1 : 2));
3391        }
3392
3393        function parseLiteralLikeNode(kind: SyntaxKind): LiteralLikeNode {
3394            const pos = getNodePos();
3395            const node =
3396                isTemplateLiteralKind(kind) ? factory.createTemplateLiteralLikeNode(kind, scanner.getTokenValue(), getTemplateLiteralRawText(kind), scanner.getTokenFlags() & TokenFlags.TemplateLiteralLikeFlags) :
3397                // Octal literals are not allowed in strict mode or ES5
3398                // Note that theoretically the following condition would hold true literals like 009,
3399                // which is not octal. But because of how the scanner separates the tokens, we would
3400                // never get a token like this. Instead, we would get 00 and 9 as two separate tokens.
3401                // We also do not need to check for negatives because any prefix operator would be part of a
3402                // parent unary expression.
3403                kind === SyntaxKind.NumericLiteral ? factory.createNumericLiteral(scanner.getTokenValue(), scanner.getNumericLiteralFlags()) :
3404                kind === SyntaxKind.StringLiteral ? factory.createStringLiteral(scanner.getTokenValue(), /*isSingleQuote*/ undefined, scanner.hasExtendedUnicodeEscape()) :
3405                isLiteralKind(kind) ? factory.createLiteralLikeNode(kind, scanner.getTokenValue()) :
3406                Debug.fail();
3407
3408            if (scanner.hasExtendedUnicodeEscape()) {
3409                node.hasExtendedUnicodeEscape = true;
3410            }
3411
3412            if (scanner.isUnterminated()) {
3413                node.isUnterminated = true;
3414            }
3415
3416            nextToken();
3417            return finishNode(node, pos);
3418        }
3419
3420        // TYPES
3421
3422        function parseEntityNameOfTypeReference() {
3423            return parseEntityName(/*allowReservedWords*/ true, Diagnostics.Type_expected);
3424        }
3425
3426        function parseTypeArgumentsOfTypeReference() {
3427            if (!scanner.hasPrecedingLineBreak() && reScanLessThanToken() === SyntaxKind.LessThanToken) {
3428                return parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken);
3429            }
3430        }
3431
3432        function parseTypeReference(): TypeReferenceNode {
3433            const pos = getNodePos();
3434            return finishNode(
3435                factory.createTypeReferenceNode(
3436                    parseEntityNameOfTypeReference(),
3437                    parseTypeArgumentsOfTypeReference()
3438                ),
3439                pos
3440            );
3441        }
3442
3443        // If true, we should abort parsing an error function.
3444        function typeHasArrowFunctionBlockingParseError(node: TypeNode): boolean {
3445            switch (node.kind) {
3446                case SyntaxKind.TypeReference:
3447                    return nodeIsMissing((node as TypeReferenceNode).typeName);
3448                case SyntaxKind.FunctionType:
3449                case SyntaxKind.ConstructorType: {
3450                    const { parameters, type } = node as FunctionOrConstructorTypeNode;
3451                    return isMissingList(parameters) || typeHasArrowFunctionBlockingParseError(type);
3452                }
3453                case SyntaxKind.ParenthesizedType:
3454                    return typeHasArrowFunctionBlockingParseError((node as ParenthesizedTypeNode).type);
3455                default:
3456                    return false;
3457            }
3458        }
3459
3460        function parseThisTypePredicate(lhs: ThisTypeNode): TypePredicateNode {
3461            nextToken();
3462            return finishNode(factory.createTypePredicateNode(/*assertsModifier*/ undefined, lhs, parseType()), lhs.pos);
3463        }
3464
3465        function parseThisTypeNode(): ThisTypeNode {
3466            const pos = getNodePos();
3467            nextToken();
3468            return finishNode(factory.createThisTypeNode(), pos);
3469        }
3470
3471        function parseJSDocAllType(): JSDocAllType | JSDocOptionalType {
3472            const pos = getNodePos();
3473            nextToken();
3474            return finishNode(factory.createJSDocAllType(), pos);
3475        }
3476
3477        function parseJSDocNonNullableType(): TypeNode {
3478            const pos = getNodePos();
3479            nextToken();
3480            return finishNode(factory.createJSDocNonNullableType(parseNonArrayType(), /*postfix*/ false), pos);
3481        }
3482
3483        function parseJSDocUnknownOrNullableType(): JSDocUnknownType | JSDocNullableType {
3484            const pos = getNodePos();
3485            // skip the ?
3486            nextToken();
3487
3488            // Need to lookahead to decide if this is a nullable or unknown type.
3489
3490            // Here are cases where we'll pick the unknown type:
3491            //
3492            //      Foo(?,
3493            //      { a: ? }
3494            //      Foo(?)
3495            //      Foo<?>
3496            //      Foo(?=
3497            //      (?|
3498            if (token() === SyntaxKind.CommaToken ||
3499                token() === SyntaxKind.CloseBraceToken ||
3500                token() === SyntaxKind.CloseParenToken ||
3501                token() === SyntaxKind.GreaterThanToken ||
3502                token() === SyntaxKind.EqualsToken ||
3503                token() === SyntaxKind.BarToken) {
3504                return finishNode(factory.createJSDocUnknownType(), pos);
3505            }
3506            else {
3507                return finishNode(factory.createJSDocNullableType(parseType(), /*postfix*/ false), pos);
3508            }
3509        }
3510
3511        function parseJSDocFunctionType(): JSDocFunctionType | TypeReferenceNode {
3512            const pos = getNodePos();
3513            const hasJSDoc = hasPrecedingJSDocComment();
3514            if (lookAhead(nextTokenIsOpenParen)) {
3515                nextToken();
3516                const parameters = parseParameters(SignatureFlags.Type | SignatureFlags.JSDoc);
3517                const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);
3518                return withJSDoc(finishNode(factory.createJSDocFunctionType(parameters, type), pos), hasJSDoc);
3519            }
3520            return finishNode(factory.createTypeReferenceNode(parseIdentifierName(), /*typeArguments*/ undefined), pos);
3521        }
3522
3523        function parseJSDocParameter(): ParameterDeclaration {
3524            const pos = getNodePos();
3525            let name: Identifier | undefined;
3526            if (token() === SyntaxKind.ThisKeyword || token() === SyntaxKind.NewKeyword) {
3527                name = parseIdentifierName();
3528                parseExpected(SyntaxKind.ColonToken);
3529            }
3530            return finishNode(
3531                factory.createParameterDeclaration(
3532                    /*modifiers*/ undefined,
3533                    /*dotDotDotToken*/ undefined,
3534                    // TODO(rbuckton): JSDoc parameters don't have names (except `this`/`new`), should we manufacture an empty identifier?
3535                    name!,
3536                    /*questionToken*/ undefined,
3537                    parseJSDocType(),
3538                    /*initializer*/ undefined
3539                ),
3540                pos
3541            );
3542        }
3543
3544        function parseJSDocType(): TypeNode {
3545            scanner.setInJSDocType(true);
3546            const pos = getNodePos();
3547            if (parseOptional(SyntaxKind.ModuleKeyword)) {
3548                // TODO(rbuckton): We never set the type for a JSDocNamepathType. What should we put here?
3549                const moduleTag = factory.createJSDocNamepathType(/*type*/ undefined!);
3550                terminate: while (true) {
3551                    switch (token()) {
3552                        case SyntaxKind.CloseBraceToken:
3553                        case SyntaxKind.EndOfFileToken:
3554                        case SyntaxKind.CommaToken:
3555                        case SyntaxKind.WhitespaceTrivia:
3556                            break terminate;
3557                        default:
3558                            nextTokenJSDoc();
3559                    }
3560                }
3561
3562                scanner.setInJSDocType(false);
3563                return finishNode(moduleTag, pos);
3564            }
3565
3566            const hasDotDotDot = parseOptional(SyntaxKind.DotDotDotToken);
3567            let type = parseTypeOrTypePredicate();
3568            scanner.setInJSDocType(false);
3569            if (hasDotDotDot) {
3570                type = finishNode(factory.createJSDocVariadicType(type), pos);
3571            }
3572            if (token() === SyntaxKind.EqualsToken) {
3573                nextToken();
3574                return finishNode(factory.createJSDocOptionalType(type), pos);
3575            }
3576            return type;
3577        }
3578
3579        function parseTypeQuery(): TypeQueryNode {
3580            const pos = getNodePos();
3581            parseExpected(SyntaxKind.TypeOfKeyword);
3582            const entityName = parseEntityName(/*allowReservedWords*/ true);
3583            // Make sure we perform ASI to prevent parsing the next line's type arguments as part of an instantiation expression.
3584            const typeArguments = !scanner.hasPrecedingLineBreak() ? tryParseTypeArguments() : undefined;
3585            return finishNode(factory.createTypeQueryNode(entityName, typeArguments), pos);
3586        }
3587
3588        function parseTypeParameter(position?: number): TypeParameterDeclaration {
3589            const pos = getNodePos();
3590            const modifiers = parseModifiers();
3591            const name = position !== undefined ? parseEtsIdentifier(position) : parseIdentifier();
3592            let constraint: TypeNode | undefined;
3593            let expression: Expression | undefined;
3594            if (parseOptional(SyntaxKind.ExtendsKeyword)) {
3595                // It's not uncommon for people to write improper constraints to a generic.  If the
3596                // user writes a constraint that is an expression and not an actual type, then parse
3597                // it out as an expression (so we can recover well), but report that a type is needed
3598                // instead.
3599                if (isStartOfType() || !isStartOfExpression()) {
3600                    constraint = parseType();
3601                }
3602                else {
3603                    // It was not a type, and it looked like an expression.  Parse out an expression
3604                    // here so we recover well.  Note: it is important that we call parseUnaryExpression
3605                    // and not parseExpression here.  If the user has:
3606                    //
3607                    //      <T extends "">
3608                    //
3609                    // We do *not* want to consume the `>` as we're consuming the expression for "".
3610                    expression = parseUnaryExpressionOrHigher();
3611                }
3612            }
3613
3614            const defaultType = parseOptional(SyntaxKind.EqualsToken) ? parseType() : undefined;
3615            const node = factory.createTypeParameterDeclaration(modifiers, name, constraint, defaultType);
3616            node.expression = expression;
3617            return position !== undefined ? finishVirtualNode(node, position, position) : finishNode(node, pos);
3618        }
3619
3620        function parseTypeParameters(): NodeArray<TypeParameterDeclaration> | undefined {
3621            if (token() === SyntaxKind.LessThanToken) {
3622                return parseBracketedList(ParsingContext.TypeParameters, parseTypeParameter, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken);
3623            }
3624        }
3625
3626        function parseEtsTypeParameters(pos: number): NodeArray<TypeParameterDeclaration> | undefined {
3627            return createNodeArray([parseTypeParameter(pos)], getNodePos());
3628        }
3629
3630        function parseEtsTypeArguments(pos: number, name: string): NodeArray<TypeNode> | undefined {
3631            if ((contextFlags & NodeFlags.JavaScriptFile) !== 0) {
3632                // TypeArguments must not be parsed in JavaScript files to avoid ambiguity with binary operators.
3633                return undefined;
3634            }
3635
3636            return createNodeArray([parseEtsType(pos, name)], getNodePos());
3637        }
3638
3639        function isStartOfParameter(isJSDocParameter: boolean): boolean {
3640            return token() === SyntaxKind.DotDotDotToken ||
3641                isBindingIdentifierOrPrivateIdentifierOrPattern() ||
3642                isModifierKind(token()) ||
3643                token() === SyntaxKind.AtToken ||
3644                isStartOfType(/*inStartOfParameter*/ !isJSDocParameter);
3645        }
3646
3647        function parseNameOfParameter(modifiers: NodeArray<ModifierLike> | undefined) {
3648            // FormalParameter [Yield,Await]:
3649            //      BindingElement[?Yield,?Await]
3650            const name = parseIdentifierOrPattern(Diagnostics.Private_identifiers_cannot_be_used_as_parameters);
3651            if (getFullWidth(name) === 0 && !some(modifiers) && isModifierKind(token())) {
3652                // in cases like
3653                // 'use strict'
3654                // function foo(static)
3655                // isParameter('static') === true, because of isModifier('static')
3656                // however 'static' is not a legal identifier in a strict mode.
3657                // so result of this function will be ParameterDeclaration (flags = 0, name = missing, type = undefined, initializer = undefined)
3658                // and current token will not change => parsing of the enclosing parameter list will last till the end of time (or OOM)
3659                // to avoid this we'll advance cursor to the next token.
3660                nextToken();
3661            }
3662            return name;
3663        }
3664
3665        function isParameterNameStart() {
3666            // Be permissive about await and yield by calling isBindingIdentifier instead of isIdentifier; disallowing
3667            // them during a speculative parse leads to many more follow-on errors than allowing the function to parse then later
3668            // complaining about the use of the keywords.
3669            return isBindingIdentifier() || token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.OpenBraceToken;
3670        }
3671
3672        function parseParameter(inOuterAwaitContext: boolean): ParameterDeclaration {
3673            return parseParameterWorker(inOuterAwaitContext);
3674        }
3675
3676        function parseParameterForSpeculation(inOuterAwaitContext: boolean): ParameterDeclaration | undefined {
3677            return parseParameterWorker(inOuterAwaitContext, /*allowAmbiguity*/ false);
3678        }
3679
3680        function parseParameterWorker(inOuterAwaitContext: boolean): ParameterDeclaration;
3681        function parseParameterWorker(inOuterAwaitContext: boolean, allowAmbiguity: false): ParameterDeclaration | undefined;
3682        function parseParameterWorker(inOuterAwaitContext: boolean, allowAmbiguity = true): ParameterDeclaration | undefined {
3683            const pos = getNodePos();
3684            const hasJSDoc = hasPrecedingJSDocComment();
3685
3686            // FormalParameter [Yield,Await]:
3687            //      BindingElement[?Yield,?Await]
3688
3689            // Decorators are parsed in the outer [Await] context, the rest of the parameter is parsed in the function's [Await] context.
3690            const decorators = inOuterAwaitContext ? doInAwaitContext(parseDecorators) : doOutsideOfAwaitContext(parseDecorators);
3691
3692            if (token() === SyntaxKind.ThisKeyword) {
3693                const node = factory.createParameterDeclaration(
3694                    decorators,
3695                    /*dotDotDotToken*/ undefined,
3696                    createIdentifier(/*isIdentifier*/ true),
3697                    /*questionToken*/ undefined,
3698                    parseTypeAnnotation(),
3699                    /*initializer*/ undefined
3700                );
3701
3702                if (decorators) {
3703                    parseErrorAtRange(decorators[0], Diagnostics.Decorators_may_not_be_applied_to_this_parameters);
3704                }
3705
3706                return withJSDoc(finishNode(node, pos), hasJSDoc);
3707            }
3708
3709            const savedTopLevel = topLevel;
3710            topLevel = false;
3711
3712            const modifiers = combineDecoratorsAndModifiers(decorators, parseModifiers());
3713            const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
3714
3715            if (!allowAmbiguity && !isParameterNameStart()) {
3716                return undefined;
3717            }
3718
3719            const node = withJSDoc(
3720                finishNode(
3721                    factory.createParameterDeclaration(
3722                        modifiers,
3723                        dotDotDotToken,
3724                        parseNameOfParameter(modifiers),
3725                        parseOptionalToken(SyntaxKind.QuestionToken),
3726                        parseTypeAnnotation(),
3727                        parseInitializer()
3728                    ),
3729                    pos
3730                ),
3731                hasJSDoc
3732            );
3733            topLevel = savedTopLevel;
3734            return node;
3735        }
3736
3737        function parseReturnType(returnToken: SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode;
3738        function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode | undefined;
3739        function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean) {
3740            if (shouldParseReturnType(returnToken, isType)) {
3741                return allowConditionalTypesAnd(parseTypeOrTypePredicate);
3742            }
3743        }
3744
3745        function shouldParseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): boolean {
3746            if (returnToken === SyntaxKind.EqualsGreaterThanToken) {
3747                parseExpected(returnToken);
3748                return true;
3749            }
3750            else if (parseOptional(SyntaxKind.ColonToken)) {
3751                return true;
3752            }
3753            else if (isType && token() === SyntaxKind.EqualsGreaterThanToken) {
3754                // This is easy to get backward, especially in type contexts, so parse the type anyway
3755                parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken));
3756                nextToken();
3757                return true;
3758            }
3759            return false;
3760        }
3761
3762        function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: true): NodeArray<ParameterDeclaration>;
3763        function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: false): NodeArray<ParameterDeclaration> | undefined;
3764        function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: boolean): NodeArray<ParameterDeclaration> | undefined {
3765            // FormalParameters [Yield,Await]: (modified)
3766            //      [empty]
3767            //      FormalParameterList[?Yield,Await]
3768            //
3769            // FormalParameter[Yield,Await]: (modified)
3770            //      BindingElement[?Yield,Await]
3771            //
3772            // BindingElement [Yield,Await]: (modified)
3773            //      SingleNameBinding[?Yield,?Await]
3774            //      BindingPattern[?Yield,?Await]Initializer [In, ?Yield,?Await] opt
3775            //
3776            // SingleNameBinding [Yield,Await]:
3777            //      BindingIdentifier[?Yield,?Await]Initializer [In, ?Yield,?Await] opt
3778            const savedYieldContext = inYieldContext();
3779            const savedAwaitContext = inAwaitContext();
3780
3781            setYieldContext(!!(flags & SignatureFlags.Yield));
3782            setAwaitContext(!!(flags & SignatureFlags.Await));
3783
3784            const parameters = flags & SignatureFlags.JSDoc ?
3785                parseDelimitedList(ParsingContext.JSDocParameters, parseJSDocParameter) :
3786                parseDelimitedList(ParsingContext.Parameters, () => allowAmbiguity ? parseParameter(savedAwaitContext) : parseParameterForSpeculation(savedAwaitContext));
3787
3788            setYieldContext(savedYieldContext);
3789            setAwaitContext(savedAwaitContext);
3790
3791            return parameters;
3792        }
3793
3794        function parseParameters(flags: SignatureFlags): NodeArray<ParameterDeclaration> {
3795            // FormalParameters [Yield,Await]: (modified)
3796            //      [empty]
3797            //      FormalParameterList[?Yield,Await]
3798            //
3799            // FormalParameter[Yield,Await]: (modified)
3800            //      BindingElement[?Yield,Await]
3801            //
3802            // BindingElement [Yield,Await]: (modified)
3803            //      SingleNameBinding[?Yield,?Await]
3804            //      BindingPattern[?Yield,?Await]Initializer [In, ?Yield,?Await] opt
3805            //
3806            // SingleNameBinding [Yield,Await]:
3807            //      BindingIdentifier[?Yield,?Await]Initializer [In, ?Yield,?Await] opt
3808            if (!parseExpected(SyntaxKind.OpenParenToken)) {
3809                return createMissingList<ParameterDeclaration>();
3810            }
3811
3812            const parameters = parseParametersWorker(flags, /*allowAmbiguity*/ true);
3813            parseExpected(SyntaxKind.CloseParenToken);
3814            return parameters;
3815        }
3816
3817        function parseTypeMemberSemicolon() {
3818            // We allow type members to be separated by commas or (possibly ASI) semicolons.
3819            // First check if it was a comma.  If so, we're done with the member.
3820            if (parseOptional(SyntaxKind.CommaToken)) {
3821                return;
3822            }
3823
3824            // Didn't have a comma.  We must have a (possible ASI) semicolon.
3825            parseSemicolon();
3826        }
3827
3828        function parseSignatureMember(kind: SyntaxKind.CallSignature | SyntaxKind.ConstructSignature): CallSignatureDeclaration | ConstructSignatureDeclaration {
3829            const pos = getNodePos();
3830            const hasJSDoc = hasPrecedingJSDocComment();
3831            if (kind === SyntaxKind.ConstructSignature) {
3832                parseExpected(SyntaxKind.NewKeyword);
3833            }
3834
3835            const typeParameters = parseTypeParameters();
3836            const parameters = parseParameters(SignatureFlags.Type);
3837            const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ true);
3838            parseTypeMemberSemicolon();
3839            const node = kind === SyntaxKind.CallSignature
3840                ? factory.createCallSignature(typeParameters, parameters, type)
3841                : factory.createConstructSignature(typeParameters, parameters, type);
3842            return withJSDoc(finishNode(node, pos), hasJSDoc);
3843        }
3844
3845        function isIndexSignature(): boolean {
3846            return token() === SyntaxKind.OpenBracketToken && lookAhead(isUnambiguouslyIndexSignature);
3847        }
3848
3849        function isUnambiguouslyIndexSignature() {
3850            // The only allowed sequence is:
3851            //
3852            //   [id:
3853            //
3854            // However, for error recovery, we also check the following cases:
3855            //
3856            //   [...
3857            //   [id,
3858            //   [id?,
3859            //   [id?:
3860            //   [id?]
3861            //   [public id
3862            //   [private id
3863            //   [protected id
3864            //   []
3865            //
3866            nextToken();
3867            if (token() === SyntaxKind.DotDotDotToken || token() === SyntaxKind.CloseBracketToken) {
3868                return true;
3869            }
3870
3871            if (isModifierKind(token())) {
3872                nextToken();
3873                if (isIdentifier()) {
3874                    return true;
3875                }
3876            }
3877            else if (!isIdentifier()) {
3878                return false;
3879            }
3880            else {
3881                // Skip the identifier
3882                nextToken();
3883            }
3884
3885            // A colon signifies a well formed indexer
3886            // A comma should be a badly formed indexer because comma expressions are not allowed
3887            // in computed properties.
3888            if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken) {
3889                return true;
3890            }
3891
3892            // Question mark could be an indexer with an optional property,
3893            // or it could be a conditional expression in a computed property.
3894            if (token() !== SyntaxKind.QuestionToken) {
3895                return false;
3896            }
3897
3898            // If any of the following tokens are after the question mark, it cannot
3899            // be a conditional expression, so treat it as an indexer.
3900            nextToken();
3901            return token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.CloseBracketToken;
3902        }
3903
3904        function parseIndexSignatureDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): IndexSignatureDeclaration {
3905            const parameters = parseBracketedList<ParameterDeclaration>(ParsingContext.Parameters, () => parseParameter(/*inOuterAwaitContext*/ false), SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
3906            const type = parseTypeAnnotation();
3907            parseTypeMemberSemicolon();
3908            const node = factory.createIndexSignature(modifiers, parameters, type);
3909            (node as Mutable<IndexSignatureDeclaration>).illegalDecorators = decorators;
3910            return withJSDoc(finishNode(node, pos), hasJSDoc);
3911        }
3912
3913        function parsePropertyOrMethodSignature(pos: number, hasJSDoc: boolean, modifiers: NodeArray<Modifier> | undefined): PropertySignature | MethodSignature {
3914            const name = parsePropertyName();
3915            const questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
3916            let node: PropertySignature | MethodSignature;
3917            if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
3918                // Method signatures don't exist in expression contexts.  So they have neither
3919                // [Yield] nor [Await]
3920                const typeParameters = parseTypeParameters();
3921                const parameters = parseParameters(SignatureFlags.Type);
3922                const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ true);
3923                node = factory.createMethodSignature(modifiers, name, questionToken, typeParameters, parameters, type);
3924            }
3925            else {
3926                const type = parseTypeAnnotation();
3927                node = factory.createPropertySignature(modifiers, name, questionToken, type);
3928                // Although type literal properties cannot not have initializers, we attempt
3929                // to parse an initializer so we can report in the checker that an interface
3930                // property or type literal property cannot have an initializer.
3931                if (token() === SyntaxKind.EqualsToken) (node as Mutable<PropertySignature>).initializer = parseInitializer();
3932            }
3933            parseTypeMemberSemicolon();
3934            return withJSDoc(finishNode(node, pos), hasJSDoc);
3935        }
3936
3937        function isTypeMemberStart(): boolean {
3938            // Return true if we have the start of a signature member
3939            if (token() === SyntaxKind.OpenParenToken ||
3940                token() === SyntaxKind.LessThanToken ||
3941                token() === SyntaxKind.GetKeyword ||
3942                token() === SyntaxKind.SetKeyword) {
3943                return true;
3944            }
3945            let idToken = false;
3946            // Eat up all modifiers, but hold on to the last one in case it is actually an identifier
3947            while (isModifierKind(token())) {
3948                idToken = true;
3949                nextToken();
3950            }
3951            // Index signatures and computed property names are type members
3952            if (token() === SyntaxKind.OpenBracketToken) {
3953                return true;
3954            }
3955            // Try to get the first property-like token following all modifiers
3956            if (isLiteralPropertyName()) {
3957                idToken = true;
3958                nextToken();
3959            }
3960            // If we were able to get any potential identifier, check that it is
3961            // the start of a member declaration
3962            if (idToken) {
3963                return token() === SyntaxKind.OpenParenToken ||
3964                    token() === SyntaxKind.LessThanToken ||
3965                    token() === SyntaxKind.QuestionToken ||
3966                    token() === SyntaxKind.ColonToken ||
3967                    token() === SyntaxKind.CommaToken ||
3968                    canParseSemicolon();
3969            }
3970            return false;
3971        }
3972
3973        function parseTypeMember(): TypeElement {
3974            if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
3975                return parseSignatureMember(SyntaxKind.CallSignature);
3976            }
3977            if (token() === SyntaxKind.NewKeyword && lookAhead(nextTokenIsOpenParenOrLessThan)) {
3978                return parseSignatureMember(SyntaxKind.ConstructSignature);
3979            }
3980            const pos = getNodePos();
3981            const hasJSDoc = hasPrecedingJSDocComment();
3982            const modifiers = parseModifiers();
3983            if (parseContextualModifier(SyntaxKind.GetKeyword)) {
3984                return parseAccessorDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers, SyntaxKind.GetAccessor, SignatureFlags.Type);
3985            }
3986
3987            if (parseContextualModifier(SyntaxKind.SetKeyword)) {
3988                return parseAccessorDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers, SyntaxKind.SetAccessor, SignatureFlags.Type);
3989            }
3990
3991            if (isIndexSignature()) {
3992                return parseIndexSignatureDeclaration(pos, hasJSDoc, /*decorators*/ undefined, modifiers);
3993            }
3994            return parsePropertyOrMethodSignature(pos, hasJSDoc, modifiers);
3995        }
3996
3997        function nextTokenIsOpenParenOrLessThan() {
3998            nextToken();
3999            return token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken;
4000        }
4001
4002        function nextTokenIsDot() {
4003            return nextToken() === SyntaxKind.DotToken;
4004        }
4005
4006        function nextTokenIsOpenParenOrLessThanOrDot() {
4007            switch (nextToken()) {
4008                case SyntaxKind.OpenParenToken:
4009                case SyntaxKind.LessThanToken:
4010                case SyntaxKind.DotToken:
4011                    return true;
4012            }
4013            return false;
4014        }
4015
4016        function parseTypeLiteral(): TypeLiteralNode {
4017            const pos = getNodePos();
4018            return finishNode(factory.createTypeLiteralNode(parseObjectTypeMembers()), pos);
4019        }
4020
4021        function parseObjectTypeMembers(): NodeArray<TypeElement> {
4022            let members: NodeArray<TypeElement>;
4023            if (parseExpected(SyntaxKind.OpenBraceToken)) {
4024                members = parseList(ParsingContext.TypeMembers, parseTypeMember);
4025                parseExpected(SyntaxKind.CloseBraceToken);
4026            }
4027            else {
4028                members = createMissingList<TypeElement>();
4029            }
4030
4031            return members;
4032        }
4033
4034        function isStartOfMappedType() {
4035            nextToken();
4036            if (token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) {
4037                return nextToken() === SyntaxKind.ReadonlyKeyword;
4038            }
4039            if (token() === SyntaxKind.ReadonlyKeyword) {
4040                nextToken();
4041            }
4042            return token() === SyntaxKind.OpenBracketToken && nextTokenIsIdentifier() && nextToken() === SyntaxKind.InKeyword;
4043        }
4044
4045        function parseMappedTypeParameter() {
4046            const pos = getNodePos();
4047            const name = parseIdentifierName();
4048            parseExpected(SyntaxKind.InKeyword);
4049            const type = parseType();
4050            return finishNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, type, /*defaultType*/ undefined), pos);
4051        }
4052
4053        function parseMappedType() {
4054            const pos = getNodePos();
4055            parseExpected(SyntaxKind.OpenBraceToken);
4056            let readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined;
4057            if (token() === SyntaxKind.ReadonlyKeyword || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) {
4058                readonlyToken = parseTokenNode<ReadonlyKeyword | PlusToken | MinusToken>();
4059                if (readonlyToken.kind !== SyntaxKind.ReadonlyKeyword) {
4060                    parseExpected(SyntaxKind.ReadonlyKeyword);
4061                }
4062            }
4063            parseExpected(SyntaxKind.OpenBracketToken);
4064            const typeParameter = parseMappedTypeParameter();
4065            const nameType = parseOptional(SyntaxKind.AsKeyword) ? parseType() : undefined;
4066            parseExpected(SyntaxKind.CloseBracketToken);
4067            let questionToken: QuestionToken | PlusToken | MinusToken | undefined;
4068            if (token() === SyntaxKind.QuestionToken || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) {
4069                questionToken = parseTokenNode<QuestionToken | PlusToken | MinusToken>();
4070                if (questionToken.kind !== SyntaxKind.QuestionToken) {
4071                    parseExpected(SyntaxKind.QuestionToken);
4072                }
4073            }
4074            const type = parseTypeAnnotation();
4075            parseSemicolon();
4076            const members = parseList(ParsingContext.TypeMembers, parseTypeMember);
4077            parseExpected(SyntaxKind.CloseBraceToken);
4078            return finishNode(factory.createMappedTypeNode(readonlyToken, typeParameter, nameType, questionToken, type, members), pos);
4079        }
4080
4081        function parseTupleElementType() {
4082            const pos = getNodePos();
4083            if (parseOptional(SyntaxKind.DotDotDotToken)) {
4084                return finishNode(factory.createRestTypeNode(parseType()), pos);
4085            }
4086            const type = parseType();
4087            if (isJSDocNullableType(type) && type.pos === type.type.pos) {
4088                const node = factory.createOptionalTypeNode(type.type);
4089                setTextRange(node, type);
4090                (node as Mutable<Node>).flags = type.flags;
4091                return node;
4092            }
4093            return type;
4094        }
4095
4096        function isNextTokenColonOrQuestionColon() {
4097            return nextToken() === SyntaxKind.ColonToken || (token() === SyntaxKind.QuestionToken && nextToken() === SyntaxKind.ColonToken);
4098        }
4099
4100        function isTupleElementName() {
4101            if (token() === SyntaxKind.DotDotDotToken) {
4102                return tokenIsIdentifierOrKeyword(nextToken()) && isNextTokenColonOrQuestionColon();
4103            }
4104            return tokenIsIdentifierOrKeyword(token()) && isNextTokenColonOrQuestionColon();
4105        }
4106
4107        function parseTupleElementNameOrTupleElementType() {
4108            if (lookAhead(isTupleElementName)) {
4109                const pos = getNodePos();
4110                const hasJSDoc = hasPrecedingJSDocComment();
4111                const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
4112                const name = parseIdentifierName();
4113                const questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
4114                parseExpected(SyntaxKind.ColonToken);
4115                const type = parseTupleElementType();
4116                const node = factory.createNamedTupleMember(dotDotDotToken, name, questionToken, type);
4117                return withJSDoc(finishNode(node, pos), hasJSDoc);
4118            }
4119            return parseTupleElementType();
4120        }
4121
4122        function parseTupleType(): TupleTypeNode {
4123            const pos = getNodePos();
4124            return finishNode(
4125                factory.createTupleTypeNode(
4126                    parseBracketedList(ParsingContext.TupleElementTypes, parseTupleElementNameOrTupleElementType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken)
4127                ),
4128                pos
4129            );
4130        }
4131
4132        function parseParenthesizedType(): TypeNode {
4133            const pos = getNodePos();
4134            parseExpected(SyntaxKind.OpenParenToken);
4135            const type = parseType();
4136            parseExpected(SyntaxKind.CloseParenToken);
4137            return finishNode(factory.createParenthesizedType(type), pos);
4138        }
4139
4140        function parseModifiersForConstructorType(): NodeArray<Modifier> | undefined {
4141            let modifiers: NodeArray<Modifier> | undefined;
4142            if (token() === SyntaxKind.AbstractKeyword) {
4143                const pos = getNodePos();
4144                nextToken();
4145                const modifier = finishNode(factory.createToken(SyntaxKind.AbstractKeyword), pos);
4146                modifiers = createNodeArray<Modifier>([modifier], pos);
4147            }
4148            return modifiers;
4149        }
4150
4151        function parseFunctionOrConstructorType(): TypeNode {
4152            const pos = getNodePos();
4153            const hasJSDoc = hasPrecedingJSDocComment();
4154            const modifiers = parseModifiersForConstructorType();
4155            const isConstructorType = parseOptional(SyntaxKind.NewKeyword);
4156            const typeParameters = parseTypeParameters();
4157            const parameters = parseParameters(SignatureFlags.Type);
4158            const type = parseReturnType(SyntaxKind.EqualsGreaterThanToken, /*isType*/ false);
4159            const node = isConstructorType
4160                ? factory.createConstructorTypeNode(modifiers, typeParameters, parameters, type)
4161                : factory.createFunctionTypeNode(typeParameters, parameters, type);
4162            if (!isConstructorType) (node as Mutable<FunctionTypeNode>).modifiers = modifiers;
4163            return withJSDoc(finishNode(node, pos), hasJSDoc);
4164        }
4165
4166        function parseKeywordAndNoDot(): TypeNode | undefined {
4167            const node = parseTokenNode<TypeNode>();
4168            return token() === SyntaxKind.DotToken ? undefined : node;
4169        }
4170
4171        function parseLiteralTypeNode(negative?: boolean): LiteralTypeNode {
4172            const pos = getNodePos();
4173            if (negative) {
4174                nextToken();
4175            }
4176            let expression: BooleanLiteral | NullLiteral | LiteralExpression | PrefixUnaryExpression =
4177                token() === SyntaxKind.TrueKeyword || token() === SyntaxKind.FalseKeyword || token() === SyntaxKind.NullKeyword ?
4178                    parseTokenNode<BooleanLiteral | NullLiteral>() :
4179                    parseLiteralLikeNode(token()) as LiteralExpression;
4180            if (negative) {
4181                expression = finishNode(factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, expression), pos);
4182            }
4183            return finishNode(factory.createLiteralTypeNode(expression), pos);
4184        }
4185
4186        function isStartOfTypeOfImportType() {
4187            nextToken();
4188            return token() === SyntaxKind.ImportKeyword;
4189        }
4190
4191        function parseImportTypeAssertions(): ImportTypeAssertionContainer {
4192            const pos = getNodePos();
4193            const openBracePosition = scanner.getTokenPos();
4194            parseExpected(SyntaxKind.OpenBraceToken);
4195            const multiLine = scanner.hasPrecedingLineBreak();
4196            parseExpected(SyntaxKind.AssertKeyword);
4197            parseExpected(SyntaxKind.ColonToken);
4198            const clause = parseAssertClause(/*skipAssertKeyword*/ true);
4199            if (!parseExpected(SyntaxKind.CloseBraceToken)) {
4200                const lastError = lastOrUndefined(parseDiagnostics);
4201                if (lastError && lastError.code === Diagnostics._0_expected.code) {
4202                    addRelatedInfo(
4203                        lastError,
4204                        createDetachedDiagnostic(fileName, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}")
4205                    );
4206                }
4207            }
4208            return finishNode(factory.createImportTypeAssertionContainer(clause, multiLine), pos);
4209        }
4210
4211        function parseImportType(): ImportTypeNode {
4212            sourceFlags |= NodeFlags.PossiblyContainsDynamicImport;
4213            const pos = getNodePos();
4214            const isTypeOf = parseOptional(SyntaxKind.TypeOfKeyword);
4215            parseExpected(SyntaxKind.ImportKeyword);
4216            parseExpected(SyntaxKind.OpenParenToken);
4217            const type = parseType();
4218            let assertions: ImportTypeAssertionContainer | undefined;
4219            if (parseOptional(SyntaxKind.CommaToken)) {
4220                assertions = parseImportTypeAssertions();
4221            }
4222            parseExpected(SyntaxKind.CloseParenToken);
4223            const qualifier = parseOptional(SyntaxKind.DotToken) ? parseEntityNameOfTypeReference() : undefined;
4224            const typeArguments = parseTypeArgumentsOfTypeReference();
4225            return finishNode(factory.createImportTypeNode(type, assertions, qualifier, typeArguments, isTypeOf), pos);
4226        }
4227
4228        function nextTokenIsNumericOrBigIntLiteral() {
4229            nextToken();
4230            return token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral;
4231        }
4232
4233        function parseNonArrayType(): TypeNode {
4234            switch (token()) {
4235                case SyntaxKind.AnyKeyword:
4236                case SyntaxKind.UnknownKeyword:
4237                case SyntaxKind.StringKeyword:
4238                case SyntaxKind.NumberKeyword:
4239                case SyntaxKind.BigIntKeyword:
4240                case SyntaxKind.SymbolKeyword:
4241                case SyntaxKind.BooleanKeyword:
4242                case SyntaxKind.UndefinedKeyword:
4243                case SyntaxKind.NeverKeyword:
4244                case SyntaxKind.ObjectKeyword:
4245                    // If these are followed by a dot, then parse these out as a dotted type reference instead.
4246                    return tryParse(parseKeywordAndNoDot) || parseTypeReference();
4247                case SyntaxKind.AsteriskEqualsToken:
4248                    // If there is '*=', treat it as * followed by postfix =
4249                    scanner.reScanAsteriskEqualsToken();
4250                    // falls through
4251                case SyntaxKind.AsteriskToken:
4252                    return parseJSDocAllType();
4253                case SyntaxKind.QuestionQuestionToken:
4254                    // If there is '??', treat it as prefix-'?' in JSDoc type.
4255                    scanner.reScanQuestionToken();
4256                    // falls through
4257                case SyntaxKind.QuestionToken:
4258                    return parseJSDocUnknownOrNullableType();
4259                case SyntaxKind.FunctionKeyword:
4260                    return parseJSDocFunctionType();
4261                case SyntaxKind.ExclamationToken:
4262                    return parseJSDocNonNullableType();
4263                case SyntaxKind.NoSubstitutionTemplateLiteral:
4264                case SyntaxKind.StringLiteral:
4265                case SyntaxKind.NumericLiteral:
4266                case SyntaxKind.BigIntLiteral:
4267                case SyntaxKind.TrueKeyword:
4268                case SyntaxKind.FalseKeyword:
4269                case SyntaxKind.NullKeyword:
4270                    return parseLiteralTypeNode();
4271                case SyntaxKind.MinusToken:
4272                    return lookAhead(nextTokenIsNumericOrBigIntLiteral) ? parseLiteralTypeNode(/*negative*/ true) : parseTypeReference();
4273                case SyntaxKind.VoidKeyword:
4274                    return parseTokenNode<TypeNode>();
4275                case SyntaxKind.ThisKeyword: {
4276                    const thisKeyword = parseThisTypeNode();
4277                    if (token() === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) {
4278                        return parseThisTypePredicate(thisKeyword);
4279                    }
4280                    else {
4281                        return thisKeyword;
4282                    }
4283                }
4284                case SyntaxKind.TypeOfKeyword:
4285                    return lookAhead(isStartOfTypeOfImportType) ? parseImportType() : parseTypeQuery();
4286                case SyntaxKind.OpenBraceToken:
4287                    return lookAhead(isStartOfMappedType) ? parseMappedType() : parseTypeLiteral();
4288                case SyntaxKind.OpenBracketToken:
4289                    return parseTupleType();
4290                case SyntaxKind.OpenParenToken:
4291                    return parseParenthesizedType();
4292                case SyntaxKind.ImportKeyword:
4293                    return parseImportType();
4294                case SyntaxKind.AssertsKeyword:
4295                    return lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine) ? parseAssertsTypePredicate() : parseTypeReference();
4296                case SyntaxKind.TemplateHead:
4297                    return parseTemplateType();
4298                default:
4299                    return parseTypeReference();
4300            }
4301        }
4302
4303        function isStartOfType(inStartOfParameter?: boolean): boolean {
4304            switch (token()) {
4305                case SyntaxKind.AnyKeyword:
4306                case SyntaxKind.UnknownKeyword:
4307                case SyntaxKind.StringKeyword:
4308                case SyntaxKind.NumberKeyword:
4309                case SyntaxKind.BigIntKeyword:
4310                case SyntaxKind.BooleanKeyword:
4311                case SyntaxKind.ReadonlyKeyword:
4312                case SyntaxKind.SymbolKeyword:
4313                case SyntaxKind.UniqueKeyword:
4314                case SyntaxKind.VoidKeyword:
4315                case SyntaxKind.UndefinedKeyword:
4316                case SyntaxKind.NullKeyword:
4317                case SyntaxKind.ThisKeyword:
4318                case SyntaxKind.TypeOfKeyword:
4319                case SyntaxKind.NeverKeyword:
4320                case SyntaxKind.OpenBraceToken:
4321                case SyntaxKind.OpenBracketToken:
4322                case SyntaxKind.LessThanToken:
4323                case SyntaxKind.BarToken:
4324                case SyntaxKind.AmpersandToken:
4325                case SyntaxKind.NewKeyword:
4326                case SyntaxKind.StringLiteral:
4327                case SyntaxKind.NumericLiteral:
4328                case SyntaxKind.BigIntLiteral:
4329                case SyntaxKind.TrueKeyword:
4330                case SyntaxKind.FalseKeyword:
4331                case SyntaxKind.ObjectKeyword:
4332                case SyntaxKind.AsteriskToken:
4333                case SyntaxKind.QuestionToken:
4334                case SyntaxKind.ExclamationToken:
4335                case SyntaxKind.DotDotDotToken:
4336                case SyntaxKind.InferKeyword:
4337                case SyntaxKind.ImportKeyword:
4338                case SyntaxKind.AssertsKeyword:
4339                case SyntaxKind.NoSubstitutionTemplateLiteral:
4340                case SyntaxKind.TemplateHead:
4341                    return true;
4342                case SyntaxKind.FunctionKeyword:
4343                    return !inStartOfParameter;
4344                case SyntaxKind.MinusToken:
4345                    return !inStartOfParameter && lookAhead(nextTokenIsNumericOrBigIntLiteral);
4346                case SyntaxKind.OpenParenToken:
4347                    // Only consider '(' the start of a type if followed by ')', '...', an identifier, a modifier,
4348                    // or something that starts a type. We don't want to consider things like '(1)' a type.
4349                    return !inStartOfParameter && lookAhead(isStartOfParenthesizedOrFunctionType);
4350                default:
4351                    return isIdentifier();
4352            }
4353        }
4354
4355        function isStartOfParenthesizedOrFunctionType() {
4356            nextToken();
4357            return token() === SyntaxKind.CloseParenToken || isStartOfParameter(/*isJSDocParameter*/ false) || isStartOfType();
4358        }
4359
4360        function parsePostfixTypeOrHigher(): TypeNode {
4361            const pos = getNodePos();
4362            let type = parseNonArrayType();
4363            while (!scanner.hasPrecedingLineBreak()) {
4364                switch (token()) {
4365                    case SyntaxKind.ExclamationToken:
4366                        nextToken();
4367                        type = finishNode(factory.createJSDocNonNullableType(type, /*postfix*/ true), pos);
4368                        break;
4369                    case SyntaxKind.QuestionToken:
4370                        // If next token is start of a type we have a conditional type
4371                        if (lookAhead(nextTokenIsStartOfType)) {
4372                            return type;
4373                        }
4374                        nextToken();
4375                        type = finishNode(factory.createJSDocNullableType(type, /*postfix*/ true), pos);
4376                        break;
4377                    case SyntaxKind.OpenBracketToken:
4378                        parseExpected(SyntaxKind.OpenBracketToken);
4379                        if (isStartOfType()) {
4380                            const indexType = parseType();
4381                            parseExpected(SyntaxKind.CloseBracketToken);
4382                            type = finishNode(factory.createIndexedAccessTypeNode(type, indexType), pos);
4383                        }
4384                        else {
4385                            parseExpected(SyntaxKind.CloseBracketToken);
4386                            type = finishNode(factory.createArrayTypeNode(type), pos);
4387                        }
4388                        break;
4389                    default:
4390                        return type;
4391                }
4392            }
4393            return type;
4394        }
4395
4396        function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword) {
4397            const pos = getNodePos();
4398            parseExpected(operator);
4399            return finishNode(factory.createTypeOperatorNode(operator, parseTypeOperatorOrHigher()), pos);
4400        }
4401
4402        function tryParseConstraintOfInferType() {
4403            if (parseOptional(SyntaxKind.ExtendsKeyword)) {
4404                const constraint = disallowConditionalTypesAnd(parseType);
4405                if (inDisallowConditionalTypesContext() || token() !== SyntaxKind.QuestionToken) {
4406                    return constraint;
4407                }
4408            }
4409        }
4410
4411        function parseTypeParameterOfInferType(): TypeParameterDeclaration {
4412            const pos = getNodePos();
4413            const name = parseIdentifier();
4414            const constraint = tryParse(tryParseConstraintOfInferType);
4415            const node = factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, constraint);
4416            return finishNode(node, pos);
4417        }
4418
4419        function parseInferType(): InferTypeNode {
4420            const pos = getNodePos();
4421            parseExpected(SyntaxKind.InferKeyword);
4422            return finishNode(factory.createInferTypeNode(parseTypeParameterOfInferType()), pos);
4423        }
4424
4425        function parseTypeOperatorOrHigher(): TypeNode {
4426            const operator = token();
4427            switch (operator) {
4428                case SyntaxKind.KeyOfKeyword:
4429                case SyntaxKind.UniqueKeyword:
4430                case SyntaxKind.ReadonlyKeyword:
4431                    return parseTypeOperator(operator);
4432                case SyntaxKind.InferKeyword:
4433                    return parseInferType();
4434            }
4435            return allowConditionalTypesAnd(parsePostfixTypeOrHigher);
4436        }
4437
4438        function parseFunctionOrConstructorTypeToError(
4439            isInUnionType: boolean
4440        ): TypeNode | undefined {
4441            // the function type and constructor type shorthand notation
4442            // are not allowed directly in unions and intersections, but we'll
4443            // try to parse them gracefully and issue a helpful message.
4444            if (isStartOfFunctionTypeOrConstructorType()) {
4445                const type = parseFunctionOrConstructorType();
4446                let diagnostic: DiagnosticMessage;
4447                if (isFunctionTypeNode(type)) {
4448                    diagnostic = isInUnionType
4449                        ? Diagnostics.Function_type_notation_must_be_parenthesized_when_used_in_a_union_type
4450                        : Diagnostics.Function_type_notation_must_be_parenthesized_when_used_in_an_intersection_type;
4451                }
4452                else {
4453                    diagnostic = isInUnionType
4454                        ? Diagnostics.Constructor_type_notation_must_be_parenthesized_when_used_in_a_union_type
4455                        : Diagnostics.Constructor_type_notation_must_be_parenthesized_when_used_in_an_intersection_type;
4456
4457                }
4458                parseErrorAtRange(type, diagnostic);
4459                return type;
4460            }
4461            return undefined;
4462        }
4463
4464        function parseUnionOrIntersectionType(
4465            operator: SyntaxKind.BarToken | SyntaxKind.AmpersandToken,
4466            parseConstituentType: () => TypeNode,
4467            createTypeNode: (types: NodeArray<TypeNode>) => UnionOrIntersectionTypeNode
4468        ): TypeNode {
4469            const pos = getNodePos();
4470            const isUnionType = operator === SyntaxKind.BarToken;
4471            const hasLeadingOperator = parseOptional(operator);
4472            let type = hasLeadingOperator && parseFunctionOrConstructorTypeToError(isUnionType)
4473                || parseConstituentType();
4474            if (token() === operator || hasLeadingOperator) {
4475                const types = [type];
4476                while (parseOptional(operator)) {
4477                    types.push(parseFunctionOrConstructorTypeToError(isUnionType) || parseConstituentType());
4478                }
4479                type = finishNode(createTypeNode(createNodeArray(types, pos)), pos);
4480            }
4481            return type;
4482        }
4483
4484        function parseIntersectionTypeOrHigher(): TypeNode {
4485            return parseUnionOrIntersectionType(SyntaxKind.AmpersandToken, parseTypeOperatorOrHigher, factory.createIntersectionTypeNode);
4486        }
4487
4488        function parseUnionTypeOrHigher(): TypeNode {
4489            return parseUnionOrIntersectionType(SyntaxKind.BarToken, parseIntersectionTypeOrHigher, factory.createUnionTypeNode);
4490        }
4491
4492        function nextTokenIsNewKeyword(): boolean {
4493            nextToken();
4494            return token() === SyntaxKind.NewKeyword;
4495        }
4496
4497        function isStartOfFunctionTypeOrConstructorType(): boolean {
4498            if (token() === SyntaxKind.LessThanToken) {
4499                return true;
4500            }
4501            if (token() === SyntaxKind.OpenParenToken && lookAhead(isUnambiguouslyStartOfFunctionType)) {
4502                return true;
4503            }
4504            return token() === SyntaxKind.NewKeyword ||
4505                token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsNewKeyword);
4506        }
4507
4508        function skipParameterStart(): boolean {
4509            if (isModifierKind(token())) {
4510                // Skip modifiers
4511                parseModifiers();
4512            }
4513            if (isIdentifier() || token() === SyntaxKind.ThisKeyword) {
4514                nextToken();
4515                return true;
4516            }
4517            if (token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.OpenBraceToken) {
4518                // Return true if we can parse an array or object binding pattern with no errors
4519                const previousErrorCount = parseDiagnostics.length;
4520                parseIdentifierOrPattern();
4521                return previousErrorCount === parseDiagnostics.length;
4522            }
4523            return false;
4524        }
4525
4526        function isUnambiguouslyStartOfFunctionType() {
4527            nextToken();
4528            if (token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.DotDotDotToken) {
4529                // ( )
4530                // ( ...
4531                return true;
4532            }
4533            if (skipParameterStart()) {
4534                // We successfully skipped modifiers (if any) and an identifier or binding pattern,
4535                // now see if we have something that indicates a parameter declaration
4536                if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken ||
4537                    token() === SyntaxKind.QuestionToken || token() === SyntaxKind.EqualsToken) {
4538                    // ( xxx :
4539                    // ( xxx ,
4540                    // ( xxx ?
4541                    // ( xxx =
4542                    return true;
4543                }
4544                if (token() === SyntaxKind.CloseParenToken) {
4545                    nextToken();
4546                    if (token() === SyntaxKind.EqualsGreaterThanToken) {
4547                        // ( xxx ) =>
4548                        return true;
4549                    }
4550                }
4551            }
4552            return false;
4553        }
4554
4555        function parseTypeOrTypePredicate(): TypeNode {
4556            const pos = getNodePos();
4557            const typePredicateVariable = isIdentifier() && tryParse(parseTypePredicatePrefix);
4558            const type = parseType();
4559            if (typePredicateVariable) {
4560                return finishNode(factory.createTypePredicateNode(/*assertsModifier*/ undefined, typePredicateVariable, type), pos);
4561            }
4562            else {
4563                return type;
4564            }
4565        }
4566
4567        function parseTypePredicatePrefix() {
4568            const id = parseIdentifier();
4569            if (token() === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) {
4570                nextToken();
4571                return id;
4572            }
4573        }
4574
4575        function parseAssertsTypePredicate(): TypeNode {
4576            const pos = getNodePos();
4577            const assertsModifier = parseExpectedToken(SyntaxKind.AssertsKeyword);
4578            const parameterName = token() === SyntaxKind.ThisKeyword ? parseThisTypeNode() : parseIdentifier();
4579            const type = parseOptional(SyntaxKind.IsKeyword) ? parseType() : undefined;
4580            return finishNode(factory.createTypePredicateNode(assertsModifier, parameterName, type), pos);
4581        }
4582
4583        function parseType(): TypeNode {
4584            if (contextFlags & NodeFlags.TypeExcludesFlags) {
4585                return doOutsideOfContext(NodeFlags.TypeExcludesFlags, parseType);
4586            }
4587
4588            if (isStartOfFunctionTypeOrConstructorType()) {
4589                return parseFunctionOrConstructorType();
4590            }
4591            const pos = getNodePos();
4592            const type = parseUnionTypeOrHigher();
4593            if (!inDisallowConditionalTypesContext() && !scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.ExtendsKeyword)) {
4594                // The type following 'extends' is not permitted to be another conditional type
4595                const extendsType = disallowConditionalTypesAnd(parseType);
4596                parseExpected(SyntaxKind.QuestionToken);
4597                const trueType = allowConditionalTypesAnd(parseType);
4598                parseExpected(SyntaxKind.ColonToken);
4599                const falseType = allowConditionalTypesAnd(parseType);
4600                return finishNode(factory.createConditionalTypeNode(type, extendsType, trueType, falseType), pos);
4601            }
4602            return type;
4603        }
4604
4605        function parseEtsType(pos: number, name: string): TypeNode {
4606            const contextFlagsToClear = NodeFlags.TypeExcludesFlags & contextFlags;
4607            if (contextFlagsToClear) {
4608                // clear the requested context flags
4609                setContextFlag(/*val*/ false, contextFlagsToClear);
4610                const result = parseEtsTypeReferenceWorker(pos, name);
4611                // restore the context flags we just cleared
4612                setContextFlag(/*val*/ true, contextFlagsToClear);
4613                return result;
4614            }
4615
4616            return parseEtsTypeReferenceWorker(pos, name);
4617        }
4618
4619        function parseEtsTypeReferenceWorker(pos: number, name: string): TypeNode {
4620            return finishVirtualNode(
4621                factory.createTypeReferenceNode(
4622                    finishVirtualNode(factory.createIdentifier(name), pos, pos)
4623                ),
4624                pos, pos
4625            );
4626        }
4627
4628        function parseTypeAnnotation(): TypeNode | undefined {
4629            return parseOptional(SyntaxKind.ColonToken) ? parseType() : undefined;
4630        }
4631
4632        // EXPRESSIONS
4633        function isStartOfLeftHandSideExpression(): boolean {
4634            switch (token()) {
4635                case SyntaxKind.ThisKeyword:
4636                case SyntaxKind.SuperKeyword:
4637                case SyntaxKind.NullKeyword:
4638                case SyntaxKind.TrueKeyword:
4639                case SyntaxKind.FalseKeyword:
4640                case SyntaxKind.NumericLiteral:
4641                case SyntaxKind.BigIntLiteral:
4642                case SyntaxKind.StringLiteral:
4643                case SyntaxKind.NoSubstitutionTemplateLiteral:
4644                case SyntaxKind.TemplateHead:
4645                case SyntaxKind.OpenParenToken:
4646                case SyntaxKind.OpenBracketToken:
4647                case SyntaxKind.OpenBraceToken:
4648                case SyntaxKind.FunctionKeyword:
4649                case SyntaxKind.ClassKeyword:
4650                case SyntaxKind.NewKeyword:
4651                case SyntaxKind.SlashToken:
4652                case SyntaxKind.SlashEqualsToken:
4653                case SyntaxKind.Identifier:
4654                    return true;
4655                case SyntaxKind.StructKeyword:
4656                    return inEtsContext();
4657                case SyntaxKind.ImportKeyword:
4658                    return lookAhead(nextTokenIsOpenParenOrLessThanOrDot);
4659                default:
4660                    return isIdentifier();
4661            }
4662        }
4663
4664        function isStartOfExpression(): boolean {
4665            if (isStartOfLeftHandSideExpression()) {
4666                return true;
4667            }
4668
4669            switch (token()) {
4670                case SyntaxKind.PlusToken:
4671                case SyntaxKind.MinusToken:
4672                case SyntaxKind.TildeToken:
4673                case SyntaxKind.ExclamationToken:
4674                case SyntaxKind.DeleteKeyword:
4675                case SyntaxKind.TypeOfKeyword:
4676                case SyntaxKind.VoidKeyword:
4677                case SyntaxKind.PlusPlusToken:
4678                case SyntaxKind.MinusMinusToken:
4679                case SyntaxKind.LessThanToken:
4680                case SyntaxKind.AwaitKeyword:
4681                case SyntaxKind.YieldKeyword:
4682                case SyntaxKind.PrivateIdentifier:
4683                    // Yield/await always starts an expression.  Either it is an identifier (in which case
4684                    // it is definitely an expression).  Or it's a keyword (either because we're in
4685                    // a generator or async function, or in strict mode (or both)) and it started a yield or await expression.
4686                    return true;
4687                case SyntaxKind.DotToken:
4688                    return isValidExtendOrStylesContext();
4689                default:
4690                    // Error tolerance.  If we see the start of some binary operator, we consider
4691                    // that the start of an expression.  That way we'll parse out a missing identifier,
4692                    // give a good message about an identifier being missing, and then consume the
4693                    // rest of the binary expression.
4694                    if (isBinaryOperator()) {
4695                        return true;
4696                    }
4697
4698                    return isIdentifier();
4699            }
4700        }
4701
4702        function isValidExtendOrStylesContext(): boolean {
4703            return (inEtsExtendComponentsContext() && !!extendEtsComponentDeclaration) ||
4704                (inEtsStylesComponentsContext() && !!stylesEtsComponentDeclaration);
4705        }
4706
4707        function isStartOfExpressionStatement(): boolean {
4708            // As per the grammar, none of '{' or 'function' or 'class' can start an expression statement.
4709            return token() !== SyntaxKind.OpenBraceToken &&
4710                token() !== SyntaxKind.FunctionKeyword &&
4711                token() !== SyntaxKind.ClassKeyword &&
4712                (!inEtsContext() || token() !== SyntaxKind.StructKeyword) &&
4713                token() !== SyntaxKind.AtToken &&
4714                isStartOfExpression();
4715        }
4716
4717        function parseExpression(): Expression {
4718            // Expression[in]:
4719            //      AssignmentExpression[in]
4720            //      Expression[in] , AssignmentExpression[in]
4721
4722            // clear the decorator context when parsing Expression, as it should be unambiguous when parsing a decorator
4723            const saveDecoratorContext = inDecoratorContext();
4724            if (saveDecoratorContext) {
4725                setDecoratorContext(/*val*/ false);
4726            }
4727
4728            const pos = getNodePos();
4729            let expr = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true);
4730            let operatorToken: BinaryOperatorToken;
4731            while ((operatorToken = parseOptionalToken(SyntaxKind.CommaToken))) {
4732                expr = makeBinaryExpression(expr, operatorToken, parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true), pos);
4733            }
4734
4735            if (saveDecoratorContext) {
4736                setDecoratorContext(/*val*/ true);
4737            }
4738            return expr;
4739        }
4740
4741        function parseInitializer(): Expression | undefined {
4742            return parseOptional(SyntaxKind.EqualsToken) ? parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true) : undefined;
4743        }
4744
4745        function parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction: boolean): Expression {
4746            //  AssignmentExpression[in,yield]:
4747            //      1) ConditionalExpression[?in,?yield]
4748            //      2) LeftHandSideExpression = AssignmentExpression[?in,?yield]
4749            //      3) LeftHandSideExpression AssignmentOperator AssignmentExpression[?in,?yield]
4750            //      4) ArrowFunctionExpression[?in,?yield]
4751            //      5) AsyncArrowFunctionExpression[in,yield,await]
4752            //      6) [+Yield] YieldExpression[?In]
4753            //
4754            // Note: for ease of implementation we treat productions '2' and '3' as the same thing.
4755            // (i.e. they're both BinaryExpressions with an assignment operator in it).
4756
4757            // First, do the simple check if we have a YieldExpression (production '6').
4758            if (isYieldExpression()) {
4759                return parseYieldExpression();
4760            }
4761
4762            // Then, check if we have an arrow function (production '4' and '5') that starts with a parenthesized
4763            // parameter list or is an async arrow function.
4764            // AsyncArrowFunctionExpression:
4765            //      1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In]
4766            //      2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In]
4767            // Production (1) of AsyncArrowFunctionExpression is parsed in "tryParseAsyncSimpleArrowFunctionExpression".
4768            // And production (2) is parsed in "tryParseParenthesizedArrowFunctionExpression".
4769            //
4770            // If we do successfully parse arrow-function, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is
4771            // not a LeftHandSideExpression, nor does it start a ConditionalExpression.  So we are done
4772            // with AssignmentExpression if we see one.
4773            const arrowExpression = tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction) || tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction);
4774            if (arrowExpression) {
4775                return arrowExpression;
4776            }
4777
4778            // Now try to see if we're in production '1', '2' or '3'.  A conditional expression can
4779            // start with a LogicalOrExpression, while the assignment productions can only start with
4780            // LeftHandSideExpressions.
4781            //
4782            // So, first, we try to just parse out a BinaryExpression.  If we get something that is a
4783            // LeftHandSide or higher, then we can try to parse out the assignment expression part.
4784            // Otherwise, we try to parse out the conditional expression bit.  We want to allow any
4785            // binary expression here, so we pass in the 'lowest' precedence here so that it matches
4786            // and consumes anything.
4787            const pos = getNodePos();
4788            const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest);
4789
4790            // To avoid a look-ahead, we did not handle the case of an arrow function with a single un-parenthesized
4791            // parameter ('x => ...') above. We handle it here by checking if the parsed expression was a single
4792            // identifier and the current token is an arrow.
4793            if (expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) {
4794                return parseSimpleArrowFunctionExpression(pos, expr as Identifier, allowReturnTypeInArrowFunction, /*asyncModifier*/ undefined);
4795            }
4796
4797            // Now see if we might be in cases '2' or '3'.
4798            // If the expression was a LHS expression, and we have an assignment operator, then
4799            // we're in '2' or '3'. Consume the assignment and return.
4800            //
4801            // Note: we call reScanGreaterToken so that we get an appropriately merged token
4802            // for cases like `> > =` becoming `>>=`
4803            if (isLeftHandSideExpression(expr) && isAssignmentOperator(reScanGreaterToken())) {
4804                return makeBinaryExpression(expr, parseTokenNode(), parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction), pos);
4805            }
4806
4807            // It's a CallExpression with open brace followed, therefore, we think it's an EtsComponentExpression
4808            if (inEtsContext() && isCallExpression(expr) && token() === SyntaxKind.OpenBraceToken) {
4809                return makeEtsComponentExpression(expr, pos);
4810            }
4811
4812            // It wasn't an assignment or a lambda.  This is a conditional expression:
4813            return parseConditionalExpressionRest(expr, pos, allowReturnTypeInArrowFunction);
4814        }
4815
4816        function makeEtsComponentExpression(expression: Expression, pos: number): EtsComponentExpression {
4817            const name = (<CallExpression>expression).expression;
4818            const body = parseFunctionBlock(SignatureFlags.None);
4819            return finishNode(factory.createEtsComponentExpression(<Identifier>name, (<CallExpression>expression).arguments, body), pos);
4820        }
4821
4822        function isYieldExpression(): boolean {
4823            if (token() === SyntaxKind.YieldKeyword) {
4824                // If we have a 'yield' keyword, and this is a context where yield expressions are
4825                // allowed, then definitely parse out a yield expression.
4826                if (inYieldContext()) {
4827                    return true;
4828                }
4829
4830                // We're in a context where 'yield expr' is not allowed.  However, if we can
4831                // definitely tell that the user was trying to parse a 'yield expr' and not
4832                // just a normal expr that start with a 'yield' identifier, then parse out
4833                // a 'yield expr'.  We can then report an error later that they are only
4834                // allowed in generator expressions.
4835                //
4836                // for example, if we see 'yield(foo)', then we'll have to treat that as an
4837                // invocation expression of something called 'yield'.  However, if we have
4838                // 'yield foo' then that is not legal as a normal expression, so we can
4839                // definitely recognize this as a yield expression.
4840                //
4841                // for now we just check if the next token is an identifier.  More heuristics
4842                // can be added here later as necessary.  We just need to make sure that we
4843                // don't accidentally consume something legal.
4844                return lookAhead(nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine);
4845            }
4846
4847            return false;
4848        }
4849
4850        function nextTokenIsIdentifierOnSameLine() {
4851            nextToken();
4852            return !scanner.hasPrecedingLineBreak() && isIdentifier();
4853        }
4854
4855        function parseYieldExpression(): YieldExpression {
4856            const pos = getNodePos();
4857
4858            // YieldExpression[In] :
4859            //      yield
4860            //      yield [no LineTerminator here] [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield]
4861            //      yield [no LineTerminator here] * [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield]
4862            nextToken();
4863
4864            if (!scanner.hasPrecedingLineBreak() &&
4865                (token() === SyntaxKind.AsteriskToken || isStartOfExpression())) {
4866                return finishNode(
4867                    factory.createYieldExpression(
4868                        parseOptionalToken(SyntaxKind.AsteriskToken),
4869                        parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)
4870                    ),
4871                    pos
4872                );
4873            }
4874            else {
4875                // if the next token is not on the same line as yield.  or we don't have an '*' or
4876                // the start of an expression, then this is just a simple "yield" expression.
4877                return finishNode(factory.createYieldExpression(/*asteriskToken*/ undefined, /*expression*/ undefined), pos);
4878            }
4879        }
4880
4881        function parseSimpleArrowFunctionExpression(pos: number, identifier: Identifier, allowReturnTypeInArrowFunction: boolean, asyncModifier?: NodeArray<Modifier> | undefined): ArrowFunction {
4882            Debug.assert(token() === SyntaxKind.EqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>");
4883            const parameter = factory.createParameterDeclaration(
4884                /*modifiers*/ undefined,
4885                /*dotDotDotToken*/ undefined,
4886                identifier,
4887                /*questionToken*/ undefined,
4888                /*type*/ undefined,
4889                /*initializer*/ undefined
4890            );
4891            finishNode(parameter, identifier.pos);
4892
4893            const parameters = createNodeArray<ParameterDeclaration>([parameter], parameter.pos, parameter.end);
4894            const equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken);
4895            const body = parseArrowFunctionExpressionBody(/*isAsync*/ !!asyncModifier, allowReturnTypeInArrowFunction);
4896            const node = factory.createArrowFunction(asyncModifier, /*typeParameters*/ undefined, parameters, /*type*/ undefined, equalsGreaterThanToken, body);
4897            return addJSDocComment(finishNode(node, pos));
4898        }
4899
4900        function tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): Expression | undefined {
4901            const triState = isParenthesizedArrowFunctionExpression();
4902            if (triState === Tristate.False) {
4903                // It's definitely not a parenthesized arrow function expression.
4904                return undefined;
4905            }
4906
4907            // If we definitely have an arrow function, then we can just parse one, not requiring a
4908            // following => or { token. Otherwise, we *might* have an arrow function.  Try to parse
4909            // it out, but don't allow any ambiguity, and return 'undefined' if this could be an
4910            // expression instead.
4911            return triState === Tristate.True ?
4912                parseParenthesizedArrowFunctionExpression(/*allowAmbiguity*/ true, /*allowReturnTypeInArrowFunction*/ true) :
4913                tryParse(() => parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction));
4914        }
4915
4916        //  True        -> We definitely expect a parenthesized arrow function here.
4917        //  False       -> There *cannot* be a parenthesized arrow function here.
4918        //  Unknown     -> There *might* be a parenthesized arrow function here.
4919        //                 Speculatively look ahead to be sure, and rollback if not.
4920        function isParenthesizedArrowFunctionExpression(): Tristate {
4921            if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken || token() === SyntaxKind.AsyncKeyword) {
4922                return lookAhead(isParenthesizedArrowFunctionExpressionWorker);
4923            }
4924
4925            if (token() === SyntaxKind.EqualsGreaterThanToken) {
4926                // ERROR RECOVERY TWEAK:
4927                // If we see a standalone => try to parse it as an arrow function expression as that's
4928                // likely what the user intended to write.
4929                return Tristate.True;
4930            }
4931            // Definitely not a parenthesized arrow function.
4932            return Tristate.False;
4933        }
4934
4935        function isParenthesizedArrowFunctionExpressionWorker() {
4936            if (token() === SyntaxKind.AsyncKeyword) {
4937                nextToken();
4938                if (scanner.hasPrecedingLineBreak()) {
4939                    return Tristate.False;
4940                }
4941                if (token() !== SyntaxKind.OpenParenToken && token() !== SyntaxKind.LessThanToken) {
4942                    return Tristate.False;
4943                }
4944            }
4945
4946            const first = token();
4947            const second = nextToken();
4948
4949            if (first === SyntaxKind.OpenParenToken) {
4950                if (second === SyntaxKind.CloseParenToken) {
4951                    // Simple cases: "() =>", "(): ", and "() {".
4952                    // This is an arrow function with no parameters.
4953                    // The last one is not actually an arrow function,
4954                    // but this is probably what the user intended.
4955                    const third = nextToken();
4956                    switch (third) {
4957                        case SyntaxKind.EqualsGreaterThanToken:
4958                        case SyntaxKind.ColonToken:
4959                        case SyntaxKind.OpenBraceToken:
4960                            return Tristate.True;
4961                        default:
4962                            return Tristate.False;
4963                    }
4964                }
4965
4966                // If encounter "([" or "({", this could be the start of a binding pattern.
4967                // Examples:
4968                //      ([ x ]) => { }
4969                //      ({ x }) => { }
4970                //      ([ x ])
4971                //      ({ x })
4972                if (second === SyntaxKind.OpenBracketToken || second === SyntaxKind.OpenBraceToken) {
4973                    return Tristate.Unknown;
4974                }
4975
4976                // Simple case: "(..."
4977                // This is an arrow function with a rest parameter.
4978                if (second === SyntaxKind.DotDotDotToken) {
4979                    return Tristate.True;
4980                }
4981
4982                // Check for "(xxx yyy", where xxx is a modifier and yyy is an identifier. This
4983                // isn't actually allowed, but we want to treat it as a lambda so we can provide
4984                // a good error message.
4985                if (isModifierKind(second) && second !== SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsIdentifier)) {
4986                    if (nextToken() === SyntaxKind.AsKeyword) {
4987                        // https://github.com/microsoft/TypeScript/issues/44466
4988                        return Tristate.False;
4989                    }
4990                    return Tristate.True;
4991                }
4992
4993                // If we had "(" followed by something that's not an identifier,
4994                // then this definitely doesn't look like a lambda.  "this" is not
4995                // valid, but we want to parse it and then give a semantic error.
4996                if (!isIdentifier() && second !== SyntaxKind.ThisKeyword) {
4997                    return Tristate.False;
4998                }
4999
5000                switch (nextToken()) {
5001                    case SyntaxKind.ColonToken:
5002                        // If we have something like "(a:", then we must have a
5003                        // type-annotated parameter in an arrow function expression.
5004                        return Tristate.True;
5005                    case SyntaxKind.QuestionToken:
5006                        nextToken();
5007                        // If we have "(a?:" or "(a?," or "(a?=" or "(a?)" then it is definitely a lambda.
5008                        if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.EqualsToken || token() === SyntaxKind.CloseParenToken) {
5009                            return Tristate.True;
5010                        }
5011                        // Otherwise it is definitely not a lambda.
5012                        return Tristate.False;
5013                    case SyntaxKind.CommaToken:
5014                    case SyntaxKind.EqualsToken:
5015                    case SyntaxKind.CloseParenToken:
5016                        // If we have "(a," or "(a=" or "(a)" this *could* be an arrow function
5017                        return Tristate.Unknown;
5018                }
5019                // It is definitely not an arrow function
5020                return Tristate.False;
5021            }
5022            else {
5023                Debug.assert(first === SyntaxKind.LessThanToken);
5024
5025                // If we have "<" not followed by an identifier,
5026                // then this definitely is not an arrow function.
5027                if (!isIdentifier()) {
5028                    return Tristate.False;
5029                }
5030
5031                // JSX overrides
5032                if (languageVariant === LanguageVariant.JSX) {
5033                    const isArrowFunctionInJsx = lookAhead(() => {
5034                        const third = nextToken();
5035                        if (third === SyntaxKind.ExtendsKeyword) {
5036                            const fourth = nextToken();
5037                            switch (fourth) {
5038                                case SyntaxKind.EqualsToken:
5039                                case SyntaxKind.GreaterThanToken:
5040                                    return false;
5041                                default:
5042                                    return true;
5043                            }
5044                        }
5045                        else if (third === SyntaxKind.CommaToken || third === SyntaxKind.EqualsToken) {
5046                            return true;
5047                        }
5048                        return false;
5049                    });
5050
5051                    if (isArrowFunctionInJsx) {
5052                        return Tristate.True;
5053                    }
5054
5055                    return Tristate.False;
5056                }
5057
5058                // This *could* be a parenthesized arrow function.
5059                return Tristate.Unknown;
5060            }
5061        }
5062
5063        function parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined {
5064            const tokenPos = scanner.getTokenPos();
5065            if (notParenthesizedArrow?.has(tokenPos)) {
5066                return undefined;
5067            }
5068
5069            const result = parseParenthesizedArrowFunctionExpression(/*allowAmbiguity*/ false, allowReturnTypeInArrowFunction);
5070            if (!result) {
5071                (notParenthesizedArrow || (notParenthesizedArrow = new Set())).add(tokenPos);
5072            }
5073
5074            return result;
5075        }
5076
5077        function tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined {
5078            // We do a check here so that we won't be doing unnecessarily call to "lookAhead"
5079            if (token() === SyntaxKind.AsyncKeyword) {
5080                if (lookAhead(isUnParenthesizedAsyncArrowFunctionWorker) === Tristate.True) {
5081                    const pos = getNodePos();
5082                    const asyncModifier = parseModifiersForArrowFunction();
5083                    const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest);
5084                    return parseSimpleArrowFunctionExpression(pos, expr as Identifier, allowReturnTypeInArrowFunction, asyncModifier);
5085                }
5086            }
5087            return undefined;
5088        }
5089
5090        function isUnParenthesizedAsyncArrowFunctionWorker(): Tristate {
5091            // AsyncArrowFunctionExpression:
5092            //      1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In]
5093            //      2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In]
5094            if (token() === SyntaxKind.AsyncKeyword) {
5095                nextToken();
5096                // If the "async" is followed by "=>" token then it is not a beginning of an async arrow-function
5097                // but instead a simple arrow-function which will be parsed inside "parseAssignmentExpressionOrHigher"
5098                if (scanner.hasPrecedingLineBreak() || token() === SyntaxKind.EqualsGreaterThanToken) {
5099                    return Tristate.False;
5100                }
5101                // Check for un-parenthesized AsyncArrowFunction
5102                const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest);
5103                if (!scanner.hasPrecedingLineBreak() && expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) {
5104                    return Tristate.True;
5105                }
5106            }
5107
5108            return Tristate.False;
5109        }
5110
5111        function parseParenthesizedArrowFunctionExpression(allowAmbiguity: boolean, allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined {
5112            const pos = getNodePos();
5113            const hasJSDoc = hasPrecedingJSDocComment();
5114            const modifiers = parseModifiersForArrowFunction();
5115            const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None;
5116            // Arrow functions are never generators.
5117            //
5118            // If we're speculatively parsing a signature for a parenthesized arrow function, then
5119            // we have to have a complete parameter list.  Otherwise we might see something like
5120            // a => (b => c)
5121            // And think that "(b =>" was actually a parenthesized arrow function with a missing
5122            // close paren.
5123            const typeParameters = parseTypeParameters();
5124
5125            let parameters: NodeArray<ParameterDeclaration>;
5126            if (!parseExpected(SyntaxKind.OpenParenToken)) {
5127                if (!allowAmbiguity) {
5128                    return undefined;
5129                }
5130                parameters = createMissingList<ParameterDeclaration>();
5131            }
5132            else {
5133                if (!allowAmbiguity) {
5134                    const maybeParameters = parseParametersWorker(isAsync, allowAmbiguity);
5135                    if (!maybeParameters) {
5136                        return undefined;
5137                    }
5138                    parameters = maybeParameters;
5139                }
5140                else {
5141                    parameters = parseParametersWorker(isAsync, allowAmbiguity);
5142                }
5143                if (!parseExpected(SyntaxKind.CloseParenToken) && !allowAmbiguity) {
5144                    return undefined;
5145                }
5146            }
5147
5148            const hasReturnColon = token() === SyntaxKind.ColonToken;
5149            const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);
5150            if (type && !allowAmbiguity && typeHasArrowFunctionBlockingParseError(type)) {
5151                return undefined;
5152            }
5153
5154            // Parsing a signature isn't enough.
5155            // Parenthesized arrow signatures often look like other valid expressions.
5156            // For instance:
5157            //  - "(x = 10)" is an assignment expression parsed as a signature with a default parameter value.
5158            //  - "(x,y)" is a comma expression parsed as a signature with two parameters.
5159            //  - "a ? (b): c" will have "(b):" parsed as a signature with a return type annotation.
5160            //  - "a ? (b): function() {}" will too, since function() is a valid JSDoc function type.
5161            //  - "a ? (b): (function() {})" as well, but inside of a parenthesized type with an arbitrary amount of nesting.
5162            //
5163            // So we need just a bit of lookahead to ensure that it can only be a signature.
5164
5165            let unwrappedType = type;
5166            while (unwrappedType?.kind === SyntaxKind.ParenthesizedType) {
5167                unwrappedType = (unwrappedType as ParenthesizedTypeNode).type;  // Skip parens if need be
5168            }
5169
5170            const hasJSDocFunctionType = unwrappedType && isJSDocFunctionType(unwrappedType);
5171            if (!allowAmbiguity && token() !== SyntaxKind.EqualsGreaterThanToken && (hasJSDocFunctionType || token() !== SyntaxKind.OpenBraceToken)) {
5172                // Returning undefined here will cause our caller to rewind to where we started from.
5173                    return undefined;
5174            }
5175
5176            // If we have an arrow, then try to parse the body. Even if not, try to parse if we
5177            // have an opening brace, just in case we're in an error state.
5178            const lastToken = token();
5179            const equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken);
5180            const body = (lastToken === SyntaxKind.EqualsGreaterThanToken || lastToken === SyntaxKind.OpenBraceToken)
5181                ? parseArrowFunctionExpressionBody(some(modifiers, isAsyncModifier), allowReturnTypeInArrowFunction)
5182                : parseIdentifier();
5183
5184            // Given:
5185            //     x ? y => ({ y }) : z => ({ z })
5186            // We try to parse the body of the first arrow function by looking at:
5187            //     ({ y }) : z => ({ z })
5188            // This is a valid arrow function with "z" as the return type.
5189            //
5190            // But, if we're in the true side of a conditional expression, this colon
5191            // terminates the expression, so we cannot allow a return type if we aren't
5192            // certain whether or not the preceding text was parsed as a parameter list.
5193            //
5194            // For example,
5195            //     a() ? (b: number, c?: string): void => d() : e
5196            // is determined by isParenthesizedArrowFunctionExpression to unambiguously
5197            // be an arrow expression, so we allow a return type.
5198            if (!allowReturnTypeInArrowFunction && hasReturnColon) {
5199                // However, if the arrow function we were able to parse is followed by another colon
5200                // as in:
5201                //     a ? (x): string => x : null
5202                // Then allow the arrow function, and treat the second colon as terminating
5203                // the conditional expression. It's okay to do this because this code would
5204                // be a syntax error in JavaScript (as the second colon shouldn't be there).
5205                if (token() !== SyntaxKind.ColonToken) {
5206                    return undefined;
5207                }
5208            }
5209
5210            const node = factory.createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanToken, body);
5211            return withJSDoc(finishNode(node, pos), hasJSDoc);
5212        }
5213
5214        function parseArrowFunctionExpressionBody(isAsync: boolean, allowReturnTypeInArrowFunction: boolean): Block | Expression {
5215            if (token() === SyntaxKind.OpenBraceToken) {
5216                return parseFunctionBlock(isAsync ? SignatureFlags.Await : SignatureFlags.None);
5217            }
5218
5219            if (token() !== SyntaxKind.SemicolonToken &&
5220                token() !== SyntaxKind.FunctionKeyword &&
5221                token() !== SyntaxKind.ClassKeyword &&
5222                (!inEtsContext() || token() !== SyntaxKind.StructKeyword) &&
5223                isStartOfStatement() &&
5224                !isStartOfExpressionStatement()) {
5225                // Check if we got a plain statement (i.e. no expression-statements, no function/class expressions/declarations)
5226                //
5227                // Here we try to recover from a potential error situation in the case where the
5228                // user meant to supply a block. For example, if the user wrote:
5229                //
5230                //  a =>
5231                //      let v = 0;
5232                //  }
5233                //
5234                // they may be missing an open brace.  Check to see if that's the case so we can
5235                // try to recover better.  If we don't do this, then the next close curly we see may end
5236                // up preemptively closing the containing construct.
5237                //
5238                // Note: even when 'IgnoreMissingOpenBrace' is passed, parseBody will still error.
5239                return parseFunctionBlock(SignatureFlags.IgnoreMissingOpenBrace | (isAsync ? SignatureFlags.Await : SignatureFlags.None));
5240            }
5241
5242            const savedTopLevel = topLevel;
5243            topLevel = false;
5244            const node = isAsync
5245                ? doInAwaitContext(() => parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction))
5246                : doOutsideOfAwaitContext(() => parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction));
5247            topLevel = savedTopLevel;
5248            return node;
5249        }
5250
5251        function parseConditionalExpressionRest(leftOperand: Expression, pos: number, allowReturnTypeInArrowFunction: boolean): Expression {
5252            // Note: we are passed in an expression which was produced from parseBinaryExpressionOrHigher.
5253            const questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
5254            if (!questionToken) {
5255                return leftOperand;
5256            }
5257
5258            // Note: we explicitly 'allowIn' in the whenTrue part of the condition expression, and
5259            // we do not that for the 'whenFalse' part.
5260            let colonToken;
5261            return finishNode(
5262                factory.createConditionalExpression(
5263                    leftOperand,
5264                    questionToken,
5265                    doOutsideOfContext(disallowInAndDecoratorContext, () => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ false)),
5266                    colonToken = parseExpectedToken(SyntaxKind.ColonToken),
5267                    nodeIsPresent(colonToken)
5268                        ? parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction)
5269                        : createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken))
5270                ),
5271                pos
5272            );
5273        }
5274
5275        function parseBinaryExpressionOrHigher(precedence: OperatorPrecedence): Expression {
5276            const pos = getNodePos();
5277            const leftOperand = parseUnaryExpressionOrHigher();
5278            return parseBinaryExpressionRest(precedence, leftOperand, pos);
5279        }
5280
5281        function isInOrOfKeyword(t: SyntaxKind) {
5282            return t === SyntaxKind.InKeyword || t === SyntaxKind.OfKeyword;
5283        }
5284
5285        function parseBinaryExpressionRest(precedence: OperatorPrecedence, leftOperand: Expression, pos: number): Expression {
5286            while (true) {
5287                // We either have a binary operator here, or we're finished.  We call
5288                // reScanGreaterToken so that we merge token sequences like > and = into >=
5289
5290                reScanGreaterToken();
5291                const newPrecedence = getBinaryOperatorPrecedence(token());
5292
5293                // Check the precedence to see if we should "take" this operator
5294                // - For left associative operator (all operator but **), consume the operator,
5295                //   recursively call the function below, and parse binaryExpression as a rightOperand
5296                //   of the caller if the new precedence of the operator is greater then or equal to the current precedence.
5297                //   For example:
5298                //      a - b - c;
5299                //            ^token; leftOperand = b. Return b to the caller as a rightOperand
5300                //      a * b - c
5301                //            ^token; leftOperand = b. Return b to the caller as a rightOperand
5302                //      a - b * c;
5303                //            ^token; leftOperand = b. Return b * c to the caller as a rightOperand
5304                // - For right associative operator (**), consume the operator, recursively call the function
5305                //   and parse binaryExpression as a rightOperand of the caller if the new precedence of
5306                //   the operator is strictly grater than the current precedence
5307                //   For example:
5308                //      a ** b ** c;
5309                //             ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand
5310                //      a - b ** c;
5311                //            ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand
5312                //      a ** b - c
5313                //             ^token; leftOperand = b. Return b to the caller as a rightOperand
5314                const consumeCurrentOperator = token() === SyntaxKind.AsteriskAsteriskToken ?
5315                    newPrecedence >= precedence :
5316                    newPrecedence > precedence;
5317
5318                if (!consumeCurrentOperator) {
5319                    break;
5320                }
5321
5322                if (token() === SyntaxKind.InKeyword && inDisallowInContext()) {
5323                    break;
5324                }
5325
5326                if (token() === SyntaxKind.AsKeyword || token() === SyntaxKind.SatisfiesKeyword) {
5327                    // Make sure we *do* perform ASI for constructs like this:
5328                    //    var x = foo
5329                    //    as (Bar)
5330                    // This should be parsed as an initialized variable, followed
5331                    // by a function call to 'as' with the argument 'Bar'
5332                    if (scanner.hasPrecedingLineBreak()) {
5333                        break;
5334                    }
5335                    else {
5336                        const keywordKind = token();
5337                        nextToken();
5338                        leftOperand = keywordKind === SyntaxKind.SatisfiesKeyword ? makeSatisfiesExpression(leftOperand, parseType()) :
5339                            makeAsExpression(leftOperand, parseType());
5340                    }
5341                }
5342                else {
5343                    leftOperand = makeBinaryExpression(leftOperand, parseTokenNode(), parseBinaryExpressionOrHigher(newPrecedence), pos);
5344                }
5345            }
5346
5347            return leftOperand;
5348        }
5349
5350        function isBinaryOperator() {
5351            if (inDisallowInContext() && token() === SyntaxKind.InKeyword) {
5352                return false;
5353            }
5354
5355            return getBinaryOperatorPrecedence(token()) > 0;
5356        }
5357
5358        function makeSatisfiesExpression(left: Expression, right: TypeNode): SatisfiesExpression {
5359            return finishNode(factory.createSatisfiesExpression(left, right), left.pos);
5360        }
5361
5362        function makeBinaryExpression(left: Expression, operatorToken: BinaryOperatorToken, right: Expression, pos: number): BinaryExpression {
5363            return finishNode(factory.createBinaryExpression(left, operatorToken, right), pos);
5364        }
5365
5366        function makeAsExpression(left: Expression, right: TypeNode): AsExpression {
5367            return finishNode(factory.createAsExpression(left, right), left.pos);
5368        }
5369
5370        function parsePrefixUnaryExpression() {
5371            const pos = getNodePos();
5372            return finishNode(factory.createPrefixUnaryExpression(token() as PrefixUnaryOperator, nextTokenAnd(parseSimpleUnaryExpression)), pos);
5373        }
5374
5375        function parseDeleteExpression() {
5376            const pos = getNodePos();
5377            return finishNode(factory.createDeleteExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos);
5378        }
5379
5380        function parseTypeOfExpression() {
5381            const pos = getNodePos();
5382            return finishNode(factory.createTypeOfExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos);
5383        }
5384
5385        function parseVoidExpression() {
5386            const pos = getNodePos();
5387            return finishNode(factory.createVoidExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos);
5388        }
5389
5390        function isAwaitExpression(): boolean {
5391            if (token() === SyntaxKind.AwaitKeyword) {
5392                if (inAwaitContext()) {
5393                    return true;
5394                }
5395
5396                // here we are using similar heuristics as 'isYieldExpression'
5397                return lookAhead(nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine);
5398            }
5399
5400            return false;
5401        }
5402
5403        function parseAwaitExpression() {
5404            const pos = getNodePos();
5405            return finishNode(factory.createAwaitExpression(nextTokenAnd(parseSimpleUnaryExpression)), pos);
5406        }
5407
5408        /**
5409         * Parse ES7 exponential expression and await expression
5410         *
5411         * ES7 ExponentiationExpression:
5412         *      1) UnaryExpression[?Yield]
5413         *      2) UpdateExpression[?Yield] ** ExponentiationExpression[?Yield]
5414         *
5415         */
5416        function parseUnaryExpressionOrHigher(): UnaryExpression | BinaryExpression {
5417            /**
5418             * ES7 UpdateExpression:
5419             *      1) LeftHandSideExpression[?Yield]
5420             *      2) LeftHandSideExpression[?Yield][no LineTerminator here]++
5421             *      3) LeftHandSideExpression[?Yield][no LineTerminator here]--
5422             *      4) ++UnaryExpression[?Yield]
5423             *      5) --UnaryExpression[?Yield]
5424             */
5425            if (isUpdateExpression()) {
5426                const pos = getNodePos();
5427                const updateExpression = parseUpdateExpression();
5428                return token() === SyntaxKind.AsteriskAsteriskToken ?
5429                    parseBinaryExpressionRest(getBinaryOperatorPrecedence(token()), updateExpression, pos) as BinaryExpression :
5430                    updateExpression;
5431            }
5432
5433            /**
5434             * ES7 UnaryExpression:
5435             *      1) UpdateExpression[?yield]
5436             *      2) delete UpdateExpression[?yield]
5437             *      3) void UpdateExpression[?yield]
5438             *      4) typeof UpdateExpression[?yield]
5439             *      5) + UpdateExpression[?yield]
5440             *      6) - UpdateExpression[?yield]
5441             *      7) ~ UpdateExpression[?yield]
5442             *      8) ! UpdateExpression[?yield]
5443             */
5444            const unaryOperator = token();
5445            const simpleUnaryExpression = parseSimpleUnaryExpression();
5446            if (token() === SyntaxKind.AsteriskAsteriskToken) {
5447                const pos = skipTrivia(sourceText, simpleUnaryExpression.pos);
5448                const { end } = simpleUnaryExpression;
5449                if (simpleUnaryExpression.kind === SyntaxKind.TypeAssertionExpression) {
5450                    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);
5451                }
5452                else {
5453                    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));
5454                }
5455            }
5456            return simpleUnaryExpression;
5457        }
5458
5459        /**
5460         * Parse ES7 simple-unary expression or higher:
5461         *
5462         * ES7 UnaryExpression:
5463         *      1) UpdateExpression[?yield]
5464         *      2) delete UnaryExpression[?yield]
5465         *      3) void UnaryExpression[?yield]
5466         *      4) typeof UnaryExpression[?yield]
5467         *      5) + UnaryExpression[?yield]
5468         *      6) - UnaryExpression[?yield]
5469         *      7) ~ UnaryExpression[?yield]
5470         *      8) ! UnaryExpression[?yield]
5471         *      9) [+Await] await UnaryExpression[?yield]
5472         */
5473        function parseSimpleUnaryExpression(): UnaryExpression {
5474            switch (token()) {
5475                case SyntaxKind.PlusToken:
5476                case SyntaxKind.MinusToken:
5477                case SyntaxKind.TildeToken:
5478                case SyntaxKind.ExclamationToken:
5479                    return parsePrefixUnaryExpression();
5480                case SyntaxKind.DeleteKeyword:
5481                    return parseDeleteExpression();
5482                case SyntaxKind.TypeOfKeyword:
5483                    return parseTypeOfExpression();
5484                case SyntaxKind.VoidKeyword:
5485                    return parseVoidExpression();
5486                case SyntaxKind.LessThanToken:
5487                    // This is modified UnaryExpression grammar in TypeScript
5488                    //  UnaryExpression (modified):
5489                    //      < type > UnaryExpression
5490                    return parseTypeAssertion();
5491                case SyntaxKind.AwaitKeyword:
5492                    if (isAwaitExpression()) {
5493                        return parseAwaitExpression();
5494                    }
5495                    // falls through
5496                default:
5497                    return parseUpdateExpression();
5498            }
5499        }
5500
5501        /**
5502         * Check if the current token can possibly be an ES7 increment expression.
5503         *
5504         * ES7 UpdateExpression:
5505         *      LeftHandSideExpression[?Yield]
5506         *      LeftHandSideExpression[?Yield][no LineTerminator here]++
5507         *      LeftHandSideExpression[?Yield][no LineTerminator here]--
5508         *      ++LeftHandSideExpression[?Yield]
5509         *      --LeftHandSideExpression[?Yield]
5510         */
5511        function isUpdateExpression(): boolean {
5512            // This function is called inside parseUnaryExpression to decide
5513            // whether to call parseSimpleUnaryExpression or call parseUpdateExpression directly
5514            switch (token()) {
5515                case SyntaxKind.PlusToken:
5516                case SyntaxKind.MinusToken:
5517                case SyntaxKind.TildeToken:
5518                case SyntaxKind.ExclamationToken:
5519                case SyntaxKind.DeleteKeyword:
5520                case SyntaxKind.TypeOfKeyword:
5521                case SyntaxKind.VoidKeyword:
5522                case SyntaxKind.AwaitKeyword:
5523                    return false;
5524                case SyntaxKind.LessThanToken:
5525                    // If we are not in JSX context, we are parsing TypeAssertion which is an UnaryExpression
5526                    if (languageVariant !== LanguageVariant.JSX) {
5527                        return false;
5528                    }
5529                    // We are in JSX context and the token is part of JSXElement.
5530                    // falls through
5531                default:
5532                    return true;
5533            }
5534        }
5535
5536        /**
5537         * Parse ES7 UpdateExpression. UpdateExpression is used instead of ES6's PostFixExpression.
5538         *
5539         * ES7 UpdateExpression[yield]:
5540         *      1) LeftHandSideExpression[?yield]
5541         *      2) LeftHandSideExpression[?yield] [[no LineTerminator here]]++
5542         *      3) LeftHandSideExpression[?yield] [[no LineTerminator here]]--
5543         *      4) ++LeftHandSideExpression[?yield]
5544         *      5) --LeftHandSideExpression[?yield]
5545         * In TypeScript (2), (3) are parsed as PostfixUnaryExpression. (4), (5) are parsed as PrefixUnaryExpression
5546         */
5547        function parseUpdateExpression(): UpdateExpression {
5548            if (token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) {
5549                const pos = getNodePos();
5550                return finishNode(factory.createPrefixUnaryExpression(token() as PrefixUnaryOperator, nextTokenAnd(parseLeftHandSideExpressionOrHigher)), pos);
5551            }
5552            else if (languageVariant === LanguageVariant.JSX && token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsIdentifierOrKeywordOrGreaterThan)) {
5553                // JSXElement is part of primaryExpression
5554                return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true);
5555            }
5556
5557            const expression = parseLeftHandSideExpressionOrHigher();
5558
5559            Debug.assert(isLeftHandSideExpression(expression));
5560            if ((token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) && !scanner.hasPrecedingLineBreak()) {
5561                const operator = token() as PostfixUnaryOperator;
5562                nextToken();
5563                return finishNode(factory.createPostfixUnaryExpression(expression, operator), expression.pos);
5564            }
5565
5566            return expression;
5567        }
5568
5569        function parseLeftHandSideExpressionOrHigher(): LeftHandSideExpression {
5570            // Original Ecma:
5571            // LeftHandSideExpression: See 11.2
5572            //      NewExpression
5573            //      CallExpression
5574            //
5575            // Our simplification:
5576            //
5577            // LeftHandSideExpression: See 11.2
5578            //      MemberExpression
5579            //      CallExpression
5580            //
5581            // See comment in parseMemberExpressionOrHigher on how we replaced NewExpression with
5582            // MemberExpression to make our lives easier.
5583            //
5584            // to best understand the below code, it's important to see how CallExpression expands
5585            // out into its own productions:
5586            //
5587            // CallExpression:
5588            //      MemberExpression Arguments
5589            //      CallExpression Arguments
5590            //      CallExpression[Expression]
5591            //      CallExpression.IdentifierName
5592            //      import (AssignmentExpression)
5593            //      super Arguments
5594            //      super.IdentifierName
5595            //
5596            // Because of the recursion in these calls, we need to bottom out first. There are three
5597            // bottom out states we can run into: 1) We see 'super' which must start either of
5598            // the last two CallExpression productions. 2) We see 'import' which must start import call.
5599            // 3)we have a MemberExpression which either completes the LeftHandSideExpression,
5600            // or starts the beginning of the first four CallExpression productions.
5601            const pos = getNodePos();
5602            let expression: MemberExpression;
5603            if (token() === SyntaxKind.ImportKeyword) {
5604                if (lookAhead(nextTokenIsOpenParenOrLessThan)) {
5605                    // We don't want to eagerly consume all import keyword as import call expression so we look ahead to find "("
5606                    // For example:
5607                    //      var foo3 = require("subfolder
5608                    //      import * as foo1 from "module-from-node
5609                    // We want this import to be a statement rather than import call expression
5610                    sourceFlags |= NodeFlags.PossiblyContainsDynamicImport;
5611                    expression = parseTokenNode<PrimaryExpression>();
5612                }
5613                else if (lookAhead(nextTokenIsDot)) {
5614                    // This is an 'import.*' metaproperty (i.e. 'import.meta')
5615                    nextToken(); // advance past the 'import'
5616                    nextToken(); // advance past the dot
5617                    expression = finishNode(factory.createMetaProperty(SyntaxKind.ImportKeyword, parseIdentifierName()), pos);
5618                    sourceFlags |= NodeFlags.PossiblyContainsImportMeta;
5619                }
5620                else {
5621                    expression = parseMemberExpressionOrHigher();
5622                }
5623            }
5624            else {
5625                expression = token() === SyntaxKind.SuperKeyword ? parseSuperExpression() : parseMemberExpressionOrHigher();
5626            }
5627
5628            // Now, we *may* be complete.  However, we might have consumed the start of a
5629            // CallExpression or OptionalExpression.  As such, we need to consume the rest
5630            // of it here to be complete.
5631            return parseCallExpressionRest(pos, expression);
5632        }
5633
5634        function parseMemberExpressionOrHigher(): MemberExpression {
5635            // Note: to make our lives simpler, we decompose the NewExpression productions and
5636            // place ObjectCreationExpression and FunctionExpression into PrimaryExpression.
5637            // like so:
5638            //
5639            //   PrimaryExpression : See 11.1
5640            //      this
5641            //      Identifier
5642            //      Literal
5643            //      ArrayLiteral
5644            //      ObjectLiteral
5645            //      (Expression)
5646            //      FunctionExpression
5647            //      new MemberExpression Arguments?
5648            //
5649            //   MemberExpression : See 11.2
5650            //      PrimaryExpression
5651            //      MemberExpression[Expression]
5652            //      MemberExpression.IdentifierName
5653            //
5654            //   CallExpression : See 11.2
5655            //      MemberExpression
5656            //      CallExpression Arguments
5657            //      CallExpression[Expression]
5658            //      CallExpression.IdentifierName
5659            //
5660            // Technically this is ambiguous.  i.e. CallExpression defines:
5661            //
5662            //   CallExpression:
5663            //      CallExpression Arguments
5664            //
5665            // If you see: "new Foo()"
5666            //
5667            // Then that could be treated as a single ObjectCreationExpression, or it could be
5668            // treated as the invocation of "new Foo".  We disambiguate that in code (to match
5669            // the original grammar) by making sure that if we see an ObjectCreationExpression
5670            // we always consume arguments if they are there. So we treat "new Foo()" as an
5671            // object creation only, and not at all as an invocation.  Another way to think
5672            // about this is that for every "new" that we see, we will consume an argument list if
5673            // it is there as part of the *associated* object creation node.  Any additional
5674            // argument lists we see, will become invocation expressions.
5675            //
5676            // Because there are no other places in the grammar now that refer to FunctionExpression
5677            // or ObjectCreationExpression, it is safe to push down into the PrimaryExpression
5678            // production.
5679            //
5680            // Because CallExpression and MemberExpression are left recursive, we need to bottom out
5681            // of the recursion immediately.  So we parse out a primary expression to start with.
5682            const pos = getNodePos();
5683            let expression;
5684
5685            if (inEtsExtendComponentsContext() && extendEtsComponentDeclaration && token() === SyntaxKind.DotToken) {
5686                expression = finishVirtualNode(factory.createIdentifier(extendEtsComponentDeclaration.instance, /*typeArguments*/ undefined, SyntaxKind.Identifier), pos, pos);
5687            }
5688            else if (inEtsStylesComponentsContext() && stylesEtsComponentDeclaration && token() === SyntaxKind.DotToken) {
5689                expression = finishVirtualNode(factory.createIdentifier(stylesEtsComponentDeclaration.instance, /*typeArguments*/ undefined, SyntaxKind.Identifier), pos, pos);
5690            }
5691            else if (inEtsStateStylesContext() && stateStylesRootNode && token() === SyntaxKind.DotToken) {
5692                expression = finishVirtualNode(factory.createIdentifier(`${stateStylesRootNode}Instance`, /*typeArguments*/ undefined, SyntaxKind.Identifier), pos, pos);
5693            }
5694            else {
5695                expression = parsePrimaryExpression();
5696            }
5697            return parseMemberExpressionRest(pos, expression, /*allowOptionalChain*/ true);
5698        }
5699
5700        function parseSuperExpression(): MemberExpression {
5701            const pos = getNodePos();
5702            let expression = parseTokenNode<MemberExpression>();
5703            if (token() === SyntaxKind.LessThanToken) {
5704                const startPos = getNodePos();
5705                const typeArguments = tryParse(parseTypeArgumentsInExpression);
5706                if (typeArguments !== undefined) {
5707                    parseErrorAt(startPos, getNodePos(), Diagnostics.super_may_not_use_type_arguments);
5708                    if (!isTemplateStartOfTaggedTemplate()) {
5709                        expression = factory.createExpressionWithTypeArguments(expression, typeArguments);
5710                    }
5711                }
5712            }
5713
5714            if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.DotToken || token() === SyntaxKind.OpenBracketToken) {
5715                return expression;
5716            }
5717
5718            // If we have seen "super" it must be followed by '(' or '.'.
5719            // If it wasn't then just try to parse out a '.' and report an error.
5720            parseExpectedToken(SyntaxKind.DotToken, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access);
5721            // private names will never work with `super` (`super.#foo`), but that's a semantic error, not syntactic
5722            return finishNode(factory.createPropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true)), pos);
5723        }
5724
5725        function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean, topInvalidNodePosition?: number, openingTag?: JsxOpeningElement | JsxOpeningFragment): JsxElement | JsxSelfClosingElement | JsxFragment {
5726            const pos = getNodePos();
5727            const opening = parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext);
5728            let result: JsxElement | JsxSelfClosingElement | JsxFragment;
5729            if (opening.kind === SyntaxKind.JsxOpeningElement) {
5730                let children = parseJsxChildren(opening);
5731                let closingElement: JsxClosingElement;
5732
5733                const lastChild: JsxChild | undefined = children[children.length - 1];
5734                if (lastChild?.kind === SyntaxKind.JsxElement
5735                    && !tagNamesAreEquivalent(lastChild.openingElement.tagName, lastChild.closingElement.tagName)
5736                    && tagNamesAreEquivalent(opening.tagName, lastChild.closingElement.tagName)) {
5737                    // when an unclosed JsxOpeningElement incorrectly parses its parent's JsxClosingElement,
5738                    // restructure (<div>(...<span>...</div>)) --> (<div>(...<span>...</>)</div>)
5739                    // (no need to error; the parent will error)
5740                    const end = lastChild.children.end;
5741                    const newLast = finishNode(factory.createJsxElement(
5742                        lastChild.openingElement,
5743                        lastChild.children,
5744                        finishNode(factory.createJsxClosingElement(finishNode(factory.createIdentifier(""), end, end)), end, end)),
5745                    lastChild.openingElement.pos,
5746                    end);
5747
5748                    children = createNodeArray([...children.slice(0, children.length - 1), newLast], children.pos, end);
5749                    closingElement = lastChild.closingElement;
5750                }
5751                else {
5752                    closingElement = parseJsxClosingElement(opening, inExpressionContext);
5753                    if (!tagNamesAreEquivalent(opening.tagName, closingElement.tagName)) {
5754                        if (openingTag && isJsxOpeningElement(openingTag) && tagNamesAreEquivalent(closingElement.tagName, openingTag.tagName)) {
5755                            // opening incorrectly matched with its parent's closing -- put error on opening
5756                            parseErrorAtRange(opening.tagName, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, opening.tagName));
5757                        }
5758                        else {
5759                            // other opening/closing mismatches -- put error on closing
5760                            parseErrorAtRange(closingElement.tagName, Diagnostics.Expected_corresponding_JSX_closing_tag_for_0, getTextOfNodeFromSourceText(sourceText, opening.tagName));
5761                        }
5762                    }
5763                }
5764                result = finishNode(factory.createJsxElement(opening, children, closingElement), pos);
5765            }
5766            else if (opening.kind === SyntaxKind.JsxOpeningFragment) {
5767                result = finishNode(factory.createJsxFragment(opening, parseJsxChildren(opening), parseJsxClosingFragment(inExpressionContext)), pos);
5768            }
5769            else {
5770                Debug.assert(opening.kind === SyntaxKind.JsxSelfClosingElement);
5771                // Nothing else to do for self-closing elements
5772                result = opening;
5773            }
5774
5775            // If the user writes the invalid code '<div></div><div></div>' in an expression context (i.e. not wrapped in
5776            // an enclosing tag), we'll naively try to parse   ^ this as a 'less than' operator and the remainder of the tag
5777            // as garbage, which will cause the formatter to badly mangle the JSX. Perform a speculative parse of a JSX
5778            // element if we see a < token so that we can wrap it in a synthetic binary expression so the formatter
5779            // does less damage and we can report a better error.
5780            // Since JSX elements are invalid < operands anyway, this lookahead parse will only occur in error scenarios
5781            // of one sort or another.
5782            if (inExpressionContext && token() === SyntaxKind.LessThanToken) {
5783                const topBadPos = typeof topInvalidNodePosition === "undefined" ? result.pos : topInvalidNodePosition;
5784                const invalidElement = tryParse(() => parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true, topBadPos));
5785                if (invalidElement) {
5786                    const operatorToken = createMissingNode(SyntaxKind.CommaToken, /*reportAtCurrentPosition*/ false);
5787                    setTextRangePosWidth(operatorToken, invalidElement.pos, 0);
5788                    parseErrorAt(skipTrivia(sourceText, topBadPos), invalidElement.end, Diagnostics.JSX_expressions_must_have_one_parent_element);
5789                    return finishNode(factory.createBinaryExpression(result, operatorToken as Token<SyntaxKind.CommaToken>, invalidElement), pos) as Node as JsxElement;
5790                }
5791            }
5792
5793            return result;
5794        }
5795
5796        function parseJsxText(): JsxText {
5797            const pos = getNodePos();
5798            const node = factory.createJsxText(scanner.getTokenValue(), currentToken === SyntaxKind.JsxTextAllWhiteSpaces);
5799            currentToken = scanner.scanJsxToken();
5800            return finishNode(node, pos);
5801        }
5802
5803        function parseJsxChild(openingTag: JsxOpeningElement | JsxOpeningFragment, token: JsxTokenSyntaxKind): JsxChild | undefined {
5804            switch (token) {
5805                case SyntaxKind.EndOfFileToken:
5806                    // If we hit EOF, issue the error at the tag that lacks the closing element
5807                    // rather than at the end of the file (which is useless)
5808                    if (isJsxOpeningFragment(openingTag)) {
5809                        parseErrorAtRange(openingTag, Diagnostics.JSX_fragment_has_no_corresponding_closing_tag);
5810                    }
5811                    else {
5812                        // We want the error span to cover only 'Foo.Bar' in < Foo.Bar >
5813                        // or to cover only 'Foo' in < Foo >
5814                        const tag = openingTag.tagName;
5815                        const start = skipTrivia(sourceText, tag.pos);
5816                        parseErrorAt(start, tag.end, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTag.tagName));
5817                    }
5818                    return undefined;
5819                case SyntaxKind.LessThanSlashToken:
5820                case SyntaxKind.ConflictMarkerTrivia:
5821                    return undefined;
5822                case SyntaxKind.JsxText:
5823                case SyntaxKind.JsxTextAllWhiteSpaces:
5824                    return parseJsxText();
5825                case SyntaxKind.OpenBraceToken:
5826                    return parseJsxExpression(/*inExpressionContext*/ false);
5827                case SyntaxKind.LessThanToken:
5828                    return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ false, /*topInvalidNodePosition*/ undefined, openingTag);
5829                default:
5830                    return Debug.assertNever(token);
5831            }
5832        }
5833
5834        function parseJsxChildren(openingTag: JsxOpeningElement | JsxOpeningFragment): NodeArray<JsxChild> {
5835            const list = [];
5836            const listPos = getNodePos();
5837            const saveParsingContext = parsingContext;
5838            parsingContext |= 1 << ParsingContext.JsxChildren;
5839
5840            while (true) {
5841                const child = parseJsxChild(openingTag, currentToken = scanner.reScanJsxToken());
5842                if (!child) break;
5843                list.push(child);
5844                if (isJsxOpeningElement(openingTag)
5845                    && child?.kind === SyntaxKind.JsxElement
5846                    && !tagNamesAreEquivalent(child.openingElement.tagName, child.closingElement.tagName)
5847                    && tagNamesAreEquivalent(openingTag.tagName, child.closingElement.tagName)) {
5848                    // stop after parsing a mismatched child like <div>...(<span></div>) in order to reattach the </div> higher
5849                    break;
5850                }
5851            }
5852
5853            parsingContext = saveParsingContext;
5854            return createNodeArray(list, listPos);
5855        }
5856
5857        function parseJsxAttributes(): JsxAttributes {
5858            const pos = getNodePos();
5859            return finishNode(factory.createJsxAttributes(parseList(ParsingContext.JsxAttributes, parseJsxAttribute)), pos);
5860        }
5861
5862        function parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext: boolean): JsxOpeningElement | JsxSelfClosingElement | JsxOpeningFragment {
5863            const pos = getNodePos();
5864
5865            parseExpected(SyntaxKind.LessThanToken);
5866
5867            if (token() === SyntaxKind.GreaterThanToken) {
5868                // See below for explanation of scanJsxText
5869                scanJsxText();
5870                return finishNode(factory.createJsxOpeningFragment(), pos);
5871            }
5872            const tagName = parseJsxElementName();
5873            const typeArguments = (contextFlags & NodeFlags.JavaScriptFile) === 0 ? tryParseTypeArguments() : undefined;
5874            const attributes = parseJsxAttributes();
5875
5876            let node: JsxOpeningLikeElement;
5877
5878            if (token() === SyntaxKind.GreaterThanToken) {
5879                // Closing tag, so scan the immediately-following text with the JSX scanning instead
5880                // of regular scanning to avoid treating illegal characters (e.g. '#') as immediate
5881                // scanning errors
5882                scanJsxText();
5883                node = factory.createJsxOpeningElement(tagName, typeArguments, attributes);
5884            }
5885            else {
5886                parseExpected(SyntaxKind.SlashToken);
5887                if (parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false)) {
5888                    // manually advance the scanner in order to look for jsx text inside jsx
5889                    if (inExpressionContext) {
5890                        nextToken();
5891                    }
5892                    else {
5893                        scanJsxText();
5894                    }
5895                }
5896                node = factory.createJsxSelfClosingElement(tagName, typeArguments, attributes);
5897            }
5898
5899            return finishNode(node, pos);
5900        }
5901
5902        function parseJsxElementName(): JsxTagNameExpression {
5903            const pos = getNodePos();
5904            scanJsxIdentifier();
5905            // JsxElement can have name in the form of
5906            //      propertyAccessExpression
5907            //      primaryExpression in the form of an identifier and "this" keyword
5908            // We can't just simply use parseLeftHandSideExpressionOrHigher because then we will start consider class,function etc as a keyword
5909            // We only want to consider "this" as a primaryExpression
5910            let expression: JsxTagNameExpression = token() === SyntaxKind.ThisKeyword ?
5911                parseTokenNode<ThisExpression>() : parseIdentifierName();
5912            while (parseOptional(SyntaxKind.DotToken)) {
5913                expression = finishNode(factory.createPropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ false)), pos) as JsxTagNamePropertyAccess;
5914            }
5915            return expression;
5916        }
5917
5918        function parseJsxExpression(inExpressionContext: boolean): JsxExpression | undefined {
5919            const pos = getNodePos();
5920            if (!parseExpected(SyntaxKind.OpenBraceToken)) {
5921                return undefined;
5922            }
5923
5924            let dotDotDotToken: DotDotDotToken | undefined;
5925            let expression: Expression | undefined;
5926            if (token() !== SyntaxKind.CloseBraceToken) {
5927                dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
5928                // Only an AssignmentExpression is valid here per the JSX spec,
5929                // but we can unambiguously parse a comma sequence and provide
5930                // a better error message in grammar checking.
5931                expression = parseExpression();
5932            }
5933            if (inExpressionContext) {
5934                parseExpected(SyntaxKind.CloseBraceToken);
5935            }
5936            else {
5937                if (parseExpected(SyntaxKind.CloseBraceToken, /*message*/ undefined, /*shouldAdvance*/ false)) {
5938                    scanJsxText();
5939                }
5940            }
5941
5942            return finishNode(factory.createJsxExpression(dotDotDotToken, expression), pos);
5943        }
5944
5945        function parseJsxAttribute(): JsxAttribute | JsxSpreadAttribute {
5946            if (token() === SyntaxKind.OpenBraceToken) {
5947                return parseJsxSpreadAttribute();
5948            }
5949
5950            scanJsxIdentifier();
5951            const pos = getNodePos();
5952            return finishNode(factory.createJsxAttribute(parseIdentifierName(), parseJsxAttributeValue()), pos);
5953        }
5954
5955        function parseJsxAttributeValue(): JsxAttributeValue | undefined {
5956            if (token() === SyntaxKind.EqualsToken) {
5957                if (scanJsxAttributeValue() === SyntaxKind.StringLiteral) {
5958                    return parseLiteralNode() as StringLiteral;
5959                }
5960                if (token() === SyntaxKind.OpenBraceToken) {
5961                    return parseJsxExpression(/*inExpressionContext*/ true);
5962                }
5963                if (token() === SyntaxKind.LessThanToken) {
5964                    return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true);
5965                }
5966                parseErrorAtCurrentToken(Diagnostics.or_JSX_element_expected);
5967            }
5968            return undefined;
5969        }
5970
5971        function parseJsxSpreadAttribute(): JsxSpreadAttribute {
5972            const pos = getNodePos();
5973            parseExpected(SyntaxKind.OpenBraceToken);
5974            parseExpected(SyntaxKind.DotDotDotToken);
5975            const expression = parseExpression();
5976            parseExpected(SyntaxKind.CloseBraceToken);
5977            return finishNode(factory.createJsxSpreadAttribute(expression), pos);
5978        }
5979
5980        function parseJsxClosingElement(open: JsxOpeningElement, inExpressionContext: boolean): JsxClosingElement {
5981            const pos = getNodePos();
5982            parseExpected(SyntaxKind.LessThanSlashToken);
5983            const tagName = parseJsxElementName();
5984            if (parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false)) {
5985                // manually advance the scanner in order to look for jsx text inside jsx
5986                if (inExpressionContext || !tagNamesAreEquivalent(open.tagName, tagName)) {
5987                    nextToken();
5988                }
5989                else {
5990                    scanJsxText();
5991                }
5992            }
5993            return finishNode(factory.createJsxClosingElement(tagName), pos);
5994        }
5995
5996        function parseJsxClosingFragment(inExpressionContext: boolean): JsxClosingFragment {
5997            const pos = getNodePos();
5998            parseExpected(SyntaxKind.LessThanSlashToken);
5999            if (tokenIsIdentifierOrKeyword(token())) {
6000                parseErrorAtRange(parseJsxElementName(), Diagnostics.Expected_corresponding_closing_tag_for_JSX_fragment);
6001            }
6002            if (parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false)) {
6003                // manually advance the scanner in order to look for jsx text inside jsx
6004                if (inExpressionContext) {
6005                    nextToken();
6006                }
6007                else {
6008                    scanJsxText();
6009                }
6010            }
6011            return finishNode(factory.createJsxJsxClosingFragment(), pos);
6012        }
6013
6014        function parseTypeAssertion(): TypeAssertion {
6015            const pos = getNodePos();
6016            parseExpected(SyntaxKind.LessThanToken);
6017            const type = parseType();
6018            parseExpected(SyntaxKind.GreaterThanToken);
6019            const expression = parseSimpleUnaryExpression();
6020            return finishNode(factory.createTypeAssertion(type, expression), pos);
6021        }
6022
6023        function nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate() {
6024            nextToken();
6025            return tokenIsIdentifierOrKeyword(token())
6026                || token() === SyntaxKind.OpenBracketToken
6027                || isTemplateStartOfTaggedTemplate();
6028        }
6029
6030        function isStartOfOptionalPropertyOrElementAccessChain() {
6031            return token() === SyntaxKind.QuestionDotToken
6032                && lookAhead(nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate);
6033        }
6034
6035        function tryReparseOptionalChain(node: Expression) {
6036            if (node.flags & NodeFlags.OptionalChain) {
6037                return true;
6038            }
6039            // check for an optional chain in a non-null expression
6040            if (isNonNullExpression(node)) {
6041                let expr = node.expression;
6042                while (isNonNullExpression(expr) && !(expr.flags & NodeFlags.OptionalChain)) {
6043                    expr = expr.expression;
6044                }
6045                if (expr.flags & NodeFlags.OptionalChain) {
6046                    // this is part of an optional chain. Walk down from `node` to `expression` and set the flag.
6047                    while (isNonNullExpression(node)) {
6048                        (node as Mutable<NonNullExpression>).flags |= NodeFlags.OptionalChain;
6049                        node = node.expression;
6050                    }
6051                    return true;
6052                }
6053            }
6054            return false;
6055        }
6056
6057        function parsePropertyAccessExpressionRest(pos: number, expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) {
6058            const name = parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true);
6059            const isOptionalChain = questionDotToken || tryReparseOptionalChain(expression);
6060            const propertyAccess = isOptionalChain ?
6061                factory.createPropertyAccessChain(expression, questionDotToken, name) :
6062                factory.createPropertyAccessExpression(expression, name);
6063            if (isOptionalChain && isPrivateIdentifier(propertyAccess.name)) {
6064                parseErrorAtRange(propertyAccess.name, Diagnostics.An_optional_chain_cannot_contain_private_identifiers);
6065            }
6066            if (isExpressionWithTypeArguments(expression) && expression.typeArguments) {
6067                const pos = expression.typeArguments.pos - 1;
6068                const end = skipTrivia(sourceText, expression.typeArguments.end) + 1;
6069                parseErrorAt(pos, end, Diagnostics.An_instantiation_expression_cannot_be_followed_by_a_property_access);
6070            }
6071            return finishNode(propertyAccess, pos);
6072        }
6073
6074        function parseElementAccessExpressionRest(pos: number, expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) {
6075            let argumentExpression: Expression;
6076            if (token() === SyntaxKind.CloseBracketToken) {
6077                argumentExpression = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.An_element_access_expression_should_take_an_argument);
6078            }
6079            else {
6080                const argument = allowInAnd(parseExpression);
6081                if (isStringOrNumericLiteralLike(argument)) {
6082                    argument.text = internIdentifier(argument.text);
6083                }
6084                argumentExpression = argument;
6085            }
6086
6087            parseExpected(SyntaxKind.CloseBracketToken);
6088
6089            const indexedAccess = questionDotToken || tryReparseOptionalChain(expression) ?
6090                factory.createElementAccessChain(expression, questionDotToken, argumentExpression) :
6091                factory.createElementAccessExpression(expression, argumentExpression);
6092            return finishNode(indexedAccess, pos);
6093        }
6094
6095        function parseMemberExpressionRest(pos: number, expression: LeftHandSideExpression, allowOptionalChain: boolean): MemberExpression {
6096            while (true) {
6097                let questionDotToken: QuestionDotToken | undefined;
6098                let isPropertyAccess = false;
6099                if (allowOptionalChain && isStartOfOptionalPropertyOrElementAccessChain()) {
6100                    questionDotToken = parseExpectedToken(SyntaxKind.QuestionDotToken);
6101                    isPropertyAccess = tokenIsIdentifierOrKeyword(token());
6102                }
6103                else {
6104                    isPropertyAccess = parseOptional(SyntaxKind.DotToken);
6105                }
6106
6107                if (isPropertyAccess) {
6108                    expression = parsePropertyAccessExpressionRest(pos, expression, questionDotToken);
6109                    continue;
6110                }
6111
6112                // when in the [Decorator] context, we do not parse ElementAccess as it could be part of a ComputedPropertyName
6113                if ((questionDotToken || !inDecoratorContext()) && parseOptional(SyntaxKind.OpenBracketToken)) {
6114                    expression = parseElementAccessExpressionRest(pos, expression, questionDotToken);
6115                    continue;
6116                }
6117
6118                if (isTemplateStartOfTaggedTemplate()) {
6119                    // Absorb type arguments into TemplateExpression when preceding expression is ExpressionWithTypeArguments
6120                    expression = !questionDotToken && expression.kind === SyntaxKind.ExpressionWithTypeArguments ?
6121                        parseTaggedTemplateRest(pos, (expression as ExpressionWithTypeArguments).expression, questionDotToken, (expression as ExpressionWithTypeArguments).typeArguments) :
6122                        parseTaggedTemplateRest(pos, expression, questionDotToken, /*typeArguments*/ undefined);
6123                    continue;
6124                }
6125
6126                if (!questionDotToken) {
6127                    if (token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) {
6128                        nextToken();
6129                        expression = finishNode(factory.createNonNullExpression(expression), pos);
6130                        continue;
6131                    }
6132                    const typeArguments = tryParse(parseTypeArgumentsInExpression);
6133                    if (typeArguments) {
6134                        expression = finishNode(factory.createExpressionWithTypeArguments(expression, typeArguments), pos);
6135                        continue;
6136                    }
6137                }
6138
6139                return expression as MemberExpression;
6140            }
6141        }
6142
6143        function isTemplateStartOfTaggedTemplate() {
6144            return token() === SyntaxKind.NoSubstitutionTemplateLiteral || token() === SyntaxKind.TemplateHead;
6145        }
6146
6147        function parseTaggedTemplateRest(pos: number, tag: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined, typeArguments: NodeArray<TypeNode> | undefined) {
6148            const tagExpression = factory.createTaggedTemplateExpression(
6149                tag,
6150                typeArguments,
6151                token() === SyntaxKind.NoSubstitutionTemplateLiteral ?
6152                    (reScanTemplateHeadOrNoSubstitutionTemplate(), parseLiteralNode() as NoSubstitutionTemplateLiteral) :
6153                    parseTemplateExpression(/*isTaggedTemplate*/ true)
6154            );
6155            if (questionDotToken || tag.flags & NodeFlags.OptionalChain) {
6156                (tagExpression as Mutable<Node>).flags |= NodeFlags.OptionalChain;
6157            }
6158            tagExpression.questionDotToken = questionDotToken;
6159            return finishNode(tagExpression, pos);
6160        }
6161
6162        function parseCallExpressionRest(pos: number, expression: LeftHandSideExpression): LeftHandSideExpression {
6163            let currentNodeName: string | undefined;
6164            while (true) {
6165                expression = parseMemberExpressionRest(pos, expression, /*allowOptionalChain*/ true);
6166                let typeArguments: NodeArray<TypeNode> | undefined;
6167                const questionDotToken = parseOptionalToken(SyntaxKind.QuestionDotToken);
6168                if (questionDotToken) {
6169                    typeArguments = tryParse(parseTypeArgumentsInExpression);
6170                    if (isTemplateStartOfTaggedTemplate()) {
6171                        expression = parseTaggedTemplateRest(pos, expression, questionDotToken, typeArguments);
6172                        continue;
6173                    }
6174                }
6175                if (typeArguments || token() === SyntaxKind.OpenParenToken) {
6176                    // Absorb type arguments into CallExpression when preceding expression is ExpressionWithTypeArguments
6177                    if (!questionDotToken && expression.kind === SyntaxKind.ExpressionWithTypeArguments) {
6178                        typeArguments = (expression as ExpressionWithTypeArguments).typeArguments;
6179                        expression = (expression as ExpressionWithTypeArguments).expression;
6180                    }
6181
6182                    if ((isValidVirtualTypeArgumentsContext() || inBuilderContext()) && isPropertyAccessExpression(expression)) {
6183                        const rootNode = getRootEtsComponent(expression);
6184                        if (rootNode) {
6185                            const rootNodeName = (<Identifier>(rootNode.expression)).escapedText.toString();
6186                            currentNodeName = getTextOfPropertyName(expression.name).toString();
6187                            if (currentNodeName === sourceFileCompilerOptions?.ets?.styles?.property) {
6188                                setEtsStateStylesContext(true);
6189                                stateStylesRootNode = rootNodeName;
6190                            }
6191                            else {
6192                                setEtsStateStylesContext(false);
6193                                stateStylesRootNode = undefined;
6194                            }
6195                            typeArguments = parseEtsTypeArguments(pos, `${rootNodeName}Attribute`);
6196                        }
6197                        else if (inEtsStateStylesContext() && stateStylesRootNode) {
6198                            typeArguments = parseEtsTypeArguments(pos, `${stateStylesRootNode}Attribute`);
6199                        }
6200                    }
6201                    const argumentList = parseArgumentList();
6202                    const callExpr = questionDotToken || tryReparseOptionalChain(expression) ?
6203                        factory.createCallChain(expression, questionDotToken, typeArguments, argumentList) :
6204                        factory.createCallExpression(expression, typeArguments, argumentList);
6205                    expression = finishNode(callExpr, pos);
6206                    continue;
6207                }
6208                if (questionDotToken) {
6209                    // We parsed `?.` but then failed to parse anything, so report a missing identifier here.
6210                    const name = createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics.Identifier_expected);
6211                    expression = finishNode(factory.createPropertyAccessChain(expression, questionDotToken, name), pos);
6212                }
6213                break;
6214            }
6215            if (currentNodeName === sourceFileCompilerOptions?.ets?.styles?.property) {
6216                setEtsStateStylesContext(false);
6217                stateStylesRootNode = undefined;
6218            }
6219            return expression;
6220        }
6221
6222        function isValidVirtualTypeArgumentsContext(): boolean {
6223            return (inBuildContext() || inBuilderContext()) && inStructContext();
6224        }
6225
6226        function parseArgumentList() {
6227            parseExpected(SyntaxKind.OpenParenToken);
6228            const result = parseDelimitedList(ParsingContext.ArgumentExpressions, parseArgumentExpression);
6229            parseExpected(SyntaxKind.CloseParenToken);
6230            return result;
6231        }
6232
6233        function parseTypeArgumentsInExpression() {
6234            if ((contextFlags & NodeFlags.JavaScriptFile) !== 0) {
6235                // TypeArguments must not be parsed in JavaScript files to avoid ambiguity with binary operators.
6236                return undefined;
6237            }
6238
6239            if (reScanLessThanToken() !== SyntaxKind.LessThanToken) {
6240                return undefined;
6241            }
6242            nextToken();
6243
6244            const typeArguments = parseDelimitedList(ParsingContext.TypeArguments, parseType);
6245            if (reScanGreaterToken() !== SyntaxKind.GreaterThanToken) {
6246                // If it doesn't have the closing `>` then it's definitely not an type argument list.
6247                return undefined;
6248            }
6249            nextToken();
6250
6251            // We successfully parsed a type argument list. The next token determines whether we want to
6252            // treat it as such. If the type argument list is followed by `(` or a template literal, as in
6253            // `f<number>(42)`, we favor the type argument interpretation even though JavaScript would view
6254            // it as a relational expression.
6255            return typeArguments && canFollowTypeArgumentsInExpression() ? typeArguments : undefined;
6256        }
6257
6258        function canFollowTypeArgumentsInExpression(): boolean {
6259            switch (token()) {
6260                // These tokens can follow a type argument list in a call expression.
6261                case SyntaxKind.OpenParenToken:                 // foo<x>(
6262                case SyntaxKind.NoSubstitutionTemplateLiteral:  // foo<T> `...`
6263                case SyntaxKind.TemplateHead:                   // foo<T> `...${100}...`
6264                    return true;
6265                // A type argument list followed by `<` never makes sense, and a type argument list followed
6266                // by `>` is ambiguous with a (re-scanned) `>>` operator, so we disqualify both. Also, in
6267                // this context, `+` and `-` are unary operators, not binary operators.
6268                case SyntaxKind.LessThanToken:
6269                case SyntaxKind.GreaterThanToken:
6270                case SyntaxKind.PlusToken:
6271                case SyntaxKind.MinusToken:
6272                    return false;
6273            }
6274            // We favor the type argument list interpretation when it is immediately followed by
6275            // a line break, a binary operator, or something that can't start an expression.
6276            return scanner.hasPrecedingLineBreak() || isBinaryOperator() || !isStartOfExpression();
6277        }
6278
6279        function isCurrentTokenAnEtsComponentExpression(): boolean {
6280            if (!inEtsComponentsContext()) {
6281                return false;
6282            }
6283            const components = sourceFileCompilerOptions.ets?.components ?? [];
6284            return components.includes(scanner.getTokenText());
6285        }
6286
6287        function parseEtsComponentExpression(): EtsComponentExpression {
6288            const pos = getNodePos();
6289            const name = parseBindingIdentifier();
6290            const argumentList = parseArgumentList();
6291            const body = token() === SyntaxKind.OpenBraceToken ? parseFunctionBlock(SignatureFlags.None) : undefined;
6292            const node = factory.createEtsComponentExpression(name, argumentList, body);
6293            return finishNode(node, pos);
6294        }
6295
6296        function parsePrimaryExpression(): PrimaryExpression {
6297            switch (token()) {
6298                case SyntaxKind.NumericLiteral:
6299                case SyntaxKind.BigIntLiteral:
6300                case SyntaxKind.StringLiteral:
6301                case SyntaxKind.NoSubstitutionTemplateLiteral:
6302                    return parseLiteralNode();
6303                case SyntaxKind.ThisKeyword:
6304                case SyntaxKind.SuperKeyword:
6305                case SyntaxKind.NullKeyword:
6306                case SyntaxKind.TrueKeyword:
6307                case SyntaxKind.FalseKeyword:
6308                    return parseTokenNode<PrimaryExpression>();
6309                case SyntaxKind.OpenParenToken:
6310                    return parseParenthesizedExpression();
6311                case SyntaxKind.OpenBracketToken:
6312                    return parseArrayLiteralExpression();
6313                case SyntaxKind.OpenBraceToken:
6314                    return parseObjectLiteralExpression();
6315                case SyntaxKind.AsyncKeyword:
6316                    // Async arrow functions are parsed earlier in parseAssignmentExpressionOrHigher.
6317                    // If we encounter `async [no LineTerminator here] function` then this is an async
6318                    // function; otherwise, its an identifier.
6319                    if (!lookAhead(nextTokenIsFunctionKeywordOnSameLine)) {
6320                        break;
6321                    }
6322
6323                    return parseFunctionExpression();
6324                case SyntaxKind.ClassKeyword:
6325                    return parseClassExpression();
6326                case SyntaxKind.FunctionKeyword:
6327                    return parseFunctionExpression();
6328                case SyntaxKind.NewKeyword:
6329                    return parseNewExpressionOrNewDotTarget();
6330                case SyntaxKind.SlashToken:
6331                case SyntaxKind.SlashEqualsToken:
6332                    if (reScanSlashToken() === SyntaxKind.RegularExpressionLiteral) {
6333                        return parseLiteralNode();
6334                    }
6335                    break;
6336                case SyntaxKind.TemplateHead:
6337                    return parseTemplateExpression(/* isTaggedTemplate */ false);
6338                case SyntaxKind.PrivateIdentifier:
6339                    return parsePrivateIdentifier();
6340            }
6341
6342            if(isCurrentTokenAnEtsComponentExpression() && !inEtsNewExpressionContext()){
6343                return parseEtsComponentExpression();
6344            }
6345
6346            return parseIdentifier(Diagnostics.Expression_expected);
6347        }
6348
6349        function parseParenthesizedExpression(): ParenthesizedExpression {
6350            const pos = getNodePos();
6351            const hasJSDoc = hasPrecedingJSDocComment();
6352            parseExpected(SyntaxKind.OpenParenToken);
6353            const expression = allowInAnd(parseExpression);
6354            parseExpected(SyntaxKind.CloseParenToken);
6355            return withJSDoc(finishNode(factory.createParenthesizedExpression(expression), pos), hasJSDoc);
6356        }
6357
6358        function parseSpreadElement(): Expression {
6359            const pos = getNodePos();
6360            parseExpected(SyntaxKind.DotDotDotToken);
6361            const expression = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true);
6362            return finishNode(factory.createSpreadElement(expression), pos);
6363        }
6364
6365        function parseArgumentOrArrayLiteralElement(): Expression {
6366            return token() === SyntaxKind.DotDotDotToken ? parseSpreadElement() :
6367                token() === SyntaxKind.CommaToken ? finishNode(factory.createOmittedExpression(), getNodePos()) :
6368                parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true);
6369        }
6370
6371        function parseArgumentExpression(): Expression {
6372            return doOutsideOfContext(disallowInAndDecoratorContext, parseArgumentOrArrayLiteralElement);
6373        }
6374
6375        function parseArrayLiteralExpression(): ArrayLiteralExpression {
6376            const pos = getNodePos();
6377            const openBracketPosition = scanner.getTokenPos();
6378            const openBracketParsed = parseExpected(SyntaxKind.OpenBracketToken);
6379            const multiLine = scanner.hasPrecedingLineBreak();
6380            const elements = parseDelimitedList(ParsingContext.ArrayLiteralMembers, parseArgumentOrArrayLiteralElement);
6381            parseExpectedMatchingBrackets(SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken, openBracketParsed, openBracketPosition);
6382            return finishNode(factory.createArrayLiteralExpression(elements, multiLine), pos);
6383        }
6384
6385        function parseObjectLiteralElement(): ObjectLiteralElementLike {
6386            const pos = getNodePos();
6387            const hasJSDoc = hasPrecedingJSDocComment();
6388
6389            if (parseOptionalToken(SyntaxKind.DotDotDotToken)) {
6390                const expression = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true);
6391                return withJSDoc(finishNode(factory.createSpreadAssignment(expression), pos), hasJSDoc);
6392            }
6393
6394            const decorators = parseDecorators();
6395            const modifiers = parseModifiers();
6396
6397            if (parseContextualModifier(SyntaxKind.GetKeyword)) {
6398                return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.GetAccessor, SignatureFlags.None);
6399            }
6400            if (parseContextualModifier(SyntaxKind.SetKeyword)) {
6401                return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.SetAccessor, SignatureFlags.None);
6402            }
6403
6404            const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
6405            const tokenIsIdentifier = isIdentifier();
6406            const name = parsePropertyName();
6407
6408            // Disallowing of optional property assignments and definite assignment assertion happens in the grammar checker.
6409            const questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
6410            const exclamationToken = parseOptionalToken(SyntaxKind.ExclamationToken);
6411
6412            if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
6413                return parseMethodDeclaration(pos, hasJSDoc, decorators, modifiers, asteriskToken, name, questionToken, exclamationToken);
6414            }
6415
6416            // check if it is short-hand property assignment or normal property assignment
6417            // NOTE: if token is EqualsToken it is interpreted as CoverInitializedName production
6418            // CoverInitializedName[Yield] :
6419            //     IdentifierReference[?Yield] Initializer[In, ?Yield]
6420            // this is necessary because ObjectLiteral productions are also used to cover grammar for ObjectAssignmentPattern
6421            let node: Mutable<ShorthandPropertyAssignment | PropertyAssignment>;
6422            const isShorthandPropertyAssignment = tokenIsIdentifier && (token() !== SyntaxKind.ColonToken);
6423            if (isShorthandPropertyAssignment) {
6424                const equalsToken = parseOptionalToken(SyntaxKind.EqualsToken);
6425                const objectAssignmentInitializer = equalsToken ? allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)) : undefined;
6426                node = factory.createShorthandPropertyAssignment(name as Identifier, objectAssignmentInitializer);
6427                // Save equals token for error reporting.
6428                // TODO(rbuckton): Consider manufacturing this when we need to report an error as it is otherwise not useful.
6429                node.equalsToken = equalsToken;
6430            }
6431            else {
6432                parseExpected(SyntaxKind.ColonToken);
6433                const initializer = allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true));
6434                node = factory.createPropertyAssignment(name, initializer);
6435            }
6436            // Decorators, Modifiers, questionToken, and exclamationToken are not supported by property assignments and are reported in the grammar checker
6437            node.illegalDecorators = decorators;
6438            node.modifiers = modifiers;
6439            node.questionToken = questionToken;
6440            node.exclamationToken = exclamationToken;
6441            return withJSDoc(finishNode(node, pos), hasJSDoc);
6442        }
6443
6444        function parseObjectLiteralExpression(): ObjectLiteralExpression {
6445            const pos = getNodePos();
6446            const openBracePosition = scanner.getTokenPos();
6447            const openBraceParsed = parseExpected(SyntaxKind.OpenBraceToken);
6448            const multiLine = scanner.hasPrecedingLineBreak();
6449            const properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralElement, /*considerSemicolonAsDelimiter*/ true);
6450            parseExpectedMatchingBrackets(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, openBraceParsed, openBracePosition);
6451            return finishNode(factory.createObjectLiteralExpression(properties, multiLine), pos);
6452        }
6453
6454        function parseFunctionExpression(): FunctionExpression {
6455            // GeneratorExpression:
6456            //      function* BindingIdentifier [Yield][opt](FormalParameters[Yield]){ GeneratorBody }
6457            //
6458            // FunctionExpression:
6459            //      function BindingIdentifier[opt](FormalParameters){ FunctionBody }
6460            const savedDecoratorContext = inDecoratorContext();
6461            setDecoratorContext(/*val*/ false);
6462
6463            const pos = getNodePos();
6464            const hasJSDoc = hasPrecedingJSDocComment();
6465            const modifiers = parseModifiers();
6466            parseExpected(SyntaxKind.FunctionKeyword);
6467            const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
6468            const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None;
6469            const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None;
6470            const name = isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalBindingIdentifier) :
6471                isGenerator ? doInYieldContext(parseOptionalBindingIdentifier) :
6472                isAsync ? doInAwaitContext(parseOptionalBindingIdentifier) :
6473                parseOptionalBindingIdentifier();
6474
6475            const typeParameters = parseTypeParameters();
6476            const parameters = parseParameters(isGenerator | isAsync);
6477            const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);
6478            const body = parseFunctionBlock(isGenerator | isAsync);
6479
6480            setDecoratorContext(savedDecoratorContext);
6481
6482            const node = factory.createFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, type, body);
6483            return withJSDoc(finishNode(node, pos), hasJSDoc);
6484        }
6485
6486        function parseOptionalBindingIdentifier(): Identifier | undefined {
6487            return isBindingIdentifier() ? parseBindingIdentifier() : undefined;
6488        }
6489
6490        function parseNewExpressionOrNewDotTarget(): NewExpression | MetaProperty {
6491            setEtsNewExpressionContext(inEtsComponentsContext());
6492            const pos = getNodePos();
6493            parseExpected(SyntaxKind.NewKeyword);
6494            if (parseOptional(SyntaxKind.DotToken)) {
6495                const name = parseIdentifierName();
6496                return finishNode(factory.createMetaProperty(SyntaxKind.NewKeyword, name), pos);
6497            }
6498            const expressionPos = getNodePos();
6499            let expression: LeftHandSideExpression = parseMemberExpressionRest(expressionPos, parsePrimaryExpression(), /*allowOptionalChain*/ false);
6500            let typeArguments: NodeArray<TypeNode> | undefined;
6501            // Absorb type arguments into NewExpression when preceding expression is ExpressionWithTypeArguments
6502            if (expression.kind === SyntaxKind.ExpressionWithTypeArguments) {
6503                typeArguments = (expression as ExpressionWithTypeArguments).typeArguments;
6504                expression = (expression as ExpressionWithTypeArguments).expression;
6505            }
6506            if (token() === SyntaxKind.QuestionDotToken) {
6507                parseErrorAtCurrentToken(Diagnostics.Invalid_optional_chain_from_new_expression_Did_you_mean_to_call_0, getTextOfNodeFromSourceText(sourceText, expression));
6508            }
6509            const argumentList = token() === SyntaxKind.OpenParenToken ? parseArgumentList() : undefined;
6510            setEtsNewExpressionContext(false);
6511            return finishNode(factory.createNewExpression(expression, typeArguments, argumentList), pos);
6512        }
6513
6514        // STATEMENTS
6515        function parseBlock(ignoreMissingOpenBrace: boolean, diagnosticMessage?: DiagnosticMessage): Block {
6516            const pos = getNodePos();
6517            const hasJSDoc = hasPrecedingJSDocComment();
6518            const openBracePosition = scanner.getTokenPos();
6519            const openBraceParsed = parseExpected(SyntaxKind.OpenBraceToken, diagnosticMessage);
6520            if (openBraceParsed || ignoreMissingOpenBrace) {
6521                const multiLine = scanner.hasPrecedingLineBreak();
6522                const statements = parseList(ParsingContext.BlockStatements, parseStatement);
6523                parseExpectedMatchingBrackets(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, openBraceParsed, openBracePosition);
6524                const result = withJSDoc(finishNode(factory.createBlock(statements, multiLine), pos), hasJSDoc);
6525                if (token() === SyntaxKind.EqualsToken) {
6526                    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);
6527                    nextToken();
6528                }
6529
6530                return result;
6531            }
6532            else {
6533                const statements = createMissingList<Statement>();
6534                return withJSDoc(finishNode(factory.createBlock(statements, /*multiLine*/ undefined), pos), hasJSDoc);
6535            }
6536        }
6537
6538        function parseFunctionBlock(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block {
6539            const savedYieldContext = inYieldContext();
6540            setYieldContext(!!(flags & SignatureFlags.Yield));
6541
6542            const savedAwaitContext = inAwaitContext();
6543            setAwaitContext(!!(flags & SignatureFlags.Await));
6544
6545            const savedTopLevel = topLevel;
6546            topLevel = false;
6547
6548            // We may be in a [Decorator] context when parsing a function expression or
6549            // arrow function. The body of the function is not in [Decorator] context.
6550            const saveDecoratorContext = inDecoratorContext();
6551            if (saveDecoratorContext) {
6552                setDecoratorContext(/*val*/ false);
6553            }
6554
6555            const block = parseBlock(!!(flags & SignatureFlags.IgnoreMissingOpenBrace), diagnosticMessage);
6556
6557            if (saveDecoratorContext) {
6558                setDecoratorContext(/*val*/ true);
6559            }
6560
6561            topLevel = savedTopLevel;
6562            setYieldContext(savedYieldContext);
6563            setAwaitContext(savedAwaitContext);
6564
6565            return block;
6566        }
6567
6568        function parseEmptyStatement(): Statement {
6569            const pos = getNodePos();
6570            const hasJSDoc = hasPrecedingJSDocComment();
6571            parseExpected(SyntaxKind.SemicolonToken);
6572            return withJSDoc(finishNode(factory.createEmptyStatement(), pos), hasJSDoc);
6573        }
6574
6575        function parseIfStatement(): IfStatement {
6576            const pos = getNodePos();
6577            const hasJSDoc = hasPrecedingJSDocComment();
6578            parseExpected(SyntaxKind.IfKeyword);
6579            const openParenPosition = scanner.getTokenPos();
6580            const openParenParsed = parseExpected(SyntaxKind.OpenParenToken);
6581            const expression = allowInAnd(parseExpression);
6582            parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition);
6583            const thenStatement = parseStatement();
6584            const elseStatement = parseOptional(SyntaxKind.ElseKeyword) ? parseStatement() : undefined;
6585            return withJSDoc(finishNode(factory.createIfStatement(expression, thenStatement, elseStatement), pos), hasJSDoc);
6586        }
6587
6588        function parseDoStatement(): DoStatement {
6589            const pos = getNodePos();
6590            const hasJSDoc = hasPrecedingJSDocComment();
6591            parseExpected(SyntaxKind.DoKeyword);
6592            const statement = parseStatement();
6593            parseExpected(SyntaxKind.WhileKeyword);
6594            const openParenPosition = scanner.getTokenPos();
6595            const openParenParsed = parseExpected(SyntaxKind.OpenParenToken);
6596            const expression = allowInAnd(parseExpression);
6597            parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition);
6598
6599            // From: https://mail.mozilla.org/pipermail/es-discuss/2011-August/016188.html
6600            // 157 min --- All allen at wirfs-brock.com CONF --- "do{;}while(false)false" prohibited in
6601            // spec but allowed in consensus reality. Approved -- this is the de-facto standard whereby
6602            //  do;while(0)x will have a semicolon inserted before x.
6603            parseOptional(SyntaxKind.SemicolonToken);
6604            return withJSDoc(finishNode(factory.createDoStatement(statement, expression), pos), hasJSDoc);
6605        }
6606
6607        function parseWhileStatement(): WhileStatement {
6608            const pos = getNodePos();
6609            const hasJSDoc = hasPrecedingJSDocComment();
6610            parseExpected(SyntaxKind.WhileKeyword);
6611            const openParenPosition = scanner.getTokenPos();
6612            const openParenParsed = parseExpected(SyntaxKind.OpenParenToken);
6613            const expression = allowInAnd(parseExpression);
6614            parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition);
6615            const statement = parseStatement();
6616            return withJSDoc(finishNode(factory.createWhileStatement(expression, statement), pos), hasJSDoc);
6617        }
6618
6619        function parseForOrForInOrForOfStatement(): Statement {
6620            const pos = getNodePos();
6621            const hasJSDoc = hasPrecedingJSDocComment();
6622            parseExpected(SyntaxKind.ForKeyword);
6623            const awaitToken = parseOptionalToken(SyntaxKind.AwaitKeyword);
6624            parseExpected(SyntaxKind.OpenParenToken);
6625
6626            let initializer!: VariableDeclarationList | Expression;
6627            if (token() !== SyntaxKind.SemicolonToken) {
6628                if (token() === SyntaxKind.VarKeyword || token() === SyntaxKind.LetKeyword || token() === SyntaxKind.ConstKeyword) {
6629                    initializer = parseVariableDeclarationList(/*inForStatementInitializer*/ true);
6630                }
6631                else {
6632                    initializer = disallowInAnd(parseExpression);
6633                }
6634            }
6635
6636            let node: IterationStatement;
6637            if (awaitToken ? parseExpected(SyntaxKind.OfKeyword) : parseOptional(SyntaxKind.OfKeyword)) {
6638                const expression = allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true));
6639                parseExpected(SyntaxKind.CloseParenToken);
6640                node = factory.createForOfStatement(awaitToken, initializer, expression, parseStatement());
6641            }
6642            else if (parseOptional(SyntaxKind.InKeyword)) {
6643                const expression = allowInAnd(parseExpression);
6644                parseExpected(SyntaxKind.CloseParenToken);
6645                node = factory.createForInStatement(initializer, expression, parseStatement());
6646            }
6647            else {
6648                parseExpected(SyntaxKind.SemicolonToken);
6649                const condition = token() !== SyntaxKind.SemicolonToken && token() !== SyntaxKind.CloseParenToken
6650                    ? allowInAnd(parseExpression)
6651                    : undefined;
6652                parseExpected(SyntaxKind.SemicolonToken);
6653                const incrementor = token() !== SyntaxKind.CloseParenToken
6654                    ? allowInAnd(parseExpression)
6655                    : undefined;
6656                parseExpected(SyntaxKind.CloseParenToken);
6657                node = factory.createForStatement(initializer, condition, incrementor, parseStatement());
6658            }
6659
6660            return withJSDoc(finishNode(node, pos) as ForStatement | ForInOrOfStatement, hasJSDoc);
6661        }
6662
6663        function parseBreakOrContinueStatement(kind: SyntaxKind): BreakOrContinueStatement {
6664            const pos = getNodePos();
6665            const hasJSDoc = hasPrecedingJSDocComment();
6666
6667            parseExpected(kind === SyntaxKind.BreakStatement ? SyntaxKind.BreakKeyword : SyntaxKind.ContinueKeyword);
6668            const label = canParseSemicolon() ? undefined : parseIdentifier();
6669
6670            parseSemicolon();
6671            const node = kind === SyntaxKind.BreakStatement
6672                ? factory.createBreakStatement(label)
6673                : factory.createContinueStatement(label);
6674            return withJSDoc(finishNode(node, pos), hasJSDoc);
6675        }
6676
6677        function parseReturnStatement(): ReturnStatement {
6678            const pos = getNodePos();
6679            const hasJSDoc = hasPrecedingJSDocComment();
6680            parseExpected(SyntaxKind.ReturnKeyword);
6681            const expression = canParseSemicolon() ? undefined : allowInAnd(parseExpression);
6682            parseSemicolon();
6683            return withJSDoc(finishNode(factory.createReturnStatement(expression), pos), hasJSDoc);
6684        }
6685
6686        function parseWithStatement(): WithStatement {
6687            const pos = getNodePos();
6688            const hasJSDoc = hasPrecedingJSDocComment();
6689            parseExpected(SyntaxKind.WithKeyword);
6690            const openParenPosition = scanner.getTokenPos();
6691            const openParenParsed = parseExpected(SyntaxKind.OpenParenToken);
6692            const expression = allowInAnd(parseExpression);
6693            parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition);
6694            const statement = doInsideOfContext(NodeFlags.InWithStatement, parseStatement);
6695            return withJSDoc(finishNode(factory.createWithStatement(expression, statement), pos), hasJSDoc);
6696        }
6697
6698        function parseCaseClause(): CaseClause {
6699            const pos = getNodePos();
6700            const hasJSDoc = hasPrecedingJSDocComment();
6701            parseExpected(SyntaxKind.CaseKeyword);
6702            const expression = allowInAnd(parseExpression);
6703            parseExpected(SyntaxKind.ColonToken);
6704            const statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement);
6705            return withJSDoc(finishNode(factory.createCaseClause(expression, statements), pos), hasJSDoc);
6706        }
6707
6708        function parseDefaultClause(): DefaultClause {
6709            const pos = getNodePos();
6710            parseExpected(SyntaxKind.DefaultKeyword);
6711            parseExpected(SyntaxKind.ColonToken);
6712            const statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement);
6713            return finishNode(factory.createDefaultClause(statements), pos);
6714        }
6715
6716        function parseCaseOrDefaultClause(): CaseOrDefaultClause {
6717            return token() === SyntaxKind.CaseKeyword ? parseCaseClause() : parseDefaultClause();
6718        }
6719
6720        function parseCaseBlock(): CaseBlock {
6721            const pos = getNodePos();
6722            parseExpected(SyntaxKind.OpenBraceToken);
6723            const clauses = parseList(ParsingContext.SwitchClauses, parseCaseOrDefaultClause);
6724            parseExpected(SyntaxKind.CloseBraceToken);
6725            return finishNode(factory.createCaseBlock(clauses), pos);
6726        }
6727
6728        function parseSwitchStatement(): SwitchStatement {
6729            const pos = getNodePos();
6730            const hasJSDoc = hasPrecedingJSDocComment();
6731            parseExpected(SyntaxKind.SwitchKeyword);
6732            parseExpected(SyntaxKind.OpenParenToken);
6733            const expression = allowInAnd(parseExpression);
6734            parseExpected(SyntaxKind.CloseParenToken);
6735            const caseBlock = parseCaseBlock();
6736            return withJSDoc(finishNode(factory.createSwitchStatement(expression, caseBlock), pos), hasJSDoc);
6737        }
6738
6739        function parseThrowStatement(): ThrowStatement {
6740            // ThrowStatement[Yield] :
6741            //      throw [no LineTerminator here]Expression[In, ?Yield];
6742
6743            const pos = getNodePos();
6744            const hasJSDoc = hasPrecedingJSDocComment();
6745            parseExpected(SyntaxKind.ThrowKeyword);
6746
6747            // Because of automatic semicolon insertion, we need to report error if this
6748            // throw could be terminated with a semicolon.  Note: we can't call 'parseExpression'
6749            // directly as that might consume an expression on the following line.
6750            // Instead, we create a "missing" identifier, but don't report an error. The actual error
6751            // will be reported in the grammar walker.
6752            let expression = scanner.hasPrecedingLineBreak() ? undefined : allowInAnd(parseExpression);
6753            if (expression === undefined) {
6754                identifierCount++;
6755                expression = finishNode(factory.createIdentifier(""), getNodePos());
6756            }
6757            if (!tryParseSemicolon()) {
6758                parseErrorForMissingSemicolonAfter(expression);
6759            }
6760            return withJSDoc(finishNode(factory.createThrowStatement(expression), pos), hasJSDoc);
6761        }
6762
6763        // TODO: Review for error recovery
6764        function parseTryStatement(): TryStatement {
6765            const pos = getNodePos();
6766            const hasJSDoc = hasPrecedingJSDocComment();
6767
6768            parseExpected(SyntaxKind.TryKeyword);
6769            const tryBlock = parseBlock(/*ignoreMissingOpenBrace*/ false);
6770            const catchClause = token() === SyntaxKind.CatchKeyword ? parseCatchClause() : undefined;
6771
6772            // If we don't have a catch clause, then we must have a finally clause.  Try to parse
6773            // one out no matter what.
6774            let finallyBlock: Block | undefined;
6775            if (!catchClause || token() === SyntaxKind.FinallyKeyword) {
6776                parseExpected(SyntaxKind.FinallyKeyword, Diagnostics.catch_or_finally_expected);
6777                finallyBlock = parseBlock(/*ignoreMissingOpenBrace*/ false);
6778            }
6779
6780            return withJSDoc(finishNode(factory.createTryStatement(tryBlock, catchClause, finallyBlock), pos), hasJSDoc);
6781        }
6782
6783        function parseCatchClause(): CatchClause {
6784            const pos = getNodePos();
6785            parseExpected(SyntaxKind.CatchKeyword);
6786
6787            let variableDeclaration;
6788            if (parseOptional(SyntaxKind.OpenParenToken)) {
6789                variableDeclaration = parseVariableDeclaration();
6790                parseExpected(SyntaxKind.CloseParenToken);
6791            }
6792            else {
6793                // Keep shape of node to avoid degrading performance.
6794                variableDeclaration = undefined;
6795            }
6796
6797            const block = parseBlock(/*ignoreMissingOpenBrace*/ false);
6798            return finishNode(factory.createCatchClause(variableDeclaration, block), pos);
6799        }
6800
6801        function parseDebuggerStatement(): Statement {
6802            const pos = getNodePos();
6803            const hasJSDoc = hasPrecedingJSDocComment();
6804            parseExpected(SyntaxKind.DebuggerKeyword);
6805            parseSemicolon();
6806            return withJSDoc(finishNode(factory.createDebuggerStatement(), pos), hasJSDoc);
6807        }
6808
6809        function parseExpressionOrLabeledStatement(): ExpressionStatement | LabeledStatement {
6810            // Avoiding having to do the lookahead for a labeled statement by just trying to parse
6811            // out an expression, seeing if it is identifier and then seeing if it is followed by
6812            // a colon.
6813            const pos = getNodePos();
6814            let hasJSDoc = hasPrecedingJSDocComment();
6815            let node: ExpressionStatement | LabeledStatement;
6816            const hasParen = token() === SyntaxKind.OpenParenToken;
6817            const expression = allowInAnd(parseExpression);
6818            if (ts.isIdentifier(expression) && parseOptional(SyntaxKind.ColonToken)) {
6819                node = factory.createLabeledStatement(expression, parseStatement());
6820            }
6821            else {
6822                if (!tryParseSemicolon()) {
6823                    parseErrorForMissingSemicolonAfter(expression);
6824                }
6825                node = factory.createExpressionStatement(expression);
6826                if (hasParen) {
6827                    // do not parse the same jsdoc twice
6828                    hasJSDoc = false;
6829                }
6830            }
6831            return withJSDoc(finishNode(node, pos), hasJSDoc);
6832        }
6833
6834        function nextTokenIsIdentifierOrKeywordOnSameLine() {
6835            nextToken();
6836            return tokenIsIdentifierOrKeyword(token()) && !scanner.hasPrecedingLineBreak();
6837        }
6838
6839        function nextTokenIsClassKeywordOnSameLine() {
6840            nextToken();
6841            return token() === SyntaxKind.ClassKeyword && !scanner.hasPrecedingLineBreak();
6842        }
6843
6844        function nextTokenIsFunctionKeywordOnSameLine() {
6845            nextToken();
6846            return token() === SyntaxKind.FunctionKeyword && !scanner.hasPrecedingLineBreak();
6847        }
6848
6849        function nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine() {
6850            nextToken();
6851            return (tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral || token() === SyntaxKind.StringLiteral) && !scanner.hasPrecedingLineBreak();
6852        }
6853
6854        function isDeclaration(): boolean {
6855            while (true) {
6856                switch (token()) {
6857                    case SyntaxKind.VarKeyword:
6858                    case SyntaxKind.LetKeyword:
6859                    case SyntaxKind.ConstKeyword:
6860                    case SyntaxKind.FunctionKeyword:
6861                    case SyntaxKind.ClassKeyword:
6862                    case SyntaxKind.EnumKeyword:
6863                        return true;
6864                    case SyntaxKind.StructKeyword:
6865                        return inEtsContext();
6866
6867
6868                    // 'declare', 'module', 'namespace', 'interface'* and 'type' are all legal JavaScript identifiers;
6869                    // however, an identifier cannot be followed by another identifier on the same line. This is what we
6870                    // count on to parse out the respective declarations. For instance, we exploit this to say that
6871                    //
6872                    //    namespace n
6873                    //
6874                    // can be none other than the beginning of a namespace declaration, but need to respect that JavaScript sees
6875                    //
6876                    //    namespace
6877                    //    n
6878                    //
6879                    // as the identifier 'namespace' on one line followed by the identifier 'n' on another.
6880                    // We need to look one token ahead to see if it permissible to try parsing a declaration.
6881                    //
6882                    // *Note*: 'interface' is actually a strict mode reserved word. So while
6883                    //
6884                    //   "use strict"
6885                    //   interface
6886                    //   I {}
6887                    //
6888                    // could be legal, it would add complexity for very little gain.
6889                    case SyntaxKind.InterfaceKeyword:
6890                    case SyntaxKind.TypeKeyword:
6891                        return nextTokenIsIdentifierOnSameLine();
6892                    case SyntaxKind.ModuleKeyword:
6893                    case SyntaxKind.NamespaceKeyword:
6894                        return nextTokenIsIdentifierOrStringLiteralOnSameLine();
6895                    case SyntaxKind.AbstractKeyword:
6896                    case SyntaxKind.AccessorKeyword:
6897                    case SyntaxKind.AsyncKeyword:
6898                    case SyntaxKind.DeclareKeyword:
6899                    case SyntaxKind.PrivateKeyword:
6900                    case SyntaxKind.ProtectedKeyword:
6901                    case SyntaxKind.PublicKeyword:
6902                    case SyntaxKind.ReadonlyKeyword:
6903                        nextToken();
6904                        // ASI takes effect for this modifier.
6905                        if (scanner.hasPrecedingLineBreak()) {
6906                            return false;
6907                        }
6908                        continue;
6909
6910                    case SyntaxKind.GlobalKeyword:
6911                        nextToken();
6912                        return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.Identifier || token() === SyntaxKind.ExportKeyword;
6913
6914                    case SyntaxKind.ImportKeyword:
6915                        nextToken();
6916                        return token() === SyntaxKind.StringLiteral || token() === SyntaxKind.AsteriskToken ||
6917                            token() === SyntaxKind.OpenBraceToken || tokenIsIdentifierOrKeyword(token());
6918                    case SyntaxKind.ExportKeyword:
6919                        let currentToken = nextToken();
6920                        if (currentToken === SyntaxKind.TypeKeyword) {
6921                            currentToken = lookAhead(nextToken);
6922                        }
6923                        if (currentToken === SyntaxKind.EqualsToken || currentToken === SyntaxKind.AsteriskToken ||
6924                            currentToken === SyntaxKind.OpenBraceToken || currentToken === SyntaxKind.DefaultKeyword ||
6925                            currentToken === SyntaxKind.AsKeyword) {
6926                            return true;
6927                        }
6928                        continue;
6929
6930                    case SyntaxKind.StaticKeyword:
6931                        nextToken();
6932                        continue;
6933                    default:
6934                        return false;
6935                }
6936            }
6937        }
6938
6939        function isStartOfDeclaration(): boolean {
6940            return lookAhead(isDeclaration);
6941        }
6942
6943        function isStartOfStatement(): boolean {
6944            switch (token()) {
6945                case SyntaxKind.AtToken:
6946                case SyntaxKind.SemicolonToken:
6947                case SyntaxKind.OpenBraceToken:
6948                case SyntaxKind.VarKeyword:
6949                case SyntaxKind.LetKeyword:
6950                case SyntaxKind.FunctionKeyword:
6951                case SyntaxKind.ClassKeyword:
6952                case SyntaxKind.EnumKeyword:
6953                case SyntaxKind.IfKeyword:
6954                case SyntaxKind.DoKeyword:
6955                case SyntaxKind.WhileKeyword:
6956                case SyntaxKind.ForKeyword:
6957                case SyntaxKind.ContinueKeyword:
6958                case SyntaxKind.BreakKeyword:
6959                case SyntaxKind.ReturnKeyword:
6960                case SyntaxKind.WithKeyword:
6961                case SyntaxKind.SwitchKeyword:
6962                case SyntaxKind.ThrowKeyword:
6963                case SyntaxKind.TryKeyword:
6964                case SyntaxKind.DebuggerKeyword:
6965                // 'catch' and 'finally' do not actually indicate that the code is part of a statement,
6966                // however, we say they are here so that we may gracefully parse them and error later.
6967                // falls through
6968                case SyntaxKind.CatchKeyword:
6969                case SyntaxKind.FinallyKeyword:
6970                    return true;
6971                case SyntaxKind.StructKeyword:
6972                    return inEtsContext();
6973
6974                case SyntaxKind.ImportKeyword:
6975                    return isStartOfDeclaration() || lookAhead(nextTokenIsOpenParenOrLessThanOrDot);
6976
6977                case SyntaxKind.ConstKeyword:
6978                case SyntaxKind.ExportKeyword:
6979                    return isStartOfDeclaration();
6980
6981                case SyntaxKind.AsyncKeyword:
6982                case SyntaxKind.DeclareKeyword:
6983                case SyntaxKind.InterfaceKeyword:
6984                case SyntaxKind.ModuleKeyword:
6985                case SyntaxKind.NamespaceKeyword:
6986                case SyntaxKind.TypeKeyword:
6987                case SyntaxKind.GlobalKeyword:
6988                    // When these don't start a declaration, they're an identifier in an expression statement
6989                    return true;
6990
6991                case SyntaxKind.AccessorKeyword:
6992                case SyntaxKind.PublicKeyword:
6993                case SyntaxKind.PrivateKeyword:
6994                case SyntaxKind.ProtectedKeyword:
6995                case SyntaxKind.StaticKeyword:
6996                case SyntaxKind.ReadonlyKeyword:
6997                    // When these don't start a declaration, they may be the start of a class member if an identifier
6998                    // immediately follows. Otherwise they're an identifier in an expression statement.
6999                    return isStartOfDeclaration() || !lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine);
7000
7001                default:
7002                    return isStartOfExpression();
7003            }
7004        }
7005
7006        function nextTokenIsBindingIdentifierOrStartOfDestructuring() {
7007            nextToken();
7008            return isBindingIdentifier() || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.OpenBracketToken;
7009        }
7010
7011        function isLetDeclaration() {
7012            // In ES6 'let' always starts a lexical declaration if followed by an identifier or {
7013            // or [.
7014            return lookAhead(nextTokenIsBindingIdentifierOrStartOfDestructuring);
7015        }
7016
7017        function parseStatement(): Statement {
7018            switch (token()) {
7019                case SyntaxKind.SemicolonToken:
7020                    return parseEmptyStatement();
7021                case SyntaxKind.OpenBraceToken:
7022                    return parseBlock(/*ignoreMissingOpenBrace*/ false);
7023                case SyntaxKind.VarKeyword:
7024                    return parseVariableStatement(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined);
7025                case SyntaxKind.LetKeyword:
7026                    if (isLetDeclaration()) {
7027                        return parseVariableStatement(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined);
7028                    }
7029                    break;
7030                case SyntaxKind.FunctionKeyword:
7031                    return parseFunctionDeclaration(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined);
7032                case SyntaxKind.StructKeyword:
7033                    if (inEtsContext()) {
7034                        return parseStructDeclaration(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined);
7035                    }
7036                    break;
7037                case SyntaxKind.ClassKeyword:
7038                    return parseClassDeclaration(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined);
7039                case SyntaxKind.IfKeyword:
7040                    return parseIfStatement();
7041                case SyntaxKind.DoKeyword:
7042                    return parseDoStatement();
7043                case SyntaxKind.WhileKeyword:
7044                    return parseWhileStatement();
7045                case SyntaxKind.ForKeyword:
7046                    return parseForOrForInOrForOfStatement();
7047                case SyntaxKind.ContinueKeyword:
7048                    return parseBreakOrContinueStatement(SyntaxKind.ContinueStatement);
7049                case SyntaxKind.BreakKeyword:
7050                    return parseBreakOrContinueStatement(SyntaxKind.BreakStatement);
7051                case SyntaxKind.ReturnKeyword:
7052                    return parseReturnStatement();
7053                case SyntaxKind.WithKeyword:
7054                    return parseWithStatement();
7055                case SyntaxKind.SwitchKeyword:
7056                    return parseSwitchStatement();
7057                case SyntaxKind.ThrowKeyword:
7058                    return parseThrowStatement();
7059                case SyntaxKind.TryKeyword:
7060                // Include 'catch' and 'finally' for error recovery.
7061                // falls through
7062                case SyntaxKind.CatchKeyword:
7063                case SyntaxKind.FinallyKeyword:
7064                    return parseTryStatement();
7065                case SyntaxKind.DebuggerKeyword:
7066                    return parseDebuggerStatement();
7067                case SyntaxKind.AtToken:
7068                    return parseDeclaration();
7069                case SyntaxKind.AsyncKeyword:
7070                case SyntaxKind.InterfaceKeyword:
7071                case SyntaxKind.TypeKeyword:
7072                case SyntaxKind.ModuleKeyword:
7073                case SyntaxKind.NamespaceKeyword:
7074                case SyntaxKind.DeclareKeyword:
7075                case SyntaxKind.ConstKeyword:
7076                case SyntaxKind.EnumKeyword:
7077                case SyntaxKind.ExportKeyword:
7078                case SyntaxKind.ImportKeyword:
7079                case SyntaxKind.PrivateKeyword:
7080                case SyntaxKind.ProtectedKeyword:
7081                case SyntaxKind.PublicKeyword:
7082                case SyntaxKind.AbstractKeyword:
7083                case SyntaxKind.AccessorKeyword:
7084                case SyntaxKind.StaticKeyword:
7085                case SyntaxKind.ReadonlyKeyword:
7086                case SyntaxKind.GlobalKeyword:
7087                    if (isStartOfDeclaration()) {
7088                        return parseDeclaration();
7089                    }
7090                    break;
7091            }
7092            return parseExpressionOrLabeledStatement();
7093        }
7094
7095        function isDeclareModifier(modifier: Modifier) {
7096            return modifier.kind === SyntaxKind.DeclareKeyword;
7097        }
7098
7099        function parseDeclaration(): Statement {
7100            // `parseListElement` attempted to get the reused node at this position,
7101            // but the ambient context flag was not yet set, so the node appeared
7102            // not reusable in that context.
7103            const pos = getNodePos();
7104            const hasJSDoc = hasPrecedingJSDocComment();
7105            const decorators = parseDecorators();
7106
7107            if (token() === SyntaxKind.FunctionKeyword || token() === SyntaxKind.ExportKeyword) {
7108                if (hasEtsExtendDecoratorNames(decorators, sourceFileCompilerOptions)) {
7109                    const extendEtsComponentDecoratorNames = getEtsExtendDecoratorsComponentNames(decorators, sourceFileCompilerOptions);
7110                    if (extendEtsComponentDecoratorNames.length > 0) {
7111                        sourceFileCompilerOptions.ets?.extend.components.forEach(({ name, type, instance }) => {
7112                            if (name === last(extendEtsComponentDecoratorNames)) {
7113                                extendEtsComponentDeclaration = { name, type, instance };
7114                            }
7115                        });
7116                    }
7117                    setEtsExtendComponentsContext(!!extendEtsComponentDeclaration);
7118                }
7119                else if (hasEtsStylesDecoratorNames(decorators, sourceFileCompilerOptions)) {
7120                    const stylesEtsComponentDecoratorNames = getEtsStylesDecoratorComponentNames(decorators, sourceFileCompilerOptions);
7121                    if (stylesEtsComponentDecoratorNames.length > 0) {
7122                        stylesEtsComponentDeclaration = sourceFileCompilerOptions.ets?.styles.component;
7123                    }
7124                    setEtsStylesComponentsContext(!!stylesEtsComponentDeclaration);
7125                }
7126                else {
7127                    setEtsComponentsContext(isTokenInsideBuilder(decorators, sourceFileCompilerOptions));
7128                }
7129            }
7130
7131            const modifiers = parseModifiers();
7132            const isAmbient = some(modifiers, isDeclareModifier);
7133            if (isAmbient) {
7134                const node = tryReuseAmbientDeclaration(pos);
7135                if (node) {
7136                    return node;
7137                }
7138
7139                for (const m of modifiers!) {
7140                    (m as Mutable<Node>).flags |= NodeFlags.Ambient;
7141                }
7142                return doInsideOfContext(NodeFlags.Ambient, () => parseDeclarationWorker(pos, hasJSDoc, decorators, modifiers));
7143            }
7144            else {
7145                return parseDeclarationWorker(pos, hasJSDoc, decorators, modifiers);
7146            }
7147        }
7148
7149        function tryReuseAmbientDeclaration(pos: number): Statement | undefined {
7150            return doInsideOfContext(NodeFlags.Ambient, () => {
7151                const node = currentNode(parsingContext, pos);
7152                if (node) {
7153                    return consumeNode(node) as Statement;
7154                }
7155            });
7156        }
7157
7158        function parseDeclarationWorker(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): Statement {
7159            switch (token()) {
7160                case SyntaxKind.VarKeyword:
7161                case SyntaxKind.LetKeyword:
7162                case SyntaxKind.ConstKeyword:
7163                    return parseVariableStatement(pos, hasJSDoc, decorators, modifiers);
7164                case SyntaxKind.FunctionKeyword:
7165                    return parseFunctionDeclaration(pos, hasJSDoc, decorators, modifiers);
7166                case SyntaxKind.ClassKeyword:
7167                    return parseClassDeclaration(pos, hasJSDoc, decorators, modifiers);
7168                case SyntaxKind.StructKeyword:
7169                    if (inEtsContext()) {
7170                        return parseStructDeclaration(pos, hasJSDoc, decorators, modifiers);
7171                    }
7172                    return parseDeclarationDefault(pos,decorators, modifiers);
7173                case SyntaxKind.InterfaceKeyword:
7174                    return parseInterfaceDeclaration(pos, hasJSDoc, decorators, modifiers);
7175                case SyntaxKind.TypeKeyword:
7176                    return parseTypeAliasDeclaration(pos, hasJSDoc, decorators, modifiers);
7177                case SyntaxKind.EnumKeyword:
7178                    return parseEnumDeclaration(pos, hasJSDoc, decorators, modifiers);
7179                case SyntaxKind.GlobalKeyword:
7180                case SyntaxKind.ModuleKeyword:
7181                case SyntaxKind.NamespaceKeyword:
7182                    return parseModuleDeclaration(pos, hasJSDoc, decorators, modifiers);
7183                case SyntaxKind.ImportKeyword:
7184                    return parseImportDeclarationOrImportEqualsDeclaration(pos, hasJSDoc, decorators, modifiers);
7185                case SyntaxKind.ExportKeyword:
7186                    nextToken();
7187                    switch (token()) {
7188                        case SyntaxKind.DefaultKeyword:
7189                        case SyntaxKind.EqualsToken:
7190                            return parseExportAssignment(pos, hasJSDoc, decorators, modifiers);
7191                        case SyntaxKind.AsKeyword:
7192                            return parseNamespaceExportDeclaration(pos, hasJSDoc, decorators, modifiers);
7193                        default:
7194                            return parseExportDeclaration(pos, hasJSDoc, decorators, modifiers);
7195                    }
7196                default:
7197                    return parseDeclarationDefault(pos,decorators, modifiers);
7198            }
7199        }
7200
7201        function parseDeclarationDefault(pos: number,decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): Statement {
7202            if (decorators || modifiers) {
7203                // We reached this point because we encountered decorators and/or modifiers and assumed a declaration
7204                // would follow. For recovery and error reporting purposes, return an incomplete declaration.
7205                const missing = createMissingNode<MissingDeclaration>(SyntaxKind.MissingDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected);
7206                setTextRangePos(missing, pos);
7207                missing.illegalDecorators = decorators;
7208                missing.modifiers = modifiers;
7209                return missing;
7210            }
7211            return undefined!; // TODO: GH#18217
7212        }
7213
7214        function nextTokenIsIdentifierOrStringLiteralOnSameLine() {
7215            nextToken();
7216            return !scanner.hasPrecedingLineBreak() && (isIdentifier() || token() === SyntaxKind.StringLiteral);
7217        }
7218
7219        function parseFunctionBlockOrSemicolon(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block | undefined {
7220            if (token() !== SyntaxKind.OpenBraceToken) {
7221                if (flags & SignatureFlags.Type) {
7222                    parseTypeMemberSemicolon();
7223                    return;
7224                }
7225                if (canParseSemicolon()) {
7226                    parseSemicolon();
7227                    return;
7228                }
7229            }
7230            return parseFunctionBlock(flags, diagnosticMessage);
7231        }
7232
7233        // DECLARATIONS
7234
7235        function parseArrayBindingElement(): ArrayBindingElement {
7236            const pos = getNodePos();
7237            if (token() === SyntaxKind.CommaToken) {
7238                return finishNode(factory.createOmittedExpression(), pos);
7239            }
7240            const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
7241            const name = parseIdentifierOrPattern();
7242            const initializer = parseInitializer();
7243            return finishNode(factory.createBindingElement(dotDotDotToken, /*propertyName*/ undefined, name, initializer), pos);
7244        }
7245
7246        function parseObjectBindingElement(): BindingElement {
7247            const pos = getNodePos();
7248            const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
7249            const tokenIsIdentifier = isBindingIdentifier();
7250            let propertyName: PropertyName | undefined = parsePropertyName();
7251            let name: BindingName;
7252            if (tokenIsIdentifier && token() !== SyntaxKind.ColonToken) {
7253                name = propertyName as Identifier;
7254                propertyName = undefined;
7255            }
7256            else {
7257                parseExpected(SyntaxKind.ColonToken);
7258                name = parseIdentifierOrPattern();
7259            }
7260            const initializer = parseInitializer();
7261            return finishNode(factory.createBindingElement(dotDotDotToken, propertyName, name, initializer), pos);
7262        }
7263
7264        function parseObjectBindingPattern(): ObjectBindingPattern {
7265            const pos = getNodePos();
7266            parseExpected(SyntaxKind.OpenBraceToken);
7267            const elements = parseDelimitedList(ParsingContext.ObjectBindingElements, parseObjectBindingElement);
7268            parseExpected(SyntaxKind.CloseBraceToken);
7269            return finishNode(factory.createObjectBindingPattern(elements), pos);
7270        }
7271
7272        function parseArrayBindingPattern(): ArrayBindingPattern {
7273            const pos = getNodePos();
7274            parseExpected(SyntaxKind.OpenBracketToken);
7275            const elements = parseDelimitedList(ParsingContext.ArrayBindingElements, parseArrayBindingElement);
7276            parseExpected(SyntaxKind.CloseBracketToken);
7277            return finishNode(factory.createArrayBindingPattern(elements), pos);
7278        }
7279
7280        function isBindingIdentifierOrPrivateIdentifierOrPattern() {
7281            return token() === SyntaxKind.OpenBraceToken
7282                || token() === SyntaxKind.OpenBracketToken
7283                || token() === SyntaxKind.PrivateIdentifier
7284                || isBindingIdentifier();
7285        }
7286
7287        function parseIdentifierOrPattern(privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier | BindingPattern {
7288            if (token() === SyntaxKind.OpenBracketToken) {
7289                return parseArrayBindingPattern();
7290            }
7291            if (token() === SyntaxKind.OpenBraceToken) {
7292                return parseObjectBindingPattern();
7293            }
7294            return parseBindingIdentifier(privateIdentifierDiagnosticMessage);
7295        }
7296
7297        function parseVariableDeclarationAllowExclamation() {
7298            return parseVariableDeclaration(/*allowExclamation*/ true);
7299        }
7300
7301        function parseVariableDeclaration(allowExclamation?: boolean): VariableDeclaration {
7302            const pos = getNodePos();
7303            const hasJSDoc = hasPrecedingJSDocComment();
7304            const name = parseIdentifierOrPattern(Diagnostics.Private_identifiers_are_not_allowed_in_variable_declarations);
7305            let exclamationToken: ExclamationToken | undefined;
7306            if (allowExclamation && name.kind === SyntaxKind.Identifier &&
7307                token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) {
7308                exclamationToken = parseTokenNode<Token<SyntaxKind.ExclamationToken>>();
7309            }
7310            const type = parseTypeAnnotation();
7311            const initializer = isInOrOfKeyword(token()) ? undefined : parseInitializer();
7312            const node = factory.createVariableDeclaration(name, exclamationToken, type, initializer);
7313            return withJSDoc(finishNode(node, pos), hasJSDoc);
7314        }
7315
7316        function parseVariableDeclarationList(inForStatementInitializer: boolean): VariableDeclarationList {
7317            const pos = getNodePos();
7318
7319            let flags: NodeFlags = 0;
7320            switch (token()) {
7321                case SyntaxKind.VarKeyword:
7322                    break;
7323                case SyntaxKind.LetKeyword:
7324                    flags |= NodeFlags.Let;
7325                    break;
7326                case SyntaxKind.ConstKeyword:
7327                    flags |= NodeFlags.Const;
7328                    break;
7329                default:
7330                    Debug.fail();
7331            }
7332
7333            nextToken();
7334
7335            // The user may have written the following:
7336            //
7337            //    for (let of X) { }
7338            //
7339            // In this case, we want to parse an empty declaration list, and then parse 'of'
7340            // as a keyword. The reason this is not automatic is that 'of' is a valid identifier.
7341            // So we need to look ahead to determine if 'of' should be treated as a keyword in
7342            // this context.
7343            // The checker will then give an error that there is an empty declaration list.
7344            let declarations: readonly VariableDeclaration[];
7345            if (token() === SyntaxKind.OfKeyword && lookAhead(canFollowContextualOfKeyword)) {
7346                declarations = createMissingList<VariableDeclaration>();
7347            }
7348            else {
7349                const savedDisallowIn = inDisallowInContext();
7350                setDisallowInContext(inForStatementInitializer);
7351
7352                declarations = parseDelimitedList(ParsingContext.VariableDeclarations,
7353                    inForStatementInitializer ? parseVariableDeclaration : parseVariableDeclarationAllowExclamation);
7354
7355                setDisallowInContext(savedDisallowIn);
7356            }
7357
7358            return finishNode(factory.createVariableDeclarationList(declarations, flags), pos);
7359        }
7360
7361        function canFollowContextualOfKeyword(): boolean {
7362            return nextTokenIsIdentifier() && nextToken() === SyntaxKind.CloseParenToken;
7363        }
7364
7365        function parseVariableStatement(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): VariableStatement {
7366            const declarationList = parseVariableDeclarationList(/*inForStatementInitializer*/ false);
7367            parseSemicolon();
7368            const node = factory.createVariableStatement(modifiers, declarationList);
7369            // Decorators are not allowed on a variable statement, so we keep track of them to report them in the grammar checker.
7370            node.illegalDecorators = decorators;
7371            return withJSDoc(finishNode(node, pos), hasJSDoc);
7372        }
7373
7374        function parseFunctionDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): FunctionDeclaration {
7375            const savedAwaitContext = inAwaitContext();
7376
7377            const modifierFlags = modifiersToFlags(modifiers);
7378            parseExpected(SyntaxKind.FunctionKeyword);
7379            const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
7380            // We don't parse the name here in await context, instead we will report a grammar error in the checker.
7381            const name = modifierFlags & ModifierFlags.Default ? parseOptionalBindingIdentifier() : parseBindingIdentifier();
7382            if(name && hasEtsStylesDecoratorNames(decorators, sourceFileCompilerOptions)) {
7383                fileStylesComponents.set(name.escapedText.toString(), SyntaxKind.FunctionDeclaration);
7384            }
7385            setEtsBuilderContext(hasEtsBuilderDecoratorNames(decorators, sourceFileCompilerOptions));
7386            const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None;
7387            const isAsync = modifierFlags & ModifierFlags.Async ? SignatureFlags.Await : SignatureFlags.None;
7388            const typeParameters = inEtsStylesComponentsContext() && stylesEtsComponentDeclaration ? parseEtsTypeParameters(scanner.getStartPos()) : parseTypeParameters();
7389            if (modifierFlags & ModifierFlags.Export) setAwaitContext(/*value*/ true);
7390            const parameters = parseParameters(isGenerator | isAsync);
7391            const typeStartPos = scanner.getStartPos();
7392            const type = getFunctionDeclarationReturnType();
7393            const body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, Diagnostics.or_expected);
7394            setEtsBuilderContext(false);
7395            setEtsExtendComponentsContext(false);
7396            extendEtsComponentDeclaration = undefined;
7397            setEtsStylesComponentsContext(false);
7398            stylesEtsComponentDeclaration = undefined;
7399            setEtsComponentsContext(inBuildContext());
7400            setAwaitContext(savedAwaitContext);
7401            const node = factory.createFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, type, body);
7402            (node as Mutable<FunctionDeclaration>).illegalDecorators = decorators;
7403            return withJSDoc(finishNode(node, pos), hasJSDoc);
7404
7405            function getFunctionDeclarationReturnType(): TypeNode | undefined {
7406                let returnType = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);
7407                // If function decorated by Extend and type is not defined, then will use Ets Extend Components Type
7408                if (!returnType && extendEtsComponentDeclaration && inEtsExtendComponentsContext()) {
7409                    returnType = finishVirtualNode(factory.createTypeReferenceNode(
7410                        finishVirtualNode(factory.createIdentifier(extendEtsComponentDeclaration.type), typeStartPos, typeStartPos)),
7411                        typeStartPos, typeStartPos);
7412                }
7413                // If function decorated by Styles and type is not defined, then will use Ets Styles Components Type
7414                if (!returnType && stylesEtsComponentDeclaration && inEtsStylesComponentsContext()) {
7415                    returnType = finishVirtualNode(factory.createTypeReferenceNode(
7416                        finishVirtualNode(factory.createIdentifier(stylesEtsComponentDeclaration.type), typeStartPos, typeStartPos)),
7417                        typeStartPos, typeStartPos);
7418                }
7419                return returnType;
7420            }
7421        }
7422
7423        function parseConstructorName() {
7424            if (token() === SyntaxKind.ConstructorKeyword) {
7425                return parseExpected(SyntaxKind.ConstructorKeyword);
7426            }
7427            if (token() === SyntaxKind.StringLiteral && lookAhead(nextToken) === SyntaxKind.OpenParenToken) {
7428                return tryParse(() => {
7429                    const literalNode = parseLiteralNode();
7430                    return literalNode.text === "constructor" ? literalNode : undefined;
7431                });
7432            }
7433        }
7434
7435        function tryParseConstructorDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ConstructorDeclaration | undefined {
7436            return tryParse(() => {
7437                if (parseConstructorName()) {
7438                    const typeParameters = parseTypeParameters();
7439                    const parameters = parseParameters(SignatureFlags.None);
7440                    const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);
7441                    const body = parseFunctionBlockOrSemicolon(SignatureFlags.None, Diagnostics.or_expected);
7442                    const node = factory.createConstructorDeclaration(modifiers, parameters, body);
7443
7444                    // Attach invalid nodes if they exist so that we can report them in the grammar checker.
7445                    (node as Mutable<ConstructorDeclaration>).illegalDecorators = decorators;
7446                    (node as Mutable<ConstructorDeclaration>).typeParameters = typeParameters;
7447                    (node as Mutable<ConstructorDeclaration>).type = type;
7448                    return withJSDoc(finishNode(node, pos), hasJSDoc);
7449                }
7450            });
7451        }
7452
7453
7454        function isTokenInsideStructBuild(methodName: PropertyName): boolean {
7455            const renderMethod = sourceFileCompilerOptions.ets?.render?.method?.find(render => render === "build") ?? "build";
7456
7457            if (methodName.kind === SyntaxKind.Identifier && methodName.escapedText === renderMethod) {
7458                return true;
7459            }
7460            return false;
7461        }
7462
7463        function isTokenInsideStructBuilder(decorators: NodeArray<Decorator> | undefined): boolean {
7464            return isTokenInsideBuilder(decorators, sourceFileCompilerOptions);
7465        }
7466
7467        function isTokenInsideStructPageTransition(methodName: PropertyName): boolean {
7468            const renderMethod = sourceFileCompilerOptions.ets?.render?.method?.find(render => render === "pageTransition") ?? "pageTransition";
7469
7470            if (methodName.kind === SyntaxKind.Identifier && methodName.escapedText === renderMethod) {
7471                return true;
7472            }
7473            return false;
7474        }
7475
7476        function parseMethodDeclaration(
7477            pos: number,
7478            hasJSDoc: boolean,
7479            decorators: NodeArray<Decorator> | undefined,
7480            modifiers: NodeArray<Modifier> | undefined,
7481            asteriskToken: AsteriskToken | undefined,
7482            name: PropertyName,
7483            questionToken: QuestionToken | undefined,
7484            exclamationToken: ExclamationToken | undefined,
7485            diagnosticMessage?: DiagnosticMessage
7486        ): MethodDeclaration {
7487            const methodName = getPropertyNameForPropertyNameNode(name)?.toString();
7488            const orignalEtsBuildContext = inBuildContext();
7489            const orignalEtsBuilderContext = inBuilderContext();
7490            setEtsBuildContext(methodName === sourceFileCompilerOptions?.ets?.render?.method?.find(render => render === "build"));
7491            setEtsBuilderContext(hasEtsBuilderDecoratorNames(decorators, sourceFileCompilerOptions));
7492            if (inStructContext() && hasEtsStylesDecoratorNames(decorators, sourceFileCompilerOptions)) {
7493                if (methodName && currentStructName) {
7494                    structStylesComponents.set(methodName, { structName: currentStructName, kind: SyntaxKind.MethodDeclaration });
7495                }
7496                const stylesEtsComponentDecoratorNames = getEtsStylesDecoratorComponentNames(decorators, sourceFileCompilerOptions);
7497                if (stylesEtsComponentDecoratorNames.length > 0) {
7498                    stylesEtsComponentDeclaration = sourceFileCompilerOptions.ets?.styles.component;
7499                }
7500                setEtsStylesComponentsContext(!!stylesEtsComponentDeclaration);
7501            }
7502            const orignalEtsComponentsContext: boolean = inEtsComponentsContext();
7503            setEtsComponentsContext(inStructContext() && (isTokenInsideStructBuild(name) || isTokenInsideStructBuilder(decorators) ||
7504                isTokenInsideStructPageTransition(name)));
7505            const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None;
7506            const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None;
7507            const typeParameters = inEtsStylesComponentsContext() && stylesEtsComponentDeclaration ? parseEtsTypeParameters(pos) : parseTypeParameters();
7508            const parameters = parseParameters(isGenerator | isAsync);
7509            const typeStartPos = scanner.getStartPos();
7510            const type = getMethodDeclarationReturnType();
7511            const body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, diagnosticMessage);
7512            const node = factory.createMethodDeclaration(
7513                combineDecoratorsAndModifiers(decorators, modifiers),
7514                asteriskToken,
7515                name,
7516                questionToken,
7517                typeParameters,
7518                parameters,
7519                type,
7520                body
7521            );
7522
7523            // An exclamation token on a method is invalid syntax and will be handled by the grammar checker
7524            (node as Mutable<MethodDeclaration>).exclamationToken = exclamationToken;
7525            setEtsBuildContext(orignalEtsBuildContext);
7526            setEtsBuilderContext(orignalEtsBuilderContext);
7527            setEtsStylesComponentsContext(false);
7528            stylesEtsComponentDeclaration = undefined;
7529            setEtsComponentsContext(orignalEtsComponentsContext);
7530            return withJSDoc(finishNode(node, pos), hasJSDoc);
7531
7532            function getMethodDeclarationReturnType(): TypeNode | undefined {
7533                let returnType = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);
7534                // If function decorated by Styles and type is not defined, then will use Ets Styles Components Type
7535                if (!returnType && stylesEtsComponentDeclaration && inEtsStylesComponentsContext()) {
7536                    returnType = finishVirtualNode(factory.createTypeReferenceNode(
7537                        finishVirtualNode(factory.createIdentifier(stylesEtsComponentDeclaration.type), typeStartPos, typeStartPos)),
7538                        typeStartPos, typeStartPos);
7539                }
7540                return returnType;
7541            }
7542        }
7543
7544        function parsePropertyDeclaration(
7545            pos: number,
7546            hasJSDoc: boolean,
7547            decorators: NodeArray<Decorator> | undefined,
7548            modifiers: NodeArray<Modifier> | undefined,
7549            name: PropertyName,
7550            questionToken: QuestionToken | undefined
7551        ): PropertyDeclaration {
7552            const exclamationToken = !questionToken && !scanner.hasPrecedingLineBreak() ? parseOptionalToken(SyntaxKind.ExclamationToken) : undefined;
7553            const type = parseTypeAnnotation();
7554            const initializer = doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext | NodeFlags.DisallowInContext, parseInitializer);
7555            parseSemicolonAfterPropertyName(name, type, initializer);
7556            const node = factory.createPropertyDeclaration(
7557                combineDecoratorsAndModifiers(decorators, modifiers),
7558                name,
7559                questionToken || exclamationToken,
7560                type,
7561                initializer);
7562            return withJSDoc(finishNode(node, pos), hasJSDoc);
7563        }
7564
7565        function parsePropertyOrMethodDeclaration(
7566            pos: number,
7567            hasJSDoc: boolean,
7568            decorators: NodeArray<Decorator> | undefined,
7569            modifiers: NodeArray<Modifier> | undefined
7570        ): PropertyDeclaration | MethodDeclaration {
7571            const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
7572            const name = parsePropertyName();
7573            // Note: this is not legal as per the grammar.  But we allow it in the parser and
7574            // report an error in the grammar checker.
7575            const questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
7576            if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
7577                return parseMethodDeclaration(pos, hasJSDoc, decorators, modifiers, asteriskToken, name, questionToken, /*exclamationToken*/ undefined, Diagnostics.or_expected);
7578            }
7579            return parsePropertyDeclaration(pos, hasJSDoc, decorators, modifiers, name, questionToken);
7580        }
7581
7582        function parseAccessorDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined, kind: AccessorDeclaration["kind"], flags: SignatureFlags): AccessorDeclaration {
7583            const name = parsePropertyName();
7584            const typeParameters = parseTypeParameters();
7585            const parameters = parseParameters(SignatureFlags.None);
7586            const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false);
7587            const body = parseFunctionBlockOrSemicolon(flags);
7588            const node = kind === SyntaxKind.GetAccessor
7589                ? factory.createGetAccessorDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, parameters, type, body)
7590                : factory.createSetAccessorDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, parameters, body);
7591            // Keep track of `typeParameters` (for both) and `type` (for setters) if they were parsed those indicate grammar errors
7592            (node as Mutable<AccessorDeclaration>).typeParameters = typeParameters;
7593            if (isSetAccessorDeclaration(node)) (node as Mutable<SetAccessorDeclaration>).type = type;
7594            return withJSDoc(finishNode(node, pos), hasJSDoc);
7595        }
7596
7597        function isClassMemberStart(): boolean {
7598            let idToken: SyntaxKind | undefined;
7599
7600            if (token() === SyntaxKind.AtToken) {
7601                return true;
7602            }
7603
7604            // Eat up all modifiers, but hold on to the last one in case it is actually an identifier.
7605            while (isModifierKind(token())) {
7606                idToken = token();
7607                // If the idToken is a class modifier (protected, private, public, and static), it is
7608                // certain that we are starting to parse class member. This allows better error recovery
7609                // Example:
7610                //      public foo() ...     // true
7611                //      public @dec blah ... // true; we will then report an error later
7612                //      export public ...    // true; we will then report an error later
7613                if (isClassMemberModifier(idToken)) {
7614                    return true;
7615                }
7616
7617                nextToken();
7618            }
7619
7620            if (token() === SyntaxKind.AsteriskToken) {
7621                return true;
7622            }
7623
7624            // Try to get the first property-like token following all modifiers.
7625            // This can either be an identifier or the 'get' or 'set' keywords.
7626            if (isLiteralPropertyName()) {
7627                idToken = token();
7628                nextToken();
7629            }
7630
7631            // Index signatures and computed properties are class members; we can parse.
7632            if (token() === SyntaxKind.OpenBracketToken) {
7633                return true;
7634            }
7635
7636            // If we were able to get any potential identifier...
7637            if (idToken !== undefined) {
7638                // If we have a non-keyword identifier, or if we have an accessor, then it's safe to parse.
7639                if (!isKeyword(idToken) || idToken === SyntaxKind.SetKeyword || idToken === SyntaxKind.GetKeyword) {
7640                    return true;
7641                }
7642
7643                // If it *is* a keyword, but not an accessor, check a little farther along
7644                // to see if it should actually be parsed as a class member.
7645                switch (token()) {
7646                    case SyntaxKind.OpenParenToken:     // Method declaration
7647                    case SyntaxKind.LessThanToken:      // Generic Method declaration
7648                    case SyntaxKind.ExclamationToken:   // Non-null assertion on property name
7649                    case SyntaxKind.ColonToken:         // Type Annotation for declaration
7650                    case SyntaxKind.EqualsToken:        // Initializer for declaration
7651                    case SyntaxKind.QuestionToken:      // Not valid, but permitted so that it gets caught later on.
7652                        return true;
7653                    default:
7654                        // Covers
7655                        //  - Semicolons     (declaration termination)
7656                        //  - Closing braces (end-of-class, must be declaration)
7657                        //  - End-of-files   (not valid, but permitted so that it gets caught later on)
7658                        //  - Line-breaks    (enabling *automatic semicolon insertion*)
7659                        return canParseSemicolon();
7660                }
7661            }
7662
7663            return false;
7664        }
7665
7666        function parseClassStaticBlockDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: ModifiersArray | undefined): ClassStaticBlockDeclaration {
7667            parseExpectedToken(SyntaxKind.StaticKeyword);
7668            const body = parseClassStaticBlockBody();
7669            const node = withJSDoc(finishNode(factory.createClassStaticBlockDeclaration(body), pos), hasJSDoc);
7670            (node as Mutable<ClassStaticBlockDeclaration>).illegalDecorators = decorators;
7671            (node as Mutable<ClassStaticBlockDeclaration>).modifiers = modifiers;
7672            return node;
7673        }
7674
7675        function parseClassStaticBlockBody() {
7676            const savedYieldContext = inYieldContext();
7677            const savedAwaitContext = inAwaitContext();
7678
7679            setYieldContext(false);
7680            setAwaitContext(true);
7681
7682            const body = parseBlock(/*ignoreMissingOpenBrace*/ false);
7683
7684            setYieldContext(savedYieldContext);
7685            setAwaitContext(savedAwaitContext);
7686
7687            return body;
7688        }
7689
7690        function parseDecoratorExpression() {
7691            if (inAwaitContext() && token() === SyntaxKind.AwaitKeyword) {
7692                // `@await` is is disallowed in an [Await] context, but can cause parsing to go off the rails
7693                // This simply parses the missing identifier and moves on.
7694                const pos = getNodePos();
7695                const awaitExpression = parseIdentifier(Diagnostics.Expression_expected);
7696                nextToken();
7697                const memberExpression = parseMemberExpressionRest(pos, awaitExpression, /*allowOptionalChain*/ true);
7698                return parseCallExpressionRest(pos, memberExpression);
7699            }
7700            return parseLeftHandSideExpressionOrHigher();
7701        }
7702
7703        function tryParseDecorator(): Decorator | undefined {
7704            const pos = getNodePos();
7705            if (!parseOptional(SyntaxKind.AtToken)) {
7706                return undefined;
7707            }
7708            const expression = doInDecoratorContext(parseDecoratorExpression);
7709            return finishNode(factory.createDecorator(expression), pos);
7710        }
7711
7712        function parseDecorators(): NodeArray<Decorator> | undefined {
7713            const pos = getNodePos();
7714            let list, decorator;
7715            while (decorator = tryParseDecorator()) {
7716                list = append(list, decorator);
7717            }
7718            return list && createNodeArray(list, pos);
7719        }
7720
7721        function tryParseModifier(permitInvalidConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean, hasSeenStaticModifier?: boolean): Modifier | undefined {
7722            const pos = getNodePos();
7723            const kind = token();
7724
7725            if (token() === SyntaxKind.ConstKeyword && permitInvalidConstAsModifier) {
7726                // We need to ensure that any subsequent modifiers appear on the same line
7727                // so that when 'const' is a standalone declaration, we don't issue an error.
7728                if (!tryParse(nextTokenIsOnSameLineAndCanFollowModifier)) {
7729                    return undefined;
7730                }
7731            }
7732            else if (stopOnStartOfClassStaticBlock && token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) {
7733                return undefined;
7734            }
7735            else if (hasSeenStaticModifier && token() === SyntaxKind.StaticKeyword) {
7736                return undefined;
7737            }
7738            else {
7739                if (!parseAnyContextualModifier()) {
7740                    return undefined;
7741                }
7742            }
7743
7744            return finishNode(factory.createToken(kind as Modifier["kind"]), pos);
7745        }
7746
7747        function combineDecoratorsAndModifiers(decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): NodeArray<ModifierLike> | undefined {
7748            if (!decorators) return modifiers;
7749            if (!modifiers) return decorators;
7750            const decoratorsAndModifiers = factory.createNodeArray(concatenate<ModifierLike>(decorators, modifiers));
7751            setTextRangePosEnd(decoratorsAndModifiers, decorators.pos, modifiers.end);
7752            return decoratorsAndModifiers;
7753        }
7754
7755        /*
7756         * There are situations in which a modifier like 'const' will appear unexpectedly, such as on a class member.
7757         * In those situations, if we are entirely sure that 'const' is not valid on its own (such as when ASI takes effect
7758         * and turns it into a standalone declaration), then it is better to parse it and report an error later.
7759         *
7760         * In such situations, 'permitInvalidConstAsModifier' should be set to true.
7761         */
7762        function parseModifiers(permitInvalidConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean): NodeArray<Modifier> | undefined {
7763            const pos = getNodePos();
7764            let list, modifier, hasSeenStatic = false;
7765            while (modifier = tryParseModifier(permitInvalidConstAsModifier, stopOnStartOfClassStaticBlock, hasSeenStatic)) {
7766                if (modifier.kind === SyntaxKind.StaticKeyword) hasSeenStatic = true;
7767                list = append(list, modifier);
7768            }
7769            return list && createNodeArray(list, pos);
7770        }
7771
7772        function parseModifiersForArrowFunction(): NodeArray<Modifier> | undefined {
7773            let modifiers: NodeArray<Modifier> | undefined;
7774            if (token() === SyntaxKind.AsyncKeyword) {
7775                const pos = getNodePos();
7776                nextToken();
7777                const modifier = finishNode(factory.createToken(SyntaxKind.AsyncKeyword), pos);
7778                modifiers = createNodeArray<Modifier>([modifier], pos);
7779            }
7780            return modifiers;
7781        }
7782
7783        function parseClassElement(): ClassElement {
7784            const pos = getNodePos();
7785            if (token() === SyntaxKind.SemicolonToken) {
7786                nextToken();
7787                return finishNode(factory.createSemicolonClassElement(), pos);
7788            }
7789
7790            const hasJSDoc = hasPrecedingJSDocComment();
7791            const decorators = parseDecorators();
7792            const modifiers = parseModifiers(/*permitInvalidConstAsModifier*/ true, /*stopOnStartOfClassStaticBlock*/ true);
7793            if (token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) {
7794                return parseClassStaticBlockDeclaration(pos, hasJSDoc, decorators, modifiers);
7795            }
7796
7797            if (parseContextualModifier(SyntaxKind.GetKeyword)) {
7798                return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.GetAccessor, SignatureFlags.None);
7799            }
7800
7801            if (parseContextualModifier(SyntaxKind.SetKeyword)) {
7802                return parseAccessorDeclaration(pos, hasJSDoc, decorators, modifiers, SyntaxKind.SetAccessor, SignatureFlags.None);
7803            }
7804
7805            if (token() === SyntaxKind.ConstructorKeyword || token() === SyntaxKind.StringLiteral) {
7806                const constructorDeclaration = tryParseConstructorDeclaration(pos, hasJSDoc, decorators, modifiers);
7807                if (constructorDeclaration) {
7808                    return constructorDeclaration;
7809                }
7810            }
7811
7812            if (isIndexSignature()) {
7813                return parseIndexSignatureDeclaration(pos, hasJSDoc, decorators, modifiers);
7814            }
7815
7816            // It is very important that we check this *after* checking indexers because
7817            // the [ token can start an index signature or a computed property name
7818            if (tokenIsIdentifierOrKeyword(token()) ||
7819                token() === SyntaxKind.StringLiteral ||
7820                token() === SyntaxKind.NumericLiteral ||
7821                token() === SyntaxKind.AsteriskToken ||
7822                token() === SyntaxKind.OpenBracketToken) {
7823                const isAmbient = some(modifiers, isDeclareModifier);
7824                if (isAmbient) {
7825                    for (const m of modifiers!) {
7826                        (m as Mutable<Node>).flags |= NodeFlags.Ambient;
7827                    }
7828                    return doInsideOfContext(NodeFlags.Ambient, () => parsePropertyOrMethodDeclaration(pos, hasJSDoc, decorators, modifiers));
7829                }
7830                else {
7831                    return parsePropertyOrMethodDeclaration(pos, hasJSDoc, decorators, modifiers);
7832                }
7833            }
7834
7835            if (decorators || modifiers) {
7836                // treat this as a property declaration with a missing name.
7837                const name = createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected);
7838                return parsePropertyDeclaration(pos, hasJSDoc, decorators, modifiers, name, /*questionToken*/ undefined);
7839            }
7840
7841            // 'isClassMemberStart' should have hinted not to attempt parsing.
7842            return Debug.fail("Should not have attempted to parse class member declaration.");
7843        }
7844
7845        function parseClassExpression(): ClassExpression {
7846            return parseClassDeclarationOrExpression(getNodePos(), hasPrecedingJSDocComment(), /*decorators*/ undefined, /*modifiers*/ undefined, SyntaxKind.ClassExpression) as ClassExpression;
7847        }
7848
7849        function parseClassDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ClassDeclaration {
7850            return parseClassDeclarationOrExpression(pos, hasJSDoc, decorators, modifiers, SyntaxKind.ClassDeclaration) as ClassDeclaration;
7851        }
7852
7853        function parseStructDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): StructDeclaration {
7854            return parseStructDeclarationOrExpression(pos, hasJSDoc, decorators, modifiers);
7855        }
7856
7857        function parseClassDeclarationOrExpression(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined, kind: ClassLikeDeclaration["kind"]): ClassLikeDeclaration {
7858            const savedAwaitContext = inAwaitContext();
7859            parseExpected(SyntaxKind.ClassKeyword);
7860
7861            // We don't parse the name here in await context, instead we will report a grammar error in the checker.
7862            const name = parseNameOfClassDeclarationOrExpression();
7863            const typeParameters = parseTypeParameters();
7864            if (some(modifiers, isExportModifier)) setAwaitContext(/*value*/ true);
7865            const heritageClauses = parseHeritageClauses();
7866
7867            let members;
7868            if (parseExpected(SyntaxKind.OpenBraceToken)) {
7869                // ClassTail[Yield,Await] : (Modified) See 14.5
7870                //      ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt }
7871                members = parseClassMembers();
7872                parseExpected(SyntaxKind.CloseBraceToken);
7873            }
7874            else {
7875                members = createMissingList<ClassElement>();
7876            }
7877            setAwaitContext(savedAwaitContext);
7878            const node = kind === SyntaxKind.ClassDeclaration
7879                ? factory.createClassDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, typeParameters, heritageClauses, members)
7880                : factory.createClassExpression(combineDecoratorsAndModifiers(decorators, modifiers), name, typeParameters, heritageClauses, members);
7881            return withJSDoc(finishNode(node, pos), hasJSDoc);
7882        }
7883
7884        function parseStructDeclarationOrExpression(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): StructDeclaration {
7885            const savedAwaitContext = inAwaitContext();
7886            parseExpected(SyntaxKind.StructKeyword);
7887            setStructContext(true);
7888            // We don't parse the name here in await context, instead we will report a grammar error in the checker.
7889            // struct Identifier logic is same to class Identifier
7890            const name = parseNameOfClassDeclarationOrExpression();
7891            const typeParameters = parseTypeParameters();
7892            if (some(modifiers, isExportModifier)) setAwaitContext(/*value*/ true);
7893            let heritageClauses = parseHeritageClauses();
7894            const customComponent = sourceFileCompilerOptions.ets?.customComponent;
7895            if (!heritageClauses && customComponent) {
7896                heritageClauses = createVirtualHeritageClauses(customComponent);
7897            }
7898            let members;
7899            if (parseExpected(SyntaxKind.OpenBraceToken)) {
7900                // ClassTail[Yield,Await] : (Modified) See 14.5
7901                //      ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt }
7902                members = parseStructMembers(pos);
7903                parseExpected(SyntaxKind.CloseBraceToken);
7904            }
7905            else {
7906                members = createMissingList<ClassElement>();
7907            }
7908            setAwaitContext(savedAwaitContext);
7909            const node = factory.createStructDeclaration(combineDecoratorsAndModifiers(decorators, modifiers), name, typeParameters, heritageClauses, members);
7910            structStylesComponents.clear();
7911            setStructContext(false);
7912            return withJSDoc(finishNode(node, pos), hasJSDoc);
7913        }
7914
7915        function createVirtualHeritageClauses(customComponent: string): NodeArray<HeritageClause> {
7916            const curPos = getNodePos();
7917            const clause = factory.createHeritageClause(
7918                SyntaxKind.ExtendsKeyword,
7919                createNodeArray([finishNode(factory.createExpressionWithTypeArguments(
7920                    finishNode(factory.createIdentifier(/*text*/ customComponent), curPos, /*end*/ undefined, /*virtual*/ true),
7921                /*typeArguments*/ undefined
7922                ), curPos)], curPos, /*end*/ undefined, /*hasTrailingComma*/ false)
7923            );
7924            return createNodeArray([finishNode(clause, curPos, /*end*/ undefined, /*virtual*/ true)], curPos, /*end*/ undefined, /*hasTrailingComma*/ false);
7925        }
7926
7927        function parseNameOfClassDeclarationOrExpression(): Identifier | undefined {
7928            // implements is a future reserved word so
7929            // 'class implements' might mean either
7930            // - class expression with omitted name, 'implements' starts heritage clause
7931            // - class with name 'implements'
7932            // 'isImplementsClause' helps to disambiguate between these two cases
7933            return isBindingIdentifier() && !isImplementsClause()
7934                ? createIdentifier(isBindingIdentifier())
7935                : undefined;
7936        }
7937
7938        function isImplementsClause() {
7939            return token() === SyntaxKind.ImplementsKeyword && lookAhead(nextTokenIsIdentifierOrKeyword);
7940        }
7941
7942        function parseHeritageClauses(): NodeArray<HeritageClause> | undefined {
7943            // ClassTail[Yield,Await] : (Modified) See 14.5
7944            //      ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt }
7945
7946            if (isHeritageClause()) {
7947                return parseList(ParsingContext.HeritageClauses, parseHeritageClause);
7948            }
7949
7950            return undefined;
7951        }
7952
7953        function parseHeritageClause(): HeritageClause {
7954            const pos = getNodePos();
7955            const tok = token();
7956            Debug.assert(tok === SyntaxKind.ExtendsKeyword || tok === SyntaxKind.ImplementsKeyword); // isListElement() should ensure this.
7957            nextToken();
7958            const types = parseDelimitedList(ParsingContext.HeritageClauseElement, parseExpressionWithTypeArguments);
7959            return finishNode(factory.createHeritageClause(tok, types), pos);
7960        }
7961
7962        function parseExpressionWithTypeArguments(): ExpressionWithTypeArguments {
7963            const pos = getNodePos();
7964            const expression = parseLeftHandSideExpressionOrHigher();
7965            if (expression.kind === SyntaxKind.ExpressionWithTypeArguments) {
7966                return expression as ExpressionWithTypeArguments;
7967            }
7968            const typeArguments = tryParseTypeArguments();
7969            return finishNode(factory.createExpressionWithTypeArguments(expression, typeArguments), pos);
7970        }
7971
7972        function tryParseTypeArguments(): NodeArray<TypeNode> | undefined {
7973            return token() === SyntaxKind.LessThanToken ?
7974                parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken) : undefined;
7975        }
7976
7977        function isHeritageClause(): boolean {
7978            return token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword;
7979        }
7980
7981        function parseClassMembers(): NodeArray<ClassElement> {
7982            return parseList(ParsingContext.ClassMembers, parseClassElement);
7983        }
7984
7985        function parseStructMembers(pos: number): NodeArray<ClassElement> {
7986            const structMembers = parseList(ParsingContext.ClassMembers, parseClassElement);
7987
7988            const virtualStructMembers: ClassElement[] = [];
7989            // create constructor function argument object properties
7990            const virtualParameterProperties: TypeElement[] = [];
7991            structMembers.forEach(member => {
7992                virtualStructMembers.push(member);
7993                if (member.kind === SyntaxKind.PropertyDeclaration) {
7994                    const property = <PropertyDeclaration>member;
7995                    virtualParameterProperties.push(
7996                        finishVirtualNode(
7997                            factory.createPropertySignature(getModifiers(property), property.name, factory.createToken(SyntaxKind.QuestionToken), property.type)
7998                        )
7999                    );
8000                }
8001            });
8002            const parameters: ParameterDeclaration[] = [];
8003            if (virtualParameterProperties.length) {
8004                const type = finishVirtualNode(factory.createTypeLiteralNode(createNodeArray(virtualParameterProperties, 0, 0)));
8005                parameters.push(
8006                    finishVirtualNode(
8007                        factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined,
8008                            finishVirtualNode(factory.createIdentifier("value")), factory.createToken(SyntaxKind.QuestionToken), type
8009                        )
8010                    )
8011                );
8012            }
8013            const emptyBody = finishVirtualNode(factory.createBlock(createNodeArray([], 0, 0)));
8014            const virtualConstructor = factory.createConstructorDeclaration(/*modifier*/ undefined, createNodeArray(parameters, 0, 0), emptyBody);
8015
8016            virtualStructMembers.unshift(finishVirtualNode(virtualConstructor, pos, pos));
8017
8018            return createNodeArray(virtualStructMembers, structMembers.pos);
8019        }
8020
8021        function finishVirtualNode<T extends Node>(node: T, start = 0, end = 0) {
8022            return finishNode(node, start, end, /*virtual*/ true);
8023        }
8024
8025        function parseInterfaceDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): InterfaceDeclaration {
8026            parseExpected(SyntaxKind.InterfaceKeyword);
8027            const name = parseIdentifier();
8028            const typeParameters = parseTypeParameters();
8029            const heritageClauses = parseHeritageClauses();
8030            const members = parseObjectTypeMembers();
8031            const node = factory.createInterfaceDeclaration(modifiers, name, typeParameters, heritageClauses, members);
8032            (node as Mutable<InterfaceDeclaration>).illegalDecorators = decorators;
8033            return withJSDoc(finishNode(node, pos), hasJSDoc);
8034        }
8035
8036        function parseTypeAliasDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): TypeAliasDeclaration {
8037            parseExpected(SyntaxKind.TypeKeyword);
8038            const name = parseIdentifier();
8039            const typeParameters = parseTypeParameters();
8040            parseExpected(SyntaxKind.EqualsToken);
8041            const type = token() === SyntaxKind.IntrinsicKeyword && tryParse(parseKeywordAndNoDot) || parseType();
8042            parseSemicolon();
8043            const node = factory.createTypeAliasDeclaration(modifiers, name, typeParameters, type);
8044            (node as Mutable<TypeAliasDeclaration>).illegalDecorators = decorators;
8045            return withJSDoc(finishNode(node, pos), hasJSDoc);
8046        }
8047
8048        // In an ambient declaration, the grammar only allows integer literals as initializers.
8049        // In a non-ambient declaration, the grammar allows uninitialized members only in a
8050        // ConstantEnumMemberSection, which starts at the beginning of an enum declaration
8051        // or any time an integer literal initializer is encountered.
8052        function parseEnumMember(): EnumMember {
8053            const pos = getNodePos();
8054            const hasJSDoc = hasPrecedingJSDocComment();
8055            const name = parsePropertyName();
8056            const initializer = allowInAnd(parseInitializer);
8057            return withJSDoc(finishNode(factory.createEnumMember(name, initializer), pos), hasJSDoc);
8058        }
8059
8060        function parseEnumDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): EnumDeclaration {
8061            parseExpected(SyntaxKind.EnumKeyword);
8062            const name = parseIdentifier();
8063            let members;
8064            if (parseExpected(SyntaxKind.OpenBraceToken)) {
8065                members = doOutsideOfYieldAndAwaitContext(() => parseDelimitedList(ParsingContext.EnumMembers, parseEnumMember));
8066                parseExpected(SyntaxKind.CloseBraceToken);
8067            }
8068            else {
8069                members = createMissingList<EnumMember>();
8070            }
8071            const node = factory.createEnumDeclaration(modifiers, name, members);
8072            (node as Mutable<EnumDeclaration>).illegalDecorators = decorators;
8073            return withJSDoc(finishNode(node, pos), hasJSDoc);
8074        }
8075
8076        function parseModuleBlock(): ModuleBlock {
8077            const pos = getNodePos();
8078            let statements;
8079            if (parseExpected(SyntaxKind.OpenBraceToken)) {
8080                statements = parseList(ParsingContext.BlockStatements, parseStatement);
8081                parseExpected(SyntaxKind.CloseBraceToken);
8082            }
8083            else {
8084                statements = createMissingList<Statement>();
8085            }
8086            return finishNode(factory.createModuleBlock(statements), pos);
8087        }
8088
8089        function parseModuleOrNamespaceDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined, flags: NodeFlags): ModuleDeclaration {
8090            // If we are parsing a dotted namespace name, we want to
8091            // propagate the 'Namespace' flag across the names if set.
8092            const namespaceFlag = flags & NodeFlags.Namespace;
8093            const name = parseIdentifier();
8094            const body = parseOptional(SyntaxKind.DotToken)
8095                ? parseModuleOrNamespaceDeclaration(getNodePos(), /*hasJSDoc*/ false, /*decorators*/ undefined, /*modifiers*/ undefined, NodeFlags.NestedNamespace | namespaceFlag) as NamespaceDeclaration
8096                : parseModuleBlock();
8097            const node = factory.createModuleDeclaration(modifiers, name, body, flags);
8098            (node as Mutable<ModuleDeclaration>).illegalDecorators = decorators;
8099            return withJSDoc(finishNode(node, pos), hasJSDoc);
8100        }
8101
8102        function parseAmbientExternalModuleDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ModuleDeclaration {
8103            let flags: NodeFlags = 0;
8104            let name;
8105            if (token() === SyntaxKind.GlobalKeyword) {
8106                // parse 'global' as name of global scope augmentation
8107                name = parseIdentifier();
8108                flags |= NodeFlags.GlobalAugmentation;
8109            }
8110            else {
8111                name = parseLiteralNode() as StringLiteral;
8112                name.text = internIdentifier(name.text);
8113            }
8114            let body: ModuleBlock | undefined;
8115            if (token() === SyntaxKind.OpenBraceToken) {
8116                body = parseModuleBlock();
8117            }
8118            else {
8119                parseSemicolon();
8120            }
8121            const node = factory.createModuleDeclaration(modifiers, name, body, flags);
8122            (node as Mutable<ModuleDeclaration>).illegalDecorators = decorators;
8123            return withJSDoc(finishNode(node, pos), hasJSDoc);
8124        }
8125
8126        function parseModuleDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ModuleDeclaration {
8127            let flags: NodeFlags = 0;
8128            if (token() === SyntaxKind.GlobalKeyword) {
8129                // global augmentation
8130                return parseAmbientExternalModuleDeclaration(pos, hasJSDoc, decorators, modifiers);
8131            }
8132            else if (parseOptional(SyntaxKind.NamespaceKeyword)) {
8133                flags |= NodeFlags.Namespace;
8134            }
8135            else {
8136                parseExpected(SyntaxKind.ModuleKeyword);
8137                if (token() === SyntaxKind.StringLiteral) {
8138                    return parseAmbientExternalModuleDeclaration(pos, hasJSDoc, decorators, modifiers);
8139                }
8140            }
8141            return parseModuleOrNamespaceDeclaration(pos, hasJSDoc, decorators, modifiers, flags);
8142        }
8143
8144        function isExternalModuleReference() {
8145            return token() === SyntaxKind.RequireKeyword &&
8146                lookAhead(nextTokenIsOpenParen);
8147        }
8148
8149        function nextTokenIsOpenParen() {
8150            return nextToken() === SyntaxKind.OpenParenToken;
8151        }
8152
8153        function nextTokenIsOpenBrace() {
8154            return nextToken() === SyntaxKind.OpenBraceToken;
8155        }
8156
8157        function nextTokenIsSlash() {
8158            return nextToken() === SyntaxKind.SlashToken;
8159        }
8160
8161        function parseNamespaceExportDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): NamespaceExportDeclaration {
8162            parseExpected(SyntaxKind.AsKeyword);
8163            parseExpected(SyntaxKind.NamespaceKeyword);
8164            const name = parseIdentifier();
8165            parseSemicolon();
8166            const node = factory.createNamespaceExportDeclaration(name);
8167            // NamespaceExportDeclaration nodes cannot have decorators or modifiers, so we attach them here so we can report them in the grammar checker
8168            (node as Mutable<NamespaceExportDeclaration>).illegalDecorators = decorators;
8169            (node as Mutable<NamespaceExportDeclaration>).modifiers = modifiers;
8170            return withJSDoc(finishNode(node, pos), hasJSDoc);
8171        }
8172
8173        function parseImportDeclarationOrImportEqualsDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ImportEqualsDeclaration | ImportDeclaration {
8174            parseExpected(SyntaxKind.ImportKeyword);
8175
8176            const afterImportPos = scanner.getStartPos();
8177
8178            // We don't parse the identifier here in await context, instead we will report a grammar error in the checker.
8179            let identifier: Identifier | undefined;
8180            if (isIdentifier()) {
8181                identifier = parseIdentifier();
8182            }
8183
8184            let isTypeOnly = false;
8185            if (token() !== SyntaxKind.FromKeyword &&
8186                identifier?.escapedText === "type" &&
8187                (isIdentifier() || tokenAfterImportDefinitelyProducesImportDeclaration())
8188            ) {
8189                isTypeOnly = true;
8190                identifier = isIdentifier() ? parseIdentifier() : undefined;
8191            }
8192
8193            if (identifier && !tokenAfterImportedIdentifierDefinitelyProducesImportDeclaration()) {
8194                return parseImportEqualsDeclaration(pos, hasJSDoc, decorators, modifiers, identifier, isTypeOnly);
8195            }
8196
8197            // ImportDeclaration:
8198            //  import ImportClause from ModuleSpecifier ;
8199            //  import ModuleSpecifier;
8200            let importClause: ImportClause | undefined;
8201            if (identifier || // import id
8202                token() === SyntaxKind.AsteriskToken || // import *
8203                token() === SyntaxKind.OpenBraceToken    // import {
8204            ) {
8205                importClause = parseImportClause(identifier, afterImportPos, isTypeOnly);
8206                parseExpected(SyntaxKind.FromKeyword);
8207            }
8208            const moduleSpecifier = parseModuleSpecifier();
8209
8210            let assertClause: AssertClause | undefined;
8211            if (token() === SyntaxKind.AssertKeyword && !scanner.hasPrecedingLineBreak()) {
8212                assertClause = parseAssertClause();
8213            }
8214
8215            parseSemicolon();
8216            const node = factory.createImportDeclaration(modifiers, importClause, moduleSpecifier, assertClause);
8217            (node as Mutable<ImportDeclaration>).illegalDecorators = decorators;
8218            return withJSDoc(finishNode(node, pos), hasJSDoc);
8219        }
8220
8221        function parseAssertEntry() {
8222            const pos = getNodePos();
8223            const name = tokenIsIdentifierOrKeyword(token()) ? parseIdentifierName() : parseLiteralLikeNode(SyntaxKind.StringLiteral) as StringLiteral;
8224            parseExpected(SyntaxKind.ColonToken);
8225            const value = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true);
8226            return finishNode(factory.createAssertEntry(name, value), pos);
8227        }
8228
8229        function parseAssertClause(skipAssertKeyword?: true) {
8230            const pos = getNodePos();
8231            if (!skipAssertKeyword) {
8232                parseExpected(SyntaxKind.AssertKeyword);
8233            }
8234            const openBracePosition = scanner.getTokenPos();
8235            if (parseExpected(SyntaxKind.OpenBraceToken)) {
8236                const multiLine = scanner.hasPrecedingLineBreak();
8237                const elements = parseDelimitedList(ParsingContext.AssertEntries, parseAssertEntry, /*considerSemicolonAsDelimiter*/ true);
8238                if (!parseExpected(SyntaxKind.CloseBraceToken)) {
8239                    const lastError = lastOrUndefined(parseDiagnostics);
8240                    if (lastError && lastError.code === Diagnostics._0_expected.code) {
8241                        addRelatedInfo(
8242                            lastError,
8243                            createDetachedDiagnostic(fileName, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}")
8244                        );
8245                    }
8246                }
8247                return finishNode(factory.createAssertClause(elements, multiLine), pos);
8248            }
8249            else {
8250                const elements = createNodeArray([], getNodePos(), /*end*/ undefined, /*hasTrailingComma*/ false);
8251                return finishNode(factory.createAssertClause(elements, /*multiLine*/ false), pos);
8252            }
8253        }
8254
8255        function tokenAfterImportDefinitelyProducesImportDeclaration() {
8256            return token() === SyntaxKind.AsteriskToken || token() === SyntaxKind.OpenBraceToken;
8257        }
8258
8259        function tokenAfterImportedIdentifierDefinitelyProducesImportDeclaration() {
8260            // In `import id ___`, the current token decides whether to produce
8261            // an ImportDeclaration or ImportEqualsDeclaration.
8262            return token() === SyntaxKind.CommaToken || token() === SyntaxKind.FromKeyword;
8263        }
8264
8265        function parseImportEqualsDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined, identifier: Identifier, isTypeOnly: boolean): ImportEqualsDeclaration {
8266            parseExpected(SyntaxKind.EqualsToken);
8267            const moduleReference = parseModuleReference();
8268            parseSemicolon();
8269            const node = factory.createImportEqualsDeclaration(modifiers, isTypeOnly, identifier, moduleReference);
8270            (node as Mutable<ImportEqualsDeclaration>).illegalDecorators = decorators;
8271            const finished = withJSDoc(finishNode(node, pos), hasJSDoc);
8272            return finished;
8273        }
8274
8275        function parseImportClause(identifier: Identifier | undefined, pos: number, isTypeOnly: boolean) {
8276            // ImportClause:
8277            //  ImportedDefaultBinding
8278            //  NameSpaceImport
8279            //  NamedImports
8280            //  ImportedDefaultBinding, NameSpaceImport
8281            //  ImportedDefaultBinding, NamedImports
8282
8283            // If there was no default import or if there is comma token after default import
8284            // parse namespace or named imports
8285            let namedBindings: NamespaceImport | NamedImports | undefined;
8286            if (!identifier ||
8287                parseOptional(SyntaxKind.CommaToken)) {
8288                namedBindings = token() === SyntaxKind.AsteriskToken ? parseNamespaceImport() : parseNamedImportsOrExports(SyntaxKind.NamedImports);
8289            }
8290
8291            return finishNode(factory.createImportClause(isTypeOnly, identifier, namedBindings), pos);
8292        }
8293
8294        function parseModuleReference() {
8295            return isExternalModuleReference()
8296                ? parseExternalModuleReference()
8297                : parseEntityName(/*allowReservedWords*/ false);
8298        }
8299
8300        function parseExternalModuleReference() {
8301            const pos = getNodePos();
8302            parseExpected(SyntaxKind.RequireKeyword);
8303            parseExpected(SyntaxKind.OpenParenToken);
8304            const expression = parseModuleSpecifier();
8305            parseExpected(SyntaxKind.CloseParenToken);
8306            return finishNode(factory.createExternalModuleReference(expression), pos);
8307        }
8308
8309        function parseModuleSpecifier(): Expression {
8310            if (token() === SyntaxKind.StringLiteral) {
8311                const result = parseLiteralNode();
8312                result.text = internIdentifier(result.text);
8313                return result;
8314            }
8315            else {
8316                // We allow arbitrary expressions here, even though the grammar only allows string
8317                // literals.  We check to ensure that it is only a string literal later in the grammar
8318                // check pass.
8319                return parseExpression();
8320            }
8321        }
8322
8323        function parseNamespaceImport(): NamespaceImport {
8324            // NameSpaceImport:
8325            //  * as ImportedBinding
8326            const pos = getNodePos();
8327            parseExpected(SyntaxKind.AsteriskToken);
8328            parseExpected(SyntaxKind.AsKeyword);
8329            const name = parseIdentifier();
8330            return finishNode(factory.createNamespaceImport(name), pos);
8331        }
8332
8333        function parseNamedImportsOrExports(kind: SyntaxKind.NamedImports): NamedImports;
8334        function parseNamedImportsOrExports(kind: SyntaxKind.NamedExports): NamedExports;
8335        function parseNamedImportsOrExports(kind: SyntaxKind): NamedImportsOrExports {
8336            const pos = getNodePos();
8337
8338            // NamedImports:
8339            //  { }
8340            //  { ImportsList }
8341            //  { ImportsList, }
8342
8343            // ImportsList:
8344            //  ImportSpecifier
8345            //  ImportsList, ImportSpecifier
8346            const node = kind === SyntaxKind.NamedImports
8347                ? factory.createNamedImports(parseBracketedList(ParsingContext.ImportOrExportSpecifiers, parseImportSpecifier, SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken))
8348                : factory.createNamedExports(parseBracketedList(ParsingContext.ImportOrExportSpecifiers, parseExportSpecifier, SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken));
8349            return finishNode(node, pos);
8350        }
8351
8352        function parseExportSpecifier() {
8353            const hasJSDoc = hasPrecedingJSDocComment();
8354            return withJSDoc(parseImportOrExportSpecifier(SyntaxKind.ExportSpecifier) as ExportSpecifier, hasJSDoc);
8355        }
8356
8357        function parseImportSpecifier() {
8358            return parseImportOrExportSpecifier(SyntaxKind.ImportSpecifier) as ImportSpecifier;
8359        }
8360
8361        function parseImportOrExportSpecifier(kind: SyntaxKind): ImportOrExportSpecifier {
8362            const pos = getNodePos();
8363            // ImportSpecifier:
8364            //   BindingIdentifier
8365            //   IdentifierName as BindingIdentifier
8366            // ExportSpecifier:
8367            //   IdentifierName
8368            //   IdentifierName as IdentifierName
8369            let checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier();
8370            let checkIdentifierStart = scanner.getTokenPos();
8371            let checkIdentifierEnd = scanner.getTextPos();
8372            let isTypeOnly = false;
8373            let propertyName: Identifier | undefined;
8374            let canParseAsKeyword = true;
8375            let name = parseIdentifierName();
8376            if (name.escapedText === "type") {
8377                // If the first token of an import specifier is 'type', there are a lot of possibilities,
8378                // especially if we see 'as' afterwards:
8379                //
8380                // import { type } from "mod";          - isTypeOnly: false,   name: type
8381                // import { type as } from "mod";       - isTypeOnly: true,    name: as
8382                // import { type as as } from "mod";    - isTypeOnly: false,   name: as,    propertyName: type
8383                // import { type as as as } from "mod"; - isTypeOnly: true,    name: as,    propertyName: as
8384                if (token() === SyntaxKind.AsKeyword) {
8385                    // { type as ...? }
8386                    const firstAs = parseIdentifierName();
8387                    if (token() === SyntaxKind.AsKeyword) {
8388                        // { type as as ...? }
8389                        const secondAs = parseIdentifierName();
8390                        if (tokenIsIdentifierOrKeyword(token())) {
8391                            // { type as as something }
8392                            isTypeOnly = true;
8393                            propertyName = firstAs;
8394                            name = parseNameWithKeywordCheck();
8395                            canParseAsKeyword = false;
8396                        }
8397                        else {
8398                            // { type as as }
8399                            propertyName = name;
8400                            name = secondAs;
8401                            canParseAsKeyword = false;
8402                        }
8403                    }
8404                    else if (tokenIsIdentifierOrKeyword(token())) {
8405                        // { type as something }
8406                        propertyName = name;
8407                        canParseAsKeyword = false;
8408                        name = parseNameWithKeywordCheck();
8409                    }
8410                    else {
8411                        // { type as }
8412                        isTypeOnly = true;
8413                        name = firstAs;
8414                    }
8415                }
8416                else if (tokenIsIdentifierOrKeyword(token())) {
8417                    // { type something ...? }
8418                    isTypeOnly = true;
8419                    name = parseNameWithKeywordCheck();
8420                }
8421            }
8422
8423            if (canParseAsKeyword && token() === SyntaxKind.AsKeyword) {
8424                propertyName = name;
8425                parseExpected(SyntaxKind.AsKeyword);
8426                name = parseNameWithKeywordCheck();
8427            }
8428            if (kind === SyntaxKind.ImportSpecifier && checkIdentifierIsKeyword) {
8429                parseErrorAt(checkIdentifierStart, checkIdentifierEnd, Diagnostics.Identifier_expected);
8430            }
8431            const node = kind === SyntaxKind.ImportSpecifier
8432                ? factory.createImportSpecifier(isTypeOnly, propertyName, name)
8433                : factory.createExportSpecifier(isTypeOnly, propertyName, name);
8434            return finishNode(node, pos);
8435
8436            function parseNameWithKeywordCheck() {
8437                checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier();
8438                checkIdentifierStart = scanner.getTokenPos();
8439                checkIdentifierEnd = scanner.getTextPos();
8440                return parseIdentifierName();
8441            }
8442        }
8443
8444        function parseNamespaceExport(pos: number): NamespaceExport {
8445            return finishNode(factory.createNamespaceExport(parseIdentifierName()), pos);
8446        }
8447
8448        function parseExportDeclaration(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ExportDeclaration {
8449            const savedAwaitContext = inAwaitContext();
8450            setAwaitContext(/*value*/ true);
8451            let exportClause: NamedExportBindings | undefined;
8452            let moduleSpecifier: Expression | undefined;
8453            let assertClause: AssertClause | undefined;
8454            const isTypeOnly = parseOptional(SyntaxKind.TypeKeyword);
8455            const namespaceExportPos = getNodePos();
8456            if (parseOptional(SyntaxKind.AsteriskToken)) {
8457                if (parseOptional(SyntaxKind.AsKeyword)) {
8458                    exportClause = parseNamespaceExport(namespaceExportPos);
8459                }
8460                parseExpected(SyntaxKind.FromKeyword);
8461                moduleSpecifier = parseModuleSpecifier();
8462            }
8463            else {
8464                exportClause = parseNamedImportsOrExports(SyntaxKind.NamedExports);
8465                // It is not uncommon to accidentally omit the 'from' keyword. Additionally, in editing scenarios,
8466                // the 'from' keyword can be parsed as a named export when the export clause is unterminated (i.e. `export { from "moduleName";`)
8467                // If we don't have a 'from' keyword, see if we have a string literal such that ASI won't take effect.
8468                if (token() === SyntaxKind.FromKeyword || (token() === SyntaxKind.StringLiteral && !scanner.hasPrecedingLineBreak())) {
8469                    parseExpected(SyntaxKind.FromKeyword);
8470                    moduleSpecifier = parseModuleSpecifier();
8471                }
8472            }
8473            if (moduleSpecifier && token() === SyntaxKind.AssertKeyword && !scanner.hasPrecedingLineBreak()) {
8474                assertClause = parseAssertClause();
8475            }
8476            parseSemicolon();
8477            setAwaitContext(savedAwaitContext);
8478            const node = factory.createExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause);
8479            (node as Mutable<ExportDeclaration>).illegalDecorators = decorators;
8480            return withJSDoc(finishNode(node, pos), hasJSDoc);
8481        }
8482
8483        function parseExportAssignment(pos: number, hasJSDoc: boolean, decorators: NodeArray<Decorator> | undefined, modifiers: NodeArray<Modifier> | undefined): ExportAssignment {
8484            const savedAwaitContext = inAwaitContext();
8485            setAwaitContext(/*value*/ true);
8486            let isExportEquals: boolean | undefined;
8487            if (parseOptional(SyntaxKind.EqualsToken)) {
8488                isExportEquals = true;
8489            }
8490            else {
8491                parseExpected(SyntaxKind.DefaultKeyword);
8492            }
8493            const expression = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true);
8494            parseSemicolon();
8495            setAwaitContext(savedAwaitContext);
8496            const node = factory.createExportAssignment(modifiers, isExportEquals, expression);
8497            (node as Mutable<ExportAssignment>).illegalDecorators = decorators;
8498            return withJSDoc(finishNode(node, pos), hasJSDoc);
8499        }
8500
8501        const enum ParsingContext {
8502            SourceElements,            // Elements in source file
8503            BlockStatements,           // Statements in block
8504            SwitchClauses,             // Clauses in switch statement
8505            SwitchClauseStatements,    // Statements in switch clause
8506            TypeMembers,               // Members in interface or type literal
8507            ClassMembers,              // Members in class declaration
8508            EnumMembers,               // Members in enum declaration
8509            HeritageClauseElement,     // Elements in a heritage clause
8510            VariableDeclarations,      // Variable declarations in variable statement
8511            ObjectBindingElements,     // Binding elements in object binding list
8512            ArrayBindingElements,      // Binding elements in array binding list
8513            ArgumentExpressions,       // Expressions in argument list
8514            ObjectLiteralMembers,      // Members in object literal
8515            JsxAttributes,             // Attributes in jsx element
8516            JsxChildren,               // Things between opening and closing JSX tags
8517            ArrayLiteralMembers,       // Members in array literal
8518            Parameters,                // Parameters in parameter list
8519            JSDocParameters,           // JSDoc parameters in parameter list of JSDoc function type
8520            RestProperties,            // Property names in a rest type list
8521            TypeParameters,            // Type parameters in type parameter list
8522            TypeArguments,             // Type arguments in type argument list
8523            TupleElementTypes,         // Element types in tuple element type list
8524            HeritageClauses,           // Heritage clauses for a class or interface declaration.
8525            ImportOrExportSpecifiers,  // Named import clause's import specifier list,
8526            AssertEntries,               // Import entries list.
8527            Count                      // Number of parsing contexts
8528        }
8529
8530        const enum Tristate {
8531            False,
8532            True,
8533            Unknown
8534        }
8535
8536        export namespace JSDocParser {
8537            export function parseJSDocTypeExpressionForTests(content: string, start: number | undefined, length: number | undefined): { jsDocTypeExpression: JSDocTypeExpression, diagnostics: Diagnostic[] } | undefined {
8538                initializeState("file.js", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS);
8539                scanner.setText(content, start, length);
8540                currentToken = scanner.scan();
8541                const jsDocTypeExpression = parseJSDocTypeExpression();
8542
8543                const sourceFile = createSourceFile("file.js", ScriptTarget.Latest, ScriptKind.JS, /*isDeclarationFile*/ false, [], factory.createToken(SyntaxKind.EndOfFileToken), NodeFlags.None, noop);
8544                const diagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile);
8545                if (jsDocDiagnostics) {
8546                    sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile);
8547                }
8548
8549                clearState();
8550
8551                return jsDocTypeExpression ? { jsDocTypeExpression, diagnostics } : undefined;
8552            }
8553
8554            // Parses out a JSDoc type expression.
8555            export function parseJSDocTypeExpression(mayOmitBraces?: boolean): JSDocTypeExpression {
8556                const pos = getNodePos();
8557                const hasBrace = (mayOmitBraces ? parseOptional : parseExpected)(SyntaxKind.OpenBraceToken);
8558                const type = doInsideOfContext(NodeFlags.JSDoc, parseJSDocType);
8559                if (!mayOmitBraces || hasBrace) {
8560                    parseExpectedJSDoc(SyntaxKind.CloseBraceToken);
8561                }
8562
8563                const result = factory.createJSDocTypeExpression(type);
8564                fixupParentReferences(result);
8565                return finishNode(result, pos);
8566            }
8567
8568            export function parseJSDocNameReference(): JSDocNameReference {
8569                const pos = getNodePos();
8570                const hasBrace = parseOptional(SyntaxKind.OpenBraceToken);
8571                const p2 = getNodePos();
8572                let entityName: EntityName | JSDocMemberName = parseEntityName(/* allowReservedWords*/ false);
8573                while (token() === SyntaxKind.PrivateIdentifier) {
8574                    reScanHashToken(); // rescan #id as # id
8575                    nextTokenJSDoc(); // then skip the #
8576                    entityName = finishNode(factory.createJSDocMemberName(entityName, parseIdentifier()), p2);
8577                }
8578                if (hasBrace) {
8579                    parseExpectedJSDoc(SyntaxKind.CloseBraceToken);
8580                }
8581
8582                const result = factory.createJSDocNameReference(entityName);
8583                fixupParentReferences(result);
8584                return finishNode(result, pos);
8585            }
8586
8587            export function parseIsolatedJSDocComment(content: string, start: number | undefined, length: number | undefined): { jsDoc: JSDoc, diagnostics: Diagnostic[] } | undefined {
8588                initializeState("", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS);
8589                const jsDoc = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length));
8590
8591                const sourceFile = { languageVariant: LanguageVariant.Standard, text: content } as SourceFile;
8592                const diagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile);
8593                clearState();
8594
8595                return jsDoc ? { jsDoc, diagnostics } : undefined;
8596            }
8597
8598            export function parseJSDocComment(parent: HasJSDoc, start: number, length: number): JSDoc | undefined {
8599                const saveToken = currentToken;
8600                const saveParseDiagnosticsLength = parseDiagnostics.length;
8601                const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode;
8602
8603                const comment = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length));
8604                setParent(comment, parent);
8605
8606                if (contextFlags & NodeFlags.JavaScriptFile) {
8607                    if (!jsDocDiagnostics) {
8608                        jsDocDiagnostics = [];
8609                    }
8610                    jsDocDiagnostics.push(...parseDiagnostics);
8611                }
8612                currentToken = saveToken;
8613                parseDiagnostics.length = saveParseDiagnosticsLength;
8614                parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode;
8615                return comment;
8616            }
8617
8618            const enum JSDocState {
8619                BeginningOfLine,
8620                SawAsterisk,
8621                SavingComments,
8622                SavingBackticks, // NOTE: Only used when parsing tag comments
8623            }
8624
8625            const enum PropertyLikeParse {
8626                Property = 1 << 0,
8627                Parameter = 1 << 1,
8628                CallbackParameter = 1 << 2,
8629            }
8630
8631            function parseJSDocCommentWorker(start = 0, length: number | undefined): JSDoc | undefined {
8632                const content = sourceText;
8633                const end = length === undefined ? content.length : start + length;
8634                length = end - start;
8635
8636                Debug.assert(start >= 0);
8637                Debug.assert(start <= end);
8638                Debug.assert(end <= content.length);
8639
8640                // Check for /** (JSDoc opening part)
8641                if (!isJSDocLikeText(content, start)) {
8642                    return undefined;
8643                }
8644
8645                let tags: JSDocTag[];
8646                let tagsPos: number;
8647                let tagsEnd: number;
8648                let linkEnd: number;
8649                let commentsPos: number | undefined;
8650                let comments: string[] = [];
8651                const parts: JSDocComment[] = [];
8652
8653                // + 3 for leading /**, - 5 in total for /** */
8654                return scanner.scanRange(start + 3, length - 5, () => {
8655                    // Initially we can parse out a tag.  We also have seen a starting asterisk.
8656                    // This is so that /** * @type */ doesn't parse.
8657                    let state = JSDocState.SawAsterisk;
8658                    let margin: number | undefined;
8659                    // + 4 for leading '/** '
8660                    // + 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
8661                    let indent = start - (content.lastIndexOf("\n", start) + 1) + 4;
8662                    function pushComment(text: string) {
8663                        if (!margin) {
8664                            margin = indent;
8665                        }
8666                        comments.push(text);
8667                        indent += text.length;
8668                    }
8669
8670                    nextTokenJSDoc();
8671                    while (parseOptionalJsdoc(SyntaxKind.WhitespaceTrivia));
8672                    if (parseOptionalJsdoc(SyntaxKind.NewLineTrivia)) {
8673                        state = JSDocState.BeginningOfLine;
8674                        indent = 0;
8675                    }
8676                    loop: while (true) {
8677                        switch (token()) {
8678                            case SyntaxKind.AtToken:
8679                                if (state === JSDocState.BeginningOfLine || state === JSDocState.SawAsterisk) {
8680                                    removeTrailingWhitespace(comments);
8681                                    if (!commentsPos) commentsPos = getNodePos();
8682                                    addTag(parseTag(indent));
8683                                    // NOTE: According to usejsdoc.org, a tag goes to end of line, except the last tag.
8684                                    // Real-world comments may break this rule, so "BeginningOfLine" will not be a real line beginning
8685                                    // for malformed examples like `/** @param {string} x @returns {number} the length */`
8686                                    state = JSDocState.BeginningOfLine;
8687                                    margin = undefined;
8688                                }
8689                                else {
8690                                    pushComment(scanner.getTokenText());
8691                                }
8692                                break;
8693                            case SyntaxKind.NewLineTrivia:
8694                                comments.push(scanner.getTokenText());
8695                                state = JSDocState.BeginningOfLine;
8696                                indent = 0;
8697                                break;
8698                            case SyntaxKind.AsteriskToken:
8699                                const asterisk = scanner.getTokenText();
8700                                if (state === JSDocState.SawAsterisk || state === JSDocState.SavingComments) {
8701                                    // If we've already seen an asterisk, then we can no longer parse a tag on this line
8702                                    state = JSDocState.SavingComments;
8703                                    pushComment(asterisk);
8704                                }
8705                                else {
8706                                    // Ignore the first asterisk on a line
8707                                    state = JSDocState.SawAsterisk;
8708                                    indent += asterisk.length;
8709                                }
8710                                break;
8711                            case SyntaxKind.WhitespaceTrivia:
8712                                // only collect whitespace if we're already saving comments or have just crossed the comment indent margin
8713                                const whitespace = scanner.getTokenText();
8714                                if (state === JSDocState.SavingComments) {
8715                                    comments.push(whitespace);
8716                                }
8717                                else if (margin !== undefined && indent + whitespace.length > margin) {
8718                                    comments.push(whitespace.slice(margin - indent));
8719                                }
8720                                indent += whitespace.length;
8721                                break;
8722                            case SyntaxKind.EndOfFileToken:
8723                                break loop;
8724                            case SyntaxKind.OpenBraceToken:
8725                                state = JSDocState.SavingComments;
8726                                const commentEnd = scanner.getStartPos();
8727                                const linkStart = scanner.getTextPos() - 1;
8728                                const link = parseJSDocLink(linkStart);
8729                                if (link) {
8730                                    if (!linkEnd) {
8731                                        removeLeadingNewlines(comments);
8732                                    }
8733                                    parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? start, commentEnd));
8734                                    parts.push(link);
8735                                    comments = [];
8736                                    linkEnd = scanner.getTextPos();
8737                                    break;
8738                                }
8739                                // fallthrough if it's not a {@link sequence
8740                            default:
8741                                // Anything else is doc comment text. We just save it. Because it
8742                                // wasn't a tag, we can no longer parse a tag on this line until we hit the next
8743                                // line break.
8744                                state = JSDocState.SavingComments;
8745                                pushComment(scanner.getTokenText());
8746                                break;
8747                        }
8748                        nextTokenJSDoc();
8749                    }
8750                    removeTrailingWhitespace(comments);
8751                    if (parts.length && comments.length) {
8752                        parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? start, commentsPos));
8753                    }
8754                    if (parts.length && tags) Debug.assertIsDefined(commentsPos, "having parsed tags implies that the end of the comment span should be set");
8755                    const tagsArray = tags && createNodeArray(tags, tagsPos, tagsEnd);
8756                    return finishNode(factory.createJSDocComment(parts.length ? createNodeArray(parts, start, commentsPos) : comments.length ? comments.join("") : undefined, tagsArray), start, end);
8757                });
8758
8759                function removeLeadingNewlines(comments: string[]) {
8760                    while (comments.length && (comments[0] === "\n" || comments[0] === "\r")) {
8761                        comments.shift();
8762                    }
8763                }
8764
8765                function removeTrailingWhitespace(comments: string[]) {
8766                    while (comments.length && comments[comments.length - 1].trim() === "") {
8767                        comments.pop();
8768                    }
8769                }
8770
8771                function isNextNonwhitespaceTokenEndOfFile(): boolean {
8772                    // We must use infinite lookahead, as there could be any number of newlines :(
8773                    while (true) {
8774                        nextTokenJSDoc();
8775                        if (token() === SyntaxKind.EndOfFileToken) {
8776                            return true;
8777                        }
8778                        if (!(token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia)) {
8779                            return false;
8780                        }
8781                    }
8782                }
8783
8784                function skipWhitespace(): void {
8785                    if (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {
8786                        if (lookAhead(isNextNonwhitespaceTokenEndOfFile)) {
8787                            return; // Don't skip whitespace prior to EoF (or end of comment) - that shouldn't be included in any node's range
8788                        }
8789                    }
8790                    while (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {
8791                        nextTokenJSDoc();
8792                    }
8793                }
8794
8795                function skipWhitespaceOrAsterisk(): string {
8796                    if (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {
8797                        if (lookAhead(isNextNonwhitespaceTokenEndOfFile)) {
8798                            return ""; // Don't skip whitespace prior to EoF (or end of comment) - that shouldn't be included in any node's range
8799                        }
8800                    }
8801
8802                    let precedingLineBreak = scanner.hasPrecedingLineBreak();
8803                    let seenLineBreak = false;
8804                    let indentText = "";
8805                    while ((precedingLineBreak && token() === SyntaxKind.AsteriskToken) || token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {
8806                        indentText += scanner.getTokenText();
8807                        if (token() === SyntaxKind.NewLineTrivia) {
8808                            precedingLineBreak = true;
8809                            seenLineBreak = true;
8810                            indentText = "";
8811                        }
8812                        else if (token() === SyntaxKind.AsteriskToken) {
8813                            precedingLineBreak = false;
8814                        }
8815                        nextTokenJSDoc();
8816                    }
8817                    return seenLineBreak ? indentText : "";
8818                }
8819
8820                function parseTag(margin: number) {
8821                    Debug.assert(token() === SyntaxKind.AtToken);
8822                    const start = scanner.getTokenPos();
8823                    nextTokenJSDoc();
8824
8825                    const tagName = parseJSDocIdentifierName(/*message*/ undefined);
8826                    const indentText = skipWhitespaceOrAsterisk();
8827
8828                    let tag: JSDocTag | undefined;
8829                    switch (tagName.escapedText) {
8830                        case "author":
8831                            tag = parseAuthorTag(start, tagName, margin, indentText);
8832                            break;
8833                        case "implements":
8834                            tag = parseImplementsTag(start, tagName, margin, indentText);
8835                            break;
8836                        case "augments":
8837                        case "extends":
8838                            tag = parseAugmentsTag(start, tagName, margin, indentText);
8839                            break;
8840                        case "class":
8841                        case "constructor":
8842                            tag = parseSimpleTag(start, factory.createJSDocClassTag, tagName, margin, indentText);
8843                            break;
8844                        case "public":
8845                            tag = parseSimpleTag(start, factory.createJSDocPublicTag, tagName, margin, indentText);
8846                            break;
8847                        case "private":
8848                            tag = parseSimpleTag(start, factory.createJSDocPrivateTag, tagName, margin, indentText);
8849                            break;
8850                        case "protected":
8851                            tag = parseSimpleTag(start, factory.createJSDocProtectedTag, tagName, margin, indentText);
8852                            break;
8853                        case "readonly":
8854                            tag = parseSimpleTag(start, factory.createJSDocReadonlyTag, tagName, margin, indentText);
8855                            break;
8856                        case "override":
8857                            tag = parseSimpleTag(start, factory.createJSDocOverrideTag, tagName, margin, indentText);
8858                            break;
8859                        case "deprecated":
8860                            hasDeprecatedTag = true;
8861                            tag = parseSimpleTag(start, factory.createJSDocDeprecatedTag, tagName, margin, indentText);
8862                            break;
8863                        case "this":
8864                            tag = parseThisTag(start, tagName, margin, indentText);
8865                            break;
8866                        case "enum":
8867                            tag = parseEnumTag(start, tagName, margin, indentText);
8868                            break;
8869                        case "arg":
8870                        case "argument":
8871                        case "param":
8872                            return parseParameterOrPropertyTag(start, tagName, PropertyLikeParse.Parameter, margin);
8873                        case "return":
8874                        case "returns":
8875                            tag = parseReturnTag(start, tagName, margin, indentText);
8876                            break;
8877                        case "template":
8878                            tag = parseTemplateTag(start, tagName, margin, indentText);
8879                            break;
8880                        case "type":
8881                            tag = parseTypeTag(start, tagName, margin, indentText);
8882                            break;
8883                        case "typedef":
8884                            tag = parseTypedefTag(start, tagName, margin, indentText);
8885                            break;
8886                        case "callback":
8887                            tag = parseCallbackTag(start, tagName, margin, indentText);
8888                            break;
8889                        case "see":
8890                            tag = parseSeeTag(start, tagName, margin, indentText);
8891                            break;
8892                        default:
8893                            tag = parseUnknownTag(start, tagName, margin, indentText);
8894                            break;
8895                    }
8896                    return tag;
8897                }
8898
8899                function parseTrailingTagComments(pos: number, end: number, margin: number, indentText: string) {
8900                    // some tags, like typedef and callback, have already parsed their comments earlier
8901                    if (!indentText) {
8902                        margin += end - pos;
8903                    }
8904                    return parseTagComments(margin, indentText.slice(margin));
8905                }
8906
8907                function parseTagComments(indent: number, initialMargin?: string): string | NodeArray<JSDocComment> | undefined {
8908                    const commentsPos = getNodePos();
8909                    let comments: string[] = [];
8910                    const parts: JSDocComment[] = [];
8911                    let linkEnd;
8912                    let state = JSDocState.BeginningOfLine;
8913                    let previousWhitespace = true;
8914                    let margin: number | undefined;
8915                    function pushComment(text: string) {
8916                        if (!margin) {
8917                            margin = indent;
8918                        }
8919                        comments.push(text);
8920                        indent += text.length;
8921                    }
8922                    if (initialMargin !== undefined) {
8923                        // jump straight to saving comments if there is some initial indentation
8924                        if (initialMargin !== "") {
8925                            pushComment(initialMargin);
8926                        }
8927                        state = JSDocState.SawAsterisk;
8928                    }
8929                    let tok = token() as JSDocSyntaxKind;
8930                    loop: while (true) {
8931                        switch (tok) {
8932                            case SyntaxKind.NewLineTrivia:
8933                                state = JSDocState.BeginningOfLine;
8934                                // don't use pushComment here because we want to keep the margin unchanged
8935                                comments.push(scanner.getTokenText());
8936                                indent = 0;
8937                                break;
8938                            case SyntaxKind.AtToken:
8939                                if (state === JSDocState.SavingBackticks
8940                                    || state === JSDocState.SavingComments && (!previousWhitespace || lookAhead(isNextJSDocTokenWhitespace))) {
8941                                    // @ doesn't start a new tag inside ``, and inside a comment, only after whitespace or not before whitespace
8942                                    comments.push(scanner.getTokenText());
8943                                    break;
8944                                }
8945                                scanner.setTextPos(scanner.getTextPos() - 1);
8946                                // falls through
8947                            case SyntaxKind.EndOfFileToken:
8948                                // Done
8949                                break loop;
8950                            case SyntaxKind.WhitespaceTrivia:
8951                                if (state === JSDocState.SavingComments || state === JSDocState.SavingBackticks) {
8952                                    pushComment(scanner.getTokenText());
8953                                }
8954                                else {
8955                                    const whitespace = scanner.getTokenText();
8956                                    // if the whitespace crosses the margin, take only the whitespace that passes the margin
8957                                    if (margin !== undefined && indent + whitespace.length > margin) {
8958                                        comments.push(whitespace.slice(margin - indent));
8959                                    }
8960                                    indent += whitespace.length;
8961                                }
8962                                break;
8963                            case SyntaxKind.OpenBraceToken:
8964                                state = JSDocState.SavingComments;
8965                                const commentEnd = scanner.getStartPos();
8966                                const linkStart = scanner.getTextPos() - 1;
8967                                const link = parseJSDocLink(linkStart);
8968                                if (link) {
8969                                    parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? commentsPos, commentEnd));
8970                                    parts.push(link);
8971                                    comments = [];
8972                                    linkEnd = scanner.getTextPos();
8973                                }
8974                                else {
8975                                    pushComment(scanner.getTokenText());
8976                                }
8977                                break;
8978                            case SyntaxKind.BacktickToken:
8979                                if (state === JSDocState.SavingBackticks) {
8980                                    state = JSDocState.SavingComments;
8981                                }
8982                                else {
8983                                    state = JSDocState.SavingBackticks;
8984                                }
8985                                pushComment(scanner.getTokenText());
8986                                break;
8987                            case SyntaxKind.AsteriskToken:
8988                                if (state === JSDocState.BeginningOfLine) {
8989                                    // leading asterisks start recording on the *next* (non-whitespace) token
8990                                    state = JSDocState.SawAsterisk;
8991                                    indent += 1;
8992                                    break;
8993                                }
8994                                // record the * as a comment
8995                                // falls through
8996                            default:
8997                                if (state !== JSDocState.SavingBackticks) {
8998                                    state = JSDocState.SavingComments; // leading identifiers start recording as well
8999                                }
9000                                pushComment(scanner.getTokenText());
9001                                break;
9002                        }
9003                        previousWhitespace = token() === SyntaxKind.WhitespaceTrivia;
9004                        tok = nextTokenJSDoc();
9005                    }
9006
9007                    removeLeadingNewlines(comments);
9008                    removeTrailingWhitespace(comments);
9009                    if (parts.length) {
9010                        if (comments.length) {
9011                            parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? commentsPos));
9012                        }
9013                        return createNodeArray(parts, commentsPos, scanner.getTextPos());
9014                    }
9015                    else if (comments.length) {
9016                        return comments.join("");
9017                    }
9018                }
9019
9020                function isNextJSDocTokenWhitespace() {
9021                    const next = nextTokenJSDoc();
9022                    return next === SyntaxKind.WhitespaceTrivia || next === SyntaxKind.NewLineTrivia;
9023                }
9024
9025                function parseJSDocLink(start: number) {
9026                    const linkType = tryParse(parseJSDocLinkPrefix);
9027                    if (!linkType) {
9028                        return undefined;
9029                    }
9030                    nextTokenJSDoc(); // start at token after link, then skip any whitespace
9031                    skipWhitespace();
9032                    // parseEntityName logs an error for non-identifier, so create a MissingNode ourselves to avoid the error
9033                    const p2 = getNodePos();
9034                    let name: EntityName | JSDocMemberName | undefined = tokenIsIdentifierOrKeyword(token())
9035                        ? parseEntityName(/*allowReservedWords*/ true)
9036                        : undefined;
9037                    if (name) {
9038                        while (token() === SyntaxKind.PrivateIdentifier) {
9039                            reScanHashToken(); // rescan #id as # id
9040                            nextTokenJSDoc(); // then skip the #
9041                            name = finishNode(factory.createJSDocMemberName(name, parseIdentifier()), p2);
9042                        }
9043                    }
9044                    const text = [];
9045                    while (token() !== SyntaxKind.CloseBraceToken && token() !== SyntaxKind.NewLineTrivia && token() !== SyntaxKind.EndOfFileToken) {
9046                        text.push(scanner.getTokenText());
9047                        nextTokenJSDoc();
9048                    }
9049                    const create = linkType === "link" ? factory.createJSDocLink
9050                        : linkType === "linkcode" ? factory.createJSDocLinkCode
9051                        : factory.createJSDocLinkPlain;
9052                    return finishNode(create(name, text.join("")), start, scanner.getTextPos());
9053                }
9054
9055                function parseJSDocLinkPrefix() {
9056                    skipWhitespaceOrAsterisk();
9057                    if (token() === SyntaxKind.OpenBraceToken
9058                        && nextTokenJSDoc() === SyntaxKind.AtToken
9059                        && tokenIsIdentifierOrKeyword(nextTokenJSDoc())) {
9060                        const kind = scanner.getTokenValue();
9061                        if (isJSDocLinkTag(kind)) return kind;
9062                    }
9063                }
9064
9065                function isJSDocLinkTag(kind: string) {
9066                    return kind === "link" || kind === "linkcode" || kind === "linkplain";
9067                }
9068
9069                function parseUnknownTag(start: number, tagName: Identifier, indent: number, indentText: string) {
9070                    return finishNode(factory.createJSDocUnknownTag(tagName, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start);
9071                }
9072
9073                function addTag(tag: JSDocTag | undefined): void {
9074                    if (!tag) {
9075                        return;
9076                    }
9077                    if (!tags) {
9078                        tags = [tag];
9079                        tagsPos = tag.pos;
9080                    }
9081                    else {
9082                        tags.push(tag);
9083                    }
9084                    tagsEnd = tag.end;
9085                }
9086
9087                function tryParseTypeExpression(): JSDocTypeExpression | undefined {
9088                    skipWhitespaceOrAsterisk();
9089                    return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined;
9090                }
9091
9092                function parseBracketNameInPropertyAndParamTag(): { name: EntityName, isBracketed: boolean } {
9093                    // Looking for something like '[foo]', 'foo', '[foo.bar]' or 'foo.bar'
9094                    const isBracketed = parseOptionalJsdoc(SyntaxKind.OpenBracketToken);
9095                    if (isBracketed) {
9096                        skipWhitespace();
9097                    }
9098                    // a markdown-quoted name: `arg` is not legal jsdoc, but occurs in the wild
9099                    const isBackquoted = parseOptionalJsdoc(SyntaxKind.BacktickToken);
9100                    const name = parseJSDocEntityName();
9101                    if (isBackquoted) {
9102                        parseExpectedTokenJSDoc(SyntaxKind.BacktickToken);
9103                    }
9104                    if (isBracketed) {
9105                        skipWhitespace();
9106                        // May have an optional default, e.g. '[foo = 42]'
9107                        if (parseOptionalToken(SyntaxKind.EqualsToken)) {
9108                            parseExpression();
9109                        }
9110
9111                        parseExpected(SyntaxKind.CloseBracketToken);
9112                    }
9113
9114                    return { name, isBracketed };
9115                }
9116
9117                function isObjectOrObjectArrayTypeReference(node: TypeNode): boolean {
9118                    switch (node.kind) {
9119                        case SyntaxKind.ObjectKeyword:
9120                            return true;
9121                        case SyntaxKind.ArrayType:
9122                            return isObjectOrObjectArrayTypeReference((node as ArrayTypeNode).elementType);
9123                        default:
9124                            return isTypeReferenceNode(node) && ts.isIdentifier(node.typeName) && node.typeName.escapedText === "Object" && !node.typeArguments;
9125                    }
9126                }
9127
9128                function parseParameterOrPropertyTag(start: number, tagName: Identifier, target: PropertyLikeParse, indent: number): JSDocParameterTag | JSDocPropertyTag {
9129                    let typeExpression = tryParseTypeExpression();
9130                    let isNameFirst = !typeExpression;
9131                    skipWhitespaceOrAsterisk();
9132
9133                    const { name, isBracketed } = parseBracketNameInPropertyAndParamTag();
9134                    const indentText = skipWhitespaceOrAsterisk();
9135
9136                    if (isNameFirst && !lookAhead(parseJSDocLinkPrefix)) {
9137                        typeExpression = tryParseTypeExpression();
9138                    }
9139
9140                    const comment = parseTrailingTagComments(start, getNodePos(), indent, indentText);
9141
9142                    const nestedTypeLiteral = target !== PropertyLikeParse.CallbackParameter && parseNestedTypeLiteral(typeExpression, name, target, indent);
9143                    if (nestedTypeLiteral) {
9144                        typeExpression = nestedTypeLiteral;
9145                        isNameFirst = true;
9146                    }
9147                    const result = target === PropertyLikeParse.Property
9148                        ? factory.createJSDocPropertyTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment)
9149                        : factory.createJSDocParameterTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment);
9150                    return finishNode(result, start);
9151                }
9152
9153                function parseNestedTypeLiteral(typeExpression: JSDocTypeExpression | undefined, name: EntityName, target: PropertyLikeParse, indent: number) {
9154                    if (typeExpression && isObjectOrObjectArrayTypeReference(typeExpression.type)) {
9155                        const pos = getNodePos();
9156                        let child: JSDocPropertyLikeTag | JSDocTypeTag | false;
9157                        let children: JSDocPropertyLikeTag[] | undefined;
9158                        while (child = tryParse(() => parseChildParameterOrPropertyTag(target, indent, name))) {
9159                            if (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) {
9160                                children = append(children, child);
9161                            }
9162                        }
9163                        if (children) {
9164                            const literal = finishNode(factory.createJSDocTypeLiteral(children, typeExpression.type.kind === SyntaxKind.ArrayType), pos);
9165                            return finishNode(factory.createJSDocTypeExpression(literal), pos);
9166                        }
9167                    }
9168                }
9169
9170                function parseReturnTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocReturnTag {
9171                    if (some(tags, isJSDocReturnTag)) {
9172                        parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText);
9173                    }
9174
9175                    const typeExpression = tryParseTypeExpression();
9176                    return finishNode(factory.createJSDocReturnTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start);
9177                }
9178
9179                function parseTypeTag(start: number, tagName: Identifier, indent?: number, indentText?: string): JSDocTypeTag {
9180                    if (some(tags, isJSDocTypeTag)) {
9181                        parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText);
9182                    }
9183
9184                    const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true);
9185                    const comments = indent !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), indent, indentText) : undefined;
9186                    return finishNode(factory.createJSDocTypeTag(tagName, typeExpression, comments), start);
9187                }
9188
9189                function parseSeeTag(start: number, tagName: Identifier, indent?: number, indentText?: string): JSDocSeeTag {
9190                    const isMarkdownOrJSDocLink = token() === SyntaxKind.OpenBracketToken
9191                        || lookAhead(() => nextTokenJSDoc() === SyntaxKind.AtToken && tokenIsIdentifierOrKeyword(nextTokenJSDoc()) && isJSDocLinkTag(scanner.getTokenValue()));
9192                    const nameExpression = isMarkdownOrJSDocLink ? undefined : parseJSDocNameReference();
9193                    const comments = indent !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), indent, indentText) : undefined;
9194                    return finishNode(factory.createJSDocSeeTag(tagName, nameExpression, comments), start);
9195                }
9196
9197                function parseAuthorTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocAuthorTag {
9198                    const commentStart = getNodePos();
9199                    const textOnly = parseAuthorNameAndEmail();
9200                    let commentEnd = scanner.getStartPos();
9201                    const comments = parseTrailingTagComments(start, commentEnd, indent, indentText);
9202                    if (!comments) {
9203                        commentEnd = scanner.getStartPos();
9204                    }
9205                    const allParts = typeof comments !== "string"
9206                        ? createNodeArray(concatenate([finishNode(textOnly, commentStart, commentEnd)], comments) as JSDocComment[], commentStart) // cast away readonly
9207                        : textOnly.text + comments;
9208                    return finishNode(factory.createJSDocAuthorTag(tagName, allParts), start);
9209                }
9210
9211                function parseAuthorNameAndEmail(): JSDocText {
9212                    const comments: string[] = [];
9213                    let inEmail = false;
9214                    let token = scanner.getToken();
9215                    while (token !== SyntaxKind.EndOfFileToken && token !== SyntaxKind.NewLineTrivia) {
9216                        if (token === SyntaxKind.LessThanToken) {
9217                            inEmail = true;
9218                        }
9219                        else if (token === SyntaxKind.AtToken && !inEmail) {
9220                            break;
9221                        }
9222                        else if (token === SyntaxKind.GreaterThanToken && inEmail) {
9223                            comments.push(scanner.getTokenText());
9224                            scanner.setTextPos(scanner.getTokenPos() + 1);
9225                            break;
9226                        }
9227                        comments.push(scanner.getTokenText());
9228                        token = nextTokenJSDoc();
9229                    }
9230
9231                    return factory.createJSDocText(comments.join(""));
9232                }
9233
9234                function parseImplementsTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocImplementsTag {
9235                    const className = parseExpressionWithTypeArgumentsForAugments();
9236                    return finishNode(factory.createJSDocImplementsTag(tagName, className, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start);
9237                }
9238
9239                function parseAugmentsTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocAugmentsTag {
9240                    const className = parseExpressionWithTypeArgumentsForAugments();
9241                    return finishNode(factory.createJSDocAugmentsTag(tagName, className, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start);
9242                }
9243
9244                function parseExpressionWithTypeArgumentsForAugments(): ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression } {
9245                    const usedBrace = parseOptional(SyntaxKind.OpenBraceToken);
9246                    const pos = getNodePos();
9247                    const expression = parsePropertyAccessEntityNameExpression();
9248                    const typeArguments = tryParseTypeArguments();
9249                    const node = factory.createExpressionWithTypeArguments(expression, typeArguments) as ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression };
9250                    const res = finishNode(node, pos);
9251                    if (usedBrace) {
9252                        parseExpected(SyntaxKind.CloseBraceToken);
9253                    }
9254                    return res;
9255                }
9256
9257                function parsePropertyAccessEntityNameExpression() {
9258                    const pos = getNodePos();
9259                    let node: Identifier | PropertyAccessEntityNameExpression = parseJSDocIdentifierName();
9260                    while (parseOptional(SyntaxKind.DotToken)) {
9261                        const name = parseJSDocIdentifierName();
9262                        node = finishNode(factory.createPropertyAccessExpression(node, name), pos) as PropertyAccessEntityNameExpression;
9263                    }
9264                    return node;
9265                }
9266
9267                function parseSimpleTag(start: number, createTag: (tagName: Identifier | undefined, comment?: string | NodeArray<JSDocComment>) => JSDocTag, tagName: Identifier, margin: number, indentText: string): JSDocTag {
9268                    return finishNode(createTag(tagName, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start);
9269                }
9270
9271                function parseThisTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocThisTag {
9272                    const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true);
9273                    skipWhitespace();
9274                    return finishNode(factory.createJSDocThisTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start);
9275                }
9276
9277                function parseEnumTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocEnumTag {
9278                    const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true);
9279                    skipWhitespace();
9280                    return finishNode(factory.createJSDocEnumTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start);
9281                }
9282
9283                function parseTypedefTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocTypedefTag {
9284                    let typeExpression: JSDocTypeExpression | JSDocTypeLiteral | undefined = tryParseTypeExpression();
9285                    skipWhitespaceOrAsterisk();
9286
9287                    const fullName = parseJSDocTypeNameWithNamespace();
9288                    skipWhitespace();
9289                    let comment = parseTagComments(indent);
9290
9291                    let end: number | undefined;
9292                    if (!typeExpression || isObjectOrObjectArrayTypeReference(typeExpression.type)) {
9293                        let child: JSDocTypeTag | JSDocPropertyTag | false;
9294                        let childTypeTag: JSDocTypeTag | undefined;
9295                        let jsDocPropertyTags: JSDocPropertyTag[] | undefined;
9296                        let hasChildren = false;
9297                        while (child = tryParse(() => parseChildPropertyTag(indent))) {
9298                            hasChildren = true;
9299                            if (child.kind === SyntaxKind.JSDocTypeTag) {
9300                                if (childTypeTag) {
9301                                    const lastError = parseErrorAtCurrentToken(Diagnostics.A_JSDoc_typedef_comment_may_not_contain_multiple_type_tags);
9302                                    if (lastError) {
9303                                        addRelatedInfo(lastError, createDetachedDiagnostic(fileName, 0, 0, Diagnostics.The_tag_was_first_specified_here));
9304                                    }
9305                                    break;
9306                                }
9307                                else {
9308                                    childTypeTag = child;
9309                                }
9310                            }
9311                            else {
9312                                jsDocPropertyTags = append(jsDocPropertyTags, child);
9313                            }
9314                        }
9315                        if (hasChildren) {
9316                            const isArrayType = typeExpression && typeExpression.type.kind === SyntaxKind.ArrayType;
9317                            const jsdocTypeLiteral = factory.createJSDocTypeLiteral(jsDocPropertyTags, isArrayType);
9318                            typeExpression = childTypeTag && childTypeTag.typeExpression && !isObjectOrObjectArrayTypeReference(childTypeTag.typeExpression.type) ?
9319                                childTypeTag.typeExpression :
9320                                finishNode(jsdocTypeLiteral, start);
9321                            end = typeExpression.end;
9322                        }
9323                    }
9324
9325                    // Only include the characters between the name end and the next token if a comment was actually parsed out - otherwise it's just whitespace
9326                    end = end || comment !== undefined ?
9327                        getNodePos() :
9328                        (fullName ?? typeExpression ?? tagName).end;
9329
9330                    if (!comment) {
9331                        comment = parseTrailingTagComments(start, end, indent, indentText);
9332                    }
9333
9334                    const typedefTag = factory.createJSDocTypedefTag(tagName, typeExpression, fullName, comment);
9335                    return finishNode(typedefTag, start, end);
9336                }
9337
9338                function parseJSDocTypeNameWithNamespace(nested?: boolean) {
9339                    const pos = scanner.getTokenPos();
9340                    if (!tokenIsIdentifierOrKeyword(token())) {
9341                        return undefined;
9342                    }
9343                    const typeNameOrNamespaceName = parseJSDocIdentifierName();
9344                    if (parseOptional(SyntaxKind.DotToken)) {
9345                        const body = parseJSDocTypeNameWithNamespace(/*nested*/ true);
9346                        const jsDocNamespaceNode = factory.createModuleDeclaration(
9347                            /*modifiers*/ undefined,
9348                            typeNameOrNamespaceName,
9349                            body,
9350                            nested ? NodeFlags.NestedNamespace : undefined
9351                        ) as JSDocNamespaceDeclaration;
9352                        return finishNode(jsDocNamespaceNode, pos);
9353                    }
9354
9355                    if (nested) {
9356                        typeNameOrNamespaceName.isInJSDocNamespace = true;
9357                    }
9358                    return typeNameOrNamespaceName;
9359                }
9360
9361
9362                function parseCallbackTagParameters(indent: number) {
9363                    const pos = getNodePos();
9364                    let child: JSDocParameterTag | false;
9365                    let parameters;
9366                    while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.CallbackParameter, indent) as JSDocParameterTag)) {
9367                        parameters = append(parameters, child);
9368                    }
9369                    return createNodeArray(parameters || [], pos);
9370                }
9371
9372                function parseCallbackTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocCallbackTag {
9373                    const fullName = parseJSDocTypeNameWithNamespace();
9374                    skipWhitespace();
9375                    let comment = parseTagComments(indent);
9376                    const parameters = parseCallbackTagParameters(indent);
9377                    const returnTag = tryParse(() => {
9378                        if (parseOptionalJsdoc(SyntaxKind.AtToken)) {
9379                            const tag = parseTag(indent);
9380                            if (tag && tag.kind === SyntaxKind.JSDocReturnTag) {
9381                                return tag as JSDocReturnTag;
9382                            }
9383                        }
9384                    });
9385                    const typeExpression = finishNode(factory.createJSDocSignature(/*typeParameters*/ undefined, parameters, returnTag), start);
9386                    if (!comment) {
9387                        comment = parseTrailingTagComments(start, getNodePos(), indent, indentText);
9388                    }
9389                    const end = comment !== undefined ? getNodePos() : typeExpression.end;
9390                    return finishNode(factory.createJSDocCallbackTag(tagName, typeExpression, fullName, comment), start, end);
9391                }
9392
9393                function escapedTextsEqual(a: EntityName, b: EntityName): boolean {
9394                    while (!ts.isIdentifier(a) || !ts.isIdentifier(b)) {
9395                        if (!ts.isIdentifier(a) && !ts.isIdentifier(b) && a.right.escapedText === b.right.escapedText) {
9396                            a = a.left;
9397                            b = b.left;
9398                        }
9399                        else {
9400                            return false;
9401                        }
9402                    }
9403                    return a.escapedText === b.escapedText;
9404                }
9405
9406                function parseChildPropertyTag(indent: number) {
9407                    return parseChildParameterOrPropertyTag(PropertyLikeParse.Property, indent) as JSDocTypeTag | JSDocPropertyTag | false;
9408                }
9409
9410                function parseChildParameterOrPropertyTag(target: PropertyLikeParse, indent: number, name?: EntityName): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false {
9411                    let canParseTag = true;
9412                    let seenAsterisk = false;
9413                    while (true) {
9414                        switch (nextTokenJSDoc()) {
9415                            case SyntaxKind.AtToken:
9416                                if (canParseTag) {
9417                                    const child = tryParseChildTag(target, indent);
9418                                    if (child && (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) &&
9419                                        target !== PropertyLikeParse.CallbackParameter &&
9420                                        name && (ts.isIdentifier(child.name) || !escapedTextsEqual(name, child.name.left))) {
9421                                        return false;
9422                                    }
9423                                    return child;
9424                                }
9425                                seenAsterisk = false;
9426                                break;
9427                            case SyntaxKind.NewLineTrivia:
9428                                canParseTag = true;
9429                                seenAsterisk = false;
9430                                break;
9431                            case SyntaxKind.AsteriskToken:
9432                                if (seenAsterisk) {
9433                                    canParseTag = false;
9434                                }
9435                                seenAsterisk = true;
9436                                break;
9437                            case SyntaxKind.Identifier:
9438                                canParseTag = false;
9439                                break;
9440                            case SyntaxKind.EndOfFileToken:
9441                                return false;
9442                        }
9443                    }
9444                }
9445
9446                function tryParseChildTag(target: PropertyLikeParse, indent: number): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false {
9447                    Debug.assert(token() === SyntaxKind.AtToken);
9448                    const start = scanner.getStartPos();
9449                    nextTokenJSDoc();
9450
9451                    const tagName = parseJSDocIdentifierName();
9452                    skipWhitespace();
9453                    let t: PropertyLikeParse;
9454                    switch (tagName.escapedText) {
9455                        case "type":
9456                            return target === PropertyLikeParse.Property && parseTypeTag(start, tagName);
9457                        case "prop":
9458                        case "property":
9459                            t = PropertyLikeParse.Property;
9460                            break;
9461                        case "arg":
9462                        case "argument":
9463                        case "param":
9464                            t = PropertyLikeParse.Parameter | PropertyLikeParse.CallbackParameter;
9465                            break;
9466                        default:
9467                            return false;
9468                    }
9469                    if (!(target & t)) {
9470                        return false;
9471                    }
9472                    return parseParameterOrPropertyTag(start, tagName, target, indent);
9473                }
9474
9475                function parseTemplateTagTypeParameter() {
9476                    const typeParameterPos = getNodePos();
9477                    const isBracketed = parseOptionalJsdoc(SyntaxKind.OpenBracketToken);
9478                    if (isBracketed) {
9479                        skipWhitespace();
9480                    }
9481                    const name = parseJSDocIdentifierName(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces);
9482
9483                    let defaultType: TypeNode | undefined;
9484                    if (isBracketed) {
9485                        skipWhitespace();
9486                        parseExpected(SyntaxKind.EqualsToken);
9487                        defaultType = doInsideOfContext(NodeFlags.JSDoc, parseJSDocType);
9488                        parseExpected(SyntaxKind.CloseBracketToken);
9489                    }
9490
9491                    if (nodeIsMissing(name)) {
9492                        return undefined;
9493                    }
9494                    return finishNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, /*constraint*/ undefined, defaultType), typeParameterPos);
9495                }
9496
9497                function parseTemplateTagTypeParameters() {
9498                    const pos = getNodePos();
9499                    const typeParameters = [];
9500                    do {
9501                        skipWhitespace();
9502                        const node = parseTemplateTagTypeParameter();
9503                        if (node !== undefined) {
9504                            typeParameters.push(node);
9505                        }
9506                        skipWhitespaceOrAsterisk();
9507                    } while (parseOptionalJsdoc(SyntaxKind.CommaToken));
9508                    return createNodeArray(typeParameters, pos);
9509                }
9510
9511                function parseTemplateTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocTemplateTag {
9512                    // The template tag looks like one of the following:
9513                    //   @template T,U,V
9514                    //   @template {Constraint} T
9515                    //
9516                    // According to the [closure docs](https://github.com/google/closure-compiler/wiki/Generic-Types#multiple-bounded-template-types):
9517                    //   > Multiple bounded generics cannot be declared on the same line. For the sake of clarity, if multiple templates share the same
9518                    //   > type bound they must be declared on separate lines.
9519                    //
9520                    // TODO: Determine whether we should enforce this in the checker.
9521                    // TODO: Consider moving the `constraint` to the first type parameter as we could then remove `getEffectiveConstraintOfTypeParameter`.
9522                    // TODO: Consider only parsing a single type parameter if there is a constraint.
9523                    const constraint = token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined;
9524                    const typeParameters = parseTemplateTagTypeParameters();
9525                    return finishNode(factory.createJSDocTemplateTag(tagName, constraint, typeParameters, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start);
9526                }
9527
9528                function parseOptionalJsdoc(t: JSDocSyntaxKind): boolean {
9529                    if (token() === t) {
9530                        nextTokenJSDoc();
9531                        return true;
9532                    }
9533                    return false;
9534                }
9535
9536                function parseJSDocEntityName(): EntityName {
9537                    let entity: EntityName = parseJSDocIdentifierName();
9538                    if (parseOptional(SyntaxKind.OpenBracketToken)) {
9539                        parseExpected(SyntaxKind.CloseBracketToken);
9540                        // Note that y[] is accepted as an entity name, but the postfix brackets are not saved for checking.
9541                        // Technically usejsdoc.org requires them for specifying a property of a type equivalent to Array<{ x: ...}>
9542                        // but it's not worth it to enforce that restriction.
9543                    }
9544                    while (parseOptional(SyntaxKind.DotToken)) {
9545                        const name = parseJSDocIdentifierName();
9546                        if (parseOptional(SyntaxKind.OpenBracketToken)) {
9547                            parseExpected(SyntaxKind.CloseBracketToken);
9548                        }
9549                        entity = createQualifiedName(entity, name);
9550                    }
9551                    return entity;
9552                }
9553
9554                function parseJSDocIdentifierName(message?: DiagnosticMessage): Identifier {
9555                    if (!tokenIsIdentifierOrKeyword(token())) {
9556                        return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ !message, message || Diagnostics.Identifier_expected);
9557                    }
9558
9559                    identifierCount++;
9560                    const pos = scanner.getTokenPos();
9561                    const end = scanner.getTextPos();
9562                    const originalKeywordKind = token();
9563                    const text = internIdentifier(scanner.getTokenValue());
9564                    const result = finishNode(factory.createIdentifier(text, /*typeArguments*/ undefined, originalKeywordKind), pos, end);
9565                    nextTokenJSDoc();
9566                    return result;
9567                }
9568            }
9569        }
9570    }
9571
9572    namespace IncrementalParser {
9573        export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean): SourceFile {
9574            aggressiveChecks = aggressiveChecks || Debug.shouldAssert(AssertionLevel.Aggressive);
9575
9576            checkChangeRange(sourceFile, newText, textChangeRange, aggressiveChecks);
9577            if (textChangeRangeIsUnchanged(textChangeRange)) {
9578                // if the text didn't change, then we can just return our current source file as-is.
9579                return sourceFile;
9580            }
9581
9582            if (sourceFile.statements.length === 0) {
9583                // If we don't have any statements in the current source file, then there's no real
9584                // way to incrementally parse.  So just do a full parse instead.
9585                return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator);
9586            }
9587
9588            // Make sure we're not trying to incrementally update a source file more than once.  Once
9589            // we do an update the original source file is considered unusable from that point onwards.
9590            //
9591            // This is because we do incremental parsing in-place.  i.e. we take nodes from the old
9592            // tree and give them new positions and parents.  From that point on, trusting the old
9593            // tree at all is not possible as far too much of it may violate invariants.
9594            const incrementalSourceFile = sourceFile as Node as IncrementalNode;
9595            Debug.assert(!incrementalSourceFile.hasBeenIncrementallyParsed);
9596            incrementalSourceFile.hasBeenIncrementallyParsed = true;
9597            Parser.fixupParentReferences(incrementalSourceFile);
9598            const oldText = sourceFile.text;
9599            const syntaxCursor = createSyntaxCursor(sourceFile);
9600
9601            // Make the actual change larger so that we know to reparse anything whose lookahead
9602            // might have intersected the change.
9603            const changeRange = extendToAffectedRange(sourceFile, textChangeRange);
9604            checkChangeRange(sourceFile, newText, changeRange, aggressiveChecks);
9605
9606            // Ensure that extending the affected range only moved the start of the change range
9607            // earlier in the file.
9608            Debug.assert(changeRange.span.start <= textChangeRange.span.start);
9609            Debug.assert(textSpanEnd(changeRange.span) === textSpanEnd(textChangeRange.span));
9610            Debug.assert(textSpanEnd(textChangeRangeNewSpan(changeRange)) === textSpanEnd(textChangeRangeNewSpan(textChangeRange)));
9611
9612            // The is the amount the nodes after the edit range need to be adjusted.  It can be
9613            // positive (if the edit added characters), negative (if the edit deleted characters)
9614            // or zero (if this was a pure overwrite with nothing added/removed).
9615            const delta = textChangeRangeNewSpan(changeRange).length - changeRange.span.length;
9616
9617            // If we added or removed characters during the edit, then we need to go and adjust all
9618            // the nodes after the edit.  Those nodes may move forward (if we inserted chars) or they
9619            // may move backward (if we deleted chars).
9620            //
9621            // Doing this helps us out in two ways.  First, it means that any nodes/tokens we want
9622            // to reuse are already at the appropriate position in the new text.  That way when we
9623            // reuse them, we don't have to figure out if they need to be adjusted.  Second, it makes
9624            // it very easy to determine if we can reuse a node.  If the node's position is at where
9625            // we are in the text, then we can reuse it.  Otherwise we can't.  If the node's position
9626            // is ahead of us, then we'll need to rescan tokens.  If the node's position is behind
9627            // us, then we'll need to skip it or crumble it as appropriate
9628            //
9629            // We will also adjust the positions of nodes that intersect the change range as well.
9630            // By doing this, we ensure that all the positions in the old tree are consistent, not
9631            // just the positions of nodes entirely before/after the change range.  By being
9632            // consistent, we can then easily map from positions to nodes in the old tree easily.
9633            //
9634            // Also, mark any syntax elements that intersect the changed span.  We know, up front,
9635            // that we cannot reuse these elements.
9636            updateTokenPositionsAndMarkElements(incrementalSourceFile,
9637                changeRange.span.start, textSpanEnd(changeRange.span), textSpanEnd(textChangeRangeNewSpan(changeRange)), delta, oldText, newText, aggressiveChecks);
9638
9639            // Now that we've set up our internal incremental state just proceed and parse the
9640            // source file in the normal fashion.  When possible the parser will retrieve and
9641            // reuse nodes from the old tree.
9642            //
9643            // Note: passing in 'true' for setNodeParents is very important.  When incrementally
9644            // parsing, we will be reusing nodes from the old tree, and placing it into new
9645            // parents.  If we don't set the parents now, we'll end up with an observably
9646            // inconsistent tree.  Setting the parents on the new tree should be very fast.  We
9647            // will immediately bail out of walking any subtrees when we can see that their parents
9648            // are already correct.
9649            const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator);
9650            result.commentDirectives = getNewCommentDirectives(
9651                sourceFile.commentDirectives,
9652                result.commentDirectives,
9653                changeRange.span.start,
9654                textSpanEnd(changeRange.span),
9655                delta,
9656                oldText,
9657                newText,
9658                aggressiveChecks
9659            );
9660            result.impliedNodeFormat = sourceFile.impliedNodeFormat;
9661            return result;
9662        }
9663
9664        function getNewCommentDirectives(
9665            oldDirectives: CommentDirective[] | undefined,
9666            newDirectives: CommentDirective[] | undefined,
9667            changeStart: number,
9668            changeRangeOldEnd: number,
9669            delta: number,
9670            oldText: string,
9671            newText: string,
9672            aggressiveChecks: boolean
9673        ): CommentDirective[] | undefined {
9674            if (!oldDirectives) return newDirectives;
9675            let commentDirectives: CommentDirective[] | undefined;
9676            let addedNewlyScannedDirectives = false;
9677            for (const directive of oldDirectives) {
9678                const { range, type } = directive;
9679                // Range before the change
9680                if (range.end < changeStart) {
9681                    commentDirectives = append(commentDirectives, directive);
9682                }
9683                else if (range.pos > changeRangeOldEnd) {
9684                    addNewlyScannedDirectives();
9685                    // Node is entirely past the change range.  We need to move both its pos and
9686                    // end, forward or backward appropriately.
9687                    const updatedDirective: CommentDirective = {
9688                        range: { pos: range.pos + delta, end: range.end + delta },
9689                        type
9690                    };
9691                    commentDirectives = append(commentDirectives, updatedDirective);
9692                    if (aggressiveChecks) {
9693                        Debug.assert(oldText.substring(range.pos, range.end) === newText.substring(updatedDirective.range.pos, updatedDirective.range.end));
9694                    }
9695                }
9696                // Ignore ranges that fall in change range
9697            }
9698            addNewlyScannedDirectives();
9699            return commentDirectives;
9700
9701            function addNewlyScannedDirectives() {
9702                if (addedNewlyScannedDirectives) return;
9703                addedNewlyScannedDirectives = true;
9704                if (!commentDirectives) {
9705                    commentDirectives = newDirectives;
9706                }
9707                else if (newDirectives) {
9708                    commentDirectives.push(...newDirectives);
9709                }
9710            }
9711        }
9712
9713        function moveElementEntirelyPastChangeRange(element: IncrementalElement, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) {
9714            if (isArray) {
9715                visitArray(element as IncrementalNodeArray);
9716            }
9717            else {
9718                visitNode(element as IncrementalNode);
9719            }
9720            return;
9721
9722            function visitNode(node: IncrementalNode) {
9723                let text = "";
9724                if (aggressiveChecks && shouldCheckNode(node)) {
9725                    text = oldText.substring(node.pos, node.end);
9726                }
9727
9728                // Ditch any existing LS children we may have created.  This way we can avoid
9729                // moving them forward.
9730                if (node._children) {
9731                    node._children = undefined;
9732                }
9733
9734                setTextRangePosEnd(node, node.pos + delta, node.end + delta);
9735
9736                if (aggressiveChecks && shouldCheckNode(node)) {
9737                    Debug.assert(text === newText.substring(node.pos, node.end));
9738                }
9739
9740                forEachChild(node, visitNode, visitArray);
9741                if (hasJSDocNodes(node)) {
9742                    for (const jsDocComment of node.jsDoc!) {
9743                        visitNode(jsDocComment as Node as IncrementalNode);
9744                    }
9745                }
9746                checkNodePositions(node, aggressiveChecks);
9747            }
9748
9749            function visitArray(array: IncrementalNodeArray) {
9750                array._children = undefined;
9751                setTextRangePosEnd(array, array.pos + delta, array.end + delta);
9752
9753                for (const node of array) {
9754                    visitNode(node);
9755                }
9756            }
9757        }
9758
9759        function shouldCheckNode(node: Node) {
9760            switch (node.kind) {
9761                case SyntaxKind.StringLiteral:
9762                case SyntaxKind.NumericLiteral:
9763                case SyntaxKind.Identifier:
9764                    return true;
9765            }
9766
9767            return false;
9768        }
9769
9770        function adjustIntersectingElement(element: IncrementalElement, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number) {
9771            Debug.assert(element.end >= changeStart, "Adjusting an element that was entirely before the change range");
9772            Debug.assert(element.pos <= changeRangeOldEnd, "Adjusting an element that was entirely after the change range");
9773            Debug.assert(element.pos <= element.end);
9774
9775            // We have an element that intersects the change range in some way.  It may have its
9776            // start, or its end (or both) in the changed range.  We want to adjust any part
9777            // that intersects such that the final tree is in a consistent state.  i.e. all
9778            // children have spans within the span of their parent, and all siblings are ordered
9779            // properly.
9780
9781            // We may need to update both the 'pos' and the 'end' of the element.
9782
9783            // If the 'pos' is before the start of the change, then we don't need to touch it.
9784            // If it isn't, then the 'pos' must be inside the change.  How we update it will
9785            // depend if delta is positive or negative. If delta is positive then we have
9786            // something like:
9787            //
9788            //  -------------------AAA-----------------
9789            //  -------------------BBBCCCCCCC-----------------
9790            //
9791            // In this case, we consider any node that started in the change range to still be
9792            // starting at the same position.
9793            //
9794            // however, if the delta is negative, then we instead have something like this:
9795            //
9796            //  -------------------XXXYYYYYYY-----------------
9797            //  -------------------ZZZ-----------------
9798            //
9799            // In this case, any element that started in the 'X' range will keep its position.
9800            // However any element that started after that will have their pos adjusted to be
9801            // at the end of the new range.  i.e. any node that started in the 'Y' range will
9802            // be adjusted to have their start at the end of the 'Z' range.
9803            //
9804            // The element will keep its position if possible.  Or Move backward to the new-end
9805            // if it's in the 'Y' range.
9806            const pos = Math.min(element.pos, changeRangeNewEnd);
9807
9808            // If the 'end' is after the change range, then we always adjust it by the delta
9809            // amount.  However, if the end is in the change range, then how we adjust it
9810            // will depend on if delta is positive or negative.  If delta is positive then we
9811            // have something like:
9812            //
9813            //  -------------------AAA-----------------
9814            //  -------------------BBBCCCCCCC-----------------
9815            //
9816            // In this case, we consider any node that ended inside the change range to keep its
9817            // end position.
9818            //
9819            // however, if the delta is negative, then we instead have something like this:
9820            //
9821            //  -------------------XXXYYYYYYY-----------------
9822            //  -------------------ZZZ-----------------
9823            //
9824            // In this case, any element that ended in the 'X' range will keep its position.
9825            // However any element that ended after that will have their pos adjusted to be
9826            // at the end of the new range.  i.e. any node that ended in the 'Y' range will
9827            // be adjusted to have their end at the end of the 'Z' range.
9828            const end = element.end >= changeRangeOldEnd ?
9829                // Element ends after the change range.  Always adjust the end pos.
9830                element.end + delta :
9831                // Element ends in the change range.  The element will keep its position if
9832                // possible. Or Move backward to the new-end if it's in the 'Y' range.
9833                Math.min(element.end, changeRangeNewEnd);
9834
9835            Debug.assert(pos <= end);
9836            if (element.parent) {
9837                Debug.assertGreaterThanOrEqual(pos, element.parent.pos);
9838                Debug.assertLessThanOrEqual(end, element.parent.end);
9839            }
9840
9841            setTextRangePosEnd(element, pos, end);
9842        }
9843
9844        function checkNodePositions(node: Node, aggressiveChecks: boolean) {
9845            if (aggressiveChecks) {
9846                let pos = node.pos;
9847                const visitNode = (child: Node) => {
9848                    Debug.assert(child.pos >= pos);
9849                    pos = child.end;
9850                };
9851                if (hasJSDocNodes(node)) {
9852                    for (const jsDocComment of node.jsDoc!) {
9853                        visitNode(jsDocComment);
9854                    }
9855                }
9856                forEachChild(node, visitNode);
9857                Debug.assert(pos <= node.end);
9858            }
9859        }
9860
9861        function updateTokenPositionsAndMarkElements(
9862            sourceFile: IncrementalNode,
9863            changeStart: number,
9864            changeRangeOldEnd: number,
9865            changeRangeNewEnd: number,
9866            delta: number,
9867            oldText: string,
9868            newText: string,
9869            aggressiveChecks: boolean): void {
9870
9871            visitNode(sourceFile);
9872            return;
9873
9874            function visitNode(child: IncrementalNode) {
9875                Debug.assert(child.pos <= child.end);
9876                if (child.pos > changeRangeOldEnd) {
9877                    // Node is entirely past the change range.  We need to move both its pos and
9878                    // end, forward or backward appropriately.
9879                    moveElementEntirelyPastChangeRange(child, /*isArray*/ false, delta, oldText, newText, aggressiveChecks);
9880                    return;
9881                }
9882
9883                // Check if the element intersects the change range.  If it does, then it is not
9884                // reusable.  Also, we'll need to recurse to see what constituent portions we may
9885                // be able to use.
9886                const fullEnd = child.end;
9887                if (fullEnd >= changeStart) {
9888                    child.intersectsChange = true;
9889                    child._children = undefined;
9890
9891                    // Adjust the pos or end (or both) of the intersecting element accordingly.
9892                    adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta);
9893                    forEachChild(child, visitNode, visitArray);
9894                    if (hasJSDocNodes(child)) {
9895                        for (const jsDocComment of child.jsDoc!) {
9896                            visitNode(jsDocComment as Node as IncrementalNode);
9897                        }
9898                    }
9899                    checkNodePositions(child, aggressiveChecks);
9900                    return;
9901                }
9902
9903                // Otherwise, the node is entirely before the change range.  No need to do anything with it.
9904                Debug.assert(fullEnd < changeStart);
9905            }
9906
9907            function visitArray(array: IncrementalNodeArray) {
9908                Debug.assert(array.pos <= array.end);
9909                if (array.pos > changeRangeOldEnd) {
9910                    // Array is entirely after the change range.  We need to move it, and move any of
9911                    // its children.
9912                    moveElementEntirelyPastChangeRange(array, /*isArray*/ true, delta, oldText, newText, aggressiveChecks);
9913                    return;
9914                }
9915
9916                // Check if the element intersects the change range.  If it does, then it is not
9917                // reusable.  Also, we'll need to recurse to see what constituent portions we may
9918                // be able to use.
9919                const fullEnd = array.end;
9920                if (fullEnd >= changeStart) {
9921                    array.intersectsChange = true;
9922                    array._children = undefined;
9923
9924                    // Adjust the pos or end (or both) of the intersecting array accordingly.
9925                    adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta);
9926                    for (const node of array) {
9927                        if (!node.virtual) {
9928                            visitNode(node);
9929                        }
9930                    }
9931                    return;
9932                }
9933
9934                // Otherwise, the array is entirely before the change range.  No need to do anything with it.
9935                Debug.assert(fullEnd < changeStart);
9936            }
9937        }
9938
9939        function extendToAffectedRange(sourceFile: SourceFile, changeRange: TextChangeRange): TextChangeRange {
9940            // Consider the following code:
9941            //      void foo() { /; }
9942            //
9943            // If the text changes with an insertion of / just before the semicolon then we end up with:
9944            //      void foo() { //; }
9945            //
9946            // If we were to just use the changeRange a is, then we would not rescan the { token
9947            // (as it does not intersect the actual original change range).  Because an edit may
9948            // change the token touching it, we actually need to look back *at least* one token so
9949            // that the prior token sees that change.
9950            const maxLookahead = 1;
9951
9952            let start = changeRange.span.start;
9953
9954            // the first iteration aligns us with the change start. subsequent iteration move us to
9955            // the left by maxLookahead tokens.  We only need to do this as long as we're not at the
9956            // start of the tree.
9957            for (let i = 0; start > 0 && i <= maxLookahead; i++) {
9958                const nearestNode = findNearestNodeStartingBeforeOrAtPosition(sourceFile, start);
9959                Debug.assert(nearestNode.pos <= start);
9960                const position = nearestNode.pos;
9961
9962                start = Math.max(0, position - 1);
9963            }
9964
9965            const finalSpan = createTextSpanFromBounds(start, textSpanEnd(changeRange.span));
9966            const finalLength = changeRange.newLength + (changeRange.span.start - start);
9967
9968            return createTextChangeRange(finalSpan, finalLength);
9969        }
9970
9971        function findNearestNodeStartingBeforeOrAtPosition(sourceFile: SourceFile, position: number): Node {
9972            let bestResult: Node = sourceFile;
9973            let lastNodeEntirelyBeforePosition: Node | undefined;
9974
9975            forEachChild(sourceFile, visit);
9976
9977            if (lastNodeEntirelyBeforePosition) {
9978                const lastChildOfLastEntireNodeBeforePosition = getLastDescendant(lastNodeEntirelyBeforePosition);
9979                if (lastChildOfLastEntireNodeBeforePosition.pos > bestResult.pos) {
9980                    bestResult = lastChildOfLastEntireNodeBeforePosition;
9981                }
9982            }
9983
9984            return bestResult;
9985
9986            function getLastDescendant(node: Node): Node {
9987                while (true) {
9988                    const lastChild = getLastChild(node);
9989                    if (lastChild) {
9990                        node = lastChild;
9991                    }
9992                    else {
9993                        return node;
9994                    }
9995                }
9996            }
9997
9998            function visit(child: Node) {
9999                if (nodeIsMissing(child)) {
10000                    // Missing nodes are effectively invisible to us.  We never even consider them
10001                    // When trying to find the nearest node before us.
10002                    return;
10003                }
10004
10005                // If the child intersects this position, then this node is currently the nearest
10006                // node that starts before the position.
10007                if (child.pos <= position) {
10008                    if (child.pos >= bestResult.pos) {
10009                        // This node starts before the position, and is closer to the position than
10010                        // the previous best node we found.  It is now the new best node.
10011                        bestResult = child;
10012                    }
10013
10014                    // Now, the node may overlap the position, or it may end entirely before the
10015                    // position.  If it overlaps with the position, then either it, or one of its
10016                    // children must be the nearest node before the position.  So we can just
10017                    // recurse into this child to see if we can find something better.
10018                    if (position < child.end) {
10019                        // The nearest node is either this child, or one of the children inside
10020                        // of it.  We've already marked this child as the best so far.  Recurse
10021                        // in case one of the children is better.
10022                        forEachChild(child, visit);
10023
10024                        // Once we look at the children of this node, then there's no need to
10025                        // continue any further.
10026                        return true;
10027                    }
10028                    else {
10029                        Debug.assert(child.end <= position);
10030                        // The child ends entirely before this position.  Say you have the following
10031                        // (where $ is the position)
10032                        //
10033                        //      <complex expr 1> ? <complex expr 2> $ : <...> <...>
10034                        //
10035                        // We would want to find the nearest preceding node in "complex expr 2".
10036                        // To support that, we keep track of this node, and once we're done searching
10037                        // for a best node, we recurse down this node to see if we can find a good
10038                        // result in it.
10039                        //
10040                        // This approach allows us to quickly skip over nodes that are entirely
10041                        // before the position, while still allowing us to find any nodes in the
10042                        // last one that might be what we want.
10043                        lastNodeEntirelyBeforePosition = child;
10044                    }
10045                }
10046                else {
10047                    Debug.assert(child.pos > position);
10048                    // We're now at a node that is entirely past the position we're searching for.
10049                    // This node (and all following nodes) could never contribute to the result,
10050                    // so just skip them by returning 'true' here.
10051                    return true;
10052                }
10053            }
10054        }
10055
10056        function checkChangeRange(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean) {
10057            const oldText = sourceFile.text;
10058            if (textChangeRange) {
10059                Debug.assert((oldText.length - textChangeRange.span.length + textChangeRange.newLength) === newText.length);
10060
10061                if (aggressiveChecks || Debug.shouldAssert(AssertionLevel.VeryAggressive)) {
10062                    const oldTextPrefix = oldText.substr(0, textChangeRange.span.start);
10063                    const newTextPrefix = newText.substr(0, textChangeRange.span.start);
10064                    Debug.assert(oldTextPrefix === newTextPrefix);
10065
10066                    const oldTextSuffix = oldText.substring(textSpanEnd(textChangeRange.span), oldText.length);
10067                    const newTextSuffix = newText.substring(textSpanEnd(textChangeRangeNewSpan(textChangeRange)), newText.length);
10068                    Debug.assert(oldTextSuffix === newTextSuffix);
10069                }
10070            }
10071        }
10072
10073        interface IncrementalElement extends ReadonlyTextRange {
10074            readonly parent: Node;
10075            intersectsChange: boolean;
10076            length?: number;
10077            _children: Node[] | undefined;
10078        }
10079
10080        export interface IncrementalNode extends Node, IncrementalElement {
10081            hasBeenIncrementallyParsed: boolean;
10082        }
10083
10084        interface IncrementalNodeArray extends NodeArray<IncrementalNode>, IncrementalElement {
10085            length: number;
10086        }
10087
10088        // Allows finding nodes in the source file at a certain position in an efficient manner.
10089        // The implementation takes advantage of the calling pattern it knows the parser will
10090        // make in order to optimize finding nodes as quickly as possible.
10091        export interface SyntaxCursor {
10092            currentNode(position: number): IncrementalNode;
10093        }
10094
10095        export function createSyntaxCursor(sourceFile: SourceFile): SyntaxCursor {
10096            let currentArray: NodeArray<Node> = sourceFile.statements;
10097            let currentArrayIndex = 0;
10098
10099            Debug.assert(currentArrayIndex < currentArray.length);
10100            let current = currentArray[currentArrayIndex];
10101            let lastQueriedPosition = InvalidPosition.Value;
10102
10103            return {
10104                currentNode(position: number) {
10105                    // Only compute the current node if the position is different than the last time
10106                    // we were asked.  The parser commonly asks for the node at the same position
10107                    // twice.  Once to know if can read an appropriate list element at a certain point,
10108                    // and then to actually read and consume the node.
10109                    if (position !== lastQueriedPosition) {
10110                        // Much of the time the parser will need the very next node in the array that
10111                        // we just returned a node from.So just simply check for that case and move
10112                        // forward in the array instead of searching for the node again.
10113                        if (current && current.end === position && currentArrayIndex < (currentArray.length - 1)) {
10114                            currentArrayIndex++;
10115                            current = currentArray[currentArrayIndex];
10116                        }
10117
10118                        // If we don't have a node, or the node we have isn't in the right position,
10119                        // then try to find a viable node at the position requested.
10120                        if (!current || current.pos !== position) {
10121                            findHighestListElementThatStartsAtPosition(position);
10122                        }
10123                    }
10124
10125                    // Cache this query so that we don't do any extra work if the parser calls back
10126                    // into us.  Note: this is very common as the parser will make pairs of calls like
10127                    // 'isListElement -> parseListElement'.  If we were unable to find a node when
10128                    // called with 'isListElement', we don't want to redo the work when parseListElement
10129                    // is called immediately after.
10130                    lastQueriedPosition = position;
10131
10132                    // Either we don'd have a node, or we have a node at the position being asked for.
10133                    Debug.assert(!current || current.pos === position);
10134                    return current as IncrementalNode;
10135                }
10136            };
10137
10138            // Finds the highest element in the tree we can find that starts at the provided position.
10139            // The element must be a direct child of some node list in the tree.  This way after we
10140            // return it, we can easily return its next sibling in the list.
10141            function findHighestListElementThatStartsAtPosition(position: number) {
10142                // Clear out any cached state about the last node we found.
10143                currentArray = undefined!;
10144                currentArrayIndex = InvalidPosition.Value;
10145                current = undefined!;
10146
10147                // Recurse into the source file to find the highest node at this position.
10148                forEachChild(sourceFile, visitNode, visitArray);
10149                return;
10150
10151                function visitNode(node: Node) {
10152                    if (position >= node.pos && position < node.end) {
10153                        // Position was within this node.  Keep searching deeper to find the node.
10154                        forEachChild(node, visitNode, visitArray);
10155
10156                        // don't proceed any further in the search.
10157                        return true;
10158                    }
10159
10160                    // position wasn't in this node, have to keep searching.
10161                    return false;
10162                }
10163
10164                function visitArray(array: NodeArray<Node>) {
10165                    if (position >= array.pos && position < array.end) {
10166                        // position was in this array.  Search through this array to see if we find a
10167                        // viable element.
10168                        for (let i = 0; i < array.length; i++) {
10169                            const child = array[i];
10170                            if (child) {
10171                                if (child.pos === position) {
10172                                    // Found the right node.  We're done.
10173                                    currentArray = array;
10174                                    currentArrayIndex = i;
10175                                    current = child;
10176                                    return true;
10177                                }
10178                                else {
10179                                    if (child.pos < position && position < child.end) {
10180                                        // Position in somewhere within this child.  Search in it and
10181                                        // stop searching in this array.
10182                                        forEachChild(child, visitNode, visitArray);
10183                                        return true;
10184                                    }
10185                                }
10186                            }
10187                        }
10188                    }
10189
10190                    // position wasn't in this array, have to keep searching.
10191                    return false;
10192                }
10193            }
10194        }
10195
10196        const enum InvalidPosition {
10197            Value = -1
10198        }
10199    }
10200
10201    /** @internal */
10202    export function isDeclarationFileName(fileName: string): boolean {
10203        return fileExtensionIsOneOf(fileName, supportedDeclarationExtensions);
10204    }
10205
10206    /*@internal*/
10207    export interface PragmaContext {
10208        languageVersion: ScriptTarget;
10209        pragmas?: PragmaMap;
10210        checkJsDirective?: CheckJsDirective;
10211        referencedFiles: FileReference[];
10212        typeReferenceDirectives: FileReference[];
10213        libReferenceDirectives: FileReference[];
10214        amdDependencies: AmdDependency[];
10215        hasNoDefaultLib?: boolean;
10216        moduleName?: string;
10217    }
10218
10219    function parseResolutionMode(mode: string | undefined, pos: number, end: number, reportDiagnostic: PragmaDiagnosticReporter): ModuleKind.ESNext | ModuleKind.CommonJS | undefined {
10220        if (!mode) {
10221            return undefined;
10222        }
10223        if (mode === "import") {
10224            return ModuleKind.ESNext;
10225        }
10226        if (mode === "require") {
10227            return ModuleKind.CommonJS;
10228        }
10229        reportDiagnostic(pos, end - pos, Diagnostics.resolution_mode_should_be_either_require_or_import);
10230        return undefined;
10231    }
10232
10233    /*@internal*/
10234    export function processCommentPragmas(context: PragmaContext, sourceText: string): void {
10235        const pragmas: PragmaPseudoMapEntry[] = [];
10236
10237        for (const range of getLeadingCommentRanges(sourceText, 0) || emptyArray) {
10238            const comment = sourceText.substring(range.pos, range.end);
10239            extractPragmas(pragmas, range, comment);
10240        }
10241
10242        context.pragmas = new Map() as PragmaMap;
10243        for (const pragma of pragmas) {
10244            if (context.pragmas.has(pragma.name)) {
10245                const currentValue = context.pragmas.get(pragma.name);
10246                if (currentValue instanceof Array) {
10247                    currentValue.push(pragma.args);
10248                }
10249                else {
10250                    context.pragmas.set(pragma.name, [currentValue, pragma.args]);
10251                }
10252                continue;
10253            }
10254            context.pragmas.set(pragma.name, pragma.args);
10255        }
10256    }
10257
10258    /*@internal*/
10259    type PragmaDiagnosticReporter = (pos: number, length: number, message: DiagnosticMessage) => void;
10260
10261    /*@internal*/
10262    export function processPragmasIntoFields(context: PragmaContext, reportDiagnostic: PragmaDiagnosticReporter): void {
10263        context.checkJsDirective = undefined;
10264        context.referencedFiles = [];
10265        context.typeReferenceDirectives = [];
10266        context.libReferenceDirectives = [];
10267        context.amdDependencies = [];
10268        context.hasNoDefaultLib = false;
10269        context.pragmas!.forEach((entryOrList, key) => { // TODO: GH#18217
10270            // TODO: The below should be strongly type-guarded and not need casts/explicit annotations, since entryOrList is related to
10271            // key and key is constrained to a union; but it's not (see GH#21483 for at least partial fix) :(
10272            switch (key) {
10273                case "reference": {
10274                    const referencedFiles = context.referencedFiles;
10275                    const typeReferenceDirectives = context.typeReferenceDirectives;
10276                    const libReferenceDirectives = context.libReferenceDirectives;
10277                    forEach(toArray(entryOrList) as PragmaPseudoMap["reference"][], arg => {
10278                        const { types, lib, path, ["resolution-mode"]: res } = arg.arguments;
10279                        if (arg.arguments["no-default-lib"]) {
10280                            context.hasNoDefaultLib = true;
10281                        }
10282                        else if (types) {
10283                            const parsed = parseResolutionMode(res, types.pos, types.end, reportDiagnostic);
10284                            typeReferenceDirectives.push({ pos: types.pos, end: types.end, fileName: types.value, ...(parsed ? { resolutionMode: parsed } : {}) });
10285                        }
10286                        else if (lib) {
10287                            libReferenceDirectives.push({ pos: lib.pos, end: lib.end, fileName: lib.value });
10288                        }
10289                        else if (path) {
10290                            referencedFiles.push({ pos: path.pos, end: path.end, fileName: path.value });
10291                        }
10292                        else {
10293                            reportDiagnostic(arg.range.pos, arg.range.end - arg.range.pos, Diagnostics.Invalid_reference_directive_syntax);
10294                        }
10295                    });
10296                    break;
10297                }
10298                case "amd-dependency": {
10299                    context.amdDependencies = map(
10300                        toArray(entryOrList) as PragmaPseudoMap["amd-dependency"][],
10301                        x => ({ name: x.arguments.name, path: x.arguments.path }));
10302                    break;
10303                }
10304                case "amd-module": {
10305                    if (entryOrList instanceof Array) {
10306                        for (const entry of entryOrList) {
10307                            if (context.moduleName) {
10308                                // TODO: It's probably fine to issue this diagnostic on all instances of the pragma
10309                                reportDiagnostic(entry.range.pos, entry.range.end - entry.range.pos, Diagnostics.An_AMD_module_cannot_have_multiple_name_assignments);
10310                            }
10311                            context.moduleName = (entry as PragmaPseudoMap["amd-module"]).arguments.name;
10312                        }
10313                    }
10314                    else {
10315                        context.moduleName = (entryOrList as PragmaPseudoMap["amd-module"]).arguments.name;
10316                    }
10317                    break;
10318                }
10319                case "ts-nocheck":
10320                case "ts-check": {
10321                    // _last_ of either nocheck or check in a file is the "winner"
10322                    forEach(toArray(entryOrList), entry => {
10323                        if (!context.checkJsDirective || entry.range.pos > context.checkJsDirective.pos) {
10324                            context.checkJsDirective = {
10325                                enabled: key === "ts-check",
10326                                end: entry.range.end,
10327                                pos: entry.range.pos
10328                            };
10329                        }
10330                    });
10331                    break;
10332                }
10333                case "jsx":
10334                case "jsxfrag":
10335                case "jsximportsource":
10336                case "jsxruntime":
10337                    return; // Accessed directly
10338                default: Debug.fail("Unhandled pragma kind"); // Can this be made into an assertNever in the future?
10339            }
10340        });
10341    }
10342
10343    const namedArgRegExCache = new Map<string, RegExp>();
10344    function getNamedArgRegEx(name: string): RegExp {
10345        if (namedArgRegExCache.has(name)) {
10346            return namedArgRegExCache.get(name)!;
10347        }
10348        const result = new RegExp(`(\\s${name}\\s*=\\s*)(?:(?:'([^']*)')|(?:"([^"]*)"))`, "im");
10349        namedArgRegExCache.set(name, result);
10350        return result;
10351    }
10352
10353    const tripleSlashXMLCommentStartRegEx = /^\/\/\/\s*<(\S+)\s.*?\/>/im;
10354    const singleLinePragmaRegEx = /^\/\/\/?\s*@(\S+)\s*(.*)\s*$/im;
10355    function extractPragmas(pragmas: PragmaPseudoMapEntry[], range: CommentRange, text: string) {
10356        const tripleSlash = range.kind === SyntaxKind.SingleLineCommentTrivia && tripleSlashXMLCommentStartRegEx.exec(text);
10357        if (tripleSlash) {
10358            const name = tripleSlash[1].toLowerCase() as keyof PragmaPseudoMap; // Technically unsafe cast, but we do it so the below check to make it safe typechecks
10359            const pragma = commentPragmas[name] as PragmaDefinition;
10360            if (!pragma || !(pragma.kind! & PragmaKindFlags.TripleSlashXML)) {
10361                return;
10362            }
10363            if (pragma.args) {
10364                const argument: {[index: string]: string | {value: string, pos: number, end: number}} = {};
10365                for (const arg of pragma.args) {
10366                    const matcher = getNamedArgRegEx(arg.name);
10367                    const matchResult = matcher.exec(text);
10368                    if (!matchResult && !arg.optional) {
10369                        return; // Missing required argument, don't parse
10370                    }
10371                    else if (matchResult) {
10372                        const value = matchResult[2] || matchResult[3];
10373                        if (arg.captureSpan) {
10374                            const startPos = range.pos + matchResult.index + matchResult[1].length + 1;
10375                            argument[arg.name] = {
10376                                value,
10377                                pos: startPos,
10378                                end: startPos + value.length
10379                            };
10380                        }
10381                        else {
10382                            argument[arg.name] = value;
10383                        }
10384                    }
10385                }
10386                pragmas.push({ name, args: { arguments: argument, range } } as PragmaPseudoMapEntry);
10387            }
10388            else {
10389                pragmas.push({ name, args: { arguments: {}, range } } as PragmaPseudoMapEntry);
10390            }
10391            return;
10392        }
10393
10394        const singleLine = range.kind === SyntaxKind.SingleLineCommentTrivia && singleLinePragmaRegEx.exec(text);
10395        if (singleLine) {
10396            return addPragmaForMatch(pragmas, range, PragmaKindFlags.SingleLine, singleLine);
10397        }
10398
10399        if (range.kind === SyntaxKind.MultiLineCommentTrivia) {
10400            const multiLinePragmaRegEx = /@(\S+)(\s+.*)?$/gim; // Defined inline since it uses the "g" flag, which keeps a persistent index (for iterating)
10401            let multiLineMatch: RegExpExecArray | null;
10402            while (multiLineMatch = multiLinePragmaRegEx.exec(text)) {
10403                addPragmaForMatch(pragmas, range, PragmaKindFlags.MultiLine, multiLineMatch);
10404            }
10405        }
10406    }
10407
10408    function addPragmaForMatch(pragmas: PragmaPseudoMapEntry[], range: CommentRange, kind: PragmaKindFlags, match: RegExpExecArray) {
10409        if (!match) return;
10410        const name = match[1].toLowerCase() as keyof PragmaPseudoMap; // Technically unsafe cast, but we do it so they below check to make it safe typechecks
10411        const pragma = commentPragmas[name] as PragmaDefinition;
10412        if (!pragma || !(pragma.kind! & kind)) {
10413            return;
10414        }
10415        const args = match[2]; // Split on spaces and match up positionally with definition
10416        const argument = getNamedPragmaArguments(pragma, args);
10417        if (argument === "fail") return; // Missing required argument, fail to parse it
10418        pragmas.push({ name, args: { arguments: argument, range } } as PragmaPseudoMapEntry);
10419        return;
10420    }
10421
10422    function getNamedPragmaArguments(pragma: PragmaDefinition, text: string | undefined): {[index: string]: string} | "fail" {
10423        if (!text) return {};
10424        if (!pragma.args) return {};
10425        const args = trimString(text).split(/\s+/);
10426        const argMap: {[index: string]: string} = {};
10427        for (let i = 0; i < pragma.args.length; i++) {
10428            const argument = pragma.args[i];
10429            if (!args[i] && !argument.optional) {
10430                return "fail";
10431            }
10432            if (argument.captureSpan) {
10433                return Debug.fail("Capture spans not yet implemented for non-xml pragmas");
10434            }
10435            argMap[argument.name] = args[i];
10436        }
10437        return argMap;
10438    }
10439
10440    /** @internal */
10441    export function tagNamesAreEquivalent(lhs: JsxTagNameExpression, rhs: JsxTagNameExpression): boolean {
10442        if (lhs.kind !== rhs.kind) {
10443            return false;
10444        }
10445
10446        if (lhs.kind === SyntaxKind.Identifier) {
10447            return lhs.escapedText === (rhs as Identifier).escapedText;
10448        }
10449
10450        if (lhs.kind === SyntaxKind.ThisKeyword) {
10451            return true;
10452        }
10453
10454        // If we are at this statement then we must have PropertyAccessExpression and because tag name in Jsx element can only
10455        // take forms of JsxTagNameExpression which includes an identifier, "this" expression, or another propertyAccessExpression
10456        // it is safe to case the expression property as such. See parseJsxElementName for how we parse tag name in Jsx element
10457        return (lhs as PropertyAccessExpression).name.escapedText === (rhs as PropertyAccessExpression).name.escapedText &&
10458            tagNamesAreEquivalent((lhs as PropertyAccessExpression).expression as JsxTagNameExpression, (rhs as PropertyAccessExpression).expression as JsxTagNameExpression);
10459    }
10460}
10461