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