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