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