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