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