1/// <reference path="utilities.ts"/> 2/// <reference path="scanner.ts"/> 3 4namespace ts { 5 const enum SignatureFlags { 6 None = 0, 7 Yield = 1 << 0, 8 Await = 1 << 1, 9 Type = 1 << 2, 10 RequireCompleteParameterList = 1 << 3, 11 IgnoreMissingOpenBrace = 1 << 4, 12 JSDoc = 1 << 5, 13 } 14 15 // tslint:disable variable-name 16 let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 17 let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 18 let IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 19 let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 20 // tslint:enable variable-name 21 22 export function createNode(kind: SyntaxKind, pos?: number, end?: number): Node { 23 if (kind === SyntaxKind.SourceFile) { 24 return new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, pos, end); 25 } 26 else if (kind === SyntaxKind.Identifier) { 27 return new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, pos, end); 28 } 29 else if (!isNodeKind(kind)) { 30 return new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, pos, end); 31 } 32 else { 33 return new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, pos, end); 34 } 35 } 36 37 function visitNode<T>(cbNode: (node: Node) => T, node: Node): T | undefined { 38 return node && cbNode(node); 39 } 40 41 function visitNodes<T>(cbNode: (node: Node) => T, cbNodes: (node: NodeArray<Node>) => T | undefined, nodes: NodeArray<Node>): T | undefined { 42 if (nodes) { 43 if (cbNodes) { 44 return cbNodes(nodes); 45 } 46 for (const node of nodes) { 47 const result = cbNode(node); 48 if (result) { 49 return result; 50 } 51 } 52 } 53 } 54 55 /** 56 * Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes 57 * stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise, 58 * embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns 59 * a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned. 60 * 61 * @param node a given node to visit its children 62 * @param cbNode a callback to be invoked for all child nodes 63 * @param cbNodes a callback to be invoked for embedded array 64 * 65 * @remarks `forEachChild` must visit the children of a node in the order 66 * that they appear in the source code. The language service depends on this property to locate nodes by position. 67 */ 68 export function forEachChild<T>(node: Node, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined { 69 if (!node || node.kind <= SyntaxKind.LastToken) { 70 return; 71 } 72 switch (node.kind) { 73 case SyntaxKind.QualifiedName: 74 return visitNode(cbNode, (<QualifiedName>node).left) || 75 visitNode(cbNode, (<QualifiedName>node).right); 76 case SyntaxKind.TypeParameter: 77 return visitNode(cbNode, (<TypeParameterDeclaration>node).name) || 78 visitNode(cbNode, (<TypeParameterDeclaration>node).constraint) || 79 visitNode(cbNode, (<TypeParameterDeclaration>node).default) || 80 visitNode(cbNode, (<TypeParameterDeclaration>node).expression); 81 case SyntaxKind.ShorthandPropertyAssignment: 82 return visitNodes(cbNode, cbNodes, node.decorators) || 83 visitNodes(cbNode, cbNodes, node.modifiers) || 84 visitNode(cbNode, (<ShorthandPropertyAssignment>node).name) || 85 visitNode(cbNode, (<ShorthandPropertyAssignment>node).questionToken) || 86 visitNode(cbNode, (<ShorthandPropertyAssignment>node).equalsToken) || 87 visitNode(cbNode, (<ShorthandPropertyAssignment>node).objectAssignmentInitializer); 88 case SyntaxKind.SpreadAssignment: 89 return visitNode(cbNode, (<SpreadAssignment>node).expression); 90 case SyntaxKind.Parameter: 91 return visitNodes(cbNode, cbNodes, node.decorators) || 92 visitNodes(cbNode, cbNodes, node.modifiers) || 93 visitNode(cbNode, (<ParameterDeclaration>node).dotDotDotToken) || 94 visitNode(cbNode, (<ParameterDeclaration>node).name) || 95 visitNode(cbNode, (<ParameterDeclaration>node).questionToken) || 96 visitNode(cbNode, (<ParameterDeclaration>node).type) || 97 visitNode(cbNode, (<ParameterDeclaration>node).initializer); 98 case SyntaxKind.PropertyDeclaration: 99 return visitNodes(cbNode, cbNodes, node.decorators) || 100 visitNodes(cbNode, cbNodes, node.modifiers) || 101 visitNode(cbNode, (<PropertyDeclaration>node).name) || 102 visitNode(cbNode, (<PropertyDeclaration>node).questionToken) || 103 visitNode(cbNode, (<PropertyDeclaration>node).exclamationToken) || 104 visitNode(cbNode, (<PropertyDeclaration>node).type) || 105 visitNode(cbNode, (<PropertyDeclaration>node).initializer); 106 case SyntaxKind.PropertySignature: 107 return visitNodes(cbNode, cbNodes, node.decorators) || 108 visitNodes(cbNode, cbNodes, node.modifiers) || 109 visitNode(cbNode, (<PropertySignature>node).name) || 110 visitNode(cbNode, (<PropertySignature>node).questionToken) || 111 visitNode(cbNode, (<PropertySignature>node).type) || 112 visitNode(cbNode, (<PropertySignature>node).initializer); 113 case SyntaxKind.PropertyAssignment: 114 return visitNodes(cbNode, cbNodes, node.decorators) || 115 visitNodes(cbNode, cbNodes, node.modifiers) || 116 visitNode(cbNode, (<PropertyAssignment>node).name) || 117 visitNode(cbNode, (<PropertyAssignment>node).questionToken) || 118 visitNode(cbNode, (<PropertyAssignment>node).initializer); 119 case SyntaxKind.VariableDeclaration: 120 return visitNodes(cbNode, cbNodes, node.decorators) || 121 visitNodes(cbNode, cbNodes, node.modifiers) || 122 visitNode(cbNode, (<VariableDeclaration>node).name) || 123 visitNode(cbNode, (<VariableDeclaration>node).exclamationToken) || 124 visitNode(cbNode, (<VariableDeclaration>node).type) || 125 visitNode(cbNode, (<VariableDeclaration>node).initializer); 126 case SyntaxKind.BindingElement: 127 return visitNodes(cbNode, cbNodes, node.decorators) || 128 visitNodes(cbNode, cbNodes, node.modifiers) || 129 visitNode(cbNode, (<BindingElement>node).dotDotDotToken) || 130 visitNode(cbNode, (<BindingElement>node).propertyName) || 131 visitNode(cbNode, (<BindingElement>node).name) || 132 visitNode(cbNode, (<BindingElement>node).initializer); 133 case SyntaxKind.FunctionType: 134 case SyntaxKind.ConstructorType: 135 case SyntaxKind.CallSignature: 136 case SyntaxKind.ConstructSignature: 137 case SyntaxKind.IndexSignature: 138 return visitNodes(cbNode, cbNodes, node.decorators) || 139 visitNodes(cbNode, cbNodes, node.modifiers) || 140 visitNodes(cbNode, cbNodes, (<SignatureDeclaration>node).typeParameters) || 141 visitNodes(cbNode, cbNodes, (<SignatureDeclaration>node).parameters) || 142 visitNode(cbNode, (<SignatureDeclaration>node).type); 143 case SyntaxKind.MethodDeclaration: 144 case SyntaxKind.MethodSignature: 145 case SyntaxKind.Constructor: 146 case SyntaxKind.GetAccessor: 147 case SyntaxKind.SetAccessor: 148 case SyntaxKind.FunctionExpression: 149 case SyntaxKind.FunctionDeclaration: 150 case SyntaxKind.ArrowFunction: 151 return visitNodes(cbNode, cbNodes, node.decorators) || 152 visitNodes(cbNode, cbNodes, node.modifiers) || 153 visitNode(cbNode, (<FunctionLikeDeclaration>node).asteriskToken) || 154 visitNode(cbNode, (<FunctionLikeDeclaration>node).name) || 155 visitNode(cbNode, (<FunctionLikeDeclaration>node).questionToken) || 156 visitNodes(cbNode, cbNodes, (<FunctionLikeDeclaration>node).typeParameters) || 157 visitNodes(cbNode, cbNodes, (<FunctionLikeDeclaration>node).parameters) || 158 visitNode(cbNode, (<FunctionLikeDeclaration>node).type) || 159 visitNode(cbNode, (<ArrowFunction>node).equalsGreaterThanToken) || 160 visitNode(cbNode, (<FunctionLikeDeclaration>node).body); 161 case SyntaxKind.TypeReference: 162 return visitNode(cbNode, (<TypeReferenceNode>node).typeName) || 163 visitNodes(cbNode, cbNodes, (<TypeReferenceNode>node).typeArguments); 164 case SyntaxKind.TypePredicate: 165 return visitNode(cbNode, (<TypePredicateNode>node).parameterName) || 166 visitNode(cbNode, (<TypePredicateNode>node).type); 167 case SyntaxKind.TypeQuery: 168 return visitNode(cbNode, (<TypeQueryNode>node).exprName); 169 case SyntaxKind.TypeLiteral: 170 return visitNodes(cbNode, cbNodes, (<TypeLiteralNode>node).members); 171 case SyntaxKind.ArrayType: 172 return visitNode(cbNode, (<ArrayTypeNode>node).elementType); 173 case SyntaxKind.TupleType: 174 return visitNodes(cbNode, cbNodes, (<TupleTypeNode>node).elementTypes); 175 case SyntaxKind.UnionType: 176 case SyntaxKind.IntersectionType: 177 return visitNodes(cbNode, cbNodes, (<UnionOrIntersectionTypeNode>node).types); 178 case SyntaxKind.ConditionalType: 179 return visitNode(cbNode, (<ConditionalTypeNode>node).checkType) || 180 visitNode(cbNode, (<ConditionalTypeNode>node).extendsType) || 181 visitNode(cbNode, (<ConditionalTypeNode>node).trueType) || 182 visitNode(cbNode, (<ConditionalTypeNode>node).falseType); 183 case SyntaxKind.InferType: 184 return visitNode(cbNode, (<InferTypeNode>node).typeParameter); 185 case SyntaxKind.ParenthesizedType: 186 case SyntaxKind.TypeOperator: 187 return visitNode(cbNode, (<ParenthesizedTypeNode | TypeOperatorNode>node).type); 188 case SyntaxKind.IndexedAccessType: 189 return visitNode(cbNode, (<IndexedAccessTypeNode>node).objectType) || 190 visitNode(cbNode, (<IndexedAccessTypeNode>node).indexType); 191 case SyntaxKind.MappedType: 192 return visitNode(cbNode, (<MappedTypeNode>node).readonlyToken) || 193 visitNode(cbNode, (<MappedTypeNode>node).typeParameter) || 194 visitNode(cbNode, (<MappedTypeNode>node).questionToken) || 195 visitNode(cbNode, (<MappedTypeNode>node).type); 196 case SyntaxKind.LiteralType: 197 return visitNode(cbNode, (<LiteralTypeNode>node).literal); 198 case SyntaxKind.ObjectBindingPattern: 199 case SyntaxKind.ArrayBindingPattern: 200 return visitNodes(cbNode, cbNodes, (<BindingPattern>node).elements); 201 case SyntaxKind.ArrayLiteralExpression: 202 return visitNodes(cbNode, cbNodes, (<ArrayLiteralExpression>node).elements); 203 case SyntaxKind.ObjectLiteralExpression: 204 return visitNodes(cbNode, cbNodes, (<ObjectLiteralExpression>node).properties); 205 case SyntaxKind.PropertyAccessExpression: 206 return visitNode(cbNode, (<PropertyAccessExpression>node).expression) || 207 visitNode(cbNode, (<PropertyAccessExpression>node).name); 208 case SyntaxKind.ElementAccessExpression: 209 return visitNode(cbNode, (<ElementAccessExpression>node).expression) || 210 visitNode(cbNode, (<ElementAccessExpression>node).argumentExpression); 211 case SyntaxKind.CallExpression: 212 case SyntaxKind.NewExpression: 213 return visitNode(cbNode, (<CallExpression>node).expression) || 214 visitNodes(cbNode, cbNodes, (<CallExpression>node).typeArguments) || 215 visitNodes(cbNode, cbNodes, (<CallExpression>node).arguments); 216 case SyntaxKind.TaggedTemplateExpression: 217 return visitNode(cbNode, (<TaggedTemplateExpression>node).tag) || 218 visitNode(cbNode, (<TaggedTemplateExpression>node).template); 219 case SyntaxKind.TypeAssertionExpression: 220 return visitNode(cbNode, (<TypeAssertion>node).type) || 221 visitNode(cbNode, (<TypeAssertion>node).expression); 222 case SyntaxKind.ParenthesizedExpression: 223 return visitNode(cbNode, (<ParenthesizedExpression>node).expression); 224 case SyntaxKind.DeleteExpression: 225 return visitNode(cbNode, (<DeleteExpression>node).expression); 226 case SyntaxKind.TypeOfExpression: 227 return visitNode(cbNode, (<TypeOfExpression>node).expression); 228 case SyntaxKind.VoidExpression: 229 return visitNode(cbNode, (<VoidExpression>node).expression); 230 case SyntaxKind.PrefixUnaryExpression: 231 return visitNode(cbNode, (<PrefixUnaryExpression>node).operand); 232 case SyntaxKind.YieldExpression: 233 return visitNode(cbNode, (<YieldExpression>node).asteriskToken) || 234 visitNode(cbNode, (<YieldExpression>node).expression); 235 case SyntaxKind.AwaitExpression: 236 return visitNode(cbNode, (<AwaitExpression>node).expression); 237 case SyntaxKind.PostfixUnaryExpression: 238 return visitNode(cbNode, (<PostfixUnaryExpression>node).operand); 239 case SyntaxKind.BinaryExpression: 240 return visitNode(cbNode, (<BinaryExpression>node).left) || 241 visitNode(cbNode, (<BinaryExpression>node).operatorToken) || 242 visitNode(cbNode, (<BinaryExpression>node).right); 243 case SyntaxKind.AsExpression: 244 return visitNode(cbNode, (<AsExpression>node).expression) || 245 visitNode(cbNode, (<AsExpression>node).type); 246 case SyntaxKind.NonNullExpression: 247 return visitNode(cbNode, (<NonNullExpression>node).expression); 248 case SyntaxKind.MetaProperty: 249 return visitNode(cbNode, (<MetaProperty>node).name); 250 case SyntaxKind.ConditionalExpression: 251 return visitNode(cbNode, (<ConditionalExpression>node).condition) || 252 visitNode(cbNode, (<ConditionalExpression>node).questionToken) || 253 visitNode(cbNode, (<ConditionalExpression>node).whenTrue) || 254 visitNode(cbNode, (<ConditionalExpression>node).colonToken) || 255 visitNode(cbNode, (<ConditionalExpression>node).whenFalse); 256 case SyntaxKind.SpreadElement: 257 return visitNode(cbNode, (<SpreadElement>node).expression); 258 case SyntaxKind.Block: 259 case SyntaxKind.ModuleBlock: 260 return visitNodes(cbNode, cbNodes, (<Block>node).statements); 261 case SyntaxKind.SourceFile: 262 return visitNodes(cbNode, cbNodes, (<SourceFile>node).statements) || 263 visitNode(cbNode, (<SourceFile>node).endOfFileToken); 264 case SyntaxKind.VariableStatement: 265 return visitNodes(cbNode, cbNodes, node.decorators) || 266 visitNodes(cbNode, cbNodes, node.modifiers) || 267 visitNode(cbNode, (<VariableStatement>node).declarationList); 268 case SyntaxKind.VariableDeclarationList: 269 return visitNodes(cbNode, cbNodes, (<VariableDeclarationList>node).declarations); 270 case SyntaxKind.ExpressionStatement: 271 return visitNode(cbNode, (<ExpressionStatement>node).expression); 272 case SyntaxKind.IfStatement: 273 return visitNode(cbNode, (<IfStatement>node).expression) || 274 visitNode(cbNode, (<IfStatement>node).thenStatement) || 275 visitNode(cbNode, (<IfStatement>node).elseStatement); 276 case SyntaxKind.DoStatement: 277 return visitNode(cbNode, (<DoStatement>node).statement) || 278 visitNode(cbNode, (<DoStatement>node).expression); 279 case SyntaxKind.WhileStatement: 280 return visitNode(cbNode, (<WhileStatement>node).expression) || 281 visitNode(cbNode, (<WhileStatement>node).statement); 282 case SyntaxKind.ForStatement: 283 return visitNode(cbNode, (<ForStatement>node).initializer) || 284 visitNode(cbNode, (<ForStatement>node).condition) || 285 visitNode(cbNode, (<ForStatement>node).incrementor) || 286 visitNode(cbNode, (<ForStatement>node).statement); 287 case SyntaxKind.ForInStatement: 288 return visitNode(cbNode, (<ForInStatement>node).initializer) || 289 visitNode(cbNode, (<ForInStatement>node).expression) || 290 visitNode(cbNode, (<ForInStatement>node).statement); 291 case SyntaxKind.ForOfStatement: 292 return visitNode(cbNode, (<ForOfStatement>node).awaitModifier) || 293 visitNode(cbNode, (<ForOfStatement>node).initializer) || 294 visitNode(cbNode, (<ForOfStatement>node).expression) || 295 visitNode(cbNode, (<ForOfStatement>node).statement); 296 case SyntaxKind.ContinueStatement: 297 case SyntaxKind.BreakStatement: 298 return visitNode(cbNode, (<BreakOrContinueStatement>node).label); 299 case SyntaxKind.ReturnStatement: 300 return visitNode(cbNode, (<ReturnStatement>node).expression); 301 case SyntaxKind.WithStatement: 302 return visitNode(cbNode, (<WithStatement>node).expression) || 303 visitNode(cbNode, (<WithStatement>node).statement); 304 case SyntaxKind.SwitchStatement: 305 return visitNode(cbNode, (<SwitchStatement>node).expression) || 306 visitNode(cbNode, (<SwitchStatement>node).caseBlock); 307 case SyntaxKind.CaseBlock: 308 return visitNodes(cbNode, cbNodes, (<CaseBlock>node).clauses); 309 case SyntaxKind.CaseClause: 310 return visitNode(cbNode, (<CaseClause>node).expression) || 311 visitNodes(cbNode, cbNodes, (<CaseClause>node).statements); 312 case SyntaxKind.DefaultClause: 313 return visitNodes(cbNode, cbNodes, (<DefaultClause>node).statements); 314 case SyntaxKind.LabeledStatement: 315 return visitNode(cbNode, (<LabeledStatement>node).label) || 316 visitNode(cbNode, (<LabeledStatement>node).statement); 317 case SyntaxKind.ThrowStatement: 318 return visitNode(cbNode, (<ThrowStatement>node).expression); 319 case SyntaxKind.TryStatement: 320 return visitNode(cbNode, (<TryStatement>node).tryBlock) || 321 visitNode(cbNode, (<TryStatement>node).catchClause) || 322 visitNode(cbNode, (<TryStatement>node).finallyBlock); 323 case SyntaxKind.CatchClause: 324 return visitNode(cbNode, (<CatchClause>node).variableDeclaration) || 325 visitNode(cbNode, (<CatchClause>node).block); 326 case SyntaxKind.Decorator: 327 return visitNode(cbNode, (<Decorator>node).expression); 328 case SyntaxKind.ClassDeclaration: 329 case SyntaxKind.ClassExpression: 330 return visitNodes(cbNode, cbNodes, node.decorators) || 331 visitNodes(cbNode, cbNodes, node.modifiers) || 332 visitNode(cbNode, (<ClassLikeDeclaration>node).name) || 333 visitNodes(cbNode, cbNodes, (<ClassLikeDeclaration>node).typeParameters) || 334 visitNodes(cbNode, cbNodes, (<ClassLikeDeclaration>node).heritageClauses) || 335 visitNodes(cbNode, cbNodes, (<ClassLikeDeclaration>node).members); 336 case SyntaxKind.InterfaceDeclaration: 337 return visitNodes(cbNode, cbNodes, node.decorators) || 338 visitNodes(cbNode, cbNodes, node.modifiers) || 339 visitNode(cbNode, (<InterfaceDeclaration>node).name) || 340 visitNodes(cbNode, cbNodes, (<InterfaceDeclaration>node).typeParameters) || 341 visitNodes(cbNode, cbNodes, (<ClassDeclaration>node).heritageClauses) || 342 visitNodes(cbNode, cbNodes, (<InterfaceDeclaration>node).members); 343 case SyntaxKind.TypeAliasDeclaration: 344 return visitNodes(cbNode, cbNodes, node.decorators) || 345 visitNodes(cbNode, cbNodes, node.modifiers) || 346 visitNode(cbNode, (<TypeAliasDeclaration>node).name) || 347 visitNodes(cbNode, cbNodes, (<TypeAliasDeclaration>node).typeParameters) || 348 visitNode(cbNode, (<TypeAliasDeclaration>node).type); 349 case SyntaxKind.EnumDeclaration: 350 return visitNodes(cbNode, cbNodes, node.decorators) || 351 visitNodes(cbNode, cbNodes, node.modifiers) || 352 visitNode(cbNode, (<EnumDeclaration>node).name) || 353 visitNodes(cbNode, cbNodes, (<EnumDeclaration>node).members); 354 case SyntaxKind.EnumMember: 355 return visitNode(cbNode, (<EnumMember>node).name) || 356 visitNode(cbNode, (<EnumMember>node).initializer); 357 case SyntaxKind.ModuleDeclaration: 358 return visitNodes(cbNode, cbNodes, node.decorators) || 359 visitNodes(cbNode, cbNodes, node.modifiers) || 360 visitNode(cbNode, (<ModuleDeclaration>node).name) || 361 visitNode(cbNode, (<ModuleDeclaration>node).body); 362 case SyntaxKind.ImportEqualsDeclaration: 363 return visitNodes(cbNode, cbNodes, node.decorators) || 364 visitNodes(cbNode, cbNodes, node.modifiers) || 365 visitNode(cbNode, (<ImportEqualsDeclaration>node).name) || 366 visitNode(cbNode, (<ImportEqualsDeclaration>node).moduleReference); 367 case SyntaxKind.ImportDeclaration: 368 return visitNodes(cbNode, cbNodes, node.decorators) || 369 visitNodes(cbNode, cbNodes, node.modifiers) || 370 visitNode(cbNode, (<ImportDeclaration>node).importClause) || 371 visitNode(cbNode, (<ImportDeclaration>node).moduleSpecifier); 372 case SyntaxKind.ImportClause: 373 return visitNode(cbNode, (<ImportClause>node).name) || 374 visitNode(cbNode, (<ImportClause>node).namedBindings); 375 case SyntaxKind.NamespaceExportDeclaration: 376 return visitNode(cbNode, (<NamespaceExportDeclaration>node).name); 377 378 case SyntaxKind.NamespaceImport: 379 return visitNode(cbNode, (<NamespaceImport>node).name); 380 case SyntaxKind.NamedImports: 381 case SyntaxKind.NamedExports: 382 return visitNodes(cbNode, cbNodes, (<NamedImportsOrExports>node).elements); 383 case SyntaxKind.ExportDeclaration: 384 return visitNodes(cbNode, cbNodes, node.decorators) || 385 visitNodes(cbNode, cbNodes, node.modifiers) || 386 visitNode(cbNode, (<ExportDeclaration>node).exportClause) || 387 visitNode(cbNode, (<ExportDeclaration>node).moduleSpecifier); 388 case SyntaxKind.ImportSpecifier: 389 case SyntaxKind.ExportSpecifier: 390 return visitNode(cbNode, (<ImportOrExportSpecifier>node).propertyName) || 391 visitNode(cbNode, (<ImportOrExportSpecifier>node).name); 392 case SyntaxKind.ExportAssignment: 393 return visitNodes(cbNode, cbNodes, node.decorators) || 394 visitNodes(cbNode, cbNodes, node.modifiers) || 395 visitNode(cbNode, (<ExportAssignment>node).expression); 396 case SyntaxKind.TemplateExpression: 397 return visitNode(cbNode, (<TemplateExpression>node).head) || visitNodes(cbNode, cbNodes, (<TemplateExpression>node).templateSpans); 398 case SyntaxKind.TemplateSpan: 399 return visitNode(cbNode, (<TemplateSpan>node).expression) || visitNode(cbNode, (<TemplateSpan>node).literal); 400 case SyntaxKind.ComputedPropertyName: 401 return visitNode(cbNode, (<ComputedPropertyName>node).expression); 402 case SyntaxKind.HeritageClause: 403 return visitNodes(cbNode, cbNodes, (<HeritageClause>node).types); 404 case SyntaxKind.ExpressionWithTypeArguments: 405 return visitNode(cbNode, (<ExpressionWithTypeArguments>node).expression) || 406 visitNodes(cbNode, cbNodes, (<ExpressionWithTypeArguments>node).typeArguments); 407 case SyntaxKind.ExternalModuleReference: 408 return visitNode(cbNode, (<ExternalModuleReference>node).expression); 409 case SyntaxKind.MissingDeclaration: 410 return visitNodes(cbNode, cbNodes, node.decorators); 411 case SyntaxKind.CommaListExpression: 412 return visitNodes(cbNode, cbNodes, (<CommaListExpression>node).elements); 413 414 case SyntaxKind.JsxElement: 415 return visitNode(cbNode, (<JsxElement>node).openingElement) || 416 visitNodes(cbNode, cbNodes, (<JsxElement>node).children) || 417 visitNode(cbNode, (<JsxElement>node).closingElement); 418 case SyntaxKind.JsxFragment: 419 return visitNode(cbNode, (<JsxFragment>node).openingFragment) || 420 visitNodes(cbNode, cbNodes, (<JsxFragment>node).children) || 421 visitNode(cbNode, (<JsxFragment>node).closingFragment); 422 case SyntaxKind.JsxSelfClosingElement: 423 case SyntaxKind.JsxOpeningElement: 424 return visitNode(cbNode, (<JsxOpeningLikeElement>node).tagName) || 425 visitNode(cbNode, (<JsxOpeningLikeElement>node).attributes); 426 case SyntaxKind.JsxAttributes: 427 return visitNodes(cbNode, cbNodes, (<JsxAttributes>node).properties); 428 case SyntaxKind.JsxAttribute: 429 return visitNode(cbNode, (<JsxAttribute>node).name) || 430 visitNode(cbNode, (<JsxAttribute>node).initializer); 431 case SyntaxKind.JsxSpreadAttribute: 432 return visitNode(cbNode, (<JsxSpreadAttribute>node).expression); 433 case SyntaxKind.JsxExpression: 434 return visitNode(cbNode, (node as JsxExpression).dotDotDotToken) || 435 visitNode(cbNode, (node as JsxExpression).expression); 436 case SyntaxKind.JsxClosingElement: 437 return visitNode(cbNode, (<JsxClosingElement>node).tagName); 438 439 case SyntaxKind.JSDocTypeExpression: 440 return visitNode(cbNode, (<JSDocTypeExpression>node).type); 441 case SyntaxKind.JSDocNonNullableType: 442 return visitNode(cbNode, (<JSDocNonNullableType>node).type); 443 case SyntaxKind.JSDocNullableType: 444 return visitNode(cbNode, (<JSDocNullableType>node).type); 445 case SyntaxKind.JSDocOptionalType: 446 return visitNode(cbNode, (<JSDocOptionalType>node).type); 447 case SyntaxKind.JSDocFunctionType: 448 return visitNodes(cbNode, cbNodes, (<JSDocFunctionType>node).parameters) || 449 visitNode(cbNode, (<JSDocFunctionType>node).type); 450 case SyntaxKind.JSDocVariadicType: 451 return visitNode(cbNode, (<JSDocVariadicType>node).type); 452 case SyntaxKind.JSDocComment: 453 return visitNodes(cbNode, cbNodes, (<JSDoc>node).tags); 454 case SyntaxKind.JSDocParameterTag: 455 case SyntaxKind.JSDocPropertyTag: 456 if ((node as JSDocPropertyLikeTag).isNameFirst) { 457 return visitNode(cbNode, (<JSDocPropertyLikeTag>node).name) || 458 visitNode(cbNode, (<JSDocPropertyLikeTag>node).typeExpression); 459 } 460 else { 461 return visitNode(cbNode, (<JSDocPropertyLikeTag>node).typeExpression) || 462 visitNode(cbNode, (<JSDocPropertyLikeTag>node).name); 463 } 464 case SyntaxKind.JSDocReturnTag: 465 return visitNode(cbNode, (<JSDocReturnTag>node).typeExpression); 466 case SyntaxKind.JSDocTypeTag: 467 return visitNode(cbNode, (<JSDocTypeTag>node).typeExpression); 468 case SyntaxKind.JSDocAugmentsTag: 469 return visitNode(cbNode, (<JSDocAugmentsTag>node).class); 470 case SyntaxKind.JSDocTemplateTag: 471 return visitNodes(cbNode, cbNodes, (<JSDocTemplateTag>node).typeParameters); 472 case SyntaxKind.JSDocTypedefTag: 473 if ((node as JSDocTypedefTag).typeExpression && 474 (node as JSDocTypedefTag).typeExpression.kind === SyntaxKind.JSDocTypeExpression) { 475 return visitNode(cbNode, (<JSDocTypedefTag>node).typeExpression) || 476 visitNode(cbNode, (<JSDocTypedefTag>node).fullName); 477 } 478 else { 479 return visitNode(cbNode, (<JSDocTypedefTag>node).fullName) || 480 visitNode(cbNode, (<JSDocTypedefTag>node).typeExpression); 481 } 482 case SyntaxKind.JSDocTypeLiteral: 483 if ((node as JSDocTypeLiteral).jsDocPropertyTags) { 484 for (const tag of (node as JSDocTypeLiteral).jsDocPropertyTags) { 485 visitNode(cbNode, tag); 486 } 487 } 488 return; 489 case SyntaxKind.PartiallyEmittedExpression: 490 return visitNode(cbNode, (<PartiallyEmittedExpression>node).expression); 491 } 492 } 493 494 export function createSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false, scriptKind?: ScriptKind): SourceFile { 495 performance.mark("beforeParse"); 496 const result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind); 497 performance.mark("afterParse"); 498 performance.measure("Parse", "beforeParse", "afterParse"); 499 return result; 500 } 501 502 export function parseIsolatedEntityName(text: string, languageVersion: ScriptTarget): EntityName { 503 return Parser.parseIsolatedEntityName(text, languageVersion); 504 } 505 506 /** 507 * Parse json text into SyntaxTree and return node and parse errors if any 508 * @param fileName 509 * @param sourceText 510 */ 511 export function parseJsonText(fileName: string, sourceText: string): JsonSourceFile { 512 return Parser.parseJsonText(fileName, sourceText); 513 } 514 515 // See also `isExternalOrCommonJsModule` in utilities.ts 516 export function isExternalModule(file: SourceFile): boolean { 517 return file.externalModuleIndicator !== undefined; 518 } 519 520 // Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter 521 // indicates what changed between the 'text' that this SourceFile has and the 'newText'. 522 // The SourceFile will be created with the compiler attempting to reuse as many nodes from 523 // this file as possible. 524 // 525 // Note: this function mutates nodes from this SourceFile. That means any existing nodes 526 // from this SourceFile that are being held onto may change as a result (including 527 // becoming detached from any SourceFile). It is recommended that this SourceFile not 528 // be used once 'update' is called on it. 529 export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile { 530 const newSourceFile = IncrementalParser.updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks); 531 // 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. 532 // We will manually port the flag to the new source file. 533 newSourceFile.flags |= (sourceFile.flags & NodeFlags.PossiblyContainsDynamicImport); 534 return newSourceFile; 535 } 536 537 /* @internal */ 538 export function parseIsolatedJSDocComment(content: string, start?: number, length?: number) { 539 const result = Parser.JSDocParser.parseIsolatedJSDocComment(content, start, length); 540 if (result && result.jsDoc) { 541 // because the jsDocComment was parsed out of the source file, it might 542 // not be covered by the fixupParentReferences. 543 Parser.fixupParentReferences(result.jsDoc); 544 } 545 546 return result; 547 } 548 549 /* @internal */ 550 // Exposed only for testing. 551 export function parseJSDocTypeExpressionForTests(content: string, start?: number, length?: number) { 552 return Parser.JSDocParser.parseJSDocTypeExpressionForTests(content, start, length); 553 } 554 555 // Implement the parser as a singleton module. We do this for perf reasons because creating 556 // parser instances can actually be expensive enough to impact us on projects with many source 557 // files. 558 namespace Parser { 559 // Share a single scanner across all calls to parse a source file. This helps speed things 560 // up by avoiding the cost of creating/compiling scanners over and over again. 561 const scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ true); 562 const disallowInAndDecoratorContext = NodeFlags.DisallowInContext | NodeFlags.DecoratorContext; 563 564 // capture constructors in 'initializeState' to avoid null checks 565 // tslint:disable variable-name 566 let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 567 let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 568 let IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 569 let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; 570 // tslint:enable variable-name 571 572 let sourceFile: SourceFile; 573 let parseDiagnostics: Diagnostic[]; 574 let syntaxCursor: IncrementalParser.SyntaxCursor; 575 576 let currentToken: SyntaxKind; 577 let sourceText: string; 578 let nodeCount: number; 579 let identifiers: Map<string>; 580 let identifierCount: number; 581 582 let parsingContext: ParsingContext; 583 584 // Flags that dictate what parsing context we're in. For example: 585 // Whether or not we are in strict parsing mode. All that changes in strict parsing mode is 586 // that some tokens that would be considered identifiers may be considered keywords. 587 // 588 // When adding more parser context flags, consider which is the more common case that the 589 // flag will be in. This should be the 'false' state for that flag. The reason for this is 590 // that we don't store data in our nodes unless the value is in the *non-default* state. So, 591 // for example, more often than code 'allows-in' (or doesn't 'disallow-in'). We opt for 592 // 'disallow-in' set to 'false'. Otherwise, if we had 'allowsIn' set to 'true', then almost 593 // all nodes would need extra state on them to store this info. 594 // 595 // Note: 'allowIn' and 'allowYield' track 1:1 with the [in] and [yield] concepts in the ES6 596 // grammar specification. 597 // 598 // An important thing about these context concepts. By default they are effectively inherited 599 // while parsing through every grammar production. i.e. if you don't change them, then when 600 // you parse a sub-production, it will have the same context values as the parent production. 601 // This is great most of the time. After all, consider all the 'expression' grammar productions 602 // and how nearly all of them pass along the 'in' and 'yield' context values: 603 // 604 // EqualityExpression[In, Yield] : 605 // RelationalExpression[?In, ?Yield] 606 // EqualityExpression[?In, ?Yield] == RelationalExpression[?In, ?Yield] 607 // EqualityExpression[?In, ?Yield] != RelationalExpression[?In, ?Yield] 608 // EqualityExpression[?In, ?Yield] === RelationalExpression[?In, ?Yield] 609 // EqualityExpression[?In, ?Yield] !== RelationalExpression[?In, ?Yield] 610 // 611 // Where you have to be careful is then understanding what the points are in the grammar 612 // where the values are *not* passed along. For example: 613 // 614 // SingleNameBinding[Yield,GeneratorParameter] 615 // [+GeneratorParameter]BindingIdentifier[Yield] Initializer[In]opt 616 // [~GeneratorParameter]BindingIdentifier[?Yield]Initializer[In, ?Yield]opt 617 // 618 // Here this is saying that if the GeneratorParameter context flag is set, that we should 619 // explicitly set the 'yield' context flag to false before calling into the BindingIdentifier 620 // and we should explicitly unset the 'yield' context flag before calling into the Initializer. 621 // production. Conversely, if the GeneratorParameter context flag is not set, then we 622 // should leave the 'yield' context flag alone. 623 // 624 // Getting this all correct is tricky and requires careful reading of the grammar to 625 // understand when these values should be changed versus when they should be inherited. 626 // 627 // Note: it should not be necessary to save/restore these flags during speculative/lookahead 628 // parsing. These context flags are naturally stored and restored through normal recursive 629 // descent parsing and unwinding. 630 let contextFlags: NodeFlags; 631 632 // Whether or not we've had a parse error since creating the last AST node. If we have 633 // encountered an error, it will be stored on the next AST node we create. Parse errors 634 // can be broken down into three categories: 635 // 636 // 1) An error that occurred during scanning. For example, an unterminated literal, or a 637 // character that was completely not understood. 638 // 639 // 2) A token was expected, but was not present. This type of error is commonly produced 640 // by the 'parseExpected' function. 641 // 642 // 3) A token was present that no parsing function was able to consume. This type of error 643 // only occurs in the 'abortParsingListOrMoveToNextToken' function when the parser 644 // decides to skip the token. 645 // 646 // In all of these cases, we want to mark the next node as having had an error before it. 647 // With this mark, we can know in incremental settings if this node can be reused, or if 648 // we have to reparse it. If we don't keep this information around, we may just reuse the 649 // node. in that event we would then not produce the same errors as we did before, causing 650 // significant confusion problems. 651 // 652 // Note: it is necessary that this value be saved/restored during speculative/lookahead 653 // parsing. During lookahead parsing, we will often create a node. That node will have 654 // this value attached, and then this value will be set back to 'false'. If we decide to 655 // rewind, we must get back to the same value we had prior to the lookahead. 656 // 657 // Note: any errors at the end of the file that do not precede a regular node, should get 658 // attached to the EOF token. 659 let parseErrorBeforeNextFinishedNode = false; 660 661 export function parseSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, syntaxCursor: IncrementalParser.SyntaxCursor, setParentNodes?: boolean, scriptKind?: ScriptKind): SourceFile { 662 scriptKind = ensureScriptKind(fileName, scriptKind); 663 664 initializeState(sourceText, languageVersion, syntaxCursor, scriptKind); 665 666 const result = parseSourceFileWorker(fileName, languageVersion, setParentNodes, scriptKind); 667 668 clearState(); 669 670 return result; 671 } 672 673 export function parseIsolatedEntityName(content: string, languageVersion: ScriptTarget): EntityName { 674 // Choice of `isDeclarationFile` should be arbitrary 675 initializeState(content, languageVersion, /*syntaxCursor*/ undefined, ScriptKind.JS); 676 // Prime the scanner. 677 nextToken(); 678 const entityName = parseEntityName(/*allowReservedWords*/ true); 679 const isInvalid = token() === SyntaxKind.EndOfFileToken && !parseDiagnostics.length; 680 clearState(); 681 return isInvalid ? entityName : undefined; 682 } 683 684 export function parseJsonText(fileName: string, sourceText: string): JsonSourceFile { 685 initializeState(sourceText, ScriptTarget.ES2015, /*syntaxCursor*/ undefined, ScriptKind.JSON); 686 // Set source file so that errors will be reported with this file name 687 sourceFile = createSourceFile(fileName, ScriptTarget.ES2015, ScriptKind.JSON, /*isDeclaration*/ false); 688 const result = <JsonSourceFile>sourceFile; 689 690 // Prime the scanner. 691 nextToken(); 692 if (token() === SyntaxKind.EndOfFileToken) { 693 sourceFile.endOfFileToken = <EndOfFileToken>parseTokenNode(); 694 } 695 else if (token() === SyntaxKind.OpenBraceToken || 696 lookAhead(() => token() === SyntaxKind.StringLiteral)) { 697 result.jsonObject = parseObjectLiteralExpression(); 698 sourceFile.endOfFileToken = parseExpectedToken(SyntaxKind.EndOfFileToken, Diagnostics.Unexpected_token); 699 } 700 else { 701 parseExpected(SyntaxKind.OpenBraceToken); 702 } 703 704 sourceFile.parseDiagnostics = parseDiagnostics; 705 clearState(); 706 return result; 707 } 708 709 function getLanguageVariant(scriptKind: ScriptKind) { 710 // .tsx and .jsx files are treated as jsx language variant. 711 return scriptKind === ScriptKind.TSX || scriptKind === ScriptKind.JSX || scriptKind === ScriptKind.JS || scriptKind === ScriptKind.JSON ? LanguageVariant.JSX : LanguageVariant.Standard; 712 } 713 714 function initializeState(_sourceText: string, languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor, scriptKind: ScriptKind) { 715 NodeConstructor = objectAllocator.getNodeConstructor(); 716 TokenConstructor = objectAllocator.getTokenConstructor(); 717 IdentifierConstructor = objectAllocator.getIdentifierConstructor(); 718 SourceFileConstructor = objectAllocator.getSourceFileConstructor(); 719 720 sourceText = _sourceText; 721 syntaxCursor = _syntaxCursor; 722 723 parseDiagnostics = []; 724 parsingContext = 0; 725 identifiers = createMap<string>(); 726 identifierCount = 0; 727 nodeCount = 0; 728 729 switch (scriptKind) { 730 case ScriptKind.JS: 731 case ScriptKind.JSX: 732 case ScriptKind.JSON: 733 contextFlags = NodeFlags.JavaScriptFile; 734 break; 735 default: 736 contextFlags = NodeFlags.None; 737 break; 738 } 739 parseErrorBeforeNextFinishedNode = false; 740 741 // Initialize and prime the scanner before parsing the source elements. 742 scanner.setText(sourceText); 743 scanner.setOnError(scanError); 744 scanner.setScriptTarget(languageVersion); 745 scanner.setLanguageVariant(getLanguageVariant(scriptKind)); 746 } 747 748 function clearState() { 749 // Clear out the text the scanner is pointing at, so it doesn't keep anything alive unnecessarily. 750 scanner.setText(""); 751 scanner.setOnError(undefined); 752 753 // Clear any data. We don't want to accidentally hold onto it for too long. 754 parseDiagnostics = undefined; 755 sourceFile = undefined; 756 identifiers = undefined; 757 syntaxCursor = undefined; 758 sourceText = undefined; 759 } 760 761 function parseSourceFileWorker(fileName: string, languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind): SourceFile { 762 const isDeclarationFile = isDeclarationFileName(fileName); 763 if (isDeclarationFile) { 764 contextFlags |= NodeFlags.Ambient; 765 } 766 767 sourceFile = createSourceFile(fileName, languageVersion, scriptKind, isDeclarationFile); 768 sourceFile.flags = contextFlags; 769 770 // Prime the scanner. 771 nextToken(); 772 processReferenceComments(sourceFile); 773 774 sourceFile.statements = parseList(ParsingContext.SourceElements, parseStatement); 775 Debug.assert(token() === SyntaxKind.EndOfFileToken); 776 sourceFile.endOfFileToken = addJSDocComment(parseTokenNode() as EndOfFileToken); 777 778 setExternalModuleIndicator(sourceFile); 779 780 sourceFile.nodeCount = nodeCount; 781 sourceFile.identifierCount = identifierCount; 782 sourceFile.identifiers = identifiers; 783 sourceFile.parseDiagnostics = parseDiagnostics; 784 785 if (setParentNodes) { 786 fixupParentReferences(sourceFile); 787 } 788 789 return sourceFile; 790 } 791 792 function addJSDocComment<T extends HasJSDoc>(node: T): T { 793 const comments = getJSDocCommentRanges(node, sourceFile.text); 794 if (comments) { 795 for (const comment of comments) { 796 node.jsDoc = append(node.jsDoc, JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos)); 797 } 798 } 799 800 return node; 801 } 802 803 export function fixupParentReferences(rootNode: Node) { 804 // normally parent references are set during binding. However, for clients that only need 805 // a syntax tree, and no semantic features, then the binding process is an unnecessary 806 // overhead. This functions allows us to set all the parents, without all the expense of 807 // binding. 808 809 let parent: Node = rootNode; 810 forEachChild(rootNode, visitNode); 811 return; 812 813 function visitNode(n: Node): void { 814 // walk down setting parents that differ from the parent we think it should be. This 815 // allows us to quickly bail out of setting parents for subtrees during incremental 816 // parsing 817 if (n.parent !== parent) { 818 n.parent = parent; 819 820 const saveParent = parent; 821 parent = n; 822 forEachChild(n, visitNode); 823 if (hasJSDocNodes(n)) { 824 for (const jsDoc of n.jsDoc) { 825 jsDoc.parent = n; 826 parent = jsDoc; 827 forEachChild(jsDoc, visitNode); 828 } 829 } 830 parent = saveParent; 831 } 832 } 833 } 834 835 function createSourceFile(fileName: string, languageVersion: ScriptTarget, scriptKind: ScriptKind, isDeclarationFile: boolean): SourceFile { 836 // code from createNode is inlined here so createNode won't have to deal with special case of creating source files 837 // this is quite rare comparing to other nodes and createNode should be as fast as possible 838 const sourceFile = <SourceFile>new SourceFileConstructor(SyntaxKind.SourceFile, /*pos*/ 0, /* end */ sourceText.length); 839 nodeCount++; 840 841 sourceFile.text = sourceText; 842 sourceFile.bindDiagnostics = []; 843 sourceFile.languageVersion = languageVersion; 844 sourceFile.fileName = normalizePath(fileName); 845 sourceFile.languageVariant = getLanguageVariant(scriptKind); 846 sourceFile.isDeclarationFile = isDeclarationFile; 847 sourceFile.scriptKind = scriptKind; 848 849 return sourceFile; 850 } 851 852 function setContextFlag(val: boolean, flag: NodeFlags) { 853 if (val) { 854 contextFlags |= flag; 855 } 856 else { 857 contextFlags &= ~flag; 858 } 859 } 860 861 function setDisallowInContext(val: boolean) { 862 setContextFlag(val, NodeFlags.DisallowInContext); 863 } 864 865 function setYieldContext(val: boolean) { 866 setContextFlag(val, NodeFlags.YieldContext); 867 } 868 869 function setDecoratorContext(val: boolean) { 870 setContextFlag(val, NodeFlags.DecoratorContext); 871 } 872 873 function setAwaitContext(val: boolean) { 874 setContextFlag(val, NodeFlags.AwaitContext); 875 } 876 877 function doOutsideOfContext<T>(context: NodeFlags, func: () => T): T { 878 // contextFlagsToClear will contain only the context flags that are 879 // currently set that we need to temporarily clear 880 // We don't just blindly reset to the previous flags to ensure 881 // that we do not mutate cached flags for the incremental 882 // parser (ThisNodeHasError, ThisNodeOrAnySubNodesHasError, and 883 // HasAggregatedChildData). 884 const contextFlagsToClear = context & contextFlags; 885 if (contextFlagsToClear) { 886 // clear the requested context flags 887 setContextFlag(/*val*/ false, contextFlagsToClear); 888 const result = func(); 889 // restore the context flags we just cleared 890 setContextFlag(/*val*/ true, contextFlagsToClear); 891 return result; 892 } 893 894 // no need to do anything special as we are not in any of the requested contexts 895 return func(); 896 } 897 898 function doInsideOfContext<T>(context: NodeFlags, func: () => T): T { 899 // contextFlagsToSet will contain only the context flags that 900 // are not currently set that we need to temporarily enable. 901 // We don't just blindly reset to the previous flags to ensure 902 // that we do not mutate cached flags for the incremental 903 // parser (ThisNodeHasError, ThisNodeOrAnySubNodesHasError, and 904 // HasAggregatedChildData). 905 const contextFlagsToSet = context & ~contextFlags; 906 if (contextFlagsToSet) { 907 // set the requested context flags 908 setContextFlag(/*val*/ true, contextFlagsToSet); 909 const result = func(); 910 // reset the context flags we just set 911 setContextFlag(/*val*/ false, contextFlagsToSet); 912 return result; 913 } 914 915 // no need to do anything special as we are already in all of the requested contexts 916 return func(); 917 } 918 919 function allowInAnd<T>(func: () => T): T { 920 return doOutsideOfContext(NodeFlags.DisallowInContext, func); 921 } 922 923 function disallowInAnd<T>(func: () => T): T { 924 return doInsideOfContext(NodeFlags.DisallowInContext, func); 925 } 926 927 function doInYieldContext<T>(func: () => T): T { 928 return doInsideOfContext(NodeFlags.YieldContext, func); 929 } 930 931 function doInDecoratorContext<T>(func: () => T): T { 932 return doInsideOfContext(NodeFlags.DecoratorContext, func); 933 } 934 935 function doInAwaitContext<T>(func: () => T): T { 936 return doInsideOfContext(NodeFlags.AwaitContext, func); 937 } 938 939 function doOutsideOfAwaitContext<T>(func: () => T): T { 940 return doOutsideOfContext(NodeFlags.AwaitContext, func); 941 } 942 943 function doInYieldAndAwaitContext<T>(func: () => T): T { 944 return doInsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext, func); 945 } 946 947 function inContext(flags: NodeFlags) { 948 return (contextFlags & flags) !== 0; 949 } 950 951 function inYieldContext() { 952 return inContext(NodeFlags.YieldContext); 953 } 954 955 function inDisallowInContext() { 956 return inContext(NodeFlags.DisallowInContext); 957 } 958 959 function inDecoratorContext() { 960 return inContext(NodeFlags.DecoratorContext); 961 } 962 963 function inAwaitContext() { 964 return inContext(NodeFlags.AwaitContext); 965 } 966 967 function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any): void { 968 const start = scanner.getTokenPos(); 969 const length = scanner.getTextPos() - start; 970 971 parseErrorAtPosition(start, length, message, arg0); 972 } 973 974 function parseErrorAtPosition(start: number, length: number, message: DiagnosticMessage, arg0?: any): void { 975 // Don't report another error if it would just be at the same position as the last error. 976 const lastError = lastOrUndefined(parseDiagnostics); 977 if (!lastError || start !== lastError.start) { 978 parseDiagnostics.push(createFileDiagnostic(sourceFile, start, length, message, arg0)); 979 } 980 981 // Mark that we've encountered an error. We'll set an appropriate bit on the next 982 // node we finish so that it can't be reused incrementally. 983 parseErrorBeforeNextFinishedNode = true; 984 } 985 986 function scanError(message: DiagnosticMessage, length?: number) { 987 const pos = scanner.getTextPos(); 988 parseErrorAtPosition(pos, length || 0, message); 989 } 990 991 function getNodePos(): number { 992 return scanner.getStartPos(); 993 } 994 995 // Use this function to access the current token instead of reading the currentToken 996 // variable. Since function results aren't narrowed in control flow analysis, this ensures 997 // that the type checker doesn't make wrong assumptions about the type of the current 998 // token (e.g. a call to nextToken() changes the current token but the checker doesn't 999 // reason about this side effect). Mainstream VMs inline simple functions like this, so 1000 // there is no performance penalty. 1001 function token(): SyntaxKind { 1002 return currentToken; 1003 } 1004 1005 function nextToken(): SyntaxKind { 1006 return currentToken = scanner.scan(); 1007 } 1008 1009 function reScanGreaterToken(): SyntaxKind { 1010 return currentToken = scanner.reScanGreaterToken(); 1011 } 1012 1013 function reScanSlashToken(): SyntaxKind { 1014 return currentToken = scanner.reScanSlashToken(); 1015 } 1016 1017 function reScanTemplateToken(): SyntaxKind { 1018 return currentToken = scanner.reScanTemplateToken(); 1019 } 1020 1021 function scanJsxIdentifier(): SyntaxKind { 1022 return currentToken = scanner.scanJsxIdentifier(); 1023 } 1024 1025 function scanJsxText(): SyntaxKind { 1026 return currentToken = scanner.scanJsxToken(); 1027 } 1028 1029 function scanJsxAttributeValue(): SyntaxKind { 1030 return currentToken = scanner.scanJsxAttributeValue(); 1031 } 1032 1033 function speculationHelper<T>(callback: () => T, isLookAhead: boolean): T { 1034 // Keep track of the state we'll need to rollback to if lookahead fails (or if the 1035 // caller asked us to always reset our state). 1036 const saveToken = currentToken; 1037 const saveParseDiagnosticsLength = parseDiagnostics.length; 1038 const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode; 1039 1040 // Note: it is not actually necessary to save/restore the context flags here. That's 1041 // because the saving/restoring of these flags happens naturally through the recursive 1042 // descent nature of our parser. However, we still store this here just so we can 1043 // assert that invariant holds. 1044 const saveContextFlags = contextFlags; 1045 1046 // If we're only looking ahead, then tell the scanner to only lookahead as well. 1047 // Otherwise, if we're actually speculatively parsing, then tell the scanner to do the 1048 // same. 1049 const result = isLookAhead 1050 ? scanner.lookAhead(callback) 1051 : scanner.tryScan(callback); 1052 1053 Debug.assert(saveContextFlags === contextFlags); 1054 1055 // If our callback returned something 'falsy' or we're just looking ahead, 1056 // then unconditionally restore us to where we were. 1057 if (!result || isLookAhead) { 1058 currentToken = saveToken; 1059 parseDiagnostics.length = saveParseDiagnosticsLength; 1060 parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode; 1061 } 1062 1063 return result; 1064 } 1065 1066 /** Invokes the provided callback then unconditionally restores the parser to the state it 1067 * was in immediately prior to invoking the callback. The result of invoking the callback 1068 * is returned from this function. 1069 */ 1070 function lookAhead<T>(callback: () => T): T { 1071 return speculationHelper(callback, /*isLookAhead*/ true); 1072 } 1073 1074 /** Invokes the provided callback. If the callback returns something falsy, then it restores 1075 * the parser to the state it was in immediately prior to invoking the callback. If the 1076 * callback returns something truthy, then the parser state is not rolled back. The result 1077 * of invoking the callback is returned from this function. 1078 */ 1079 function tryParse<T>(callback: () => T): T { 1080 return speculationHelper(callback, /*isLookAhead*/ false); 1081 } 1082 1083 // Ignore strict mode flag because we will report an error in type checker instead. 1084 function isIdentifier(): boolean { 1085 if (token() === SyntaxKind.Identifier) { 1086 return true; 1087 } 1088 1089 // If we have a 'yield' keyword, and we're in the [yield] context, then 'yield' is 1090 // considered a keyword and is not an identifier. 1091 if (token() === SyntaxKind.YieldKeyword && inYieldContext()) { 1092 return false; 1093 } 1094 1095 // If we have a 'await' keyword, and we're in the [Await] context, then 'await' is 1096 // considered a keyword and is not an identifier. 1097 if (token() === SyntaxKind.AwaitKeyword && inAwaitContext()) { 1098 return false; 1099 } 1100 1101 return token() > SyntaxKind.LastReservedWord; 1102 } 1103 1104 function parseExpected(kind: SyntaxKind, diagnosticMessage?: DiagnosticMessage, shouldAdvance = true): boolean { 1105 if (token() === kind) { 1106 if (shouldAdvance) { 1107 nextToken(); 1108 } 1109 return true; 1110 } 1111 1112 // Report specific message if provided with one. Otherwise, report generic fallback message. 1113 if (diagnosticMessage) { 1114 parseErrorAtCurrentToken(diagnosticMessage); 1115 } 1116 else { 1117 parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind)); 1118 } 1119 return false; 1120 } 1121 1122 function parseOptional(t: SyntaxKind): boolean { 1123 if (token() === t) { 1124 nextToken(); 1125 return true; 1126 } 1127 return false; 1128 } 1129 1130 function parseOptionalToken<TKind extends SyntaxKind>(t: TKind): Token<TKind>; 1131 function parseOptionalToken(t: SyntaxKind): Node { 1132 if (token() === t) { 1133 return parseTokenNode(); 1134 } 1135 return undefined; 1136 } 1137 1138 function parseExpectedToken<TKind extends SyntaxKind>(t: TKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Token<TKind>; 1139 function parseExpectedToken(t: SyntaxKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Node { 1140 return parseOptionalToken(t) || 1141 createMissingNode(t, /*reportAtCurrentPosition*/ false, diagnosticMessage || Diagnostics._0_expected, arg0 || tokenToString(t)); 1142 } 1143 1144 function parseTokenNode<T extends Node>(): T { 1145 const node = <T>createNode(token()); 1146 nextToken(); 1147 return finishNode(node); 1148 } 1149 1150 function canParseSemicolon() { 1151 // If there's a real semicolon, then we can always parse it out. 1152 if (token() === SyntaxKind.SemicolonToken) { 1153 return true; 1154 } 1155 1156 // We can parse out an optional semicolon in ASI cases in the following cases. 1157 return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.EndOfFileToken || scanner.hasPrecedingLineBreak(); 1158 } 1159 1160 function parseSemicolon(): boolean { 1161 if (canParseSemicolon()) { 1162 if (token() === SyntaxKind.SemicolonToken) { 1163 // consume the semicolon if it was explicitly provided. 1164 nextToken(); 1165 } 1166 1167 return true; 1168 } 1169 else { 1170 return parseExpected(SyntaxKind.SemicolonToken); 1171 } 1172 } 1173 1174 function createNode(kind: SyntaxKind, pos?: number): Node { 1175 nodeCount++; 1176 const p = pos >= 0 ? pos : scanner.getStartPos(); 1177 return isNodeKind(kind) || kind === SyntaxKind.Unknown ? new NodeConstructor(kind, p, p) : 1178 kind === SyntaxKind.Identifier ? new IdentifierConstructor(kind, p, p) : 1179 new TokenConstructor(kind, p, p); 1180 } 1181 1182 function createNodeWithJSDoc(kind: SyntaxKind): Node { 1183 const node = createNode(kind); 1184 if (scanner.getTokenFlags() & TokenFlags.PrecedingJSDocComment) { 1185 addJSDocComment(<HasJSDoc>node); 1186 } 1187 return node; 1188 } 1189 1190 function createNodeArray<T extends Node>(elements: T[], pos: number, end?: number): NodeArray<T> { 1191 // Since the element list of a node array is typically created by starting with an empty array and 1192 // repeatedly calling push(), the list may not have the optimal memory layout. We invoke slice() for 1193 // small arrays (1 to 4 elements) to give the VM a chance to allocate an optimal representation. 1194 const length = elements.length; 1195 const array = <MutableNodeArray<T>>(length >= 1 && length <= 4 ? elements.slice() : elements); 1196 array.pos = pos; 1197 array.end = end === undefined ? scanner.getStartPos() : end; 1198 return array; 1199 } 1200 1201 function finishNode<T extends Node>(node: T, end?: number): T { 1202 node.end = end === undefined ? scanner.getStartPos() : end; 1203 1204 if (contextFlags) { 1205 node.flags |= contextFlags; 1206 } 1207 1208 // Keep track on the node if we encountered an error while parsing it. If we did, then 1209 // we cannot reuse the node incrementally. Once we've marked this node, clear out the 1210 // flag so that we don't mark any subsequent nodes. 1211 if (parseErrorBeforeNextFinishedNode) { 1212 parseErrorBeforeNextFinishedNode = false; 1213 node.flags |= NodeFlags.ThisNodeHasError; 1214 } 1215 1216 return node; 1217 } 1218 1219 function createMissingNode<T extends Node>(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): T { 1220 if (reportAtCurrentPosition) { 1221 parseErrorAtPosition(scanner.getStartPos(), 0, diagnosticMessage, arg0); 1222 } 1223 else { 1224 parseErrorAtCurrentToken(diagnosticMessage, arg0); 1225 } 1226 1227 const result = createNode(kind); 1228 1229 if (kind === SyntaxKind.Identifier) { 1230 (result as Identifier).escapedText = "" as __String; 1231 } 1232 else if (isLiteralKind(kind) || isTemplateLiteralKind(kind)) { 1233 (result as LiteralLikeNode).text = ""; 1234 } 1235 1236 return finishNode(result) as T; 1237 } 1238 1239 function internIdentifier(text: string): string { 1240 let identifier = identifiers.get(text); 1241 if (identifier === undefined) { 1242 identifiers.set(text, identifier = text); 1243 } 1244 return identifier; 1245 } 1246 1247 // An identifier that starts with two underscores has an extra underscore character prepended to it to avoid issues 1248 // with magic property names like '__proto__'. The 'identifiers' object is used to share a single string instance for 1249 // each identifier in order to reduce memory consumption. 1250 function createIdentifier(isIdentifier: boolean, diagnosticMessage?: DiagnosticMessage): Identifier { 1251 identifierCount++; 1252 if (isIdentifier) { 1253 const node = <Identifier>createNode(SyntaxKind.Identifier); 1254 1255 // Store original token kind if it is not just an Identifier so we can report appropriate error later in type checker 1256 if (token() !== SyntaxKind.Identifier) { 1257 node.originalKeywordKind = token(); 1258 } 1259 node.escapedText = escapeLeadingUnderscores(internIdentifier(scanner.getTokenValue())); 1260 nextToken(); 1261 return finishNode(node); 1262 } 1263 1264 // Only for end of file because the error gets reported incorrectly on embedded script tags. 1265 const reportAtCurrentPosition = token() === SyntaxKind.EndOfFileToken; 1266 1267 return createMissingNode<Identifier>(SyntaxKind.Identifier, reportAtCurrentPosition, diagnosticMessage || Diagnostics.Identifier_expected); 1268 } 1269 1270 function parseIdentifier(diagnosticMessage?: DiagnosticMessage): Identifier { 1271 return createIdentifier(isIdentifier(), diagnosticMessage); 1272 } 1273 1274 function parseIdentifierName(diagnosticMessage?: DiagnosticMessage): Identifier { 1275 return createIdentifier(tokenIsIdentifierOrKeyword(token()), diagnosticMessage); 1276 } 1277 1278 function isLiteralPropertyName(): boolean { 1279 return tokenIsIdentifierOrKeyword(token()) || 1280 token() === SyntaxKind.StringLiteral || 1281 token() === SyntaxKind.NumericLiteral; 1282 } 1283 1284 function parsePropertyNameWorker(allowComputedPropertyNames: boolean): PropertyName { 1285 if (token() === SyntaxKind.StringLiteral || token() === SyntaxKind.NumericLiteral) { 1286 const node = <StringLiteral | NumericLiteral>parseLiteralNode(); 1287 node.text = internIdentifier(node.text); 1288 return node; 1289 } 1290 if (allowComputedPropertyNames && token() === SyntaxKind.OpenBracketToken) { 1291 return parseComputedPropertyName(); 1292 } 1293 return parseIdentifierName(); 1294 } 1295 1296 function parsePropertyName(): PropertyName { 1297 return parsePropertyNameWorker(/*allowComputedPropertyNames*/ true); 1298 } 1299 1300 function parseComputedPropertyName(): ComputedPropertyName { 1301 // PropertyName [Yield]: 1302 // LiteralPropertyName 1303 // ComputedPropertyName[?Yield] 1304 const node = <ComputedPropertyName>createNode(SyntaxKind.ComputedPropertyName); 1305 parseExpected(SyntaxKind.OpenBracketToken); 1306 1307 // We parse any expression (including a comma expression). But the grammar 1308 // says that only an assignment expression is allowed, so the grammar checker 1309 // will error if it sees a comma expression. 1310 node.expression = allowInAnd(parseExpression); 1311 1312 parseExpected(SyntaxKind.CloseBracketToken); 1313 return finishNode(node); 1314 } 1315 1316 function parseContextualModifier(t: SyntaxKind): boolean { 1317 return token() === t && tryParse(nextTokenCanFollowModifier); 1318 } 1319 1320 function nextTokenIsOnSameLineAndCanFollowModifier() { 1321 nextToken(); 1322 if (scanner.hasPrecedingLineBreak()) { 1323 return false; 1324 } 1325 return canFollowModifier(); 1326 } 1327 1328 function nextTokenCanFollowModifier() { 1329 if (token() === SyntaxKind.ConstKeyword) { 1330 // 'const' is only a modifier if followed by 'enum'. 1331 return nextToken() === SyntaxKind.EnumKeyword; 1332 } 1333 if (token() === SyntaxKind.ExportKeyword) { 1334 nextToken(); 1335 if (token() === SyntaxKind.DefaultKeyword) { 1336 return lookAhead(nextTokenCanFollowDefaultKeyword); 1337 } 1338 return token() !== SyntaxKind.AsteriskToken && token() !== SyntaxKind.AsKeyword && token() !== SyntaxKind.OpenBraceToken && canFollowModifier(); 1339 } 1340 if (token() === SyntaxKind.DefaultKeyword) { 1341 return nextTokenCanFollowDefaultKeyword(); 1342 } 1343 if (token() === SyntaxKind.StaticKeyword) { 1344 nextToken(); 1345 return canFollowModifier(); 1346 } 1347 1348 return nextTokenIsOnSameLineAndCanFollowModifier(); 1349 } 1350 1351 function parseAnyContextualModifier(): boolean { 1352 return isModifierKind(token()) && tryParse(nextTokenCanFollowModifier); 1353 } 1354 1355 function canFollowModifier(): boolean { 1356 return token() === SyntaxKind.OpenBracketToken 1357 || token() === SyntaxKind.OpenBraceToken 1358 || token() === SyntaxKind.AsteriskToken 1359 || token() === SyntaxKind.DotDotDotToken 1360 || isLiteralPropertyName(); 1361 } 1362 1363 function nextTokenCanFollowDefaultKeyword(): boolean { 1364 nextToken(); 1365 return token() === SyntaxKind.ClassKeyword || token() === SyntaxKind.FunctionKeyword || 1366 token() === SyntaxKind.InterfaceKeyword || 1367 (token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsClassKeywordOnSameLine)) || 1368 (token() === SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsFunctionKeywordOnSameLine)); 1369 } 1370 1371 // True if positioned at the start of a list element 1372 function isListElement(parsingContext: ParsingContext, inErrorRecovery: boolean): boolean { 1373 const node = currentNode(parsingContext); 1374 if (node) { 1375 return true; 1376 } 1377 1378 switch (parsingContext) { 1379 case ParsingContext.SourceElements: 1380 case ParsingContext.BlockStatements: 1381 case ParsingContext.SwitchClauseStatements: 1382 // If we're in error recovery, then we don't want to treat ';' as an empty statement. 1383 // The problem is that ';' can show up in far too many contexts, and if we see one 1384 // and assume it's a statement, then we may bail out inappropriately from whatever 1385 // we're parsing. For example, if we have a semicolon in the middle of a class, then 1386 // we really don't want to assume the class is over and we're on a statement in the 1387 // outer module. We just want to consume and move on. 1388 return !(token() === SyntaxKind.SemicolonToken && inErrorRecovery) && isStartOfStatement(); 1389 case ParsingContext.SwitchClauses: 1390 return token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword; 1391 case ParsingContext.TypeMembers: 1392 return lookAhead(isTypeMemberStart); 1393 case ParsingContext.ClassMembers: 1394 // We allow semicolons as class elements (as specified by ES6) as long as we're 1395 // not in error recovery. If we're in error recovery, we don't want an errant 1396 // semicolon to be treated as a class member (since they're almost always used 1397 // for statements. 1398 return lookAhead(isClassMemberStart) || (token() === SyntaxKind.SemicolonToken && !inErrorRecovery); 1399 case ParsingContext.EnumMembers: 1400 // Include open bracket computed properties. This technically also lets in indexers, 1401 // which would be a candidate for improved error reporting. 1402 return token() === SyntaxKind.OpenBracketToken || isLiteralPropertyName(); 1403 case ParsingContext.ObjectLiteralMembers: 1404 return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.AsteriskToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName(); 1405 case ParsingContext.RestProperties: 1406 return isLiteralPropertyName(); 1407 case ParsingContext.ObjectBindingElements: 1408 return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName(); 1409 case ParsingContext.HeritageClauseElement: 1410 // If we see `{ ... }` then only consume it as an expression if it is followed by `,` or `{` 1411 // That way we won't consume the body of a class in its heritage clause. 1412 if (token() === SyntaxKind.OpenBraceToken) { 1413 return lookAhead(isValidHeritageClauseObjectLiteral); 1414 } 1415 1416 if (!inErrorRecovery) { 1417 return isStartOfLeftHandSideExpression() && !isHeritageClauseExtendsOrImplementsKeyword(); 1418 } 1419 else { 1420 // If we're in error recovery we tighten up what we're willing to match. 1421 // That way we don't treat something like "this" as a valid heritage clause 1422 // element during recovery. 1423 return isIdentifier() && !isHeritageClauseExtendsOrImplementsKeyword(); 1424 } 1425 case ParsingContext.VariableDeclarations: 1426 return isIdentifierOrPattern(); 1427 case ParsingContext.ArrayBindingElements: 1428 return token() === SyntaxKind.CommaToken || token() === SyntaxKind.DotDotDotToken || isIdentifierOrPattern(); 1429 case ParsingContext.TypeParameters: 1430 return isIdentifier(); 1431 case ParsingContext.ArrayLiteralMembers: 1432 if (token() === SyntaxKind.CommaToken) { 1433 return true; 1434 } 1435 // falls through 1436 case ParsingContext.ArgumentExpressions: 1437 return token() === SyntaxKind.DotDotDotToken || isStartOfExpression(); 1438 case ParsingContext.Parameters: 1439 return isStartOfParameter(); 1440 case ParsingContext.TypeArguments: 1441 case ParsingContext.TupleElementTypes: 1442 return token() === SyntaxKind.CommaToken || isStartOfType(); 1443 case ParsingContext.HeritageClauses: 1444 return isHeritageClause(); 1445 case ParsingContext.ImportOrExportSpecifiers: 1446 return tokenIsIdentifierOrKeyword(token()); 1447 case ParsingContext.JsxAttributes: 1448 return tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.OpenBraceToken; 1449 case ParsingContext.JsxChildren: 1450 return true; 1451 } 1452 1453 Debug.fail("Non-exhaustive case in 'isListElement'."); 1454 } 1455 1456 function isValidHeritageClauseObjectLiteral() { 1457 Debug.assert(token() === SyntaxKind.OpenBraceToken); 1458 if (nextToken() === SyntaxKind.CloseBraceToken) { 1459 // if we see "extends {}" then only treat the {} as what we're extending (and not 1460 // the class body) if we have: 1461 // 1462 // extends {} { 1463 // extends {}, 1464 // extends {} extends 1465 // extends {} implements 1466 1467 const next = nextToken(); 1468 return next === SyntaxKind.CommaToken || next === SyntaxKind.OpenBraceToken || next === SyntaxKind.ExtendsKeyword || next === SyntaxKind.ImplementsKeyword; 1469 } 1470 1471 return true; 1472 } 1473 1474 function nextTokenIsIdentifier() { 1475 nextToken(); 1476 return isIdentifier(); 1477 } 1478 1479 function nextTokenIsIdentifierOrKeyword() { 1480 nextToken(); 1481 return tokenIsIdentifierOrKeyword(token()); 1482 } 1483 1484 function nextTokenIsIdentifierOrKeywordOrGreaterThan() { 1485 nextToken(); 1486 return tokenIsIdentifierOrKeywordOrGreaterThan(token()); 1487 } 1488 1489 function isHeritageClauseExtendsOrImplementsKeyword(): boolean { 1490 if (token() === SyntaxKind.ImplementsKeyword || 1491 token() === SyntaxKind.ExtendsKeyword) { 1492 1493 return lookAhead(nextTokenIsStartOfExpression); 1494 } 1495 1496 return false; 1497 } 1498 1499 function nextTokenIsStartOfExpression() { 1500 nextToken(); 1501 return isStartOfExpression(); 1502 } 1503 1504 function nextTokenIsStartOfType() { 1505 nextToken(); 1506 return isStartOfType(); 1507 } 1508 1509 // True if positioned at a list terminator 1510 function isListTerminator(kind: ParsingContext): boolean { 1511 if (token() === SyntaxKind.EndOfFileToken) { 1512 // Being at the end of the file ends all lists. 1513 return true; 1514 } 1515 1516 switch (kind) { 1517 case ParsingContext.BlockStatements: 1518 case ParsingContext.SwitchClauses: 1519 case ParsingContext.TypeMembers: 1520 case ParsingContext.ClassMembers: 1521 case ParsingContext.EnumMembers: 1522 case ParsingContext.ObjectLiteralMembers: 1523 case ParsingContext.ObjectBindingElements: 1524 case ParsingContext.ImportOrExportSpecifiers: 1525 return token() === SyntaxKind.CloseBraceToken; 1526 case ParsingContext.SwitchClauseStatements: 1527 return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword; 1528 case ParsingContext.HeritageClauseElement: 1529 return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword; 1530 case ParsingContext.VariableDeclarations: 1531 return isVariableDeclaratorListTerminator(); 1532 case ParsingContext.TypeParameters: 1533 // Tokens other than '>' are here for better error recovery 1534 return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword; 1535 case ParsingContext.ArgumentExpressions: 1536 // Tokens other than ')' are here for better error recovery 1537 return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.SemicolonToken; 1538 case ParsingContext.ArrayLiteralMembers: 1539 case ParsingContext.TupleElementTypes: 1540 case ParsingContext.ArrayBindingElements: 1541 return token() === SyntaxKind.CloseBracketToken; 1542 case ParsingContext.Parameters: 1543 case ParsingContext.RestProperties: 1544 // Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery 1545 return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.CloseBracketToken /*|| token === SyntaxKind.OpenBraceToken*/; 1546 case ParsingContext.TypeArguments: 1547 // All other tokens should cause the type-argument to terminate except comma token 1548 return token() !== SyntaxKind.CommaToken; 1549 case ParsingContext.HeritageClauses: 1550 return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.CloseBraceToken; 1551 case ParsingContext.JsxAttributes: 1552 return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.SlashToken; 1553 case ParsingContext.JsxChildren: 1554 return token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsSlash); 1555 } 1556 } 1557 1558 function isVariableDeclaratorListTerminator(): boolean { 1559 // If we can consume a semicolon (either explicitly, or with ASI), then consider us done 1560 // with parsing the list of variable declarators. 1561 if (canParseSemicolon()) { 1562 return true; 1563 } 1564 1565 // in the case where we're parsing the variable declarator of a 'for-in' statement, we 1566 // are done if we see an 'in' keyword in front of us. Same with for-of 1567 if (isInOrOfKeyword(token())) { 1568 return true; 1569 } 1570 1571 // ERROR RECOVERY TWEAK: 1572 // For better error recovery, if we see an '=>' then we just stop immediately. We've got an 1573 // arrow function here and it's going to be very unlikely that we'll resynchronize and get 1574 // another variable declaration. 1575 if (token() === SyntaxKind.EqualsGreaterThanToken) { 1576 return true; 1577 } 1578 1579 // Keep trying to parse out variable declarators. 1580 return false; 1581 } 1582 1583 // True if positioned at element or terminator of the current list or any enclosing list 1584 function isInSomeParsingContext(): boolean { 1585 for (let kind = 0; kind < ParsingContext.Count; kind++) { 1586 if (parsingContext & (1 << kind)) { 1587 if (isListElement(kind, /*inErrorRecovery*/ true) || isListTerminator(kind)) { 1588 return true; 1589 } 1590 } 1591 } 1592 1593 return false; 1594 } 1595 1596 // Parses a list of elements 1597 function parseList<T extends Node>(kind: ParsingContext, parseElement: () => T): NodeArray<T> { 1598 const saveParsingContext = parsingContext; 1599 parsingContext |= 1 << kind; 1600 const list = []; 1601 const listPos = getNodePos(); 1602 1603 while (!isListTerminator(kind)) { 1604 if (isListElement(kind, /*inErrorRecovery*/ false)) { 1605 const element = parseListElement(kind, parseElement); 1606 list.push(element); 1607 1608 continue; 1609 } 1610 1611 if (abortParsingListOrMoveToNextToken(kind)) { 1612 break; 1613 } 1614 } 1615 1616 parsingContext = saveParsingContext; 1617 return createNodeArray(list, listPos); 1618 } 1619 1620 function parseListElement<T extends Node>(parsingContext: ParsingContext, parseElement: () => T): T { 1621 const node = currentNode(parsingContext); 1622 if (node) { 1623 return <T>consumeNode(node); 1624 } 1625 1626 return parseElement(); 1627 } 1628 1629 function currentNode(parsingContext: ParsingContext): Node { 1630 // If there is an outstanding parse error that we've encountered, but not attached to 1631 // some node, then we cannot get a node from the old source tree. This is because we 1632 // want to mark the next node we encounter as being unusable. 1633 // 1634 // Note: This may be too conservative. Perhaps we could reuse the node and set the bit 1635 // on it (or its leftmost child) as having the error. For now though, being conservative 1636 // is nice and likely won't ever affect perf. 1637 if (parseErrorBeforeNextFinishedNode) { 1638 return undefined; 1639 } 1640 1641 if (!syntaxCursor) { 1642 // if we don't have a cursor, we could never return a node from the old tree. 1643 return undefined; 1644 } 1645 1646 const node = syntaxCursor.currentNode(scanner.getStartPos()); 1647 1648 // Can't reuse a missing node. 1649 if (nodeIsMissing(node)) { 1650 return undefined; 1651 } 1652 1653 // Can't reuse a node that intersected the change range. 1654 if (node.intersectsChange) { 1655 return undefined; 1656 } 1657 1658 // Can't reuse a node that contains a parse error. This is necessary so that we 1659 // produce the same set of errors again. 1660 if (containsParseError(node)) { 1661 return undefined; 1662 } 1663 1664 // We can only reuse a node if it was parsed under the same strict mode that we're 1665 // currently in. i.e. if we originally parsed a node in non-strict mode, but then 1666 // the user added 'using strict' at the top of the file, then we can't use that node 1667 // again as the presence of strict mode may cause us to parse the tokens in the file 1668 // differently. 1669 // 1670 // Note: we *can* reuse tokens when the strict mode changes. That's because tokens 1671 // are unaffected by strict mode. It's just the parser will decide what to do with it 1672 // differently depending on what mode it is in. 1673 // 1674 // This also applies to all our other context flags as well. 1675 const nodeContextFlags = node.flags & NodeFlags.ContextFlags; 1676 if (nodeContextFlags !== contextFlags) { 1677 return undefined; 1678 } 1679 1680 // Ok, we have a node that looks like it could be reused. Now verify that it is valid 1681 // in the current list parsing context that we're currently at. 1682 if (!canReuseNode(node, parsingContext)) { 1683 return undefined; 1684 } 1685 1686 if ((node as JSDocContainer).jsDocCache) { 1687 // jsDocCache may include tags from parent nodes, which might have been modified. 1688 (node as JSDocContainer).jsDocCache = undefined; 1689 } 1690 1691 return node; 1692 } 1693 1694 function consumeNode(node: Node) { 1695 // Move the scanner so it is after the node we just consumed. 1696 scanner.setTextPos(node.end); 1697 nextToken(); 1698 return node; 1699 } 1700 1701 function canReuseNode(node: Node, parsingContext: ParsingContext): boolean { 1702 switch (parsingContext) { 1703 case ParsingContext.ClassMembers: 1704 return isReusableClassMember(node); 1705 1706 case ParsingContext.SwitchClauses: 1707 return isReusableSwitchClause(node); 1708 1709 case ParsingContext.SourceElements: 1710 case ParsingContext.BlockStatements: 1711 case ParsingContext.SwitchClauseStatements: 1712 return isReusableStatement(node); 1713 1714 case ParsingContext.EnumMembers: 1715 return isReusableEnumMember(node); 1716 1717 case ParsingContext.TypeMembers: 1718 return isReusableTypeMember(node); 1719 1720 case ParsingContext.VariableDeclarations: 1721 return isReusableVariableDeclaration(node); 1722 1723 case ParsingContext.Parameters: 1724 return isReusableParameter(node); 1725 1726 case ParsingContext.RestProperties: 1727 return false; 1728 1729 // Any other lists we do not care about reusing nodes in. But feel free to add if 1730 // you can do so safely. Danger areas involve nodes that may involve speculative 1731 // parsing. If speculative parsing is involved with the node, then the range the 1732 // parser reached while looking ahead might be in the edited range (see the example 1733 // in canReuseVariableDeclaratorNode for a good case of this). 1734 case ParsingContext.HeritageClauses: 1735 // This would probably be safe to reuse. There is no speculative parsing with 1736 // heritage clauses. 1737 1738 case ParsingContext.TypeParameters: 1739 // This would probably be safe to reuse. There is no speculative parsing with 1740 // type parameters. Note that that's because type *parameters* only occur in 1741 // unambiguous *type* contexts. While type *arguments* occur in very ambiguous 1742 // *expression* contexts. 1743 1744 case ParsingContext.TupleElementTypes: 1745 // This would probably be safe to reuse. There is no speculative parsing with 1746 // tuple types. 1747 1748 // Technically, type argument list types are probably safe to reuse. While 1749 // speculative parsing is involved with them (since type argument lists are only 1750 // produced from speculative parsing a < as a type argument list), we only have 1751 // the types because speculative parsing succeeded. Thus, the lookahead never 1752 // went past the end of the list and rewound. 1753 case ParsingContext.TypeArguments: 1754 1755 // Note: these are almost certainly not safe to ever reuse. Expressions commonly 1756 // need a large amount of lookahead, and we should not reuse them as they may 1757 // have actually intersected the edit. 1758 case ParsingContext.ArgumentExpressions: 1759 1760 // This is not safe to reuse for the same reason as the 'AssignmentExpression' 1761 // cases. i.e. a property assignment may end with an expression, and thus might 1762 // have lookahead far beyond it's old node. 1763 case ParsingContext.ObjectLiteralMembers: 1764 1765 // This is probably not safe to reuse. There can be speculative parsing with 1766 // type names in a heritage clause. There can be generic names in the type 1767 // name list, and there can be left hand side expressions (which can have type 1768 // arguments.) 1769 case ParsingContext.HeritageClauseElement: 1770 1771 // Perhaps safe to reuse, but it's unlikely we'd see more than a dozen attributes 1772 // on any given element. Same for children. 1773 case ParsingContext.JsxAttributes: 1774 case ParsingContext.JsxChildren: 1775 1776 } 1777 1778 return false; 1779 } 1780 1781 function isReusableClassMember(node: Node) { 1782 if (node) { 1783 switch (node.kind) { 1784 case SyntaxKind.Constructor: 1785 case SyntaxKind.IndexSignature: 1786 case SyntaxKind.GetAccessor: 1787 case SyntaxKind.SetAccessor: 1788 case SyntaxKind.PropertyDeclaration: 1789 case SyntaxKind.SemicolonClassElement: 1790 return true; 1791 case SyntaxKind.MethodDeclaration: 1792 // Method declarations are not necessarily reusable. An object-literal 1793 // may have a method calls "constructor(...)" and we must reparse that 1794 // into an actual .ConstructorDeclaration. 1795 const methodDeclaration = <MethodDeclaration>node; 1796 const nameIsConstructor = methodDeclaration.name.kind === SyntaxKind.Identifier && 1797 (<Identifier>methodDeclaration.name).originalKeywordKind === SyntaxKind.ConstructorKeyword; 1798 1799 return !nameIsConstructor; 1800 } 1801 } 1802 1803 return false; 1804 } 1805 1806 function isReusableSwitchClause(node: Node) { 1807 if (node) { 1808 switch (node.kind) { 1809 case SyntaxKind.CaseClause: 1810 case SyntaxKind.DefaultClause: 1811 return true; 1812 } 1813 } 1814 1815 return false; 1816 } 1817 1818 function isReusableStatement(node: Node) { 1819 if (node) { 1820 switch (node.kind) { 1821 case SyntaxKind.FunctionDeclaration: 1822 case SyntaxKind.VariableStatement: 1823 case SyntaxKind.Block: 1824 case SyntaxKind.IfStatement: 1825 case SyntaxKind.ExpressionStatement: 1826 case SyntaxKind.ThrowStatement: 1827 case SyntaxKind.ReturnStatement: 1828 case SyntaxKind.SwitchStatement: 1829 case SyntaxKind.BreakStatement: 1830 case SyntaxKind.ContinueStatement: 1831 case SyntaxKind.ForInStatement: 1832 case SyntaxKind.ForOfStatement: 1833 case SyntaxKind.ForStatement: 1834 case SyntaxKind.WhileStatement: 1835 case SyntaxKind.WithStatement: 1836 case SyntaxKind.EmptyStatement: 1837 case SyntaxKind.TryStatement: 1838 case SyntaxKind.LabeledStatement: 1839 case SyntaxKind.DoStatement: 1840 case SyntaxKind.DebuggerStatement: 1841 case SyntaxKind.ImportDeclaration: 1842 case SyntaxKind.ImportEqualsDeclaration: 1843 case SyntaxKind.ExportDeclaration: 1844 case SyntaxKind.ExportAssignment: 1845 case SyntaxKind.ModuleDeclaration: 1846 case SyntaxKind.ClassDeclaration: 1847 case SyntaxKind.InterfaceDeclaration: 1848 case SyntaxKind.EnumDeclaration: 1849 case SyntaxKind.TypeAliasDeclaration: 1850 return true; 1851 } 1852 } 1853 1854 return false; 1855 } 1856 1857 function isReusableEnumMember(node: Node) { 1858 return node.kind === SyntaxKind.EnumMember; 1859 } 1860 1861 function isReusableTypeMember(node: Node) { 1862 if (node) { 1863 switch (node.kind) { 1864 case SyntaxKind.ConstructSignature: 1865 case SyntaxKind.MethodSignature: 1866 case SyntaxKind.IndexSignature: 1867 case SyntaxKind.PropertySignature: 1868 case SyntaxKind.CallSignature: 1869 return true; 1870 } 1871 } 1872 1873 return false; 1874 } 1875 1876 function isReusableVariableDeclaration(node: Node) { 1877 if (node.kind !== SyntaxKind.VariableDeclaration) { 1878 return false; 1879 } 1880 1881 // Very subtle incremental parsing bug. Consider the following code: 1882 // 1883 // let v = new List < A, B 1884 // 1885 // This is actually legal code. It's a list of variable declarators "v = new List<A" 1886 // on one side and "B" on the other. If you then change that to: 1887 // 1888 // let v = new List < A, B >() 1889 // 1890 // then we have a problem. "v = new List<A" doesn't intersect the change range, so we 1891 // start reparsing at "B" and we completely fail to handle this properly. 1892 // 1893 // In order to prevent this, we do not allow a variable declarator to be reused if it 1894 // has an initializer. 1895 const variableDeclarator = <VariableDeclaration>node; 1896 return variableDeclarator.initializer === undefined; 1897 } 1898 1899 function isReusableParameter(node: Node) { 1900 if (node.kind !== SyntaxKind.Parameter) { 1901 return false; 1902 } 1903 1904 // See the comment in isReusableVariableDeclaration for why we do this. 1905 const parameter = <ParameterDeclaration>node; 1906 return parameter.initializer === undefined; 1907 } 1908 1909 // Returns true if we should abort parsing. 1910 function abortParsingListOrMoveToNextToken(kind: ParsingContext) { 1911 parseErrorAtCurrentToken(parsingContextErrors(kind)); 1912 if (isInSomeParsingContext()) { 1913 return true; 1914 } 1915 1916 nextToken(); 1917 return false; 1918 } 1919 1920 function parsingContextErrors(context: ParsingContext): DiagnosticMessage { 1921 switch (context) { 1922 case ParsingContext.SourceElements: return Diagnostics.Declaration_or_statement_expected; 1923 case ParsingContext.BlockStatements: return Diagnostics.Declaration_or_statement_expected; 1924 case ParsingContext.SwitchClauses: return Diagnostics.case_or_default_expected; 1925 case ParsingContext.SwitchClauseStatements: return Diagnostics.Statement_expected; 1926 case ParsingContext.RestProperties: // fallthrough 1927 case ParsingContext.TypeMembers: return Diagnostics.Property_or_signature_expected; 1928 case ParsingContext.ClassMembers: return Diagnostics.Unexpected_token_A_constructor_method_accessor_or_property_was_expected; 1929 case ParsingContext.EnumMembers: return Diagnostics.Enum_member_expected; 1930 case ParsingContext.HeritageClauseElement: return Diagnostics.Expression_expected; 1931 case ParsingContext.VariableDeclarations: return Diagnostics.Variable_declaration_expected; 1932 case ParsingContext.ObjectBindingElements: return Diagnostics.Property_destructuring_pattern_expected; 1933 case ParsingContext.ArrayBindingElements: return Diagnostics.Array_element_destructuring_pattern_expected; 1934 case ParsingContext.ArgumentExpressions: return Diagnostics.Argument_expression_expected; 1935 case ParsingContext.ObjectLiteralMembers: return Diagnostics.Property_assignment_expected; 1936 case ParsingContext.ArrayLiteralMembers: return Diagnostics.Expression_or_comma_expected; 1937 case ParsingContext.Parameters: return Diagnostics.Parameter_declaration_expected; 1938 case ParsingContext.TypeParameters: return Diagnostics.Type_parameter_declaration_expected; 1939 case ParsingContext.TypeArguments: return Diagnostics.Type_argument_expected; 1940 case ParsingContext.TupleElementTypes: return Diagnostics.Type_expected; 1941 case ParsingContext.HeritageClauses: return Diagnostics.Unexpected_token_expected; 1942 case ParsingContext.ImportOrExportSpecifiers: return Diagnostics.Identifier_expected; 1943 case ParsingContext.JsxAttributes: return Diagnostics.Identifier_expected; 1944 case ParsingContext.JsxChildren: return Diagnostics.Identifier_expected; 1945 } 1946 } 1947 1948 // Parses a comma-delimited list of elements 1949 function parseDelimitedList<T extends Node>(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray<T> { 1950 const saveParsingContext = parsingContext; 1951 parsingContext |= 1 << kind; 1952 const list = []; 1953 const listPos = getNodePos(); 1954 1955 let commaStart = -1; // Meaning the previous token was not a comma 1956 while (true) { 1957 if (isListElement(kind, /*inErrorRecovery*/ false)) { 1958 const startPos = scanner.getStartPos(); 1959 list.push(parseListElement(kind, parseElement)); 1960 commaStart = scanner.getTokenPos(); 1961 1962 if (parseOptional(SyntaxKind.CommaToken)) { 1963 // No need to check for a zero length node since we know we parsed a comma 1964 continue; 1965 } 1966 1967 commaStart = -1; // Back to the state where the last token was not a comma 1968 if (isListTerminator(kind)) { 1969 break; 1970 } 1971 1972 // We didn't get a comma, and the list wasn't terminated, explicitly parse 1973 // out a comma so we give a good error message. 1974 parseExpected(SyntaxKind.CommaToken); 1975 1976 // If the token was a semicolon, and the caller allows that, then skip it and 1977 // continue. This ensures we get back on track and don't result in tons of 1978 // parse errors. For example, this can happen when people do things like use 1979 // a semicolon to delimit object literal members. Note: we'll have already 1980 // reported an error when we called parseExpected above. 1981 if (considerSemicolonAsDelimiter && token() === SyntaxKind.SemicolonToken && !scanner.hasPrecedingLineBreak()) { 1982 nextToken(); 1983 } 1984 if (startPos === scanner.getStartPos()) { 1985 // What we're parsing isn't actually remotely recognizable as a element and we've consumed no tokens whatsoever 1986 // Consume a token to advance the parser in some way and avoid an infinite loop 1987 // This can happen when we're speculatively parsing parenthesized expressions which we think may be arrow functions, 1988 // or when a modifier keyword which is disallowed as a parameter name (ie, `static` in strict mode) is supplied 1989 nextToken(); 1990 } 1991 continue; 1992 } 1993 1994 if (isListTerminator(kind)) { 1995 break; 1996 } 1997 1998 if (abortParsingListOrMoveToNextToken(kind)) { 1999 break; 2000 } 2001 } 2002 2003 parsingContext = saveParsingContext; 2004 const result = createNodeArray(list, listPos); 2005 // Recording the trailing comma is deliberately done after the previous 2006 // loop, and not just if we see a list terminator. This is because the list 2007 // may have ended incorrectly, but it is still important to know if there 2008 // was a trailing comma. 2009 // Check if the last token was a comma. 2010 if (commaStart >= 0) { 2011 // Always preserve a trailing comma by marking it on the NodeArray 2012 result.hasTrailingComma = true; 2013 } 2014 return result; 2015 } 2016 2017 function createMissingList<T extends Node>(): NodeArray<T> { 2018 return createNodeArray<T>([], getNodePos()); 2019 } 2020 2021 function parseBracketedList<T extends Node>(kind: ParsingContext, parseElement: () => T, open: SyntaxKind, close: SyntaxKind): NodeArray<T> { 2022 if (parseExpected(open)) { 2023 const result = parseDelimitedList(kind, parseElement); 2024 parseExpected(close); 2025 return result; 2026 } 2027 2028 return createMissingList<T>(); 2029 } 2030 2031 function parseEntityName(allowReservedWords: boolean, diagnosticMessage?: DiagnosticMessage): EntityName { 2032 let entity: EntityName = allowReservedWords ? parseIdentifierName(diagnosticMessage) : parseIdentifier(diagnosticMessage); 2033 let dotPos = scanner.getStartPos(); 2034 while (parseOptional(SyntaxKind.DotToken)) { 2035 if (token() === SyntaxKind.LessThanToken) { 2036 // the entity is part of a JSDoc-style generic, so record the trailing dot for later error reporting 2037 entity.jsdocDotPos = dotPos; 2038 break; 2039 } 2040 dotPos = scanner.getStartPos(); 2041 entity = createQualifiedName(entity, parseRightSideOfDot(allowReservedWords)); 2042 } 2043 return entity; 2044 } 2045 2046 function createQualifiedName(entity: EntityName, name: Identifier): QualifiedName { 2047 const node = createNode(SyntaxKind.QualifiedName, entity.pos) as QualifiedName; 2048 node.left = entity; 2049 node.right = name; 2050 return finishNode(node); 2051 } 2052 2053 function parseRightSideOfDot(allowIdentifierNames: boolean): Identifier { 2054 // Technically a keyword is valid here as all identifiers and keywords are identifier names. 2055 // However, often we'll encounter this in error situations when the identifier or keyword 2056 // is actually starting another valid construct. 2057 // 2058 // So, we check for the following specific case: 2059 // 2060 // name. 2061 // identifierOrKeyword identifierNameOrKeyword 2062 // 2063 // Note: the newlines are important here. For example, if that above code 2064 // were rewritten into: 2065 // 2066 // name.identifierOrKeyword 2067 // identifierNameOrKeyword 2068 // 2069 // Then we would consider it valid. That's because ASI would take effect and 2070 // the code would be implicitly: "name.identifierOrKeyword; identifierNameOrKeyword". 2071 // In the first case though, ASI will not take effect because there is not a 2072 // line terminator after the identifier or keyword. 2073 if (scanner.hasPrecedingLineBreak() && tokenIsIdentifierOrKeyword(token())) { 2074 const matchesPattern = lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine); 2075 2076 if (matchesPattern) { 2077 // Report that we need an identifier. However, report it right after the dot, 2078 // and not on the next token. This is because the next token might actually 2079 // be an identifier and the error would be quite confusing. 2080 return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected); 2081 } 2082 } 2083 2084 return allowIdentifierNames ? parseIdentifierName() : parseIdentifier(); 2085 } 2086 2087 function parseTemplateExpression(): TemplateExpression { 2088 const template = <TemplateExpression>createNode(SyntaxKind.TemplateExpression); 2089 2090 template.head = parseTemplateHead(); 2091 Debug.assert(template.head.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind"); 2092 2093 const list = []; 2094 const listPos = getNodePos(); 2095 2096 do { 2097 list.push(parseTemplateSpan()); 2098 } 2099 while (lastOrUndefined(list).literal.kind === SyntaxKind.TemplateMiddle); 2100 2101 template.templateSpans = createNodeArray(list, listPos); 2102 2103 return finishNode(template); 2104 } 2105 2106 function parseTemplateSpan(): TemplateSpan { 2107 const span = <TemplateSpan>createNode(SyntaxKind.TemplateSpan); 2108 span.expression = allowInAnd(parseExpression); 2109 2110 let literal: TemplateMiddle | TemplateTail; 2111 if (token() === SyntaxKind.CloseBraceToken) { 2112 reScanTemplateToken(); 2113 literal = parseTemplateMiddleOrTemplateTail(); 2114 } 2115 else { 2116 literal = <TemplateTail>parseExpectedToken(SyntaxKind.TemplateTail, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken)); 2117 } 2118 2119 span.literal = literal; 2120 return finishNode(span); 2121 } 2122 2123 function parseLiteralNode(): LiteralExpression { 2124 return <LiteralExpression>parseLiteralLikeNode(token()); 2125 } 2126 2127 function parseTemplateHead(): TemplateHead { 2128 const fragment = parseLiteralLikeNode(token()); 2129 Debug.assert(fragment.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind"); 2130 return <TemplateHead>fragment; 2131 } 2132 2133 function parseTemplateMiddleOrTemplateTail(): TemplateMiddle | TemplateTail { 2134 const fragment = parseLiteralLikeNode(token()); 2135 Debug.assert(fragment.kind === SyntaxKind.TemplateMiddle || fragment.kind === SyntaxKind.TemplateTail, "Template fragment has wrong token kind"); 2136 return <TemplateMiddle | TemplateTail>fragment; 2137 } 2138 2139 function parseLiteralLikeNode(kind: SyntaxKind): LiteralExpression | LiteralLikeNode { 2140 const node = <LiteralExpression>createNode(kind); 2141 const text = scanner.getTokenValue(); 2142 node.text = text; 2143 2144 if (scanner.hasExtendedUnicodeEscape()) { 2145 node.hasExtendedUnicodeEscape = true; 2146 } 2147 2148 if (scanner.isUnterminated()) { 2149 node.isUnterminated = true; 2150 } 2151 2152 // Octal literals are not allowed in strict mode or ES5 2153 // Note that theoretically the following condition would hold true literals like 009, 2154 // which is not octal.But because of how the scanner separates the tokens, we would 2155 // never get a token like this. Instead, we would get 00 and 9 as two separate tokens. 2156 // We also do not need to check for negatives because any prefix operator would be part of a 2157 // parent unary expression. 2158 if (node.kind === SyntaxKind.NumericLiteral) { 2159 (<NumericLiteral>node).numericLiteralFlags = scanner.getTokenFlags() & TokenFlags.NumericLiteralFlags; 2160 } 2161 2162 nextToken(); 2163 finishNode(node); 2164 2165 return node; 2166 } 2167 2168 // TYPES 2169 2170 function parseTypeReference(): TypeReferenceNode { 2171 const node = <TypeReferenceNode>createNode(SyntaxKind.TypeReference); 2172 node.typeName = parseEntityName(/*allowReservedWords*/ true, Diagnostics.Type_expected); 2173 if (!scanner.hasPrecedingLineBreak() && token() === SyntaxKind.LessThanToken) { 2174 node.typeArguments = parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); 2175 } 2176 return finishNode(node); 2177 } 2178 2179 function parseThisTypePredicate(lhs: ThisTypeNode): TypePredicateNode { 2180 nextToken(); 2181 const node = createNode(SyntaxKind.TypePredicate, lhs.pos) as TypePredicateNode; 2182 node.parameterName = lhs; 2183 node.type = parseType(); 2184 return finishNode(node); 2185 } 2186 2187 function parseThisTypeNode(): ThisTypeNode { 2188 const node = createNode(SyntaxKind.ThisType) as ThisTypeNode; 2189 nextToken(); 2190 return finishNode(node); 2191 } 2192 2193 function parseJSDocAllType(): JSDocAllType { 2194 const result = <JSDocAllType>createNode(SyntaxKind.JSDocAllType); 2195 nextToken(); 2196 return finishNode(result); 2197 } 2198 2199 function parseJSDocUnknownOrNullableType(): JSDocUnknownType | JSDocNullableType { 2200 const pos = scanner.getStartPos(); 2201 // skip the ? 2202 nextToken(); 2203 2204 // Need to lookahead to decide if this is a nullable or unknown type. 2205 2206 // Here are cases where we'll pick the unknown type: 2207 // 2208 // Foo(?, 2209 // { a: ? } 2210 // Foo(?) 2211 // Foo<?> 2212 // Foo(?= 2213 // (?| 2214 if (token() === SyntaxKind.CommaToken || 2215 token() === SyntaxKind.CloseBraceToken || 2216 token() === SyntaxKind.CloseParenToken || 2217 token() === SyntaxKind.GreaterThanToken || 2218 token() === SyntaxKind.EqualsToken || 2219 token() === SyntaxKind.BarToken) { 2220 2221 const result = <JSDocUnknownType>createNode(SyntaxKind.JSDocUnknownType, pos); 2222 return finishNode(result); 2223 } 2224 else { 2225 const result = <JSDocNullableType>createNode(SyntaxKind.JSDocNullableType, pos); 2226 result.type = parseType(); 2227 return finishNode(result); 2228 } 2229 } 2230 2231 function parseJSDocFunctionType(): JSDocFunctionType | TypeReferenceNode { 2232 if (lookAhead(nextTokenIsOpenParen)) { 2233 const result = <JSDocFunctionType>createNodeWithJSDoc(SyntaxKind.JSDocFunctionType); 2234 nextToken(); 2235 fillSignature(SyntaxKind.ColonToken, SignatureFlags.Type | SignatureFlags.JSDoc, result); 2236 return finishNode(result); 2237 } 2238 const node = <TypeReferenceNode>createNode(SyntaxKind.TypeReference); 2239 node.typeName = parseIdentifierName(); 2240 return finishNode(node); 2241 } 2242 2243 function parseJSDocParameter(): ParameterDeclaration { 2244 const parameter = createNode(SyntaxKind.Parameter) as ParameterDeclaration; 2245 if (token() === SyntaxKind.ThisKeyword || token() === SyntaxKind.NewKeyword) { 2246 parameter.name = parseIdentifierName(); 2247 parseExpected(SyntaxKind.ColonToken); 2248 } 2249 parameter.type = parseType(); 2250 return finishNode(parameter); 2251 } 2252 2253 function parseJSDocNodeWithType(kind: SyntaxKind.JSDocVariadicType | SyntaxKind.JSDocNonNullableType): TypeNode { 2254 const result = createNode(kind) as JSDocVariadicType | JSDocNonNullableType; 2255 nextToken(); 2256 result.type = parseNonArrayType(); 2257 return finishNode(result); 2258 } 2259 2260 function parseTypeQuery(): TypeQueryNode { 2261 const node = <TypeQueryNode>createNode(SyntaxKind.TypeQuery); 2262 parseExpected(SyntaxKind.TypeOfKeyword); 2263 node.exprName = parseEntityName(/*allowReservedWords*/ true); 2264 return finishNode(node); 2265 } 2266 2267 function parseTypeParameter(): TypeParameterDeclaration { 2268 const node = <TypeParameterDeclaration>createNode(SyntaxKind.TypeParameter); 2269 node.name = parseIdentifier(); 2270 if (parseOptional(SyntaxKind.ExtendsKeyword)) { 2271 // It's not uncommon for people to write improper constraints to a generic. If the 2272 // user writes a constraint that is an expression and not an actual type, then parse 2273 // it out as an expression (so we can recover well), but report that a type is needed 2274 // instead. 2275 if (isStartOfType() || !isStartOfExpression()) { 2276 node.constraint = parseType(); 2277 } 2278 else { 2279 // It was not a type, and it looked like an expression. Parse out an expression 2280 // here so we recover well. Note: it is important that we call parseUnaryExpression 2281 // and not parseExpression here. If the user has: 2282 // 2283 // <T extends ""> 2284 // 2285 // We do *not* want to consume the `>` as we're consuming the expression for "". 2286 node.expression = parseUnaryExpressionOrHigher(); 2287 } 2288 } 2289 2290 if (parseOptional(SyntaxKind.EqualsToken)) { 2291 node.default = parseType(); 2292 } 2293 2294 return finishNode(node); 2295 } 2296 2297 function parseTypeParameters(): NodeArray<TypeParameterDeclaration> | undefined { 2298 if (token() === SyntaxKind.LessThanToken) { 2299 return parseBracketedList(ParsingContext.TypeParameters, parseTypeParameter, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); 2300 } 2301 } 2302 2303 function parseParameterType(): TypeNode { 2304 if (parseOptional(SyntaxKind.ColonToken)) { 2305 return parseType(); 2306 } 2307 2308 return undefined; 2309 } 2310 2311 function isStartOfParameter(): boolean { 2312 return token() === SyntaxKind.DotDotDotToken || 2313 isIdentifierOrPattern() || 2314 isModifierKind(token()) || 2315 token() === SyntaxKind.AtToken || 2316 isStartOfType(/*inStartOfParameter*/ true); 2317 } 2318 2319 function parseParameter(): ParameterDeclaration { 2320 const node = <ParameterDeclaration>createNodeWithJSDoc(SyntaxKind.Parameter); 2321 if (token() === SyntaxKind.ThisKeyword) { 2322 node.name = createIdentifier(/*isIdentifier*/ true); 2323 node.type = parseParameterType(); 2324 return finishNode(node); 2325 } 2326 2327 node.decorators = parseDecorators(); 2328 node.modifiers = parseModifiers(); 2329 node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); 2330 2331 // FormalParameter [Yield,Await]: 2332 // BindingElement[?Yield,?Await] 2333 node.name = parseIdentifierOrPattern(); 2334 if (getFullWidth(node.name) === 0 && !hasModifiers(node) && isModifierKind(token())) { 2335 // in cases like 2336 // 'use strict' 2337 // function foo(static) 2338 // isParameter('static') === true, because of isModifier('static') 2339 // however 'static' is not a legal identifier in a strict mode. 2340 // so result of this function will be ParameterDeclaration (flags = 0, name = missing, type = undefined, initializer = undefined) 2341 // and current token will not change => parsing of the enclosing parameter list will last till the end of time (or OOM) 2342 // to avoid this we'll advance cursor to the next token. 2343 nextToken(); 2344 } 2345 2346 node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken); 2347 node.type = parseParameterType(); 2348 node.initializer = parseInitializer(); 2349 2350 return finishNode(node); 2351 } 2352 2353 function fillSignature( 2354 returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, 2355 flags: SignatureFlags, 2356 signature: SignatureDeclaration): void { 2357 if (!(flags & SignatureFlags.JSDoc)) { 2358 signature.typeParameters = parseTypeParameters(); 2359 } 2360 signature.parameters = parseParameterList(flags); 2361 signature.type = parseReturnType(returnToken, !!(flags & SignatureFlags.Type)); 2362 } 2363 2364 function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode | undefined { 2365 return shouldParseReturnType(returnToken, isType) ? parseTypeOrTypePredicate() : undefined; 2366 } 2367 function shouldParseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): boolean { 2368 if (returnToken === SyntaxKind.EqualsGreaterThanToken) { 2369 parseExpected(returnToken); 2370 return true; 2371 } 2372 else if (parseOptional(SyntaxKind.ColonToken)) { 2373 return true; 2374 } 2375 else if (isType && token() === SyntaxKind.EqualsGreaterThanToken) { 2376 // This is easy to get backward, especially in type contexts, so parse the type anyway 2377 parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken)); 2378 nextToken(); 2379 return true; 2380 } 2381 return false; 2382 } 2383 2384 function parseParameterList(flags: SignatureFlags) { 2385 // FormalParameters [Yield,Await]: (modified) 2386 // [empty] 2387 // FormalParameterList[?Yield,Await] 2388 // 2389 // FormalParameter[Yield,Await]: (modified) 2390 // BindingElement[?Yield,Await] 2391 // 2392 // BindingElement [Yield,Await]: (modified) 2393 // SingleNameBinding[?Yield,?Await] 2394 // BindingPattern[?Yield,?Await]Initializer [In, ?Yield,?Await] opt 2395 // 2396 // SingleNameBinding [Yield,Await]: 2397 // BindingIdentifier[?Yield,?Await]Initializer [In, ?Yield,?Await] opt 2398 if (parseExpected(SyntaxKind.OpenParenToken)) { 2399 const savedYieldContext = inYieldContext(); 2400 const savedAwaitContext = inAwaitContext(); 2401 2402 setYieldContext(!!(flags & SignatureFlags.Yield)); 2403 setAwaitContext(!!(flags & SignatureFlags.Await)); 2404 2405 const result = parseDelimitedList(ParsingContext.Parameters, flags & SignatureFlags.JSDoc ? parseJSDocParameter : parseParameter); 2406 2407 setYieldContext(savedYieldContext); 2408 setAwaitContext(savedAwaitContext); 2409 2410 if (!parseExpected(SyntaxKind.CloseParenToken) && (flags & SignatureFlags.RequireCompleteParameterList)) { 2411 // Caller insisted that we had to end with a ) We didn't. So just return 2412 // undefined here. 2413 return undefined; 2414 } 2415 2416 return result; 2417 } 2418 2419 // We didn't even have an open paren. If the caller requires a complete parameter list, 2420 // we definitely can't provide that. However, if they're ok with an incomplete one, 2421 // then just return an empty set of parameters. 2422 return (flags & SignatureFlags.RequireCompleteParameterList) ? undefined : createMissingList<ParameterDeclaration>(); 2423 } 2424 2425 function parseTypeMemberSemicolon() { 2426 // We allow type members to be separated by commas or (possibly ASI) semicolons. 2427 // First check if it was a comma. If so, we're done with the member. 2428 if (parseOptional(SyntaxKind.CommaToken)) { 2429 return; 2430 } 2431 2432 // Didn't have a comma. We must have a (possible ASI) semicolon. 2433 parseSemicolon(); 2434 } 2435 2436 function parseSignatureMember(kind: SyntaxKind.CallSignature | SyntaxKind.ConstructSignature): CallSignatureDeclaration | ConstructSignatureDeclaration { 2437 const node = <CallSignatureDeclaration | ConstructSignatureDeclaration>createNodeWithJSDoc(kind); 2438 if (kind === SyntaxKind.ConstructSignature) { 2439 parseExpected(SyntaxKind.NewKeyword); 2440 } 2441 fillSignature(SyntaxKind.ColonToken, SignatureFlags.Type, node); 2442 parseTypeMemberSemicolon(); 2443 return finishNode(node); 2444 } 2445 2446 function isIndexSignature(): boolean { 2447 return token() === SyntaxKind.OpenBracketToken && lookAhead(isUnambiguouslyIndexSignature); 2448 } 2449 2450 function isUnambiguouslyIndexSignature() { 2451 // The only allowed sequence is: 2452 // 2453 // [id: 2454 // 2455 // However, for error recovery, we also check the following cases: 2456 // 2457 // [... 2458 // [id, 2459 // [id?, 2460 // [id?: 2461 // [id?] 2462 // [public id 2463 // [private id 2464 // [protected id 2465 // [] 2466 // 2467 nextToken(); 2468 if (token() === SyntaxKind.DotDotDotToken || token() === SyntaxKind.CloseBracketToken) { 2469 return true; 2470 } 2471 2472 if (isModifierKind(token())) { 2473 nextToken(); 2474 if (isIdentifier()) { 2475 return true; 2476 } 2477 } 2478 else if (!isIdentifier()) { 2479 return false; 2480 } 2481 else { 2482 // Skip the identifier 2483 nextToken(); 2484 } 2485 2486 // A colon signifies a well formed indexer 2487 // A comma should be a badly formed indexer because comma expressions are not allowed 2488 // in computed properties. 2489 if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken) { 2490 return true; 2491 } 2492 2493 // Question mark could be an indexer with an optional property, 2494 // or it could be a conditional expression in a computed property. 2495 if (token() !== SyntaxKind.QuestionToken) { 2496 return false; 2497 } 2498 2499 // If any of the following tokens are after the question mark, it cannot 2500 // be a conditional expression, so treat it as an indexer. 2501 nextToken(); 2502 return token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.CloseBracketToken; 2503 } 2504 2505 function parseIndexSignatureDeclaration(node: IndexSignatureDeclaration): IndexSignatureDeclaration { 2506 node.kind = SyntaxKind.IndexSignature; 2507 node.parameters = parseBracketedList(ParsingContext.Parameters, parseParameter, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken); 2508 node.type = parseTypeAnnotation(); 2509 parseTypeMemberSemicolon(); 2510 return finishNode(node); 2511 } 2512 2513 function parsePropertyOrMethodSignature(node: PropertySignature | MethodSignature): PropertySignature | MethodSignature { 2514 node.name = parsePropertyName(); 2515 node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken); 2516 if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { 2517 node.kind = SyntaxKind.MethodSignature; 2518 // Method signatures don't exist in expression contexts. So they have neither 2519 // [Yield] nor [Await] 2520 fillSignature(SyntaxKind.ColonToken, SignatureFlags.Type, <MethodSignature>node); 2521 } 2522 else { 2523 node.kind = SyntaxKind.PropertySignature; 2524 node.type = parseTypeAnnotation(); 2525 if (token() === SyntaxKind.EqualsToken) { 2526 // Although type literal properties cannot not have initializers, we attempt 2527 // to parse an initializer so we can report in the checker that an interface 2528 // property or type literal property cannot have an initializer. 2529 (<PropertySignature>node).initializer = parseInitializer(); 2530 } 2531 } 2532 parseTypeMemberSemicolon(); 2533 return finishNode(node); 2534 } 2535 2536 function isTypeMemberStart(): boolean { 2537 // Return true if we have the start of a signature member 2538 if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { 2539 return true; 2540 } 2541 let idToken: boolean; 2542 // Eat up all modifiers, but hold on to the last one in case it is actually an identifier 2543 while (isModifierKind(token())) { 2544 idToken = true; 2545 nextToken(); 2546 } 2547 // Index signatures and computed property names are type members 2548 if (token() === SyntaxKind.OpenBracketToken) { 2549 return true; 2550 } 2551 // Try to get the first property-like token following all modifiers 2552 if (isLiteralPropertyName()) { 2553 idToken = true; 2554 nextToken(); 2555 } 2556 // If we were able to get any potential identifier, check that it is 2557 // the start of a member declaration 2558 if (idToken) { 2559 return token() === SyntaxKind.OpenParenToken || 2560 token() === SyntaxKind.LessThanToken || 2561 token() === SyntaxKind.QuestionToken || 2562 token() === SyntaxKind.ColonToken || 2563 token() === SyntaxKind.CommaToken || 2564 canParseSemicolon(); 2565 } 2566 return false; 2567 } 2568 2569 function parseTypeMember(): TypeElement { 2570 if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { 2571 return parseSignatureMember(SyntaxKind.CallSignature); 2572 } 2573 if (token() === SyntaxKind.NewKeyword && lookAhead(nextTokenIsOpenParenOrLessThan)) { 2574 return parseSignatureMember(SyntaxKind.ConstructSignature); 2575 } 2576 const node = <TypeElement>createNodeWithJSDoc(SyntaxKind.Unknown); 2577 node.modifiers = parseModifiers(); 2578 if (isIndexSignature()) { 2579 return parseIndexSignatureDeclaration(<IndexSignatureDeclaration>node); 2580 } 2581 return parsePropertyOrMethodSignature(<PropertySignature | MethodSignature>node); 2582 } 2583 2584 function nextTokenIsOpenParenOrLessThan() { 2585 nextToken(); 2586 return token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken; 2587 } 2588 2589 function parseTypeLiteral(): TypeLiteralNode { 2590 const node = <TypeLiteralNode>createNode(SyntaxKind.TypeLiteral); 2591 node.members = parseObjectTypeMembers(); 2592 return finishNode(node); 2593 } 2594 2595 function parseObjectTypeMembers(): NodeArray<TypeElement> { 2596 let members: NodeArray<TypeElement>; 2597 if (parseExpected(SyntaxKind.OpenBraceToken)) { 2598 members = parseList(ParsingContext.TypeMembers, parseTypeMember); 2599 parseExpected(SyntaxKind.CloseBraceToken); 2600 } 2601 else { 2602 members = createMissingList<TypeElement>(); 2603 } 2604 2605 return members; 2606 } 2607 2608 function isStartOfMappedType() { 2609 nextToken(); 2610 if (token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { 2611 return nextToken() === SyntaxKind.ReadonlyKeyword; 2612 } 2613 if (token() === SyntaxKind.ReadonlyKeyword) { 2614 nextToken(); 2615 } 2616 return token() === SyntaxKind.OpenBracketToken && nextTokenIsIdentifier() && nextToken() === SyntaxKind.InKeyword; 2617 } 2618 2619 function parseMappedTypeParameter() { 2620 const node = <TypeParameterDeclaration>createNode(SyntaxKind.TypeParameter); 2621 node.name = parseIdentifier(); 2622 parseExpected(SyntaxKind.InKeyword); 2623 node.constraint = parseType(); 2624 return finishNode(node); 2625 } 2626 2627 function parseMappedType() { 2628 const node = <MappedTypeNode>createNode(SyntaxKind.MappedType); 2629 parseExpected(SyntaxKind.OpenBraceToken); 2630 if (token() === SyntaxKind.ReadonlyKeyword || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { 2631 node.readonlyToken = parseTokenNode(); 2632 if (node.readonlyToken.kind !== SyntaxKind.ReadonlyKeyword) { 2633 parseExpectedToken(SyntaxKind.ReadonlyKeyword); 2634 } 2635 } 2636 parseExpected(SyntaxKind.OpenBracketToken); 2637 node.typeParameter = parseMappedTypeParameter(); 2638 parseExpected(SyntaxKind.CloseBracketToken); 2639 if (token() === SyntaxKind.QuestionToken || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { 2640 node.questionToken = parseTokenNode(); 2641 if (node.questionToken.kind !== SyntaxKind.QuestionToken) { 2642 parseExpectedToken(SyntaxKind.QuestionToken); 2643 } 2644 } 2645 node.type = parseTypeAnnotation(); 2646 parseSemicolon(); 2647 parseExpected(SyntaxKind.CloseBraceToken); 2648 return finishNode(node); 2649 } 2650 2651 function parseTupleType(): TupleTypeNode { 2652 const node = <TupleTypeNode>createNode(SyntaxKind.TupleType); 2653 node.elementTypes = parseBracketedList(ParsingContext.TupleElementTypes, parseType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken); 2654 return finishNode(node); 2655 } 2656 2657 function parseParenthesizedType(): ParenthesizedTypeNode { 2658 const node = <ParenthesizedTypeNode>createNode(SyntaxKind.ParenthesizedType); 2659 parseExpected(SyntaxKind.OpenParenToken); 2660 node.type = parseType(); 2661 parseExpected(SyntaxKind.CloseParenToken); 2662 return finishNode(node); 2663 } 2664 2665 function parseFunctionOrConstructorType(kind: SyntaxKind): FunctionOrConstructorTypeNode { 2666 const node = <FunctionOrConstructorTypeNode>createNodeWithJSDoc(kind); 2667 if (kind === SyntaxKind.ConstructorType) { 2668 parseExpected(SyntaxKind.NewKeyword); 2669 } 2670 fillSignature(SyntaxKind.EqualsGreaterThanToken, SignatureFlags.Type, node); 2671 return finishNode(node); 2672 } 2673 2674 function parseKeywordAndNoDot(): TypeNode | undefined { 2675 const node = parseTokenNode<TypeNode>(); 2676 return token() === SyntaxKind.DotToken ? undefined : node; 2677 } 2678 2679 function parseLiteralTypeNode(negative?: boolean): LiteralTypeNode { 2680 const node = createNode(SyntaxKind.LiteralType) as LiteralTypeNode; 2681 let unaryMinusExpression: PrefixUnaryExpression; 2682 if (negative) { 2683 unaryMinusExpression = createNode(SyntaxKind.PrefixUnaryExpression) as PrefixUnaryExpression; 2684 unaryMinusExpression.operator = SyntaxKind.MinusToken; 2685 nextToken(); 2686 } 2687 let expression: BooleanLiteral | LiteralExpression | PrefixUnaryExpression = token() === SyntaxKind.TrueKeyword || token() === SyntaxKind.FalseKeyword 2688 ? parseTokenNode<BooleanLiteral>() 2689 : parseLiteralLikeNode(token()) as LiteralExpression; 2690 if (negative) { 2691 unaryMinusExpression.operand = expression; 2692 finishNode(unaryMinusExpression); 2693 expression = unaryMinusExpression; 2694 } 2695 node.literal = expression; 2696 return finishNode(node); 2697 } 2698 2699 function nextTokenIsNumericLiteral() { 2700 return nextToken() === SyntaxKind.NumericLiteral; 2701 } 2702 2703 function parseNonArrayType(): TypeNode { 2704 switch (token()) { 2705 case SyntaxKind.AnyKeyword: 2706 case SyntaxKind.StringKeyword: 2707 case SyntaxKind.NumberKeyword: 2708 case SyntaxKind.SymbolKeyword: 2709 case SyntaxKind.BooleanKeyword: 2710 case SyntaxKind.UndefinedKeyword: 2711 case SyntaxKind.NeverKeyword: 2712 case SyntaxKind.ObjectKeyword: 2713 // If these are followed by a dot, then parse these out as a dotted type reference instead. 2714 return tryParse(parseKeywordAndNoDot) || parseTypeReference(); 2715 case SyntaxKind.AsteriskToken: 2716 return parseJSDocAllType(); 2717 case SyntaxKind.QuestionToken: 2718 return parseJSDocUnknownOrNullableType(); 2719 case SyntaxKind.FunctionKeyword: 2720 return parseJSDocFunctionType(); 2721 case SyntaxKind.ExclamationToken: 2722 return parseJSDocNodeWithType(SyntaxKind.JSDocNonNullableType); 2723 case SyntaxKind.NoSubstitutionTemplateLiteral: 2724 case SyntaxKind.StringLiteral: 2725 case SyntaxKind.NumericLiteral: 2726 case SyntaxKind.TrueKeyword: 2727 case SyntaxKind.FalseKeyword: 2728 return parseLiteralTypeNode(); 2729 case SyntaxKind.MinusToken: 2730 return lookAhead(nextTokenIsNumericLiteral) ? parseLiteralTypeNode(/*negative*/ true) : parseTypeReference(); 2731 case SyntaxKind.VoidKeyword: 2732 case SyntaxKind.NullKeyword: 2733 return parseTokenNode<TypeNode>(); 2734 case SyntaxKind.ThisKeyword: { 2735 const thisKeyword = parseThisTypeNode(); 2736 if (token() === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) { 2737 return parseThisTypePredicate(thisKeyword); 2738 } 2739 else { 2740 return thisKeyword; 2741 } 2742 } 2743 case SyntaxKind.TypeOfKeyword: 2744 return parseTypeQuery(); 2745 case SyntaxKind.OpenBraceToken: 2746 return lookAhead(isStartOfMappedType) ? parseMappedType() : parseTypeLiteral(); 2747 case SyntaxKind.OpenBracketToken: 2748 return parseTupleType(); 2749 case SyntaxKind.OpenParenToken: 2750 return parseParenthesizedType(); 2751 default: 2752 return parseTypeReference(); 2753 } 2754 } 2755 2756 function isStartOfType(inStartOfParameter?: boolean): boolean { 2757 switch (token()) { 2758 case SyntaxKind.AnyKeyword: 2759 case SyntaxKind.StringKeyword: 2760 case SyntaxKind.NumberKeyword: 2761 case SyntaxKind.BooleanKeyword: 2762 case SyntaxKind.SymbolKeyword: 2763 case SyntaxKind.UniqueKeyword: 2764 case SyntaxKind.VoidKeyword: 2765 case SyntaxKind.UndefinedKeyword: 2766 case SyntaxKind.NullKeyword: 2767 case SyntaxKind.ThisKeyword: 2768 case SyntaxKind.TypeOfKeyword: 2769 case SyntaxKind.NeverKeyword: 2770 case SyntaxKind.OpenBraceToken: 2771 case SyntaxKind.OpenBracketToken: 2772 case SyntaxKind.LessThanToken: 2773 case SyntaxKind.BarToken: 2774 case SyntaxKind.AmpersandToken: 2775 case SyntaxKind.NewKeyword: 2776 case SyntaxKind.StringLiteral: 2777 case SyntaxKind.NumericLiteral: 2778 case SyntaxKind.TrueKeyword: 2779 case SyntaxKind.FalseKeyword: 2780 case SyntaxKind.ObjectKeyword: 2781 case SyntaxKind.AsteriskToken: 2782 case SyntaxKind.QuestionToken: 2783 case SyntaxKind.ExclamationToken: 2784 case SyntaxKind.DotDotDotToken: 2785 case SyntaxKind.InferKeyword: 2786 return true; 2787 case SyntaxKind.MinusToken: 2788 return !inStartOfParameter && lookAhead(nextTokenIsNumericLiteral); 2789 case SyntaxKind.OpenParenToken: 2790 // Only consider '(' the start of a type if followed by ')', '...', an identifier, a modifier, 2791 // or something that starts a type. We don't want to consider things like '(1)' a type. 2792 return !inStartOfParameter && lookAhead(isStartOfParenthesizedOrFunctionType); 2793 default: 2794 return isIdentifier(); 2795 } 2796 } 2797 2798 function isStartOfParenthesizedOrFunctionType() { 2799 nextToken(); 2800 return token() === SyntaxKind.CloseParenToken || isStartOfParameter() || isStartOfType(); 2801 } 2802 2803 function parsePostfixTypeOrHigher(): TypeNode { 2804 let type = parseNonArrayType(); 2805 while (!scanner.hasPrecedingLineBreak()) { 2806 switch (token()) { 2807 case SyntaxKind.EqualsToken: 2808 // only parse postfix = inside jsdoc, because it's ambiguous elsewhere 2809 if (!(contextFlags & NodeFlags.JSDoc)) { 2810 return type; 2811 } 2812 type = createJSDocPostfixType(SyntaxKind.JSDocOptionalType, type); 2813 break; 2814 case SyntaxKind.ExclamationToken: 2815 type = createJSDocPostfixType(SyntaxKind.JSDocNonNullableType, type); 2816 break; 2817 case SyntaxKind.QuestionToken: 2818 // If not in JSDoc and next token is start of a type we have a conditional type 2819 if (!(contextFlags & NodeFlags.JSDoc) && lookAhead(nextTokenIsStartOfType)) { 2820 return type; 2821 } 2822 type = createJSDocPostfixType(SyntaxKind.JSDocNullableType, type); 2823 break; 2824 case SyntaxKind.OpenBracketToken: 2825 parseExpected(SyntaxKind.OpenBracketToken); 2826 if (isStartOfType()) { 2827 const node = createNode(SyntaxKind.IndexedAccessType, type.pos) as IndexedAccessTypeNode; 2828 node.objectType = type; 2829 node.indexType = parseType(); 2830 parseExpected(SyntaxKind.CloseBracketToken); 2831 type = finishNode(node); 2832 } 2833 else { 2834 const node = createNode(SyntaxKind.ArrayType, type.pos) as ArrayTypeNode; 2835 node.elementType = type; 2836 parseExpected(SyntaxKind.CloseBracketToken); 2837 type = finishNode(node); 2838 } 2839 break; 2840 default: 2841 return type; 2842 } 2843 } 2844 return type; 2845 } 2846 2847 function createJSDocPostfixType(kind: SyntaxKind, type: TypeNode) { 2848 nextToken(); 2849 const postfix = createNode(kind, type.pos) as JSDocOptionalType | JSDocNonNullableType | JSDocNullableType; 2850 postfix.type = type; 2851 return finishNode(postfix); 2852 } 2853 2854 function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword) { 2855 const node = <TypeOperatorNode>createNode(SyntaxKind.TypeOperator); 2856 parseExpected(operator); 2857 node.operator = operator; 2858 node.type = parseTypeOperatorOrHigher(); 2859 return finishNode(node); 2860 } 2861 2862 function parseInferType(): InferTypeNode { 2863 const node = <InferTypeNode>createNode(SyntaxKind.InferType); 2864 parseExpected(SyntaxKind.InferKeyword); 2865 const typeParameter = <TypeParameterDeclaration>createNode(SyntaxKind.TypeParameter); 2866 typeParameter.name = parseIdentifier(); 2867 node.typeParameter = finishNode(typeParameter); 2868 return finishNode(node); 2869 } 2870 2871 function parseTypeOperatorOrHigher(): TypeNode { 2872 const operator = token(); 2873 switch (operator) { 2874 case SyntaxKind.KeyOfKeyword: 2875 case SyntaxKind.UniqueKeyword: 2876 return parseTypeOperator(operator); 2877 case SyntaxKind.InferKeyword: 2878 return parseInferType(); 2879 case SyntaxKind.DotDotDotToken: { 2880 const result = createNode(SyntaxKind.JSDocVariadicType) as JSDocVariadicType; 2881 nextToken(); 2882 result.type = parsePostfixTypeOrHigher(); 2883 return finishNode(result); 2884 } 2885 } 2886 return parsePostfixTypeOrHigher(); 2887 } 2888 2889 function parseUnionOrIntersectionType(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, parseConstituentType: () => TypeNode, operator: SyntaxKind.BarToken | SyntaxKind.AmpersandToken): TypeNode { 2890 parseOptional(operator); 2891 let type = parseConstituentType(); 2892 if (token() === operator) { 2893 const types = [type]; 2894 while (parseOptional(operator)) { 2895 types.push(parseConstituentType()); 2896 } 2897 const node = <UnionOrIntersectionTypeNode>createNode(kind, type.pos); 2898 node.types = createNodeArray(types, type.pos); 2899 type = finishNode(node); 2900 } 2901 return type; 2902 } 2903 2904 function parseIntersectionTypeOrHigher(): TypeNode { 2905 return parseUnionOrIntersectionType(SyntaxKind.IntersectionType, parseTypeOperatorOrHigher, SyntaxKind.AmpersandToken); 2906 } 2907 2908 function parseUnionTypeOrHigher(): TypeNode { 2909 return parseUnionOrIntersectionType(SyntaxKind.UnionType, parseIntersectionTypeOrHigher, SyntaxKind.BarToken); 2910 } 2911 2912 function isStartOfFunctionType(): boolean { 2913 if (token() === SyntaxKind.LessThanToken) { 2914 return true; 2915 } 2916 return token() === SyntaxKind.OpenParenToken && lookAhead(isUnambiguouslyStartOfFunctionType); 2917 } 2918 2919 function skipParameterStart(): boolean { 2920 if (isModifierKind(token())) { 2921 // Skip modifiers 2922 parseModifiers(); 2923 } 2924 if (isIdentifier() || token() === SyntaxKind.ThisKeyword) { 2925 nextToken(); 2926 return true; 2927 } 2928 if (token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.OpenBraceToken) { 2929 // Return true if we can parse an array or object binding pattern with no errors 2930 const previousErrorCount = parseDiagnostics.length; 2931 parseIdentifierOrPattern(); 2932 return previousErrorCount === parseDiagnostics.length; 2933 } 2934 return false; 2935 } 2936 2937 function isUnambiguouslyStartOfFunctionType() { 2938 nextToken(); 2939 if (token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.DotDotDotToken) { 2940 // ( ) 2941 // ( ... 2942 return true; 2943 } 2944 if (skipParameterStart()) { 2945 // We successfully skipped modifiers (if any) and an identifier or binding pattern, 2946 // now see if we have something that indicates a parameter declaration 2947 if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || 2948 token() === SyntaxKind.QuestionToken || token() === SyntaxKind.EqualsToken) { 2949 // ( xxx : 2950 // ( xxx , 2951 // ( xxx ? 2952 // ( xxx = 2953 return true; 2954 } 2955 if (token() === SyntaxKind.CloseParenToken) { 2956 nextToken(); 2957 if (token() === SyntaxKind.EqualsGreaterThanToken) { 2958 // ( xxx ) => 2959 return true; 2960 } 2961 } 2962 } 2963 return false; 2964 } 2965 2966 function parseTypeOrTypePredicate(): TypeNode { 2967 const typePredicateVariable = isIdentifier() && tryParse(parseTypePredicatePrefix); 2968 const type = parseType(); 2969 if (typePredicateVariable) { 2970 const node = <TypePredicateNode>createNode(SyntaxKind.TypePredicate, typePredicateVariable.pos); 2971 node.parameterName = typePredicateVariable; 2972 node.type = type; 2973 return finishNode(node); 2974 } 2975 else { 2976 return type; 2977 } 2978 } 2979 2980 function parseTypePredicatePrefix() { 2981 const id = parseIdentifier(); 2982 if (token() === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) { 2983 nextToken(); 2984 return id; 2985 } 2986 } 2987 2988 function parseType(): TypeNode { 2989 // The rules about 'yield' only apply to actual code/expression contexts. They don't 2990 // apply to 'type' contexts. So we disable these parameters here before moving on. 2991 return doOutsideOfContext(NodeFlags.TypeExcludesFlags, parseTypeWorker); 2992 } 2993 2994 function parseTypeWorker(noConditionalTypes?: boolean): TypeNode { 2995 if (isStartOfFunctionType()) { 2996 return parseFunctionOrConstructorType(SyntaxKind.FunctionType); 2997 } 2998 if (token() === SyntaxKind.NewKeyword) { 2999 return parseFunctionOrConstructorType(SyntaxKind.ConstructorType); 3000 } 3001 const type = parseUnionTypeOrHigher(); 3002 if (!noConditionalTypes && !scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.ExtendsKeyword)) { 3003 const node = <ConditionalTypeNode>createNode(SyntaxKind.ConditionalType, type.pos); 3004 node.checkType = type; 3005 // The type following 'extends' is not permitted to be another conditional type 3006 node.extendsType = parseTypeWorker(/*noConditionalTypes*/ true); 3007 parseExpected(SyntaxKind.QuestionToken); 3008 node.trueType = parseTypeWorker(); 3009 parseExpected(SyntaxKind.ColonToken); 3010 node.falseType = parseTypeWorker(); 3011 return finishNode(node); 3012 } 3013 return type; 3014 } 3015 3016 function parseTypeAnnotation(): TypeNode { 3017 return parseOptional(SyntaxKind.ColonToken) ? parseType() : undefined; 3018 } 3019 3020 // EXPRESSIONS 3021 function isStartOfLeftHandSideExpression(): boolean { 3022 switch (token()) { 3023 case SyntaxKind.ThisKeyword: 3024 case SyntaxKind.SuperKeyword: 3025 case SyntaxKind.NullKeyword: 3026 case SyntaxKind.TrueKeyword: 3027 case SyntaxKind.FalseKeyword: 3028 case SyntaxKind.NumericLiteral: 3029 case SyntaxKind.StringLiteral: 3030 case SyntaxKind.NoSubstitutionTemplateLiteral: 3031 case SyntaxKind.TemplateHead: 3032 case SyntaxKind.OpenParenToken: 3033 case SyntaxKind.OpenBracketToken: 3034 case SyntaxKind.OpenBraceToken: 3035 case SyntaxKind.FunctionKeyword: 3036 case SyntaxKind.ClassKeyword: 3037 case SyntaxKind.NewKeyword: 3038 case SyntaxKind.SlashToken: 3039 case SyntaxKind.SlashEqualsToken: 3040 case SyntaxKind.Identifier: 3041 return true; 3042 case SyntaxKind.ImportKeyword: 3043 return lookAhead(nextTokenIsOpenParenOrLessThan); 3044 default: 3045 return isIdentifier(); 3046 } 3047 } 3048 3049 function isStartOfExpression(): boolean { 3050 if (isStartOfLeftHandSideExpression()) { 3051 return true; 3052 } 3053 3054 switch (token()) { 3055 case SyntaxKind.PlusToken: 3056 case SyntaxKind.MinusToken: 3057 case SyntaxKind.TildeToken: 3058 case SyntaxKind.ExclamationToken: 3059 case SyntaxKind.DeleteKeyword: 3060 case SyntaxKind.TypeOfKeyword: 3061 case SyntaxKind.VoidKeyword: 3062 case SyntaxKind.PlusPlusToken: 3063 case SyntaxKind.MinusMinusToken: 3064 case SyntaxKind.LessThanToken: 3065 case SyntaxKind.AwaitKeyword: 3066 case SyntaxKind.YieldKeyword: 3067 // Yield/await always starts an expression. Either it is an identifier (in which case 3068 // it is definitely an expression). Or it's a keyword (either because we're in 3069 // a generator or async function, or in strict mode (or both)) and it started a yield or await expression. 3070 return true; 3071 default: 3072 // Error tolerance. If we see the start of some binary operator, we consider 3073 // that the start of an expression. That way we'll parse out a missing identifier, 3074 // give a good message about an identifier being missing, and then consume the 3075 // rest of the binary expression. 3076 if (isBinaryOperator()) { 3077 return true; 3078 } 3079 3080 return isIdentifier(); 3081 } 3082 } 3083 3084 function isStartOfExpressionStatement(): boolean { 3085 // As per the grammar, none of '{' or 'function' or 'class' can start an expression statement. 3086 return token() !== SyntaxKind.OpenBraceToken && 3087 token() !== SyntaxKind.FunctionKeyword && 3088 token() !== SyntaxKind.ClassKeyword && 3089 token() !== SyntaxKind.AtToken && 3090 isStartOfExpression(); 3091 } 3092 3093 function parseExpression(): Expression { 3094 // Expression[in]: 3095 // AssignmentExpression[in] 3096 // Expression[in] , AssignmentExpression[in] 3097 3098 // clear the decorator context when parsing Expression, as it should be unambiguous when parsing a decorator 3099 const saveDecoratorContext = inDecoratorContext(); 3100 if (saveDecoratorContext) { 3101 setDecoratorContext(/*val*/ false); 3102 } 3103 3104 let expr = parseAssignmentExpressionOrHigher(); 3105 let operatorToken: BinaryOperatorToken; 3106 while ((operatorToken = parseOptionalToken(SyntaxKind.CommaToken))) { 3107 expr = makeBinaryExpression(expr, operatorToken, parseAssignmentExpressionOrHigher()); 3108 } 3109 3110 if (saveDecoratorContext) { 3111 setDecoratorContext(/*val*/ true); 3112 } 3113 return expr; 3114 } 3115 3116 function parseInitializer(): Expression | undefined { 3117 return parseOptional(SyntaxKind.EqualsToken) ? parseAssignmentExpressionOrHigher() : undefined; 3118 } 3119 3120 function parseAssignmentExpressionOrHigher(): Expression { 3121 // AssignmentExpression[in,yield]: 3122 // 1) ConditionalExpression[?in,?yield] 3123 // 2) LeftHandSideExpression = AssignmentExpression[?in,?yield] 3124 // 3) LeftHandSideExpression AssignmentOperator AssignmentExpression[?in,?yield] 3125 // 4) ArrowFunctionExpression[?in,?yield] 3126 // 5) AsyncArrowFunctionExpression[in,yield,await] 3127 // 6) [+Yield] YieldExpression[?In] 3128 // 3129 // Note: for ease of implementation we treat productions '2' and '3' as the same thing. 3130 // (i.e. they're both BinaryExpressions with an assignment operator in it). 3131 3132 // First, do the simple check if we have a YieldExpression (production '6'). 3133 if (isYieldExpression()) { 3134 return parseYieldExpression(); 3135 } 3136 3137 // Then, check if we have an arrow function (production '4' and '5') that starts with a parenthesized 3138 // parameter list or is an async arrow function. 3139 // AsyncArrowFunctionExpression: 3140 // 1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In] 3141 // 2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In] 3142 // Production (1) of AsyncArrowFunctionExpression is parsed in "tryParseAsyncSimpleArrowFunctionExpression". 3143 // And production (2) is parsed in "tryParseParenthesizedArrowFunctionExpression". 3144 // 3145 // If we do successfully parse arrow-function, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is 3146 // not a LeftHandSideExpression, nor does it start a ConditionalExpression. So we are done 3147 // with AssignmentExpression if we see one. 3148 const arrowExpression = tryParseParenthesizedArrowFunctionExpression() || tryParseAsyncSimpleArrowFunctionExpression(); 3149 if (arrowExpression) { 3150 return arrowExpression; 3151 } 3152 3153 // Now try to see if we're in production '1', '2' or '3'. A conditional expression can 3154 // start with a LogicalOrExpression, while the assignment productions can only start with 3155 // LeftHandSideExpressions. 3156 // 3157 // So, first, we try to just parse out a BinaryExpression. If we get something that is a 3158 // LeftHandSide or higher, then we can try to parse out the assignment expression part. 3159 // Otherwise, we try to parse out the conditional expression bit. We want to allow any 3160 // binary expression here, so we pass in the 'lowest' precedence here so that it matches 3161 // and consumes anything. 3162 const expr = parseBinaryExpressionOrHigher(/*precedence*/ 0); 3163 3164 // To avoid a look-ahead, we did not handle the case of an arrow function with a single un-parenthesized 3165 // parameter ('x => ...') above. We handle it here by checking if the parsed expression was a single 3166 // identifier and the current token is an arrow. 3167 if (expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) { 3168 return parseSimpleArrowFunctionExpression(<Identifier>expr); 3169 } 3170 3171 // Now see if we might be in cases '2' or '3'. 3172 // If the expression was a LHS expression, and we have an assignment operator, then 3173 // we're in '2' or '3'. Consume the assignment and return. 3174 // 3175 // Note: we call reScanGreaterToken so that we get an appropriately merged token 3176 // for cases like `> > =` becoming `>>=` 3177 if (isLeftHandSideExpression(expr) && isAssignmentOperator(reScanGreaterToken())) { 3178 return makeBinaryExpression(expr, <BinaryOperatorToken>parseTokenNode(), parseAssignmentExpressionOrHigher()); 3179 } 3180 3181 // It wasn't an assignment or a lambda. This is a conditional expression: 3182 return parseConditionalExpressionRest(expr); 3183 } 3184 3185 function isYieldExpression(): boolean { 3186 if (token() === SyntaxKind.YieldKeyword) { 3187 // If we have a 'yield' keyword, and this is a context where yield expressions are 3188 // allowed, then definitely parse out a yield expression. 3189 if (inYieldContext()) { 3190 return true; 3191 } 3192 3193 // We're in a context where 'yield expr' is not allowed. However, if we can 3194 // definitely tell that the user was trying to parse a 'yield expr' and not 3195 // just a normal expr that start with a 'yield' identifier, then parse out 3196 // a 'yield expr'. We can then report an error later that they are only 3197 // allowed in generator expressions. 3198 // 3199 // for example, if we see 'yield(foo)', then we'll have to treat that as an 3200 // invocation expression of something called 'yield'. However, if we have 3201 // 'yield foo' then that is not legal as a normal expression, so we can 3202 // definitely recognize this as a yield expression. 3203 // 3204 // for now we just check if the next token is an identifier. More heuristics 3205 // can be added here later as necessary. We just need to make sure that we 3206 // don't accidentally consume something legal. 3207 return lookAhead(nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine); 3208 } 3209 3210 return false; 3211 } 3212 3213 function nextTokenIsIdentifierOnSameLine() { 3214 nextToken(); 3215 return !scanner.hasPrecedingLineBreak() && isIdentifier(); 3216 } 3217 3218 function parseYieldExpression(): YieldExpression { 3219 const node = <YieldExpression>createNode(SyntaxKind.YieldExpression); 3220 3221 // YieldExpression[In] : 3222 // yield 3223 // yield [no LineTerminator here] [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield] 3224 // yield [no LineTerminator here] * [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield] 3225 nextToken(); 3226 3227 if (!scanner.hasPrecedingLineBreak() && 3228 (token() === SyntaxKind.AsteriskToken || isStartOfExpression())) { 3229 node.asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); 3230 node.expression = parseAssignmentExpressionOrHigher(); 3231 return finishNode(node); 3232 } 3233 else { 3234 // if the next token is not on the same line as yield. or we don't have an '*' or 3235 // the start of an expression, then this is just a simple "yield" expression. 3236 return finishNode(node); 3237 } 3238 } 3239 3240 function parseSimpleArrowFunctionExpression(identifier: Identifier, asyncModifier?: NodeArray<Modifier>): ArrowFunction { 3241 Debug.assert(token() === SyntaxKind.EqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>"); 3242 3243 let node: ArrowFunction; 3244 if (asyncModifier) { 3245 node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction, asyncModifier.pos); 3246 node.modifiers = asyncModifier; 3247 } 3248 else { 3249 node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction, identifier.pos); 3250 } 3251 3252 const parameter = <ParameterDeclaration>createNode(SyntaxKind.Parameter, identifier.pos); 3253 parameter.name = identifier; 3254 finishNode(parameter); 3255 3256 node.parameters = createNodeArray<ParameterDeclaration>([parameter], parameter.pos, parameter.end); 3257 3258 node.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken); 3259 node.body = parseArrowFunctionExpressionBody(/*isAsync*/ !!asyncModifier); 3260 3261 return addJSDocComment(finishNode(node)); 3262 } 3263 3264 function tryParseParenthesizedArrowFunctionExpression(): Expression | undefined { 3265 const triState = isParenthesizedArrowFunctionExpression(); 3266 if (triState === Tristate.False) { 3267 // It's definitely not a parenthesized arrow function expression. 3268 return undefined; 3269 } 3270 3271 // If we definitely have an arrow function, then we can just parse one, not requiring a 3272 // following => or { token. Otherwise, we *might* have an arrow function. Try to parse 3273 // it out, but don't allow any ambiguity, and return 'undefined' if this could be an 3274 // expression instead. 3275 const arrowFunction = triState === Tristate.True 3276 ? parseParenthesizedArrowFunctionExpressionHead(/*allowAmbiguity*/ true) 3277 : tryParse(parsePossibleParenthesizedArrowFunctionExpressionHead); 3278 3279 if (!arrowFunction) { 3280 // Didn't appear to actually be a parenthesized arrow function. Just bail out. 3281 return undefined; 3282 } 3283 3284 const isAsync = hasModifier(arrowFunction, ModifierFlags.Async); 3285 3286 // If we have an arrow, then try to parse the body. Even if not, try to parse if we 3287 // have an opening brace, just in case we're in an error state. 3288 const lastToken = token(); 3289 arrowFunction.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken); 3290 arrowFunction.body = (lastToken === SyntaxKind.EqualsGreaterThanToken || lastToken === SyntaxKind.OpenBraceToken) 3291 ? parseArrowFunctionExpressionBody(isAsync) 3292 : parseIdentifier(); 3293 3294 return finishNode(arrowFunction); 3295 } 3296 3297 // True -> We definitely expect a parenthesized arrow function here. 3298 // False -> There *cannot* be a parenthesized arrow function here. 3299 // Unknown -> There *might* be a parenthesized arrow function here. 3300 // Speculatively look ahead to be sure, and rollback if not. 3301 function isParenthesizedArrowFunctionExpression(): Tristate { 3302 if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken || token() === SyntaxKind.AsyncKeyword) { 3303 return lookAhead(isParenthesizedArrowFunctionExpressionWorker); 3304 } 3305 3306 if (token() === SyntaxKind.EqualsGreaterThanToken) { 3307 // ERROR RECOVERY TWEAK: 3308 // If we see a standalone => try to parse it as an arrow function expression as that's 3309 // likely what the user intended to write. 3310 return Tristate.True; 3311 } 3312 // Definitely not a parenthesized arrow function. 3313 return Tristate.False; 3314 } 3315 3316 function isParenthesizedArrowFunctionExpressionWorker() { 3317 if (token() === SyntaxKind.AsyncKeyword) { 3318 nextToken(); 3319 if (scanner.hasPrecedingLineBreak()) { 3320 return Tristate.False; 3321 } 3322 if (token() !== SyntaxKind.OpenParenToken && token() !== SyntaxKind.LessThanToken) { 3323 return Tristate.False; 3324 } 3325 } 3326 3327 const first = token(); 3328 const second = nextToken(); 3329 3330 if (first === SyntaxKind.OpenParenToken) { 3331 if (second === SyntaxKind.CloseParenToken) { 3332 // Simple cases: "() =>", "(): ", and "() {". 3333 // This is an arrow function with no parameters. 3334 // The last one is not actually an arrow function, 3335 // but this is probably what the user intended. 3336 const third = nextToken(); 3337 switch (third) { 3338 case SyntaxKind.EqualsGreaterThanToken: 3339 case SyntaxKind.ColonToken: 3340 case SyntaxKind.OpenBraceToken: 3341 return Tristate.True; 3342 default: 3343 return Tristate.False; 3344 } 3345 } 3346 3347 // If encounter "([" or "({", this could be the start of a binding pattern. 3348 // Examples: 3349 // ([ x ]) => { } 3350 // ({ x }) => { } 3351 // ([ x ]) 3352 // ({ x }) 3353 if (second === SyntaxKind.OpenBracketToken || second === SyntaxKind.OpenBraceToken) { 3354 return Tristate.Unknown; 3355 } 3356 3357 // Simple case: "(..." 3358 // This is an arrow function with a rest parameter. 3359 if (second === SyntaxKind.DotDotDotToken) { 3360 return Tristate.True; 3361 } 3362 3363 // Check for "(xxx yyy", where xxx is a modifier and yyy is an identifier. This 3364 // isn't actually allowed, but we want to treat it as a lambda so we can provide 3365 // a good error message. 3366 if (isModifierKind(second) && second !== SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsIdentifier)) { 3367 return Tristate.True; 3368 } 3369 3370 // If we had "(" followed by something that's not an identifier, 3371 // then this definitely doesn't look like a lambda. 3372 if (!isIdentifier()) { 3373 return Tristate.False; 3374 } 3375 3376 switch (nextToken()) { 3377 case SyntaxKind.ColonToken: 3378 // If we have something like "(a:", then we must have a 3379 // type-annotated parameter in an arrow function expression. 3380 return Tristate.True; 3381 case SyntaxKind.QuestionToken: 3382 nextToken(); 3383 // If we have "(a?:" or "(a?," or "(a?=" or "(a?)" then it is definitely a lambda. 3384 if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.EqualsToken || token() === SyntaxKind.CloseParenToken) { 3385 return Tristate.True; 3386 } 3387 // Otherwise it is definitely not a lambda. 3388 return Tristate.False; 3389 case SyntaxKind.CommaToken: 3390 case SyntaxKind.EqualsToken: 3391 case SyntaxKind.CloseParenToken: 3392 // If we have "(a," or "(a=" or "(a)" this *could* be an arrow function 3393 return Tristate.Unknown; 3394 } 3395 // It is definitely not an arrow function 3396 return Tristate.False; 3397 } 3398 else { 3399 Debug.assert(first === SyntaxKind.LessThanToken); 3400 3401 // If we have "<" not followed by an identifier, 3402 // then this definitely is not an arrow function. 3403 if (!isIdentifier()) { 3404 return Tristate.False; 3405 } 3406 3407 // JSX overrides 3408 if (sourceFile.languageVariant === LanguageVariant.JSX) { 3409 const isArrowFunctionInJsx = lookAhead(() => { 3410 const third = nextToken(); 3411 if (third === SyntaxKind.ExtendsKeyword) { 3412 const fourth = nextToken(); 3413 switch (fourth) { 3414 case SyntaxKind.EqualsToken: 3415 case SyntaxKind.GreaterThanToken: 3416 return false; 3417 default: 3418 return true; 3419 } 3420 } 3421 else if (third === SyntaxKind.CommaToken) { 3422 return true; 3423 } 3424 return false; 3425 }); 3426 3427 if (isArrowFunctionInJsx) { 3428 return Tristate.True; 3429 } 3430 3431 return Tristate.False; 3432 } 3433 3434 // This *could* be a parenthesized arrow function. 3435 return Tristate.Unknown; 3436 } 3437 } 3438 3439 function parsePossibleParenthesizedArrowFunctionExpressionHead(): ArrowFunction { 3440 return parseParenthesizedArrowFunctionExpressionHead(/*allowAmbiguity*/ false); 3441 } 3442 3443 function tryParseAsyncSimpleArrowFunctionExpression(): ArrowFunction | undefined { 3444 // We do a check here so that we won't be doing unnecessarily call to "lookAhead" 3445 if (token() === SyntaxKind.AsyncKeyword) { 3446 if (lookAhead(isUnParenthesizedAsyncArrowFunctionWorker) === Tristate.True) { 3447 const asyncModifier = parseModifiersForArrowFunction(); 3448 const expr = parseBinaryExpressionOrHigher(/*precedence*/ 0); 3449 return parseSimpleArrowFunctionExpression(<Identifier>expr, asyncModifier); 3450 } 3451 } 3452 return undefined; 3453 } 3454 3455 function isUnParenthesizedAsyncArrowFunctionWorker(): Tristate { 3456 // AsyncArrowFunctionExpression: 3457 // 1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In] 3458 // 2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In] 3459 if (token() === SyntaxKind.AsyncKeyword) { 3460 nextToken(); 3461 // If the "async" is followed by "=>" token then it is not a begining of an async arrow-function 3462 // but instead a simple arrow-function which will be parsed inside "parseAssignmentExpressionOrHigher" 3463 if (scanner.hasPrecedingLineBreak() || token() === SyntaxKind.EqualsGreaterThanToken) { 3464 return Tristate.False; 3465 } 3466 // Check for un-parenthesized AsyncArrowFunction 3467 const expr = parseBinaryExpressionOrHigher(/*precedence*/ 0); 3468 if (!scanner.hasPrecedingLineBreak() && expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) { 3469 return Tristate.True; 3470 } 3471 } 3472 3473 return Tristate.False; 3474 } 3475 3476 function parseParenthesizedArrowFunctionExpressionHead(allowAmbiguity: boolean): ArrowFunction { 3477 const node = <ArrowFunction>createNodeWithJSDoc(SyntaxKind.ArrowFunction); 3478 node.modifiers = parseModifiersForArrowFunction(); 3479 const isAsync = hasModifier(node, ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None; 3480 // Arrow functions are never generators. 3481 // 3482 // If we're speculatively parsing a signature for a parenthesized arrow function, then 3483 // we have to have a complete parameter list. Otherwise we might see something like 3484 // a => (b => c) 3485 // And think that "(b =>" was actually a parenthesized arrow function with a missing 3486 // close paren. 3487 fillSignature(SyntaxKind.ColonToken, isAsync | (allowAmbiguity ? SignatureFlags.None : SignatureFlags.RequireCompleteParameterList), node); 3488 3489 // If we couldn't get parameters, we definitely could not parse out an arrow function. 3490 if (!node.parameters) { 3491 return undefined; 3492 } 3493 3494 // Parsing a signature isn't enough. 3495 // Parenthesized arrow signatures often look like other valid expressions. 3496 // For instance: 3497 // - "(x = 10)" is an assignment expression parsed as a signature with a default parameter value. 3498 // - "(x,y)" is a comma expression parsed as a signature with two parameters. 3499 // - "a ? (b): c" will have "(b):" parsed as a signature with a return type annotation. 3500 // 3501 // So we need just a bit of lookahead to ensure that it can only be a signature. 3502 if (!allowAmbiguity && token() !== SyntaxKind.EqualsGreaterThanToken && token() !== SyntaxKind.OpenBraceToken) { 3503 // Returning undefined here will cause our caller to rewind to where we started from. 3504 return undefined; 3505 } 3506 3507 return node; 3508 } 3509 3510 function parseArrowFunctionExpressionBody(isAsync: boolean): Block | Expression { 3511 if (token() === SyntaxKind.OpenBraceToken) { 3512 return parseFunctionBlock(isAsync ? SignatureFlags.Await : SignatureFlags.None); 3513 } 3514 3515 if (token() !== SyntaxKind.SemicolonToken && 3516 token() !== SyntaxKind.FunctionKeyword && 3517 token() !== SyntaxKind.ClassKeyword && 3518 isStartOfStatement() && 3519 !isStartOfExpressionStatement()) { 3520 // Check if we got a plain statement (i.e. no expression-statements, no function/class expressions/declarations) 3521 // 3522 // Here we try to recover from a potential error situation in the case where the 3523 // user meant to supply a block. For example, if the user wrote: 3524 // 3525 // a => 3526 // let v = 0; 3527 // } 3528 // 3529 // they may be missing an open brace. Check to see if that's the case so we can 3530 // try to recover better. If we don't do this, then the next close curly we see may end 3531 // up preemptively closing the containing construct. 3532 // 3533 // Note: even when 'IgnoreMissingOpenBrace' is passed, parseBody will still error. 3534 return parseFunctionBlock(SignatureFlags.IgnoreMissingOpenBrace | (isAsync ? SignatureFlags.Await : SignatureFlags.None)); 3535 } 3536 3537 return isAsync 3538 ? doInAwaitContext(parseAssignmentExpressionOrHigher) 3539 : doOutsideOfAwaitContext(parseAssignmentExpressionOrHigher); 3540 } 3541 3542 function parseConditionalExpressionRest(leftOperand: Expression): Expression { 3543 // Note: we are passed in an expression which was produced from parseBinaryExpressionOrHigher. 3544 const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); 3545 if (!questionToken) { 3546 return leftOperand; 3547 } 3548 3549 // Note: we explicitly 'allowIn' in the whenTrue part of the condition expression, and 3550 // we do not that for the 'whenFalse' part. 3551 const node = <ConditionalExpression>createNode(SyntaxKind.ConditionalExpression, leftOperand.pos); 3552 node.condition = leftOperand; 3553 node.questionToken = questionToken; 3554 node.whenTrue = doOutsideOfContext(disallowInAndDecoratorContext, parseAssignmentExpressionOrHigher); 3555 node.colonToken = parseExpectedToken(SyntaxKind.ColonToken); 3556 node.whenFalse = nodeIsPresent(node.colonToken) 3557 ? parseAssignmentExpressionOrHigher() 3558 : createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken)); 3559 return finishNode(node); 3560 } 3561 3562 function parseBinaryExpressionOrHigher(precedence: number): Expression { 3563 const leftOperand = parseUnaryExpressionOrHigher(); 3564 return parseBinaryExpressionRest(precedence, leftOperand); 3565 } 3566 3567 function isInOrOfKeyword(t: SyntaxKind) { 3568 return t === SyntaxKind.InKeyword || t === SyntaxKind.OfKeyword; 3569 } 3570 3571 function parseBinaryExpressionRest(precedence: number, leftOperand: Expression): Expression { 3572 while (true) { 3573 // We either have a binary operator here, or we're finished. We call 3574 // reScanGreaterToken so that we merge token sequences like > and = into >= 3575 3576 reScanGreaterToken(); 3577 const newPrecedence = getBinaryOperatorPrecedence(); 3578 3579 // Check the precedence to see if we should "take" this operator 3580 // - For left associative operator (all operator but **), consume the operator, 3581 // recursively call the function below, and parse binaryExpression as a rightOperand 3582 // of the caller if the new precedence of the operator is greater then or equal to the current precedence. 3583 // For example: 3584 // a - b - c; 3585 // ^token; leftOperand = b. Return b to the caller as a rightOperand 3586 // a * b - c 3587 // ^token; leftOperand = b. Return b to the caller as a rightOperand 3588 // a - b * c; 3589 // ^token; leftOperand = b. Return b * c to the caller as a rightOperand 3590 // - For right associative operator (**), consume the operator, recursively call the function 3591 // and parse binaryExpression as a rightOperand of the caller if the new precedence of 3592 // the operator is strictly grater than the current precedence 3593 // For example: 3594 // a ** b ** c; 3595 // ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand 3596 // a - b ** c; 3597 // ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand 3598 // a ** b - c 3599 // ^token; leftOperand = b. Return b to the caller as a rightOperand 3600 const consumeCurrentOperator = token() === SyntaxKind.AsteriskAsteriskToken ? 3601 newPrecedence >= precedence : 3602 newPrecedence > precedence; 3603 3604 if (!consumeCurrentOperator) { 3605 break; 3606 } 3607 3608 if (token() === SyntaxKind.InKeyword && inDisallowInContext()) { 3609 break; 3610 } 3611 3612 if (token() === SyntaxKind.AsKeyword) { 3613 // Make sure we *do* perform ASI for constructs like this: 3614 // var x = foo 3615 // as (Bar) 3616 // This should be parsed as an initialized variable, followed 3617 // by a function call to 'as' with the argument 'Bar' 3618 if (scanner.hasPrecedingLineBreak()) { 3619 break; 3620 } 3621 else { 3622 nextToken(); 3623 leftOperand = makeAsExpression(leftOperand, parseType()); 3624 } 3625 } 3626 else { 3627 leftOperand = makeBinaryExpression(leftOperand, <BinaryOperatorToken>parseTokenNode(), parseBinaryExpressionOrHigher(newPrecedence)); 3628 } 3629 } 3630 3631 return leftOperand; 3632 } 3633 3634 function isBinaryOperator() { 3635 if (inDisallowInContext() && token() === SyntaxKind.InKeyword) { 3636 return false; 3637 } 3638 3639 return getBinaryOperatorPrecedence() > 0; 3640 } 3641 3642 function getBinaryOperatorPrecedence(): number { 3643 switch (token()) { 3644 case SyntaxKind.BarBarToken: 3645 return 1; 3646 case SyntaxKind.AmpersandAmpersandToken: 3647 return 2; 3648 case SyntaxKind.BarToken: 3649 return 3; 3650 case SyntaxKind.CaretToken: 3651 return 4; 3652 case SyntaxKind.AmpersandToken: 3653 return 5; 3654 case SyntaxKind.EqualsEqualsToken: 3655 case SyntaxKind.ExclamationEqualsToken: 3656 case SyntaxKind.EqualsEqualsEqualsToken: 3657 case SyntaxKind.ExclamationEqualsEqualsToken: 3658 return 6; 3659 case SyntaxKind.LessThanToken: 3660 case SyntaxKind.GreaterThanToken: 3661 case SyntaxKind.LessThanEqualsToken: 3662 case SyntaxKind.GreaterThanEqualsToken: 3663 case SyntaxKind.InstanceOfKeyword: 3664 case SyntaxKind.InKeyword: 3665 case SyntaxKind.AsKeyword: 3666 return 7; 3667 case SyntaxKind.LessThanLessThanToken: 3668 case SyntaxKind.GreaterThanGreaterThanToken: 3669 case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: 3670 return 8; 3671 case SyntaxKind.PlusToken: 3672 case SyntaxKind.MinusToken: 3673 return 9; 3674 case SyntaxKind.AsteriskToken: 3675 case SyntaxKind.SlashToken: 3676 case SyntaxKind.PercentToken: 3677 return 10; 3678 case SyntaxKind.AsteriskAsteriskToken: 3679 return 11; 3680 } 3681 3682 // -1 is lower than all other precedences. Returning it will cause binary expression 3683 // parsing to stop. 3684 return -1; 3685 } 3686 3687 function makeBinaryExpression(left: Expression, operatorToken: BinaryOperatorToken, right: Expression): BinaryExpression { 3688 const node = <BinaryExpression>createNode(SyntaxKind.BinaryExpression, left.pos); 3689 node.left = left; 3690 node.operatorToken = operatorToken; 3691 node.right = right; 3692 return finishNode(node); 3693 } 3694 3695 function makeAsExpression(left: Expression, right: TypeNode): AsExpression { 3696 const node = <AsExpression>createNode(SyntaxKind.AsExpression, left.pos); 3697 node.expression = left; 3698 node.type = right; 3699 return finishNode(node); 3700 } 3701 3702 function parsePrefixUnaryExpression() { 3703 const node = <PrefixUnaryExpression>createNode(SyntaxKind.PrefixUnaryExpression); 3704 node.operator = <PrefixUnaryOperator>token(); 3705 nextToken(); 3706 node.operand = parseSimpleUnaryExpression(); 3707 3708 return finishNode(node); 3709 } 3710 3711 function parseDeleteExpression() { 3712 const node = <DeleteExpression>createNode(SyntaxKind.DeleteExpression); 3713 nextToken(); 3714 node.expression = parseSimpleUnaryExpression(); 3715 return finishNode(node); 3716 } 3717 3718 function parseTypeOfExpression() { 3719 const node = <TypeOfExpression>createNode(SyntaxKind.TypeOfExpression); 3720 nextToken(); 3721 node.expression = parseSimpleUnaryExpression(); 3722 return finishNode(node); 3723 } 3724 3725 function parseVoidExpression() { 3726 const node = <VoidExpression>createNode(SyntaxKind.VoidExpression); 3727 nextToken(); 3728 node.expression = parseSimpleUnaryExpression(); 3729 return finishNode(node); 3730 } 3731 3732 function isAwaitExpression(): boolean { 3733 if (token() === SyntaxKind.AwaitKeyword) { 3734 if (inAwaitContext()) { 3735 return true; 3736 } 3737 3738 // here we are using similar heuristics as 'isYieldExpression' 3739 return lookAhead(nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine); 3740 } 3741 3742 return false; 3743 } 3744 3745 function parseAwaitExpression() { 3746 const node = <AwaitExpression>createNode(SyntaxKind.AwaitExpression); 3747 nextToken(); 3748 node.expression = parseSimpleUnaryExpression(); 3749 return finishNode(node); 3750 } 3751 3752 /** 3753 * Parse ES7 exponential expression and await expression 3754 * 3755 * ES7 ExponentiationExpression: 3756 * 1) UnaryExpression[?Yield] 3757 * 2) UpdateExpression[?Yield] ** ExponentiationExpression[?Yield] 3758 * 3759 */ 3760 function parseUnaryExpressionOrHigher(): UnaryExpression | BinaryExpression { 3761 /** 3762 * ES7 UpdateExpression: 3763 * 1) LeftHandSideExpression[?Yield] 3764 * 2) LeftHandSideExpression[?Yield][no LineTerminator here]++ 3765 * 3) LeftHandSideExpression[?Yield][no LineTerminator here]-- 3766 * 4) ++UnaryExpression[?Yield] 3767 * 5) --UnaryExpression[?Yield] 3768 */ 3769 if (isUpdateExpression()) { 3770 const updateExpression = parseUpdateExpression(); 3771 return token() === SyntaxKind.AsteriskAsteriskToken ? 3772 <BinaryExpression>parseBinaryExpressionRest(getBinaryOperatorPrecedence(), updateExpression) : 3773 updateExpression; 3774 } 3775 3776 /** 3777 * ES7 UnaryExpression: 3778 * 1) UpdateExpression[?yield] 3779 * 2) delete UpdateExpression[?yield] 3780 * 3) void UpdateExpression[?yield] 3781 * 4) typeof UpdateExpression[?yield] 3782 * 5) + UpdateExpression[?yield] 3783 * 6) - UpdateExpression[?yield] 3784 * 7) ~ UpdateExpression[?yield] 3785 * 8) ! UpdateExpression[?yield] 3786 */ 3787 const unaryOperator = token(); 3788 const simpleUnaryExpression = parseSimpleUnaryExpression(); 3789 if (token() === SyntaxKind.AsteriskAsteriskToken) { 3790 const start = skipTrivia(sourceText, simpleUnaryExpression.pos); 3791 if (simpleUnaryExpression.kind === SyntaxKind.TypeAssertionExpression) { 3792 parseErrorAtPosition(start, simpleUnaryExpression.end - start, Diagnostics.A_type_assertion_expression_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses); 3793 } 3794 else { 3795 parseErrorAtPosition(start, simpleUnaryExpression.end - start, 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)); 3796 } 3797 } 3798 return simpleUnaryExpression; 3799 } 3800 3801 /** 3802 * Parse ES7 simple-unary expression or higher: 3803 * 3804 * ES7 UnaryExpression: 3805 * 1) UpdateExpression[?yield] 3806 * 2) delete UnaryExpression[?yield] 3807 * 3) void UnaryExpression[?yield] 3808 * 4) typeof UnaryExpression[?yield] 3809 * 5) + UnaryExpression[?yield] 3810 * 6) - UnaryExpression[?yield] 3811 * 7) ~ UnaryExpression[?yield] 3812 * 8) ! UnaryExpression[?yield] 3813 * 9) [+Await] await UnaryExpression[?yield] 3814 */ 3815 function parseSimpleUnaryExpression(): UnaryExpression { 3816 switch (token()) { 3817 case SyntaxKind.PlusToken: 3818 case SyntaxKind.MinusToken: 3819 case SyntaxKind.TildeToken: 3820 case SyntaxKind.ExclamationToken: 3821 return parsePrefixUnaryExpression(); 3822 case SyntaxKind.DeleteKeyword: 3823 return parseDeleteExpression(); 3824 case SyntaxKind.TypeOfKeyword: 3825 return parseTypeOfExpression(); 3826 case SyntaxKind.VoidKeyword: 3827 return parseVoidExpression(); 3828 case SyntaxKind.LessThanToken: 3829 // This is modified UnaryExpression grammar in TypeScript 3830 // UnaryExpression (modified): 3831 // < type > UnaryExpression 3832 return parseTypeAssertion(); 3833 case SyntaxKind.AwaitKeyword: 3834 if (isAwaitExpression()) { 3835 return parseAwaitExpression(); 3836 } 3837 // falls through 3838 default: 3839 return parseUpdateExpression(); 3840 } 3841 } 3842 3843 /** 3844 * Check if the current token can possibly be an ES7 increment expression. 3845 * 3846 * ES7 UpdateExpression: 3847 * LeftHandSideExpression[?Yield] 3848 * LeftHandSideExpression[?Yield][no LineTerminator here]++ 3849 * LeftHandSideExpression[?Yield][no LineTerminator here]-- 3850 * ++LeftHandSideExpression[?Yield] 3851 * --LeftHandSideExpression[?Yield] 3852 */ 3853 function isUpdateExpression(): boolean { 3854 // This function is called inside parseUnaryExpression to decide 3855 // whether to call parseSimpleUnaryExpression or call parseUpdateExpression directly 3856 switch (token()) { 3857 case SyntaxKind.PlusToken: 3858 case SyntaxKind.MinusToken: 3859 case SyntaxKind.TildeToken: 3860 case SyntaxKind.ExclamationToken: 3861 case SyntaxKind.DeleteKeyword: 3862 case SyntaxKind.TypeOfKeyword: 3863 case SyntaxKind.VoidKeyword: 3864 case SyntaxKind.AwaitKeyword: 3865 return false; 3866 case SyntaxKind.LessThanToken: 3867 // If we are not in JSX context, we are parsing TypeAssertion which is an UnaryExpression 3868 if (sourceFile.languageVariant !== LanguageVariant.JSX) { 3869 return false; 3870 } 3871 // We are in JSX context and the token is part of JSXElement. 3872 // falls through 3873 default: 3874 return true; 3875 } 3876 } 3877 3878 /** 3879 * Parse ES7 UpdateExpression. UpdateExpression is used instead of ES6's PostFixExpression. 3880 * 3881 * ES7 UpdateExpression[yield]: 3882 * 1) LeftHandSideExpression[?yield] 3883 * 2) LeftHandSideExpression[?yield] [[no LineTerminator here]]++ 3884 * 3) LeftHandSideExpression[?yield] [[no LineTerminator here]]-- 3885 * 4) ++LeftHandSideExpression[?yield] 3886 * 5) --LeftHandSideExpression[?yield] 3887 * In TypeScript (2), (3) are parsed as PostfixUnaryExpression. (4), (5) are parsed as PrefixUnaryExpression 3888 */ 3889 function parseUpdateExpression(): UpdateExpression { 3890 if (token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) { 3891 const node = <PrefixUnaryExpression>createNode(SyntaxKind.PrefixUnaryExpression); 3892 node.operator = <PrefixUnaryOperator>token(); 3893 nextToken(); 3894 node.operand = parseLeftHandSideExpressionOrHigher(); 3895 return finishNode(node); 3896 } 3897 else if (sourceFile.languageVariant === LanguageVariant.JSX && token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsIdentifierOrKeywordOrGreaterThan)) { 3898 // JSXElement is part of primaryExpression 3899 return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true); 3900 } 3901 3902 const expression = parseLeftHandSideExpressionOrHigher(); 3903 3904 Debug.assert(isLeftHandSideExpression(expression)); 3905 if ((token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) && !scanner.hasPrecedingLineBreak()) { 3906 const node = <PostfixUnaryExpression>createNode(SyntaxKind.PostfixUnaryExpression, expression.pos); 3907 node.operand = expression; 3908 node.operator = <PostfixUnaryOperator>token(); 3909 nextToken(); 3910 return finishNode(node); 3911 } 3912 3913 return expression; 3914 } 3915 3916 function parseLeftHandSideExpressionOrHigher(): LeftHandSideExpression { 3917 // Original Ecma: 3918 // LeftHandSideExpression: See 11.2 3919 // NewExpression 3920 // CallExpression 3921 // 3922 // Our simplification: 3923 // 3924 // LeftHandSideExpression: See 11.2 3925 // MemberExpression 3926 // CallExpression 3927 // 3928 // See comment in parseMemberExpressionOrHigher on how we replaced NewExpression with 3929 // MemberExpression to make our lives easier. 3930 // 3931 // to best understand the below code, it's important to see how CallExpression expands 3932 // out into its own productions: 3933 // 3934 // CallExpression: 3935 // MemberExpression Arguments 3936 // CallExpression Arguments 3937 // CallExpression[Expression] 3938 // CallExpression.IdentifierName 3939 // import (AssignmentExpression) 3940 // super Arguments 3941 // super.IdentifierName 3942 // 3943 // Because of the recursion in these calls, we need to bottom out first. There are three 3944 // bottom out states we can run into: 1) We see 'super' which must start either of 3945 // the last two CallExpression productions. 2) We see 'import' which must start import call. 3946 // 3)we have a MemberExpression which either completes the LeftHandSideExpression, 3947 // or starts the beginning of the first four CallExpression productions. 3948 let expression: MemberExpression; 3949 if (token() === SyntaxKind.ImportKeyword && lookAhead(nextTokenIsOpenParenOrLessThan)) { 3950 // We don't want to eagerly consume all import keyword as import call expression so we look a head to find "(" 3951 // For example: 3952 // var foo3 = require("subfolder 3953 // import * as foo1 from "module-from-node 3954 // We want this import to be a statement rather than import call expression 3955 sourceFile.flags |= NodeFlags.PossiblyContainsDynamicImport; 3956 expression = parseTokenNode<PrimaryExpression>(); 3957 } 3958 else { 3959 expression = token() === SyntaxKind.SuperKeyword ? parseSuperExpression() : parseMemberExpressionOrHigher(); 3960 } 3961 3962 // Now, we *may* be complete. However, we might have consumed the start of a 3963 // CallExpression. As such, we need to consume the rest of it here to be complete. 3964 return parseCallExpressionRest(expression); 3965 } 3966 3967 function parseMemberExpressionOrHigher(): MemberExpression { 3968 // Note: to make our lives simpler, we decompose the NewExpression productions and 3969 // place ObjectCreationExpression and FunctionExpression into PrimaryExpression. 3970 // like so: 3971 // 3972 // PrimaryExpression : See 11.1 3973 // this 3974 // Identifier 3975 // Literal 3976 // ArrayLiteral 3977 // ObjectLiteral 3978 // (Expression) 3979 // FunctionExpression 3980 // new MemberExpression Arguments? 3981 // 3982 // MemberExpression : See 11.2 3983 // PrimaryExpression 3984 // MemberExpression[Expression] 3985 // MemberExpression.IdentifierName 3986 // 3987 // CallExpression : See 11.2 3988 // MemberExpression 3989 // CallExpression Arguments 3990 // CallExpression[Expression] 3991 // CallExpression.IdentifierName 3992 // 3993 // Technically this is ambiguous. i.e. CallExpression defines: 3994 // 3995 // CallExpression: 3996 // CallExpression Arguments 3997 // 3998 // If you see: "new Foo()" 3999 // 4000 // Then that could be treated as a single ObjectCreationExpression, or it could be 4001 // treated as the invocation of "new Foo". We disambiguate that in code (to match 4002 // the original grammar) by making sure that if we see an ObjectCreationExpression 4003 // we always consume arguments if they are there. So we treat "new Foo()" as an 4004 // object creation only, and not at all as an invocation. Another way to think 4005 // about this is that for every "new" that we see, we will consume an argument list if 4006 // it is there as part of the *associated* object creation node. Any additional 4007 // argument lists we see, will become invocation expressions. 4008 // 4009 // Because there are no other places in the grammar now that refer to FunctionExpression 4010 // or ObjectCreationExpression, it is safe to push down into the PrimaryExpression 4011 // production. 4012 // 4013 // Because CallExpression and MemberExpression are left recursive, we need to bottom out 4014 // of the recursion immediately. So we parse out a primary expression to start with. 4015 const expression = parsePrimaryExpression(); 4016 return parseMemberExpressionRest(expression); 4017 } 4018 4019 function parseSuperExpression(): MemberExpression { 4020 const expression = parseTokenNode<PrimaryExpression>(); 4021 if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.DotToken || token() === SyntaxKind.OpenBracketToken) { 4022 return expression; 4023 } 4024 4025 // If we have seen "super" it must be followed by '(' or '.'. 4026 // If it wasn't then just try to parse out a '.' and report an error. 4027 const node = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos); 4028 node.expression = expression; 4029 parseExpectedToken(SyntaxKind.DotToken, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access); 4030 node.name = parseRightSideOfDot(/*allowIdentifierNames*/ true); 4031 return finishNode(node); 4032 } 4033 4034 function tagNamesAreEquivalent(lhs: JsxTagNameExpression, rhs: JsxTagNameExpression): boolean { 4035 if (lhs.kind !== rhs.kind) { 4036 return false; 4037 } 4038 4039 if (lhs.kind === SyntaxKind.Identifier) { 4040 return (<Identifier>lhs).escapedText === (<Identifier>rhs).escapedText; 4041 } 4042 4043 if (lhs.kind === SyntaxKind.ThisKeyword) { 4044 return true; 4045 } 4046 4047 // If we are at this statement then we must have PropertyAccessExpression and because tag name in Jsx element can only 4048 // take forms of JsxTagNameExpression which includes an identifier, "this" expression, or another propertyAccessExpression 4049 // it is safe to case the expression property as such. See parseJsxElementName for how we parse tag name in Jsx element 4050 return (<PropertyAccessExpression>lhs).name.escapedText === (<PropertyAccessExpression>rhs).name.escapedText && 4051 tagNamesAreEquivalent((<PropertyAccessExpression>lhs).expression as JsxTagNameExpression, (<PropertyAccessExpression>rhs).expression as JsxTagNameExpression); 4052 } 4053 4054 4055 function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean): JsxElement | JsxSelfClosingElement | JsxFragment { 4056 const opening = parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext); 4057 let result: JsxElement | JsxSelfClosingElement | JsxFragment; 4058 if (opening.kind === SyntaxKind.JsxOpeningElement) { 4059 const node = <JsxElement>createNode(SyntaxKind.JsxElement, opening.pos); 4060 node.openingElement = opening; 4061 4062 node.children = parseJsxChildren(node.openingElement); 4063 node.closingElement = parseJsxClosingElement(inExpressionContext); 4064 4065 if (!tagNamesAreEquivalent(node.openingElement.tagName, node.closingElement.tagName)) { 4066 parseErrorAtPosition(node.closingElement.pos, node.closingElement.end - node.closingElement.pos, Diagnostics.Expected_corresponding_JSX_closing_tag_for_0, getTextOfNodeFromSourceText(sourceText, node.openingElement.tagName)); 4067 } 4068 4069 result = finishNode(node); 4070 } 4071 else if (opening.kind === SyntaxKind.JsxOpeningFragment) { 4072 const node = <JsxFragment>createNode(SyntaxKind.JsxFragment, opening.pos); 4073 node.openingFragment = opening; 4074 node.children = parseJsxChildren(node.openingFragment); 4075 node.closingFragment = parseJsxClosingFragment(inExpressionContext); 4076 4077 result = finishNode(node); 4078 } 4079 else { 4080 Debug.assert(opening.kind === SyntaxKind.JsxSelfClosingElement); 4081 // Nothing else to do for self-closing elements 4082 result = <JsxSelfClosingElement>opening; 4083 } 4084 4085 // If the user writes the invalid code '<div></div><div></div>' in an expression context (i.e. not wrapped in 4086 // an enclosing tag), we'll naively try to parse ^ this as a 'less than' operator and the remainder of the tag 4087 // as garbage, which will cause the formatter to badly mangle the JSX. Perform a speculative parse of a JSX 4088 // element if we see a < token so that we can wrap it in a synthetic binary expression so the formatter 4089 // does less damage and we can report a better error. 4090 // Since JSX elements are invalid < operands anyway, this lookahead parse will only occur in error scenarios 4091 // of one sort or another. 4092 if (inExpressionContext && token() === SyntaxKind.LessThanToken) { 4093 const invalidElement = tryParse(() => parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true)); 4094 if (invalidElement) { 4095 parseErrorAtCurrentToken(Diagnostics.JSX_expressions_must_have_one_parent_element); 4096 const badNode = <BinaryExpression>createNode(SyntaxKind.BinaryExpression, result.pos); 4097 badNode.end = invalidElement.end; 4098 badNode.left = result; 4099 badNode.right = invalidElement; 4100 badNode.operatorToken = <BinaryOperatorToken>createMissingNode(SyntaxKind.CommaToken, /*reportAtCurrentPosition*/ false, /*diagnosticMessage*/ undefined); 4101 badNode.operatorToken.pos = badNode.operatorToken.end = badNode.right.pos; 4102 return <JsxElement><Node>badNode; 4103 } 4104 } 4105 4106 return result; 4107 } 4108 4109 function parseJsxText(): JsxText { 4110 const node = <JsxText>createNode(SyntaxKind.JsxText); 4111 node.containsOnlyWhiteSpaces = currentToken === SyntaxKind.JsxTextAllWhiteSpaces; 4112 currentToken = scanner.scanJsxToken(); 4113 return finishNode(node); 4114 } 4115 4116 function parseJsxChild(): JsxChild { 4117 switch (token()) { 4118 case SyntaxKind.JsxText: 4119 case SyntaxKind.JsxTextAllWhiteSpaces: 4120 return parseJsxText(); 4121 case SyntaxKind.OpenBraceToken: 4122 return parseJsxExpression(/*inExpressionContext*/ false); 4123 case SyntaxKind.LessThanToken: 4124 return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ false); 4125 } 4126 Debug.fail("Unknown JSX child kind " + token()); 4127 } 4128 4129 function parseJsxChildren(openingTag: JsxOpeningElement | JsxOpeningFragment): NodeArray<JsxChild> { 4130 const list = []; 4131 const listPos = getNodePos(); 4132 const saveParsingContext = parsingContext; 4133 parsingContext |= 1 << ParsingContext.JsxChildren; 4134 4135 while (true) { 4136 currentToken = scanner.reScanJsxToken(); 4137 if (token() === SyntaxKind.LessThanSlashToken) { 4138 // Closing tag 4139 break; 4140 } 4141 else if (token() === SyntaxKind.EndOfFileToken) { 4142 // If we hit EOF, issue the error at the tag that lacks the closing element 4143 // rather than at the end of the file (which is useless) 4144 if (isJsxOpeningFragment(openingTag)) { 4145 parseErrorAtPosition(openingTag.pos, openingTag.end - openingTag.pos, Diagnostics.JSX_fragment_has_no_corresponding_closing_tag); 4146 } 4147 else { 4148 const openingTagName = openingTag.tagName; 4149 parseErrorAtPosition(openingTagName.pos, openingTagName.end - openingTagName.pos, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTagName)); 4150 } 4151 break; 4152 } 4153 else if (token() === SyntaxKind.ConflictMarkerTrivia) { 4154 break; 4155 } 4156 const child = parseJsxChild(); 4157 if (child) { 4158 list.push(child); 4159 } 4160 } 4161 4162 parsingContext = saveParsingContext; 4163 4164 return createNodeArray(list, listPos); 4165 } 4166 4167 function parseJsxAttributes(): JsxAttributes { 4168 const jsxAttributes = <JsxAttributes>createNode(SyntaxKind.JsxAttributes); 4169 jsxAttributes.properties = parseList(ParsingContext.JsxAttributes, parseJsxAttribute); 4170 return finishNode(jsxAttributes); 4171 } 4172 4173 function parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext: boolean): JsxOpeningElement | JsxSelfClosingElement | JsxOpeningFragment { 4174 const fullStart = scanner.getStartPos(); 4175 4176 parseExpected(SyntaxKind.LessThanToken); 4177 4178 if (token() === SyntaxKind.GreaterThanToken) { 4179 parseExpected(SyntaxKind.GreaterThanToken); 4180 const node: JsxOpeningFragment = <JsxOpeningFragment>createNode(SyntaxKind.JsxOpeningFragment, fullStart); 4181 return finishNode(node); 4182 } 4183 4184 const tagName = parseJsxElementName(); 4185 const attributes = parseJsxAttributes(); 4186 4187 let node: JsxOpeningLikeElement; 4188 4189 if (token() === SyntaxKind.GreaterThanToken) { 4190 // Closing tag, so scan the immediately-following text with the JSX scanning instead 4191 // of regular scanning to avoid treating illegal characters (e.g. '#') as immediate 4192 // scanning errors 4193 node = <JsxOpeningElement>createNode(SyntaxKind.JsxOpeningElement, fullStart); 4194 scanJsxText(); 4195 } 4196 else { 4197 parseExpected(SyntaxKind.SlashToken); 4198 if (inExpressionContext) { 4199 parseExpected(SyntaxKind.GreaterThanToken); 4200 } 4201 else { 4202 parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false); 4203 scanJsxText(); 4204 } 4205 node = <JsxSelfClosingElement>createNode(SyntaxKind.JsxSelfClosingElement, fullStart); 4206 } 4207 4208 node.tagName = tagName; 4209 node.attributes = attributes; 4210 4211 return finishNode(node); 4212 } 4213 4214 function parseJsxElementName(): JsxTagNameExpression { 4215 scanJsxIdentifier(); 4216 // JsxElement can have name in the form of 4217 // propertyAccessExpression 4218 // primaryExpression in the form of an identifier and "this" keyword 4219 // We can't just simply use parseLeftHandSideExpressionOrHigher because then we will start consider class,function etc as a keyword 4220 // We only want to consider "this" as a primaryExpression 4221 let expression: JsxTagNameExpression = token() === SyntaxKind.ThisKeyword ? 4222 parseTokenNode<PrimaryExpression>() : parseIdentifierName(); 4223 while (parseOptional(SyntaxKind.DotToken)) { 4224 const propertyAccess: PropertyAccessExpression = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos); 4225 propertyAccess.expression = expression; 4226 propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true); 4227 expression = finishNode(propertyAccess); 4228 } 4229 return expression; 4230 } 4231 4232 function parseJsxExpression(inExpressionContext: boolean): JsxExpression { 4233 const node = <JsxExpression>createNode(SyntaxKind.JsxExpression); 4234 4235 parseExpected(SyntaxKind.OpenBraceToken); 4236 if (token() !== SyntaxKind.CloseBraceToken) { 4237 node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); 4238 node.expression = parseAssignmentExpressionOrHigher(); 4239 } 4240 if (inExpressionContext) { 4241 parseExpected(SyntaxKind.CloseBraceToken); 4242 } 4243 else { 4244 parseExpected(SyntaxKind.CloseBraceToken, /*message*/ undefined, /*shouldAdvance*/ false); 4245 scanJsxText(); 4246 } 4247 4248 return finishNode(node); 4249 } 4250 4251 function parseJsxAttribute(): JsxAttribute | JsxSpreadAttribute { 4252 if (token() === SyntaxKind.OpenBraceToken) { 4253 return parseJsxSpreadAttribute(); 4254 } 4255 4256 scanJsxIdentifier(); 4257 const node = <JsxAttribute>createNode(SyntaxKind.JsxAttribute); 4258 node.name = parseIdentifierName(); 4259 if (token() === SyntaxKind.EqualsToken) { 4260 switch (scanJsxAttributeValue()) { 4261 case SyntaxKind.StringLiteral: 4262 node.initializer = <StringLiteral>parseLiteralNode(); 4263 break; 4264 default: 4265 node.initializer = parseJsxExpression(/*inExpressionContext*/ true); 4266 break; 4267 } 4268 } 4269 return finishNode(node); 4270 } 4271 4272 function parseJsxSpreadAttribute(): JsxSpreadAttribute { 4273 const node = <JsxSpreadAttribute>createNode(SyntaxKind.JsxSpreadAttribute); 4274 parseExpected(SyntaxKind.OpenBraceToken); 4275 parseExpected(SyntaxKind.DotDotDotToken); 4276 node.expression = parseExpression(); 4277 parseExpected(SyntaxKind.CloseBraceToken); 4278 return finishNode(node); 4279 } 4280 4281 function parseJsxClosingElement(inExpressionContext: boolean): JsxClosingElement { 4282 const node = <JsxClosingElement>createNode(SyntaxKind.JsxClosingElement); 4283 parseExpected(SyntaxKind.LessThanSlashToken); 4284 node.tagName = parseJsxElementName(); 4285 if (inExpressionContext) { 4286 parseExpected(SyntaxKind.GreaterThanToken); 4287 } 4288 else { 4289 parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false); 4290 scanJsxText(); 4291 } 4292 return finishNode(node); 4293 } 4294 4295 function parseJsxClosingFragment(inExpressionContext: boolean): JsxClosingFragment { 4296 const node = <JsxClosingFragment>createNode(SyntaxKind.JsxClosingFragment); 4297 parseExpected(SyntaxKind.LessThanSlashToken); 4298 if (tokenIsIdentifierOrKeyword(token())) { 4299 const unexpectedTagName = parseJsxElementName(); 4300 parseErrorAtPosition(unexpectedTagName.pos, unexpectedTagName.end - unexpectedTagName.pos, Diagnostics.Expected_corresponding_closing_tag_for_JSX_fragment); 4301 } 4302 if (inExpressionContext) { 4303 parseExpected(SyntaxKind.GreaterThanToken); 4304 } 4305 else { 4306 parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false); 4307 scanJsxText(); 4308 } 4309 return finishNode(node); 4310 } 4311 4312 function parseTypeAssertion(): TypeAssertion { 4313 const node = <TypeAssertion>createNode(SyntaxKind.TypeAssertionExpression); 4314 parseExpected(SyntaxKind.LessThanToken); 4315 node.type = parseType(); 4316 parseExpected(SyntaxKind.GreaterThanToken); 4317 node.expression = parseSimpleUnaryExpression(); 4318 return finishNode(node); 4319 } 4320 4321 function parseMemberExpressionRest(expression: LeftHandSideExpression): MemberExpression { 4322 while (true) { 4323 const dotToken = parseOptionalToken(SyntaxKind.DotToken); 4324 if (dotToken) { 4325 const propertyAccess = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos); 4326 propertyAccess.expression = expression; 4327 propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true); 4328 expression = finishNode(propertyAccess); 4329 continue; 4330 } 4331 4332 if (token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) { 4333 nextToken(); 4334 const nonNullExpression = <NonNullExpression>createNode(SyntaxKind.NonNullExpression, expression.pos); 4335 nonNullExpression.expression = expression; 4336 expression = finishNode(nonNullExpression); 4337 continue; 4338 } 4339 4340 // when in the [Decorator] context, we do not parse ElementAccess as it could be part of a ComputedPropertyName 4341 if (!inDecoratorContext() && parseOptional(SyntaxKind.OpenBracketToken)) { 4342 const indexedAccess = <ElementAccessExpression>createNode(SyntaxKind.ElementAccessExpression, expression.pos); 4343 indexedAccess.expression = expression; 4344 4345 // It's not uncommon for a user to write: "new Type[]". 4346 // Check for that common pattern and report a better error message. 4347 if (token() !== SyntaxKind.CloseBracketToken) { 4348 indexedAccess.argumentExpression = allowInAnd(parseExpression); 4349 if (indexedAccess.argumentExpression.kind === SyntaxKind.StringLiteral || indexedAccess.argumentExpression.kind === SyntaxKind.NumericLiteral) { 4350 const literal = <LiteralExpression>indexedAccess.argumentExpression; 4351 literal.text = internIdentifier(literal.text); 4352 } 4353 } 4354 4355 parseExpected(SyntaxKind.CloseBracketToken); 4356 expression = finishNode(indexedAccess); 4357 continue; 4358 } 4359 4360 if (token() === SyntaxKind.NoSubstitutionTemplateLiteral || token() === SyntaxKind.TemplateHead) { 4361 const tagExpression = <TaggedTemplateExpression>createNode(SyntaxKind.TaggedTemplateExpression, expression.pos); 4362 tagExpression.tag = expression; 4363 tagExpression.template = token() === SyntaxKind.NoSubstitutionTemplateLiteral 4364 ? <NoSubstitutionTemplateLiteral>parseLiteralNode() 4365 : parseTemplateExpression(); 4366 expression = finishNode(tagExpression); 4367 continue; 4368 } 4369 4370 return <MemberExpression>expression; 4371 } 4372 } 4373 4374 function parseCallExpressionRest(expression: LeftHandSideExpression): LeftHandSideExpression { 4375 while (true) { 4376 expression = parseMemberExpressionRest(expression); 4377 if (token() === SyntaxKind.LessThanToken) { 4378 // See if this is the start of a generic invocation. If so, consume it and 4379 // keep checking for postfix expressions. Otherwise, it's just a '<' that's 4380 // part of an arithmetic expression. Break out so we consume it higher in the 4381 // stack. 4382 const typeArguments = tryParse(parseTypeArgumentsInExpression); 4383 if (!typeArguments) { 4384 return expression; 4385 } 4386 4387 const callExpr = <CallExpression>createNode(SyntaxKind.CallExpression, expression.pos); 4388 callExpr.expression = expression; 4389 callExpr.typeArguments = typeArguments; 4390 callExpr.arguments = parseArgumentList(); 4391 expression = finishNode(callExpr); 4392 continue; 4393 } 4394 else if (token() === SyntaxKind.OpenParenToken) { 4395 const callExpr = <CallExpression>createNode(SyntaxKind.CallExpression, expression.pos); 4396 callExpr.expression = expression; 4397 callExpr.arguments = parseArgumentList(); 4398 expression = finishNode(callExpr); 4399 continue; 4400 } 4401 4402 return expression; 4403 } 4404 } 4405 4406 function parseArgumentList() { 4407 parseExpected(SyntaxKind.OpenParenToken); 4408 const result = parseDelimitedList(ParsingContext.ArgumentExpressions, parseArgumentExpression); 4409 parseExpected(SyntaxKind.CloseParenToken); 4410 return result; 4411 } 4412 4413 function parseTypeArgumentsInExpression() { 4414 if (!parseOptional(SyntaxKind.LessThanToken)) { 4415 return undefined; 4416 } 4417 4418 const typeArguments = parseDelimitedList(ParsingContext.TypeArguments, parseType); 4419 if (!parseExpected(SyntaxKind.GreaterThanToken)) { 4420 // If it doesn't have the closing `>` then it's definitely not an type argument list. 4421 return undefined; 4422 } 4423 4424 // If we have a '<', then only parse this as a argument list if the type arguments 4425 // are complete and we have an open paren. if we don't, rewind and return nothing. 4426 return typeArguments && canFollowTypeArgumentsInExpression() 4427 ? typeArguments 4428 : undefined; 4429 } 4430 4431 function canFollowTypeArgumentsInExpression(): boolean { 4432 switch (token()) { 4433 case SyntaxKind.OpenParenToken: // foo<x>( 4434 // this case are the only case where this token can legally follow a type argument 4435 // list. So we definitely want to treat this as a type arg list. 4436 4437 case SyntaxKind.DotToken: // foo<x>. 4438 case SyntaxKind.CloseParenToken: // foo<x>) 4439 case SyntaxKind.CloseBracketToken: // foo<x>] 4440 case SyntaxKind.ColonToken: // foo<x>: 4441 case SyntaxKind.SemicolonToken: // foo<x>; 4442 case SyntaxKind.QuestionToken: // foo<x>? 4443 case SyntaxKind.EqualsEqualsToken: // foo<x> == 4444 case SyntaxKind.EqualsEqualsEqualsToken: // foo<x> === 4445 case SyntaxKind.ExclamationEqualsToken: // foo<x> != 4446 case SyntaxKind.ExclamationEqualsEqualsToken: // foo<x> !== 4447 case SyntaxKind.AmpersandAmpersandToken: // foo<x> && 4448 case SyntaxKind.BarBarToken: // foo<x> || 4449 case SyntaxKind.CaretToken: // foo<x> ^ 4450 case SyntaxKind.AmpersandToken: // foo<x> & 4451 case SyntaxKind.BarToken: // foo<x> | 4452 case SyntaxKind.CloseBraceToken: // foo<x> } 4453 case SyntaxKind.EndOfFileToken: // foo<x> 4454 // these cases can't legally follow a type arg list. However, they're not legal 4455 // expressions either. The user is probably in the middle of a generic type. So 4456 // treat it as such. 4457 return true; 4458 4459 case SyntaxKind.CommaToken: // foo<x>, 4460 case SyntaxKind.OpenBraceToken: // foo<x> { 4461 // We don't want to treat these as type arguments. Otherwise we'll parse this 4462 // as an invocation expression. Instead, we want to parse out the expression 4463 // in isolation from the type arguments. 4464 4465 default: 4466 // Anything else treat as an expression. 4467 return false; 4468 } 4469 } 4470 4471 function parsePrimaryExpression(): PrimaryExpression { 4472 switch (token()) { 4473 case SyntaxKind.NumericLiteral: 4474 case SyntaxKind.StringLiteral: 4475 case SyntaxKind.NoSubstitutionTemplateLiteral: 4476 return parseLiteralNode(); 4477 case SyntaxKind.ThisKeyword: 4478 case SyntaxKind.SuperKeyword: 4479 case SyntaxKind.NullKeyword: 4480 case SyntaxKind.TrueKeyword: 4481 case SyntaxKind.FalseKeyword: 4482 return parseTokenNode<PrimaryExpression>(); 4483 case SyntaxKind.OpenParenToken: 4484 return parseParenthesizedExpression(); 4485 case SyntaxKind.OpenBracketToken: 4486 return parseArrayLiteralExpression(); 4487 case SyntaxKind.OpenBraceToken: 4488 return parseObjectLiteralExpression(); 4489 case SyntaxKind.AsyncKeyword: 4490 // Async arrow functions are parsed earlier in parseAssignmentExpressionOrHigher. 4491 // If we encounter `async [no LineTerminator here] function` then this is an async 4492 // function; otherwise, its an identifier. 4493 if (!lookAhead(nextTokenIsFunctionKeywordOnSameLine)) { 4494 break; 4495 } 4496 4497 return parseFunctionExpression(); 4498 case SyntaxKind.ClassKeyword: 4499 return parseClassExpression(); 4500 case SyntaxKind.FunctionKeyword: 4501 return parseFunctionExpression(); 4502 case SyntaxKind.NewKeyword: 4503 return parseNewExpression(); 4504 case SyntaxKind.SlashToken: 4505 case SyntaxKind.SlashEqualsToken: 4506 if (reScanSlashToken() === SyntaxKind.RegularExpressionLiteral) { 4507 return parseLiteralNode(); 4508 } 4509 break; 4510 case SyntaxKind.TemplateHead: 4511 return parseTemplateExpression(); 4512 } 4513 4514 return parseIdentifier(Diagnostics.Expression_expected); 4515 } 4516 4517 function parseParenthesizedExpression(): ParenthesizedExpression { 4518 const node = <ParenthesizedExpression>createNodeWithJSDoc(SyntaxKind.ParenthesizedExpression); 4519 parseExpected(SyntaxKind.OpenParenToken); 4520 node.expression = allowInAnd(parseExpression); 4521 parseExpected(SyntaxKind.CloseParenToken); 4522 return finishNode(node); 4523 } 4524 4525 function parseSpreadElement(): Expression { 4526 const node = <SpreadElement>createNode(SyntaxKind.SpreadElement); 4527 parseExpected(SyntaxKind.DotDotDotToken); 4528 node.expression = parseAssignmentExpressionOrHigher(); 4529 return finishNode(node); 4530 } 4531 4532 function parseArgumentOrArrayLiteralElement(): Expression { 4533 return token() === SyntaxKind.DotDotDotToken ? parseSpreadElement() : 4534 token() === SyntaxKind.CommaToken ? <Expression>createNode(SyntaxKind.OmittedExpression) : 4535 parseAssignmentExpressionOrHigher(); 4536 } 4537 4538 function parseArgumentExpression(): Expression { 4539 return doOutsideOfContext(disallowInAndDecoratorContext, parseArgumentOrArrayLiteralElement); 4540 } 4541 4542 function parseArrayLiteralExpression(): ArrayLiteralExpression { 4543 const node = <ArrayLiteralExpression>createNode(SyntaxKind.ArrayLiteralExpression); 4544 parseExpected(SyntaxKind.OpenBracketToken); 4545 if (scanner.hasPrecedingLineBreak()) { 4546 node.multiLine = true; 4547 } 4548 node.elements = parseDelimitedList(ParsingContext.ArrayLiteralMembers, parseArgumentOrArrayLiteralElement); 4549 parseExpected(SyntaxKind.CloseBracketToken); 4550 return finishNode(node); 4551 } 4552 4553 function parseObjectLiteralElement(): ObjectLiteralElementLike { 4554 const node = <ObjectLiteralElementLike>createNodeWithJSDoc(SyntaxKind.Unknown); 4555 4556 if (parseOptionalToken(SyntaxKind.DotDotDotToken)) { 4557 node.kind = SyntaxKind.SpreadAssignment; 4558 (<SpreadAssignment>node).expression = parseAssignmentExpressionOrHigher(); 4559 return finishNode(node); 4560 } 4561 4562 node.decorators = parseDecorators(); 4563 node.modifiers = parseModifiers(); 4564 4565 if (parseContextualModifier(SyntaxKind.GetKeyword)) { 4566 return parseAccessorDeclaration(<AccessorDeclaration>node, SyntaxKind.GetAccessor); 4567 } 4568 if (parseContextualModifier(SyntaxKind.SetKeyword)) { 4569 return parseAccessorDeclaration(<AccessorDeclaration>node, SyntaxKind.SetAccessor); 4570 } 4571 4572 const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); 4573 const tokenIsIdentifier = isIdentifier(); 4574 node.name = parsePropertyName(); 4575 // Disallowing of optional property assignments happens in the grammar checker. 4576 (<MethodDeclaration>node).questionToken = parseOptionalToken(SyntaxKind.QuestionToken); 4577 if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { 4578 return parseMethodDeclaration(<MethodDeclaration>node, asteriskToken); 4579 } 4580 4581 // check if it is short-hand property assignment or normal property assignment 4582 // NOTE: if token is EqualsToken it is interpreted as CoverInitializedName production 4583 // CoverInitializedName[Yield] : 4584 // IdentifierReference[?Yield] Initializer[In, ?Yield] 4585 // this is necessary because ObjectLiteral productions are also used to cover grammar for ObjectAssignmentPattern 4586 const isShorthandPropertyAssignment = 4587 tokenIsIdentifier && (token() === SyntaxKind.CommaToken || token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.EqualsToken); 4588 if (isShorthandPropertyAssignment) { 4589 node.kind = SyntaxKind.ShorthandPropertyAssignment; 4590 const equalsToken = parseOptionalToken(SyntaxKind.EqualsToken); 4591 if (equalsToken) { 4592 (<ShorthandPropertyAssignment>node).equalsToken = equalsToken; 4593 (<ShorthandPropertyAssignment>node).objectAssignmentInitializer = allowInAnd(parseAssignmentExpressionOrHigher); 4594 } 4595 } 4596 else { 4597 node.kind = SyntaxKind.PropertyAssignment; 4598 parseExpected(SyntaxKind.ColonToken); 4599 (<PropertyAssignment>node).initializer = allowInAnd(parseAssignmentExpressionOrHigher); 4600 } 4601 return finishNode(node); 4602 } 4603 4604 function parseObjectLiteralExpression(): ObjectLiteralExpression { 4605 const node = <ObjectLiteralExpression>createNode(SyntaxKind.ObjectLiteralExpression); 4606 parseExpected(SyntaxKind.OpenBraceToken); 4607 if (scanner.hasPrecedingLineBreak()) { 4608 node.multiLine = true; 4609 } 4610 4611 node.properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralElement, /*considerSemicolonAsDelimiter*/ true); 4612 parseExpected(SyntaxKind.CloseBraceToken); 4613 return finishNode(node); 4614 } 4615 4616 function parseFunctionExpression(): FunctionExpression { 4617 // GeneratorExpression: 4618 // function* BindingIdentifier [Yield][opt](FormalParameters[Yield]){ GeneratorBody } 4619 // 4620 // FunctionExpression: 4621 // function BindingIdentifier[opt](FormalParameters){ FunctionBody } 4622 const saveDecoratorContext = inDecoratorContext(); 4623 if (saveDecoratorContext) { 4624 setDecoratorContext(/*val*/ false); 4625 } 4626 4627 const node = <FunctionExpression>createNodeWithJSDoc(SyntaxKind.FunctionExpression); 4628 node.modifiers = parseModifiers(); 4629 parseExpected(SyntaxKind.FunctionKeyword); 4630 node.asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); 4631 4632 const isGenerator = node.asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; 4633 const isAsync = hasModifier(node, ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None; 4634 node.name = 4635 isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalIdentifier) : 4636 isGenerator ? doInYieldContext(parseOptionalIdentifier) : 4637 isAsync ? doInAwaitContext(parseOptionalIdentifier) : 4638 parseOptionalIdentifier(); 4639 4640 fillSignature(SyntaxKind.ColonToken, isGenerator | isAsync, node); 4641 node.body = parseFunctionBlock(isGenerator | isAsync); 4642 4643 if (saveDecoratorContext) { 4644 setDecoratorContext(/*val*/ true); 4645 } 4646 4647 return finishNode(node); 4648 } 4649 4650 function parseOptionalIdentifier(): Identifier | undefined { 4651 return isIdentifier() ? parseIdentifier() : undefined; 4652 } 4653 4654 function parseNewExpression(): NewExpression | MetaProperty { 4655 const fullStart = scanner.getStartPos(); 4656 parseExpected(SyntaxKind.NewKeyword); 4657 if (parseOptional(SyntaxKind.DotToken)) { 4658 const node = <MetaProperty>createNode(SyntaxKind.MetaProperty, fullStart); 4659 node.keywordToken = SyntaxKind.NewKeyword; 4660 node.name = parseIdentifierName(); 4661 return finishNode(node); 4662 } 4663 4664 const node = <NewExpression>createNode(SyntaxKind.NewExpression, fullStart); 4665 node.expression = parseMemberExpressionOrHigher(); 4666 node.typeArguments = tryParse(parseTypeArgumentsInExpression); 4667 if (node.typeArguments || token() === SyntaxKind.OpenParenToken) { 4668 node.arguments = parseArgumentList(); 4669 } 4670 return finishNode(node); 4671 } 4672 4673 // STATEMENTS 4674 function parseBlock(ignoreMissingOpenBrace: boolean, diagnosticMessage?: DiagnosticMessage): Block { 4675 const node = <Block>createNode(SyntaxKind.Block); 4676 if (parseExpected(SyntaxKind.OpenBraceToken, diagnosticMessage) || ignoreMissingOpenBrace) { 4677 if (scanner.hasPrecedingLineBreak()) { 4678 node.multiLine = true; 4679 } 4680 4681 node.statements = parseList(ParsingContext.BlockStatements, parseStatement); 4682 parseExpected(SyntaxKind.CloseBraceToken); 4683 } 4684 else { 4685 node.statements = createMissingList<Statement>(); 4686 } 4687 return finishNode(node); 4688 } 4689 4690 function parseFunctionBlock(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block { 4691 const savedYieldContext = inYieldContext(); 4692 setYieldContext(!!(flags & SignatureFlags.Yield)); 4693 4694 const savedAwaitContext = inAwaitContext(); 4695 setAwaitContext(!!(flags & SignatureFlags.Await)); 4696 4697 // We may be in a [Decorator] context when parsing a function expression or 4698 // arrow function. The body of the function is not in [Decorator] context. 4699 const saveDecoratorContext = inDecoratorContext(); 4700 if (saveDecoratorContext) { 4701 setDecoratorContext(/*val*/ false); 4702 } 4703 4704 const block = parseBlock(!!(flags & SignatureFlags.IgnoreMissingOpenBrace), diagnosticMessage); 4705 4706 if (saveDecoratorContext) { 4707 setDecoratorContext(/*val*/ true); 4708 } 4709 4710 setYieldContext(savedYieldContext); 4711 setAwaitContext(savedAwaitContext); 4712 4713 return block; 4714 } 4715 4716 function parseEmptyStatement(): Statement { 4717 const node = <Statement>createNode(SyntaxKind.EmptyStatement); 4718 parseExpected(SyntaxKind.SemicolonToken); 4719 return finishNode(node); 4720 } 4721 4722 function parseIfStatement(): IfStatement { 4723 const node = <IfStatement>createNode(SyntaxKind.IfStatement); 4724 parseExpected(SyntaxKind.IfKeyword); 4725 parseExpected(SyntaxKind.OpenParenToken); 4726 node.expression = allowInAnd(parseExpression); 4727 parseExpected(SyntaxKind.CloseParenToken); 4728 node.thenStatement = parseStatement(); 4729 node.elseStatement = parseOptional(SyntaxKind.ElseKeyword) ? parseStatement() : undefined; 4730 return finishNode(node); 4731 } 4732 4733 function parseDoStatement(): DoStatement { 4734 const node = <DoStatement>createNode(SyntaxKind.DoStatement); 4735 parseExpected(SyntaxKind.DoKeyword); 4736 node.statement = parseStatement(); 4737 parseExpected(SyntaxKind.WhileKeyword); 4738 parseExpected(SyntaxKind.OpenParenToken); 4739 node.expression = allowInAnd(parseExpression); 4740 parseExpected(SyntaxKind.CloseParenToken); 4741 4742 // From: https://mail.mozilla.org/pipermail/es-discuss/2011-August/016188.html 4743 // 157 min --- All allen at wirfs-brock.com CONF --- "do{;}while(false)false" prohibited in 4744 // spec but allowed in consensus reality. Approved -- this is the de-facto standard whereby 4745 // do;while(0)x will have a semicolon inserted before x. 4746 parseOptional(SyntaxKind.SemicolonToken); 4747 return finishNode(node); 4748 } 4749 4750 function parseWhileStatement(): WhileStatement { 4751 const node = <WhileStatement>createNode(SyntaxKind.WhileStatement); 4752 parseExpected(SyntaxKind.WhileKeyword); 4753 parseExpected(SyntaxKind.OpenParenToken); 4754 node.expression = allowInAnd(parseExpression); 4755 parseExpected(SyntaxKind.CloseParenToken); 4756 node.statement = parseStatement(); 4757 return finishNode(node); 4758 } 4759 4760 function parseForOrForInOrForOfStatement(): Statement { 4761 const pos = getNodePos(); 4762 parseExpected(SyntaxKind.ForKeyword); 4763 const awaitToken = parseOptionalToken(SyntaxKind.AwaitKeyword); 4764 parseExpected(SyntaxKind.OpenParenToken); 4765 4766 let initializer: VariableDeclarationList | Expression = undefined; 4767 if (token() !== SyntaxKind.SemicolonToken) { 4768 if (token() === SyntaxKind.VarKeyword || token() === SyntaxKind.LetKeyword || token() === SyntaxKind.ConstKeyword) { 4769 initializer = parseVariableDeclarationList(/*inForStatementInitializer*/ true); 4770 } 4771 else { 4772 initializer = disallowInAnd(parseExpression); 4773 } 4774 } 4775 let forOrForInOrForOfStatement: IterationStatement; 4776 if (awaitToken ? parseExpected(SyntaxKind.OfKeyword) : parseOptional(SyntaxKind.OfKeyword)) { 4777 const forOfStatement = <ForOfStatement>createNode(SyntaxKind.ForOfStatement, pos); 4778 forOfStatement.awaitModifier = awaitToken; 4779 forOfStatement.initializer = initializer; 4780 forOfStatement.expression = allowInAnd(parseAssignmentExpressionOrHigher); 4781 parseExpected(SyntaxKind.CloseParenToken); 4782 forOrForInOrForOfStatement = forOfStatement; 4783 } 4784 else if (parseOptional(SyntaxKind.InKeyword)) { 4785 const forInStatement = <ForInStatement>createNode(SyntaxKind.ForInStatement, pos); 4786 forInStatement.initializer = initializer; 4787 forInStatement.expression = allowInAnd(parseExpression); 4788 parseExpected(SyntaxKind.CloseParenToken); 4789 forOrForInOrForOfStatement = forInStatement; 4790 } 4791 else { 4792 const forStatement = <ForStatement>createNode(SyntaxKind.ForStatement, pos); 4793 forStatement.initializer = initializer; 4794 parseExpected(SyntaxKind.SemicolonToken); 4795 if (token() !== SyntaxKind.SemicolonToken && token() !== SyntaxKind.CloseParenToken) { 4796 forStatement.condition = allowInAnd(parseExpression); 4797 } 4798 parseExpected(SyntaxKind.SemicolonToken); 4799 if (token() !== SyntaxKind.CloseParenToken) { 4800 forStatement.incrementor = allowInAnd(parseExpression); 4801 } 4802 parseExpected(SyntaxKind.CloseParenToken); 4803 forOrForInOrForOfStatement = forStatement; 4804 } 4805 4806 forOrForInOrForOfStatement.statement = parseStatement(); 4807 4808 return finishNode(forOrForInOrForOfStatement); 4809 } 4810 4811 function parseBreakOrContinueStatement(kind: SyntaxKind): BreakOrContinueStatement { 4812 const node = <BreakOrContinueStatement>createNode(kind); 4813 4814 parseExpected(kind === SyntaxKind.BreakStatement ? SyntaxKind.BreakKeyword : SyntaxKind.ContinueKeyword); 4815 if (!canParseSemicolon()) { 4816 node.label = parseIdentifier(); 4817 } 4818 4819 parseSemicolon(); 4820 return finishNode(node); 4821 } 4822 4823 function parseReturnStatement(): ReturnStatement { 4824 const node = <ReturnStatement>createNode(SyntaxKind.ReturnStatement); 4825 4826 parseExpected(SyntaxKind.ReturnKeyword); 4827 if (!canParseSemicolon()) { 4828 node.expression = allowInAnd(parseExpression); 4829 } 4830 4831 parseSemicolon(); 4832 return finishNode(node); 4833 } 4834 4835 function parseWithStatement(): WithStatement { 4836 const node = <WithStatement>createNode(SyntaxKind.WithStatement); 4837 parseExpected(SyntaxKind.WithKeyword); 4838 parseExpected(SyntaxKind.OpenParenToken); 4839 node.expression = allowInAnd(parseExpression); 4840 parseExpected(SyntaxKind.CloseParenToken); 4841 node.statement = doInsideOfContext(NodeFlags.InWithStatement, parseStatement); 4842 return finishNode(node); 4843 } 4844 4845 function parseCaseClause(): CaseClause { 4846 const node = <CaseClause>createNode(SyntaxKind.CaseClause); 4847 parseExpected(SyntaxKind.CaseKeyword); 4848 node.expression = allowInAnd(parseExpression); 4849 parseExpected(SyntaxKind.ColonToken); 4850 node.statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement); 4851 return finishNode(node); 4852 } 4853 4854 function parseDefaultClause(): DefaultClause { 4855 const node = <DefaultClause>createNode(SyntaxKind.DefaultClause); 4856 parseExpected(SyntaxKind.DefaultKeyword); 4857 parseExpected(SyntaxKind.ColonToken); 4858 node.statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement); 4859 return finishNode(node); 4860 } 4861 4862 function parseCaseOrDefaultClause(): CaseOrDefaultClause { 4863 return token() === SyntaxKind.CaseKeyword ? parseCaseClause() : parseDefaultClause(); 4864 } 4865 4866 function parseSwitchStatement(): SwitchStatement { 4867 const node = <SwitchStatement>createNode(SyntaxKind.SwitchStatement); 4868 parseExpected(SyntaxKind.SwitchKeyword); 4869 parseExpected(SyntaxKind.OpenParenToken); 4870 node.expression = allowInAnd(parseExpression); 4871 parseExpected(SyntaxKind.CloseParenToken); 4872 const caseBlock = <CaseBlock>createNode(SyntaxKind.CaseBlock); 4873 parseExpected(SyntaxKind.OpenBraceToken); 4874 caseBlock.clauses = parseList(ParsingContext.SwitchClauses, parseCaseOrDefaultClause); 4875 parseExpected(SyntaxKind.CloseBraceToken); 4876 node.caseBlock = finishNode(caseBlock); 4877 return finishNode(node); 4878 } 4879 4880 function parseThrowStatement(): ThrowStatement { 4881 // ThrowStatement[Yield] : 4882 // throw [no LineTerminator here]Expression[In, ?Yield]; 4883 4884 // Because of automatic semicolon insertion, we need to report error if this 4885 // throw could be terminated with a semicolon. Note: we can't call 'parseExpression' 4886 // directly as that might consume an expression on the following line. 4887 // We just return 'undefined' in that case. The actual error will be reported in the 4888 // grammar walker. 4889 const node = <ThrowStatement>createNode(SyntaxKind.ThrowStatement); 4890 parseExpected(SyntaxKind.ThrowKeyword); 4891 node.expression = scanner.hasPrecedingLineBreak() ? undefined : allowInAnd(parseExpression); 4892 parseSemicolon(); 4893 return finishNode(node); 4894 } 4895 4896 // TODO: Review for error recovery 4897 function parseTryStatement(): TryStatement { 4898 const node = <TryStatement>createNode(SyntaxKind.TryStatement); 4899 4900 parseExpected(SyntaxKind.TryKeyword); 4901 node.tryBlock = parseBlock(/*ignoreMissingOpenBrace*/ false); 4902 node.catchClause = token() === SyntaxKind.CatchKeyword ? parseCatchClause() : undefined; 4903 4904 // If we don't have a catch clause, then we must have a finally clause. Try to parse 4905 // one out no matter what. 4906 if (!node.catchClause || token() === SyntaxKind.FinallyKeyword) { 4907 parseExpected(SyntaxKind.FinallyKeyword); 4908 node.finallyBlock = parseBlock(/*ignoreMissingOpenBrace*/ false); 4909 } 4910 4911 return finishNode(node); 4912 } 4913 4914 function parseCatchClause(): CatchClause { 4915 const result = <CatchClause>createNode(SyntaxKind.CatchClause); 4916 parseExpected(SyntaxKind.CatchKeyword); 4917 4918 if (parseOptional(SyntaxKind.OpenParenToken)) { 4919 result.variableDeclaration = parseVariableDeclaration(); 4920 parseExpected(SyntaxKind.CloseParenToken); 4921 } 4922 else { 4923 // Keep shape of node to avoid degrading performance. 4924 result.variableDeclaration = undefined; 4925 } 4926 4927 result.block = parseBlock(/*ignoreMissingOpenBrace*/ false); 4928 return finishNode(result); 4929 } 4930 4931 function parseDebuggerStatement(): Statement { 4932 const node = <Statement>createNode(SyntaxKind.DebuggerStatement); 4933 parseExpected(SyntaxKind.DebuggerKeyword); 4934 parseSemicolon(); 4935 return finishNode(node); 4936 } 4937 4938 function parseExpressionOrLabeledStatement(): ExpressionStatement | LabeledStatement { 4939 // Avoiding having to do the lookahead for a labeled statement by just trying to parse 4940 // out an expression, seeing if it is identifier and then seeing if it is followed by 4941 // a colon. 4942 const node = <ExpressionStatement | LabeledStatement>createNodeWithJSDoc(SyntaxKind.Unknown); 4943 const expression = allowInAnd(parseExpression); 4944 if (expression.kind === SyntaxKind.Identifier && parseOptional(SyntaxKind.ColonToken)) { 4945 node.kind = SyntaxKind.LabeledStatement; 4946 (<LabeledStatement>node).label = <Identifier>expression; 4947 (<LabeledStatement>node).statement = parseStatement(); 4948 } 4949 else { 4950 node.kind = SyntaxKind.ExpressionStatement; 4951 (<ExpressionStatement>node).expression = expression; 4952 parseSemicolon(); 4953 } 4954 return finishNode(node); 4955 } 4956 4957 function nextTokenIsIdentifierOrKeywordOnSameLine() { 4958 nextToken(); 4959 return tokenIsIdentifierOrKeyword(token()) && !scanner.hasPrecedingLineBreak(); 4960 } 4961 4962 function nextTokenIsClassKeywordOnSameLine() { 4963 nextToken(); 4964 return token() === SyntaxKind.ClassKeyword && !scanner.hasPrecedingLineBreak(); 4965 } 4966 4967 function nextTokenIsFunctionKeywordOnSameLine() { 4968 nextToken(); 4969 return token() === SyntaxKind.FunctionKeyword && !scanner.hasPrecedingLineBreak(); 4970 } 4971 4972 function nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine() { 4973 nextToken(); 4974 return (tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.StringLiteral) && !scanner.hasPrecedingLineBreak(); 4975 } 4976 4977 function isDeclaration(): boolean { 4978 while (true) { 4979 switch (token()) { 4980 case SyntaxKind.VarKeyword: 4981 case SyntaxKind.LetKeyword: 4982 case SyntaxKind.ConstKeyword: 4983 case SyntaxKind.FunctionKeyword: 4984 case SyntaxKind.ClassKeyword: 4985 case SyntaxKind.EnumKeyword: 4986 return true; 4987 4988 // 'declare', 'module', 'namespace', 'interface'* and 'type' are all legal JavaScript identifiers; 4989 // however, an identifier cannot be followed by another identifier on the same line. This is what we 4990 // count on to parse out the respective declarations. For instance, we exploit this to say that 4991 // 4992 // namespace n 4993 // 4994 // can be none other than the beginning of a namespace declaration, but need to respect that JavaScript sees 4995 // 4996 // namespace 4997 // n 4998 // 4999 // as the identifier 'namespace' on one line followed by the identifier 'n' on another. 5000 // We need to look one token ahead to see if it permissible to try parsing a declaration. 5001 // 5002 // *Note*: 'interface' is actually a strict mode reserved word. So while 5003 // 5004 // "use strict" 5005 // interface 5006 // I {} 5007 // 5008 // could be legal, it would add complexity for very little gain. 5009 case SyntaxKind.InterfaceKeyword: 5010 case SyntaxKind.TypeKeyword: 5011 return nextTokenIsIdentifierOnSameLine(); 5012 case SyntaxKind.ModuleKeyword: 5013 case SyntaxKind.NamespaceKeyword: 5014 return nextTokenIsIdentifierOrStringLiteralOnSameLine(); 5015 case SyntaxKind.AbstractKeyword: 5016 case SyntaxKind.AsyncKeyword: 5017 case SyntaxKind.DeclareKeyword: 5018 case SyntaxKind.PrivateKeyword: 5019 case SyntaxKind.ProtectedKeyword: 5020 case SyntaxKind.PublicKeyword: 5021 case SyntaxKind.ReadonlyKeyword: 5022 nextToken(); 5023 // ASI takes effect for this modifier. 5024 if (scanner.hasPrecedingLineBreak()) { 5025 return false; 5026 } 5027 continue; 5028 5029 case SyntaxKind.GlobalKeyword: 5030 nextToken(); 5031 return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.Identifier || token() === SyntaxKind.ExportKeyword; 5032 5033 case SyntaxKind.ImportKeyword: 5034 nextToken(); 5035 return token() === SyntaxKind.StringLiteral || token() === SyntaxKind.AsteriskToken || 5036 token() === SyntaxKind.OpenBraceToken || tokenIsIdentifierOrKeyword(token()); 5037 case SyntaxKind.ExportKeyword: 5038 nextToken(); 5039 if (token() === SyntaxKind.EqualsToken || token() === SyntaxKind.AsteriskToken || 5040 token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.DefaultKeyword || 5041 token() === SyntaxKind.AsKeyword) { 5042 return true; 5043 } 5044 continue; 5045 5046 case SyntaxKind.StaticKeyword: 5047 nextToken(); 5048 continue; 5049 default: 5050 return false; 5051 } 5052 } 5053 } 5054 5055 function isStartOfDeclaration(): boolean { 5056 return lookAhead(isDeclaration); 5057 } 5058 5059 function isStartOfStatement(): boolean { 5060 switch (token()) { 5061 case SyntaxKind.AtToken: 5062 case SyntaxKind.SemicolonToken: 5063 case SyntaxKind.OpenBraceToken: 5064 case SyntaxKind.VarKeyword: 5065 case SyntaxKind.LetKeyword: 5066 case SyntaxKind.FunctionKeyword: 5067 case SyntaxKind.ClassKeyword: 5068 case SyntaxKind.EnumKeyword: 5069 case SyntaxKind.IfKeyword: 5070 case SyntaxKind.DoKeyword: 5071 case SyntaxKind.WhileKeyword: 5072 case SyntaxKind.ForKeyword: 5073 case SyntaxKind.ContinueKeyword: 5074 case SyntaxKind.BreakKeyword: 5075 case SyntaxKind.ReturnKeyword: 5076 case SyntaxKind.WithKeyword: 5077 case SyntaxKind.SwitchKeyword: 5078 case SyntaxKind.ThrowKeyword: 5079 case SyntaxKind.TryKeyword: 5080 case SyntaxKind.DebuggerKeyword: 5081 // 'catch' and 'finally' do not actually indicate that the code is part of a statement, 5082 // however, we say they are here so that we may gracefully parse them and error later. 5083 case SyntaxKind.CatchKeyword: 5084 case SyntaxKind.FinallyKeyword: 5085 return true; 5086 5087 case SyntaxKind.ImportKeyword: 5088 return isStartOfDeclaration() || lookAhead(nextTokenIsOpenParenOrLessThan); 5089 5090 case SyntaxKind.ConstKeyword: 5091 case SyntaxKind.ExportKeyword: 5092 return isStartOfDeclaration(); 5093 5094 case SyntaxKind.AsyncKeyword: 5095 case SyntaxKind.DeclareKeyword: 5096 case SyntaxKind.InterfaceKeyword: 5097 case SyntaxKind.ModuleKeyword: 5098 case SyntaxKind.NamespaceKeyword: 5099 case SyntaxKind.TypeKeyword: 5100 case SyntaxKind.GlobalKeyword: 5101 // When these don't start a declaration, they're an identifier in an expression statement 5102 return true; 5103 5104 case SyntaxKind.PublicKeyword: 5105 case SyntaxKind.PrivateKeyword: 5106 case SyntaxKind.ProtectedKeyword: 5107 case SyntaxKind.StaticKeyword: 5108 case SyntaxKind.ReadonlyKeyword: 5109 // When these don't start a declaration, they may be the start of a class member if an identifier 5110 // immediately follows. Otherwise they're an identifier in an expression statement. 5111 return isStartOfDeclaration() || !lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine); 5112 5113 default: 5114 return isStartOfExpression(); 5115 } 5116 } 5117 5118 function nextTokenIsIdentifierOrStartOfDestructuring() { 5119 nextToken(); 5120 return isIdentifier() || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.OpenBracketToken; 5121 } 5122 5123 function isLetDeclaration() { 5124 // In ES6 'let' always starts a lexical declaration if followed by an identifier or { 5125 // or [. 5126 return lookAhead(nextTokenIsIdentifierOrStartOfDestructuring); 5127 } 5128 5129 function parseStatement(): Statement { 5130 switch (token()) { 5131 case SyntaxKind.SemicolonToken: 5132 return parseEmptyStatement(); 5133 case SyntaxKind.OpenBraceToken: 5134 return parseBlock(/*ignoreMissingOpenBrace*/ false); 5135 case SyntaxKind.VarKeyword: 5136 return parseVariableStatement(<VariableStatement>createNodeWithJSDoc(SyntaxKind.VariableDeclaration)); 5137 case SyntaxKind.LetKeyword: 5138 if (isLetDeclaration()) { 5139 return parseVariableStatement(<VariableStatement>createNodeWithJSDoc(SyntaxKind.VariableDeclaration)); 5140 } 5141 break; 5142 case SyntaxKind.FunctionKeyword: 5143 return parseFunctionDeclaration(<FunctionDeclaration>createNodeWithJSDoc(SyntaxKind.FunctionDeclaration)); 5144 case SyntaxKind.ClassKeyword: 5145 return parseClassDeclaration(<ClassDeclaration>createNodeWithJSDoc(SyntaxKind.ClassDeclaration)); 5146 case SyntaxKind.IfKeyword: 5147 return parseIfStatement(); 5148 case SyntaxKind.DoKeyword: 5149 return parseDoStatement(); 5150 case SyntaxKind.WhileKeyword: 5151 return parseWhileStatement(); 5152 case SyntaxKind.ForKeyword: 5153 return parseForOrForInOrForOfStatement(); 5154 case SyntaxKind.ContinueKeyword: 5155 return parseBreakOrContinueStatement(SyntaxKind.ContinueStatement); 5156 case SyntaxKind.BreakKeyword: 5157 return parseBreakOrContinueStatement(SyntaxKind.BreakStatement); 5158 case SyntaxKind.ReturnKeyword: 5159 return parseReturnStatement(); 5160 case SyntaxKind.WithKeyword: 5161 return parseWithStatement(); 5162 case SyntaxKind.SwitchKeyword: 5163 return parseSwitchStatement(); 5164 case SyntaxKind.ThrowKeyword: 5165 return parseThrowStatement(); 5166 case SyntaxKind.TryKeyword: 5167 // Include 'catch' and 'finally' for error recovery. 5168 case SyntaxKind.CatchKeyword: 5169 case SyntaxKind.FinallyKeyword: 5170 return parseTryStatement(); 5171 case SyntaxKind.DebuggerKeyword: 5172 return parseDebuggerStatement(); 5173 case SyntaxKind.AtToken: 5174 return parseDeclaration(); 5175 case SyntaxKind.AsyncKeyword: 5176 case SyntaxKind.InterfaceKeyword: 5177 case SyntaxKind.TypeKeyword: 5178 case SyntaxKind.ModuleKeyword: 5179 case SyntaxKind.NamespaceKeyword: 5180 case SyntaxKind.DeclareKeyword: 5181 case SyntaxKind.ConstKeyword: 5182 case SyntaxKind.EnumKeyword: 5183 case SyntaxKind.ExportKeyword: 5184 case SyntaxKind.ImportKeyword: 5185 case SyntaxKind.PrivateKeyword: 5186 case SyntaxKind.ProtectedKeyword: 5187 case SyntaxKind.PublicKeyword: 5188 case SyntaxKind.AbstractKeyword: 5189 case SyntaxKind.StaticKeyword: 5190 case SyntaxKind.ReadonlyKeyword: 5191 case SyntaxKind.GlobalKeyword: 5192 if (isStartOfDeclaration()) { 5193 return parseDeclaration(); 5194 } 5195 break; 5196 } 5197 return parseExpressionOrLabeledStatement(); 5198 } 5199 5200 function isDeclareModifier(modifier: Modifier) { 5201 return modifier.kind === SyntaxKind.DeclareKeyword; 5202 } 5203 5204 function parseDeclaration(): Statement { 5205 const node = <Statement>createNodeWithJSDoc(SyntaxKind.Unknown); 5206 node.decorators = parseDecorators(); 5207 node.modifiers = parseModifiers(); 5208 if (some(node.modifiers, isDeclareModifier)) { 5209 for (const m of node.modifiers) { 5210 m.flags |= NodeFlags.Ambient; 5211 } 5212 return doInsideOfContext(NodeFlags.Ambient, () => parseDeclarationWorker(node)); 5213 } 5214 else { 5215 return parseDeclarationWorker(node); 5216 } 5217 } 5218 5219 function parseDeclarationWorker(node: Statement): Statement { 5220 switch (token()) { 5221 case SyntaxKind.VarKeyword: 5222 case SyntaxKind.LetKeyword: 5223 case SyntaxKind.ConstKeyword: 5224 return parseVariableStatement(<VariableStatement>node); 5225 case SyntaxKind.FunctionKeyword: 5226 return parseFunctionDeclaration(<FunctionDeclaration>node); 5227 case SyntaxKind.ClassKeyword: 5228 return parseClassDeclaration(<ClassDeclaration>node); 5229 case SyntaxKind.InterfaceKeyword: 5230 return parseInterfaceDeclaration(<InterfaceDeclaration>node); 5231 case SyntaxKind.TypeKeyword: 5232 return parseTypeAliasDeclaration(<TypeAliasDeclaration>node); 5233 case SyntaxKind.EnumKeyword: 5234 return parseEnumDeclaration(<EnumDeclaration>node); 5235 case SyntaxKind.GlobalKeyword: 5236 case SyntaxKind.ModuleKeyword: 5237 case SyntaxKind.NamespaceKeyword: 5238 return parseModuleDeclaration(<ModuleDeclaration>node); 5239 case SyntaxKind.ImportKeyword: 5240 return parseImportDeclarationOrImportEqualsDeclaration(<ImportDeclaration | ImportEqualsDeclaration>node); 5241 case SyntaxKind.ExportKeyword: 5242 nextToken(); 5243 switch (token()) { 5244 case SyntaxKind.DefaultKeyword: 5245 case SyntaxKind.EqualsToken: 5246 return parseExportAssignment(<ExportAssignment>node); 5247 case SyntaxKind.AsKeyword: 5248 return parseNamespaceExportDeclaration(<NamespaceExportDeclaration>node); 5249 default: 5250 return parseExportDeclaration(<ExportDeclaration>node); 5251 } 5252 default: 5253 if (node.decorators || node.modifiers) { 5254 // We reached this point because we encountered decorators and/or modifiers and assumed a declaration 5255 // would follow. For recovery and error reporting purposes, return an incomplete declaration. 5256 const missing = <Statement>createMissingNode(SyntaxKind.MissingDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected); 5257 missing.pos = node.pos; 5258 missing.decorators = node.decorators; 5259 missing.modifiers = node.modifiers; 5260 return finishNode(missing); 5261 } 5262 } 5263 } 5264 5265 function nextTokenIsIdentifierOrStringLiteralOnSameLine() { 5266 nextToken(); 5267 return !scanner.hasPrecedingLineBreak() && (isIdentifier() || token() === SyntaxKind.StringLiteral); 5268 } 5269 5270 function parseFunctionBlockOrSemicolon(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block { 5271 if (token() !== SyntaxKind.OpenBraceToken && canParseSemicolon()) { 5272 parseSemicolon(); 5273 return; 5274 } 5275 5276 return parseFunctionBlock(flags, diagnosticMessage); 5277 } 5278 5279 // DECLARATIONS 5280 5281 function parseArrayBindingElement(): ArrayBindingElement { 5282 if (token() === SyntaxKind.CommaToken) { 5283 return <OmittedExpression>createNode(SyntaxKind.OmittedExpression); 5284 } 5285 const node = <BindingElement>createNode(SyntaxKind.BindingElement); 5286 node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); 5287 node.name = parseIdentifierOrPattern(); 5288 node.initializer = parseInitializer(); 5289 return finishNode(node); 5290 } 5291 5292 function parseObjectBindingElement(): BindingElement { 5293 const node = <BindingElement>createNode(SyntaxKind.BindingElement); 5294 node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); 5295 const tokenIsIdentifier = isIdentifier(); 5296 const propertyName = parsePropertyName(); 5297 if (tokenIsIdentifier && token() !== SyntaxKind.ColonToken) { 5298 node.name = <Identifier>propertyName; 5299 } 5300 else { 5301 parseExpected(SyntaxKind.ColonToken); 5302 node.propertyName = propertyName; 5303 node.name = parseIdentifierOrPattern(); 5304 } 5305 node.initializer = parseInitializer(); 5306 return finishNode(node); 5307 } 5308 5309 function parseObjectBindingPattern(): ObjectBindingPattern { 5310 const node = <ObjectBindingPattern>createNode(SyntaxKind.ObjectBindingPattern); 5311 parseExpected(SyntaxKind.OpenBraceToken); 5312 node.elements = parseDelimitedList(ParsingContext.ObjectBindingElements, parseObjectBindingElement); 5313 parseExpected(SyntaxKind.CloseBraceToken); 5314 return finishNode(node); 5315 } 5316 5317 function parseArrayBindingPattern(): ArrayBindingPattern { 5318 const node = <ArrayBindingPattern>createNode(SyntaxKind.ArrayBindingPattern); 5319 parseExpected(SyntaxKind.OpenBracketToken); 5320 node.elements = parseDelimitedList(ParsingContext.ArrayBindingElements, parseArrayBindingElement); 5321 parseExpected(SyntaxKind.CloseBracketToken); 5322 return finishNode(node); 5323 } 5324 5325 function isIdentifierOrPattern() { 5326 return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.OpenBracketToken || isIdentifier(); 5327 } 5328 5329 function parseIdentifierOrPattern(): Identifier | BindingPattern { 5330 if (token() === SyntaxKind.OpenBracketToken) { 5331 return parseArrayBindingPattern(); 5332 } 5333 if (token() === SyntaxKind.OpenBraceToken) { 5334 return parseObjectBindingPattern(); 5335 } 5336 return parseIdentifier(); 5337 } 5338 5339 function parseVariableDeclarationAllowExclamation() { 5340 return parseVariableDeclaration(/*allowExclamation*/ true); 5341 } 5342 5343 function parseVariableDeclaration(allowExclamation?: boolean): VariableDeclaration { 5344 const node = <VariableDeclaration>createNode(SyntaxKind.VariableDeclaration); 5345 node.name = parseIdentifierOrPattern(); 5346 if (allowExclamation && node.name.kind === SyntaxKind.Identifier && 5347 token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) { 5348 node.exclamationToken = parseTokenNode(); 5349 } 5350 node.type = parseTypeAnnotation(); 5351 if (!isInOrOfKeyword(token())) { 5352 node.initializer = parseInitializer(); 5353 } 5354 return finishNode(node); 5355 } 5356 5357 function parseVariableDeclarationList(inForStatementInitializer: boolean): VariableDeclarationList { 5358 const node = <VariableDeclarationList>createNode(SyntaxKind.VariableDeclarationList); 5359 5360 switch (token()) { 5361 case SyntaxKind.VarKeyword: 5362 break; 5363 case SyntaxKind.LetKeyword: 5364 node.flags |= NodeFlags.Let; 5365 break; 5366 case SyntaxKind.ConstKeyword: 5367 node.flags |= NodeFlags.Const; 5368 break; 5369 default: 5370 Debug.fail(); 5371 } 5372 5373 nextToken(); 5374 5375 // The user may have written the following: 5376 // 5377 // for (let of X) { } 5378 // 5379 // In this case, we want to parse an empty declaration list, and then parse 'of' 5380 // as a keyword. The reason this is not automatic is that 'of' is a valid identifier. 5381 // So we need to look ahead to determine if 'of' should be treated as a keyword in 5382 // this context. 5383 // The checker will then give an error that there is an empty declaration list. 5384 if (token() === SyntaxKind.OfKeyword && lookAhead(canFollowContextualOfKeyword)) { 5385 node.declarations = createMissingList<VariableDeclaration>(); 5386 } 5387 else { 5388 const savedDisallowIn = inDisallowInContext(); 5389 setDisallowInContext(inForStatementInitializer); 5390 5391 node.declarations = parseDelimitedList(ParsingContext.VariableDeclarations, 5392 inForStatementInitializer ? parseVariableDeclaration : parseVariableDeclarationAllowExclamation); 5393 5394 setDisallowInContext(savedDisallowIn); 5395 } 5396 5397 return finishNode(node); 5398 } 5399 5400 function canFollowContextualOfKeyword(): boolean { 5401 return nextTokenIsIdentifier() && nextToken() === SyntaxKind.CloseParenToken; 5402 } 5403 5404 function parseVariableStatement(node: VariableStatement): VariableStatement { 5405 node.kind = SyntaxKind.VariableStatement; 5406 node.declarationList = parseVariableDeclarationList(/*inForStatementInitializer*/ false); 5407 parseSemicolon(); 5408 return finishNode(node); 5409 } 5410 5411 function parseFunctionDeclaration(node: FunctionDeclaration): FunctionDeclaration { 5412 node.kind = SyntaxKind.FunctionDeclaration; 5413 parseExpected(SyntaxKind.FunctionKeyword); 5414 node.asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); 5415 node.name = hasModifier(node, ModifierFlags.Default) ? parseOptionalIdentifier() : parseIdentifier(); 5416 const isGenerator = node.asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; 5417 const isAsync = hasModifier(node, ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None; 5418 fillSignature(SyntaxKind.ColonToken, isGenerator | isAsync, node); 5419 node.body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, Diagnostics.or_expected); 5420 return finishNode(node); 5421 } 5422 5423 function parseConstructorDeclaration(node: ConstructorDeclaration): ConstructorDeclaration { 5424 node.kind = SyntaxKind.Constructor; 5425 parseExpected(SyntaxKind.ConstructorKeyword); 5426 fillSignature(SyntaxKind.ColonToken, SignatureFlags.None, node); 5427 node.body = parseFunctionBlockOrSemicolon(SignatureFlags.None, Diagnostics.or_expected); 5428 return finishNode(node); 5429 } 5430 5431 function parseMethodDeclaration(node: MethodDeclaration, asteriskToken: AsteriskToken, diagnosticMessage?: DiagnosticMessage): MethodDeclaration { 5432 node.kind = SyntaxKind.MethodDeclaration; 5433 node.asteriskToken = asteriskToken; 5434 const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; 5435 const isAsync = hasModifier(node, ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None; 5436 fillSignature(SyntaxKind.ColonToken, isGenerator | isAsync, node); 5437 node.body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, diagnosticMessage); 5438 return finishNode(node); 5439 } 5440 5441 function parsePropertyDeclaration(node: PropertyDeclaration): PropertyDeclaration { 5442 node.kind = SyntaxKind.PropertyDeclaration; 5443 if (!node.questionToken && token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) { 5444 node.exclamationToken = parseTokenNode(); 5445 } 5446 node.type = parseTypeAnnotation(); 5447 5448 // For instance properties specifically, since they are evaluated inside the constructor, 5449 // we do *not * want to parse yield expressions, so we specifically turn the yield context 5450 // off. The grammar would look something like this: 5451 // 5452 // MemberVariableDeclaration[Yield]: 5453 // AccessibilityModifier_opt PropertyName TypeAnnotation_opt Initializer_opt[In]; 5454 // AccessibilityModifier_opt static_opt PropertyName TypeAnnotation_opt Initializer_opt[In, ?Yield]; 5455 // 5456 // The checker may still error in the static case to explicitly disallow the yield expression. 5457 node.initializer = hasModifier(node, ModifierFlags.Static) 5458 ? allowInAnd(parseInitializer) 5459 : doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.DisallowInContext, parseInitializer); 5460 5461 parseSemicolon(); 5462 return finishNode(node); 5463 } 5464 5465 function parsePropertyOrMethodDeclaration(node: PropertyDeclaration | MethodDeclaration): PropertyDeclaration | MethodDeclaration { 5466 const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); 5467 node.name = parsePropertyName(); 5468 // Note: this is not legal as per the grammar. But we allow it in the parser and 5469 // report an error in the grammar checker. 5470 node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken); 5471 if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { 5472 return parseMethodDeclaration(<MethodDeclaration>node, asteriskToken, Diagnostics.or_expected); 5473 } 5474 return parsePropertyDeclaration(<PropertyDeclaration>node); 5475 } 5476 5477 function parseAccessorDeclaration(node: AccessorDeclaration, kind: AccessorDeclaration["kind"]): AccessorDeclaration { 5478 node.kind = kind; 5479 node.name = parsePropertyName(); 5480 fillSignature(SyntaxKind.ColonToken, SignatureFlags.None, node); 5481 node.body = parseFunctionBlockOrSemicolon(SignatureFlags.None); 5482 return finishNode(node); 5483 } 5484 5485 function isClassMemberModifier(idToken: SyntaxKind) { 5486 switch (idToken) { 5487 case SyntaxKind.PublicKeyword: 5488 case SyntaxKind.PrivateKeyword: 5489 case SyntaxKind.ProtectedKeyword: 5490 case SyntaxKind.StaticKeyword: 5491 case SyntaxKind.ReadonlyKeyword: 5492 return true; 5493 default: 5494 return false; 5495 } 5496 } 5497 5498 function isClassMemberStart(): boolean { 5499 let idToken: SyntaxKind; 5500 5501 if (token() === SyntaxKind.AtToken) { 5502 return true; 5503 } 5504 5505 // Eat up all modifiers, but hold on to the last one in case it is actually an identifier. 5506 while (isModifierKind(token())) { 5507 idToken = token(); 5508 // If the idToken is a class modifier (protected, private, public, and static), it is 5509 // certain that we are starting to parse class member. This allows better error recovery 5510 // Example: 5511 // public foo() ... // true 5512 // public @dec blah ... // true; we will then report an error later 5513 // export public ... // true; we will then report an error later 5514 if (isClassMemberModifier(idToken)) { 5515 return true; 5516 } 5517 5518 nextToken(); 5519 } 5520 5521 if (token() === SyntaxKind.AsteriskToken) { 5522 return true; 5523 } 5524 5525 // Try to get the first property-like token following all modifiers. 5526 // This can either be an identifier or the 'get' or 'set' keywords. 5527 if (isLiteralPropertyName()) { 5528 idToken = token(); 5529 nextToken(); 5530 } 5531 5532 // Index signatures and computed properties are class members; we can parse. 5533 if (token() === SyntaxKind.OpenBracketToken) { 5534 return true; 5535 } 5536 5537 // If we were able to get any potential identifier... 5538 if (idToken !== undefined) { 5539 // If we have a non-keyword identifier, or if we have an accessor, then it's safe to parse. 5540 if (!isKeyword(idToken) || idToken === SyntaxKind.SetKeyword || idToken === SyntaxKind.GetKeyword) { 5541 return true; 5542 } 5543 5544 // If it *is* a keyword, but not an accessor, check a little farther along 5545 // to see if it should actually be parsed as a class member. 5546 switch (token()) { 5547 case SyntaxKind.OpenParenToken: // Method declaration 5548 case SyntaxKind.LessThanToken: // Generic Method declaration 5549 case SyntaxKind.ExclamationToken: // Non-null assertion on property name 5550 case SyntaxKind.ColonToken: // Type Annotation for declaration 5551 case SyntaxKind.EqualsToken: // Initializer for declaration 5552 case SyntaxKind.QuestionToken: // Not valid, but permitted so that it gets caught later on. 5553 return true; 5554 default: 5555 // Covers 5556 // - Semicolons (declaration termination) 5557 // - Closing braces (end-of-class, must be declaration) 5558 // - End-of-files (not valid, but permitted so that it gets caught later on) 5559 // - Line-breaks (enabling *automatic semicolon insertion*) 5560 return canParseSemicolon(); 5561 } 5562 } 5563 5564 return false; 5565 } 5566 5567 function parseDecorators(): NodeArray<Decorator> | undefined { 5568 let list: Decorator[] | undefined; 5569 const listPos = getNodePos(); 5570 while (true) { 5571 const decoratorStart = getNodePos(); 5572 if (!parseOptional(SyntaxKind.AtToken)) { 5573 break; 5574 } 5575 const decorator = <Decorator>createNode(SyntaxKind.Decorator, decoratorStart); 5576 decorator.expression = doInDecoratorContext(parseLeftHandSideExpressionOrHigher); 5577 finishNode(decorator); 5578 (list || (list = [])).push(decorator); 5579 } 5580 return list && createNodeArray(list, listPos); 5581 } 5582 5583 /* 5584 * There are situations in which a modifier like 'const' will appear unexpectedly, such as on a class member. 5585 * In those situations, if we are entirely sure that 'const' is not valid on its own (such as when ASI takes effect 5586 * and turns it into a standalone declaration), then it is better to parse it and report an error later. 5587 * 5588 * In such situations, 'permitInvalidConstAsModifier' should be set to true. 5589 */ 5590 function parseModifiers(permitInvalidConstAsModifier?: boolean): NodeArray<Modifier> | undefined { 5591 let list: Modifier[]; 5592 const listPos = getNodePos(); 5593 while (true) { 5594 const modifierStart = scanner.getStartPos(); 5595 const modifierKind = token(); 5596 5597 if (token() === SyntaxKind.ConstKeyword && permitInvalidConstAsModifier) { 5598 // We need to ensure that any subsequent modifiers appear on the same line 5599 // so that when 'const' is a standalone declaration, we don't issue an error. 5600 if (!tryParse(nextTokenIsOnSameLineAndCanFollowModifier)) { 5601 break; 5602 } 5603 } 5604 else { 5605 if (!parseAnyContextualModifier()) { 5606 break; 5607 } 5608 } 5609 5610 const modifier = finishNode(<Modifier>createNode(modifierKind, modifierStart)); 5611 (list || (list = [])).push(modifier); 5612 } 5613 return list && createNodeArray(list, listPos); 5614 } 5615 5616 function parseModifiersForArrowFunction(): NodeArray<Modifier> { 5617 let modifiers: NodeArray<Modifier>; 5618 if (token() === SyntaxKind.AsyncKeyword) { 5619 const modifierStart = scanner.getStartPos(); 5620 const modifierKind = token(); 5621 nextToken(); 5622 const modifier = finishNode(<Modifier>createNode(modifierKind, modifierStart)); 5623 modifiers = createNodeArray<Modifier>([modifier], modifierStart); 5624 } 5625 return modifiers; 5626 } 5627 5628 function parseClassElement(): ClassElement { 5629 if (token() === SyntaxKind.SemicolonToken) { 5630 const result = <SemicolonClassElement>createNode(SyntaxKind.SemicolonClassElement); 5631 nextToken(); 5632 return finishNode(result); 5633 } 5634 5635 const node = <ClassElement>createNodeWithJSDoc(SyntaxKind.Unknown); 5636 node.decorators = parseDecorators(); 5637 node.modifiers = parseModifiers(/*permitInvalidConstAsModifier*/ true); 5638 5639 if (parseContextualModifier(SyntaxKind.GetKeyword)) { 5640 return parseAccessorDeclaration(<AccessorDeclaration>node, SyntaxKind.GetAccessor); 5641 } 5642 5643 if (parseContextualModifier(SyntaxKind.SetKeyword)) { 5644 return parseAccessorDeclaration(<AccessorDeclaration>node, SyntaxKind.SetAccessor); 5645 } 5646 5647 if (token() === SyntaxKind.ConstructorKeyword) { 5648 return parseConstructorDeclaration(<ConstructorDeclaration>node); 5649 } 5650 5651 if (isIndexSignature()) { 5652 return parseIndexSignatureDeclaration(<IndexSignatureDeclaration>node); 5653 } 5654 5655 // It is very important that we check this *after* checking indexers because 5656 // the [ token can start an index signature or a computed property name 5657 if (tokenIsIdentifierOrKeyword(token()) || 5658 token() === SyntaxKind.StringLiteral || 5659 token() === SyntaxKind.NumericLiteral || 5660 token() === SyntaxKind.AsteriskToken || 5661 token() === SyntaxKind.OpenBracketToken) { 5662 5663 return parsePropertyOrMethodDeclaration(<PropertyDeclaration | MethodDeclaration>node); 5664 } 5665 5666 if (node.decorators || node.modifiers) { 5667 // treat this as a property declaration with a missing name. 5668 node.name = createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected); 5669 return parsePropertyDeclaration(<PropertyDeclaration>node); 5670 } 5671 5672 // 'isClassMemberStart' should have hinted not to attempt parsing. 5673 Debug.fail("Should not have attempted to parse class member declaration."); 5674 } 5675 5676 function parseClassExpression(): ClassExpression { 5677 return <ClassExpression>parseClassDeclarationOrExpression(<ClassLikeDeclaration>createNodeWithJSDoc(SyntaxKind.Unknown), SyntaxKind.ClassExpression); 5678 } 5679 5680 function parseClassDeclaration(node: ClassLikeDeclaration): ClassDeclaration { 5681 return <ClassDeclaration>parseClassDeclarationOrExpression(node, SyntaxKind.ClassDeclaration); 5682 } 5683 5684 function parseClassDeclarationOrExpression(node: ClassLikeDeclaration, kind: ClassLikeDeclaration["kind"]): ClassLikeDeclaration { 5685 node.kind = kind; 5686 parseExpected(SyntaxKind.ClassKeyword); 5687 node.name = parseNameOfClassDeclarationOrExpression(); 5688 node.typeParameters = parseTypeParameters(); 5689 node.heritageClauses = parseHeritageClauses(); 5690 5691 if (parseExpected(SyntaxKind.OpenBraceToken)) { 5692 // ClassTail[Yield,Await] : (Modified) See 14.5 5693 // ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt } 5694 node.members = parseClassMembers(); 5695 parseExpected(SyntaxKind.CloseBraceToken); 5696 } 5697 else { 5698 node.members = createMissingList<ClassElement>(); 5699 } 5700 5701 return finishNode(node); 5702 } 5703 5704 function parseNameOfClassDeclarationOrExpression(): Identifier | undefined { 5705 // implements is a future reserved word so 5706 // 'class implements' might mean either 5707 // - class expression with omitted name, 'implements' starts heritage clause 5708 // - class with name 'implements' 5709 // 'isImplementsClause' helps to disambiguate between these two cases 5710 return isIdentifier() && !isImplementsClause() 5711 ? parseIdentifier() 5712 : undefined; 5713 } 5714 5715 function isImplementsClause() { 5716 return token() === SyntaxKind.ImplementsKeyword && lookAhead(nextTokenIsIdentifierOrKeyword); 5717 } 5718 5719 function parseHeritageClauses(): NodeArray<HeritageClause> | undefined { 5720 // ClassTail[Yield,Await] : (Modified) See 14.5 5721 // ClassHeritage[?Yield,?Await]opt { ClassBody[?Yield,?Await]opt } 5722 5723 if (isHeritageClause()) { 5724 return parseList(ParsingContext.HeritageClauses, parseHeritageClause); 5725 } 5726 5727 return undefined; 5728 } 5729 5730 function parseHeritageClause(): HeritageClause | undefined { 5731 const tok = token(); 5732 if (tok === SyntaxKind.ExtendsKeyword || tok === SyntaxKind.ImplementsKeyword) { 5733 const node = <HeritageClause>createNode(SyntaxKind.HeritageClause); 5734 node.token = tok; 5735 nextToken(); 5736 node.types = parseDelimitedList(ParsingContext.HeritageClauseElement, parseExpressionWithTypeArguments); 5737 return finishNode(node); 5738 } 5739 5740 return undefined; 5741 } 5742 5743 function parseExpressionWithTypeArguments(): ExpressionWithTypeArguments { 5744 const node = <ExpressionWithTypeArguments>createNode(SyntaxKind.ExpressionWithTypeArguments); 5745 node.expression = parseLeftHandSideExpressionOrHigher(); 5746 node.typeArguments = tryParseTypeArguments(); 5747 return finishNode(node); 5748 } 5749 5750 function tryParseTypeArguments(): NodeArray<TypeNode> | undefined { 5751 return token() === SyntaxKind.LessThanToken 5752 ? parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken) 5753 : undefined; 5754 } 5755 5756 function isHeritageClause(): boolean { 5757 return token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword; 5758 } 5759 5760 function parseClassMembers(): NodeArray<ClassElement> { 5761 return parseList(ParsingContext.ClassMembers, parseClassElement); 5762 } 5763 5764 function parseInterfaceDeclaration(node: InterfaceDeclaration): InterfaceDeclaration { 5765 node.kind = SyntaxKind.InterfaceDeclaration; 5766 parseExpected(SyntaxKind.InterfaceKeyword); 5767 node.name = parseIdentifier(); 5768 node.typeParameters = parseTypeParameters(); 5769 node.heritageClauses = parseHeritageClauses(); 5770 node.members = parseObjectTypeMembers(); 5771 return finishNode(node); 5772 } 5773 5774 function parseTypeAliasDeclaration(node: TypeAliasDeclaration): TypeAliasDeclaration { 5775 node.kind = SyntaxKind.TypeAliasDeclaration; 5776 parseExpected(SyntaxKind.TypeKeyword); 5777 node.name = parseIdentifier(); 5778 node.typeParameters = parseTypeParameters(); 5779 parseExpected(SyntaxKind.EqualsToken); 5780 node.type = parseType(); 5781 parseSemicolon(); 5782 return finishNode(node); 5783 } 5784 5785 // In an ambient declaration, the grammar only allows integer literals as initializers. 5786 // In a non-ambient declaration, the grammar allows uninitialized members only in a 5787 // ConstantEnumMemberSection, which starts at the beginning of an enum declaration 5788 // or any time an integer literal initializer is encountered. 5789 function parseEnumMember(): EnumMember { 5790 const node = <EnumMember>createNodeWithJSDoc(SyntaxKind.EnumMember); 5791 node.name = parsePropertyName(); 5792 node.initializer = allowInAnd(parseInitializer); 5793 return finishNode(node); 5794 } 5795 5796 function parseEnumDeclaration(node: EnumDeclaration): EnumDeclaration { 5797 node.kind = SyntaxKind.EnumDeclaration; 5798 parseExpected(SyntaxKind.EnumKeyword); 5799 node.name = parseIdentifier(); 5800 if (parseExpected(SyntaxKind.OpenBraceToken)) { 5801 node.members = parseDelimitedList(ParsingContext.EnumMembers, parseEnumMember); 5802 parseExpected(SyntaxKind.CloseBraceToken); 5803 } 5804 else { 5805 node.members = createMissingList<EnumMember>(); 5806 } 5807 return finishNode(node); 5808 } 5809 5810 function parseModuleBlock(): ModuleBlock { 5811 const node = <ModuleBlock>createNode(SyntaxKind.ModuleBlock); 5812 if (parseExpected(SyntaxKind.OpenBraceToken)) { 5813 node.statements = parseList(ParsingContext.BlockStatements, parseStatement); 5814 parseExpected(SyntaxKind.CloseBraceToken); 5815 } 5816 else { 5817 node.statements = createMissingList<Statement>(); 5818 } 5819 return finishNode(node); 5820 } 5821 5822 function parseModuleOrNamespaceDeclaration(node: ModuleDeclaration, flags: NodeFlags): ModuleDeclaration { 5823 node.kind = SyntaxKind.ModuleDeclaration; 5824 // If we are parsing a dotted namespace name, we want to 5825 // propagate the 'Namespace' flag across the names if set. 5826 const namespaceFlag = flags & NodeFlags.Namespace; 5827 node.flags |= flags; 5828 node.name = parseIdentifier(); 5829 node.body = parseOptional(SyntaxKind.DotToken) 5830 ? <NamespaceDeclaration>parseModuleOrNamespaceDeclaration(<ModuleDeclaration>createNode(SyntaxKind.Unknown), NodeFlags.NestedNamespace | namespaceFlag) 5831 : parseModuleBlock(); 5832 return finishNode(node); 5833 } 5834 5835 function parseAmbientExternalModuleDeclaration(node: ModuleDeclaration): ModuleDeclaration { 5836 node.kind = SyntaxKind.ModuleDeclaration; 5837 if (token() === SyntaxKind.GlobalKeyword) { 5838 // parse 'global' as name of global scope augmentation 5839 node.name = parseIdentifier(); 5840 node.flags |= NodeFlags.GlobalAugmentation; 5841 } 5842 else { 5843 node.name = <StringLiteral>parseLiteralNode(); 5844 node.name.text = internIdentifier(node.name.text); 5845 } 5846 if (token() === SyntaxKind.OpenBraceToken) { 5847 node.body = parseModuleBlock(); 5848 } 5849 else { 5850 parseSemicolon(); 5851 } 5852 return finishNode(node); 5853 } 5854 5855 function parseModuleDeclaration(node: ModuleDeclaration): ModuleDeclaration { 5856 let flags: NodeFlags = 0; 5857 if (token() === SyntaxKind.GlobalKeyword) { 5858 // global augmentation 5859 return parseAmbientExternalModuleDeclaration(node); 5860 } 5861 else if (parseOptional(SyntaxKind.NamespaceKeyword)) { 5862 flags |= NodeFlags.Namespace; 5863 } 5864 else { 5865 parseExpected(SyntaxKind.ModuleKeyword); 5866 if (token() === SyntaxKind.StringLiteral) { 5867 return parseAmbientExternalModuleDeclaration(node); 5868 } 5869 } 5870 return parseModuleOrNamespaceDeclaration(node, flags); 5871 } 5872 5873 function isExternalModuleReference() { 5874 return token() === SyntaxKind.RequireKeyword && 5875 lookAhead(nextTokenIsOpenParen); 5876 } 5877 5878 function nextTokenIsOpenParen() { 5879 return nextToken() === SyntaxKind.OpenParenToken; 5880 } 5881 5882 function nextTokenIsSlash() { 5883 return nextToken() === SyntaxKind.SlashToken; 5884 } 5885 5886 function parseNamespaceExportDeclaration(node: NamespaceExportDeclaration): NamespaceExportDeclaration { 5887 node.kind = SyntaxKind.NamespaceExportDeclaration; 5888 parseExpected(SyntaxKind.AsKeyword); 5889 parseExpected(SyntaxKind.NamespaceKeyword); 5890 node.name = parseIdentifier(); 5891 parseSemicolon(); 5892 return finishNode(node); 5893 } 5894 5895 function parseImportDeclarationOrImportEqualsDeclaration(node: ImportEqualsDeclaration | ImportDeclaration): ImportEqualsDeclaration | ImportDeclaration { 5896 parseExpected(SyntaxKind.ImportKeyword); 5897 const afterImportPos = scanner.getStartPos(); 5898 5899 let identifier: Identifier; 5900 if (isIdentifier()) { 5901 identifier = parseIdentifier(); 5902 if (token() !== SyntaxKind.CommaToken && token() !== SyntaxKind.FromKeyword) { 5903 return parseImportEqualsDeclaration(<ImportEqualsDeclaration>node, identifier); 5904 } 5905 } 5906 5907 // Import statement 5908 node.kind = SyntaxKind.ImportDeclaration; 5909 // ImportDeclaration: 5910 // import ImportClause from ModuleSpecifier ; 5911 // import ModuleSpecifier; 5912 if (identifier || // import id 5913 token() === SyntaxKind.AsteriskToken || // import * 5914 token() === SyntaxKind.OpenBraceToken) { // import { 5915 (<ImportDeclaration>node).importClause = parseImportClause(identifier, afterImportPos); 5916 parseExpected(SyntaxKind.FromKeyword); 5917 } 5918 5919 (<ImportDeclaration>node).moduleSpecifier = parseModuleSpecifier(); 5920 parseSemicolon(); 5921 return finishNode(node); 5922 } 5923 5924 function parseImportEqualsDeclaration(node: ImportEqualsDeclaration, identifier: ts.Identifier): ImportEqualsDeclaration { 5925 node.kind = SyntaxKind.ImportEqualsDeclaration; 5926 node.name = identifier; 5927 parseExpected(SyntaxKind.EqualsToken); 5928 node.moduleReference = parseModuleReference(); 5929 parseSemicolon(); 5930 return finishNode(node); 5931 } 5932 5933 function parseImportClause(identifier: Identifier, fullStart: number) { 5934 // ImportClause: 5935 // ImportedDefaultBinding 5936 // NameSpaceImport 5937 // NamedImports 5938 // ImportedDefaultBinding, NameSpaceImport 5939 // ImportedDefaultBinding, NamedImports 5940 5941 const importClause = <ImportClause>createNode(SyntaxKind.ImportClause, fullStart); 5942 if (identifier) { 5943 // ImportedDefaultBinding: 5944 // ImportedBinding 5945 importClause.name = identifier; 5946 } 5947 5948 // If there was no default import or if there is comma token after default import 5949 // parse namespace or named imports 5950 if (!importClause.name || 5951 parseOptional(SyntaxKind.CommaToken)) { 5952 importClause.namedBindings = token() === SyntaxKind.AsteriskToken ? parseNamespaceImport() : parseNamedImportsOrExports(SyntaxKind.NamedImports); 5953 } 5954 5955 return finishNode(importClause); 5956 } 5957 5958 function parseModuleReference() { 5959 return isExternalModuleReference() 5960 ? parseExternalModuleReference() 5961 : parseEntityName(/*allowReservedWords*/ false); 5962 } 5963 5964 function parseExternalModuleReference() { 5965 const node = <ExternalModuleReference>createNode(SyntaxKind.ExternalModuleReference); 5966 parseExpected(SyntaxKind.RequireKeyword); 5967 parseExpected(SyntaxKind.OpenParenToken); 5968 node.expression = parseModuleSpecifier(); 5969 parseExpected(SyntaxKind.CloseParenToken); 5970 return finishNode(node); 5971 } 5972 5973 function parseModuleSpecifier(): Expression { 5974 if (token() === SyntaxKind.StringLiteral) { 5975 const result = parseLiteralNode(); 5976 result.text = internIdentifier(result.text); 5977 return result; 5978 } 5979 else { 5980 // We allow arbitrary expressions here, even though the grammar only allows string 5981 // literals. We check to ensure that it is only a string literal later in the grammar 5982 // check pass. 5983 return parseExpression(); 5984 } 5985 } 5986 5987 function parseNamespaceImport(): NamespaceImport { 5988 // NameSpaceImport: 5989 // * as ImportedBinding 5990 const namespaceImport = <NamespaceImport>createNode(SyntaxKind.NamespaceImport); 5991 parseExpected(SyntaxKind.AsteriskToken); 5992 parseExpected(SyntaxKind.AsKeyword); 5993 namespaceImport.name = parseIdentifier(); 5994 return finishNode(namespaceImport); 5995 } 5996 5997 function parseNamedImportsOrExports(kind: SyntaxKind.NamedImports): NamedImports; 5998 function parseNamedImportsOrExports(kind: SyntaxKind.NamedExports): NamedExports; 5999 function parseNamedImportsOrExports(kind: SyntaxKind): NamedImportsOrExports { 6000 const node = <NamedImports | NamedExports>createNode(kind); 6001 6002 // NamedImports: 6003 // { } 6004 // { ImportsList } 6005 // { ImportsList, } 6006 6007 // ImportsList: 6008 // ImportSpecifier 6009 // ImportsList, ImportSpecifier 6010 node.elements = <NodeArray<ImportSpecifier> | NodeArray<ExportSpecifier>>parseBracketedList(ParsingContext.ImportOrExportSpecifiers, 6011 kind === SyntaxKind.NamedImports ? parseImportSpecifier : parseExportSpecifier, 6012 SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken); 6013 return finishNode(node); 6014 } 6015 6016 function parseExportSpecifier() { 6017 return parseImportOrExportSpecifier(SyntaxKind.ExportSpecifier); 6018 } 6019 6020 function parseImportSpecifier() { 6021 return parseImportOrExportSpecifier(SyntaxKind.ImportSpecifier); 6022 } 6023 6024 function parseImportOrExportSpecifier(kind: SyntaxKind): ImportOrExportSpecifier { 6025 const node = <ImportSpecifier>createNode(kind); 6026 // ImportSpecifier: 6027 // BindingIdentifier 6028 // IdentifierName as BindingIdentifier 6029 // ExportSpecifier: 6030 // IdentifierName 6031 // IdentifierName as IdentifierName 6032 let checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier(); 6033 let checkIdentifierStart = scanner.getTokenPos(); 6034 let checkIdentifierEnd = scanner.getTextPos(); 6035 const identifierName = parseIdentifierName(); 6036 if (token() === SyntaxKind.AsKeyword) { 6037 node.propertyName = identifierName; 6038 parseExpected(SyntaxKind.AsKeyword); 6039 checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier(); 6040 checkIdentifierStart = scanner.getTokenPos(); 6041 checkIdentifierEnd = scanner.getTextPos(); 6042 node.name = parseIdentifierName(); 6043 } 6044 else { 6045 node.name = identifierName; 6046 } 6047 if (kind === SyntaxKind.ImportSpecifier && checkIdentifierIsKeyword) { 6048 // Report error identifier expected 6049 parseErrorAtPosition(checkIdentifierStart, checkIdentifierEnd - checkIdentifierStart, Diagnostics.Identifier_expected); 6050 } 6051 return finishNode(node); 6052 } 6053 6054 function parseExportDeclaration(node: ExportDeclaration): ExportDeclaration { 6055 node.kind = SyntaxKind.ExportDeclaration; 6056 if (parseOptional(SyntaxKind.AsteriskToken)) { 6057 parseExpected(SyntaxKind.FromKeyword); 6058 node.moduleSpecifier = parseModuleSpecifier(); 6059 } 6060 else { 6061 node.exportClause = parseNamedImportsOrExports(SyntaxKind.NamedExports); 6062 // It is not uncommon to accidentally omit the 'from' keyword. Additionally, in editing scenarios, 6063 // the 'from' keyword can be parsed as a named export when the export clause is unterminated (i.e. `export { from "moduleName";`) 6064 // If we don't have a 'from' keyword, see if we have a string literal such that ASI won't take effect. 6065 if (token() === SyntaxKind.FromKeyword || (token() === SyntaxKind.StringLiteral && !scanner.hasPrecedingLineBreak())) { 6066 parseExpected(SyntaxKind.FromKeyword); 6067 node.moduleSpecifier = parseModuleSpecifier(); 6068 } 6069 } 6070 parseSemicolon(); 6071 return finishNode(node); 6072 } 6073 6074 function parseExportAssignment(node: ExportAssignment): ExportAssignment { 6075 node.kind = SyntaxKind.ExportAssignment; 6076 if (parseOptional(SyntaxKind.EqualsToken)) { 6077 node.isExportEquals = true; 6078 } 6079 else { 6080 parseExpected(SyntaxKind.DefaultKeyword); 6081 } 6082 node.expression = parseAssignmentExpressionOrHigher(); 6083 parseSemicolon(); 6084 return finishNode(node); 6085 } 6086 6087 function processReferenceComments(sourceFile: SourceFile): void { 6088 const triviaScanner = createScanner(sourceFile.languageVersion, /*skipTrivia*/ false, LanguageVariant.Standard, sourceText); 6089 const referencedFiles: FileReference[] = []; 6090 const typeReferenceDirectives: FileReference[] = []; 6091 const amdDependencies: { path: string; name: string }[] = []; 6092 let amdModuleName: string; 6093 let checkJsDirective: CheckJsDirective = undefined; 6094 6095 // Keep scanning all the leading trivia in the file until we get to something that 6096 // isn't trivia. Any single line comment will be analyzed to see if it is a 6097 // reference comment. 6098 while (true) { 6099 const kind = triviaScanner.scan(); 6100 if (kind !== SyntaxKind.SingleLineCommentTrivia) { 6101 if (isTrivia(kind)) { 6102 continue; 6103 } 6104 else { 6105 break; 6106 } 6107 } 6108 6109 const range = { 6110 kind: <SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia>triviaScanner.getToken(), 6111 pos: triviaScanner.getTokenPos(), 6112 end: triviaScanner.getTextPos(), 6113 }; 6114 6115 const comment = sourceText.substring(range.pos, range.end); 6116 const referencePathMatchResult = getFileReferenceFromReferencePath(comment, range); 6117 if (referencePathMatchResult) { 6118 const fileReference = referencePathMatchResult.fileReference; 6119 sourceFile.hasNoDefaultLib = referencePathMatchResult.isNoDefaultLib; 6120 const diagnosticMessage = referencePathMatchResult.diagnosticMessage; 6121 if (fileReference) { 6122 if (referencePathMatchResult.isTypeReferenceDirective) { 6123 typeReferenceDirectives.push(fileReference); 6124 } 6125 else { 6126 referencedFiles.push(fileReference); 6127 } 6128 } 6129 if (diagnosticMessage) { 6130 parseDiagnostics.push(createFileDiagnostic(sourceFile, range.pos, range.end - range.pos, diagnosticMessage)); 6131 } 6132 } 6133 else { 6134 const amdModuleNameRegEx = /^\/\/\/\s*<amd-module\s+name\s*=\s*('|")(.+?)\1/gim; 6135 const amdModuleNameMatchResult = amdModuleNameRegEx.exec(comment); 6136 if (amdModuleNameMatchResult) { 6137 if (amdModuleName) { 6138 parseDiagnostics.push(createFileDiagnostic(sourceFile, range.pos, range.end - range.pos, Diagnostics.An_AMD_module_cannot_have_multiple_name_assignments)); 6139 } 6140 amdModuleName = amdModuleNameMatchResult[2]; 6141 } 6142 6143 const amdDependencyRegEx = /^\/\/\/\s*<amd-dependency\s/gim; 6144 const pathRegex = /\spath\s*=\s*('|")(.+?)\1/gim; 6145 const nameRegex = /\sname\s*=\s*('|")(.+?)\1/gim; 6146 const amdDependencyMatchResult = amdDependencyRegEx.exec(comment); 6147 if (amdDependencyMatchResult) { 6148 const pathMatchResult = pathRegex.exec(comment); 6149 const nameMatchResult = nameRegex.exec(comment); 6150 if (pathMatchResult) { 6151 const amdDependency = { path: pathMatchResult[2], name: nameMatchResult ? nameMatchResult[2] : undefined }; 6152 amdDependencies.push(amdDependency); 6153 } 6154 } 6155 6156 const checkJsDirectiveRegEx = /^\/\/\/?\s*(@ts-check|@ts-nocheck)\s*$/gim; 6157 const checkJsDirectiveMatchResult = checkJsDirectiveRegEx.exec(comment); 6158 if (checkJsDirectiveMatchResult) { 6159 checkJsDirective = { 6160 enabled: equateStringsCaseInsensitive(checkJsDirectiveMatchResult[1], "@ts-check"), 6161 end: range.end, 6162 pos: range.pos 6163 }; 6164 } 6165 } 6166 } 6167 6168 sourceFile.referencedFiles = referencedFiles; 6169 sourceFile.typeReferenceDirectives = typeReferenceDirectives; 6170 sourceFile.amdDependencies = amdDependencies; 6171 sourceFile.moduleName = amdModuleName; 6172 sourceFile.checkJsDirective = checkJsDirective; 6173 } 6174 6175 function setExternalModuleIndicator(sourceFile: SourceFile) { 6176 sourceFile.externalModuleIndicator = forEach(sourceFile.statements, node => 6177 hasModifier(node, ModifierFlags.Export) 6178 || node.kind === SyntaxKind.ImportEqualsDeclaration && (<ImportEqualsDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference 6179 || node.kind === SyntaxKind.ImportDeclaration 6180 || node.kind === SyntaxKind.ExportAssignment 6181 || node.kind === SyntaxKind.ExportDeclaration 6182 ? node 6183 : undefined); 6184 } 6185 6186 const enum ParsingContext { 6187 SourceElements, // Elements in source file 6188 BlockStatements, // Statements in block 6189 SwitchClauses, // Clauses in switch statement 6190 SwitchClauseStatements, // Statements in switch clause 6191 TypeMembers, // Members in interface or type literal 6192 ClassMembers, // Members in class declaration 6193 EnumMembers, // Members in enum declaration 6194 HeritageClauseElement, // Elements in a heritage clause 6195 VariableDeclarations, // Variable declarations in variable statement 6196 ObjectBindingElements, // Binding elements in object binding list 6197 ArrayBindingElements, // Binding elements in array binding list 6198 ArgumentExpressions, // Expressions in argument list 6199 ObjectLiteralMembers, // Members in object literal 6200 JsxAttributes, // Attributes in jsx element 6201 JsxChildren, // Things between opening and closing JSX tags 6202 ArrayLiteralMembers, // Members in array literal 6203 Parameters, // Parameters in parameter list 6204 RestProperties, // Property names in a rest type list 6205 TypeParameters, // Type parameters in type parameter list 6206 TypeArguments, // Type arguments in type argument list 6207 TupleElementTypes, // Element types in tuple element type list 6208 HeritageClauses, // Heritage clauses for a class or interface declaration. 6209 ImportOrExportSpecifiers, // Named import clause's import specifier list 6210 Count // Number of parsing contexts 6211 } 6212 6213 const enum Tristate { 6214 False, 6215 True, 6216 Unknown 6217 } 6218 6219 export namespace JSDocParser { 6220 export function parseJSDocTypeExpressionForTests(content: string, start: number, length: number): { jsDocTypeExpression: JSDocTypeExpression, diagnostics: Diagnostic[] } | undefined { 6221 initializeState(content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS); 6222 sourceFile = createSourceFile("file.js", ScriptTarget.Latest, ScriptKind.JS, /*isDeclarationFile*/ false); 6223 scanner.setText(content, start, length); 6224 currentToken = scanner.scan(); 6225 const jsDocTypeExpression = parseJSDocTypeExpression(); 6226 const diagnostics = parseDiagnostics; 6227 clearState(); 6228 6229 return jsDocTypeExpression ? { jsDocTypeExpression, diagnostics } : undefined; 6230 } 6231 6232 // Parses out a JSDoc type expression. 6233 export function parseJSDocTypeExpression(mayOmitBraces?: boolean): JSDocTypeExpression { 6234 const result = <JSDocTypeExpression>createNode(SyntaxKind.JSDocTypeExpression, scanner.getTokenPos()); 6235 6236 const hasBrace = (mayOmitBraces ? parseOptional : parseExpected)(SyntaxKind.OpenBraceToken); 6237 result.type = doInsideOfContext(NodeFlags.JSDoc, parseType); 6238 if (!mayOmitBraces || hasBrace) { 6239 parseExpected(SyntaxKind.CloseBraceToken); 6240 } 6241 6242 fixupParentReferences(result); 6243 return finishNode(result); 6244 } 6245 6246 export function parseIsolatedJSDocComment(content: string, start: number, length: number): { jsDoc: JSDoc, diagnostics: Diagnostic[] } | undefined { 6247 initializeState(content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS); 6248 sourceFile = <SourceFile>{ languageVariant: LanguageVariant.Standard, text: content }; // tslint:disable-line no-object-literal-type-assertion 6249 const jsDoc = parseJSDocCommentWorker(start, length); 6250 const diagnostics = parseDiagnostics; 6251 clearState(); 6252 6253 return jsDoc ? { jsDoc, diagnostics } : undefined; 6254 } 6255 6256 export function parseJSDocComment(parent: HasJSDoc, start: number, length: number): JSDoc { 6257 const saveToken = currentToken; 6258 const saveParseDiagnosticsLength = parseDiagnostics.length; 6259 const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode; 6260 6261 const comment = parseJSDocCommentWorker(start, length); 6262 if (comment) { 6263 comment.parent = parent; 6264 } 6265 6266 if (contextFlags & NodeFlags.JavaScriptFile) { 6267 if (!sourceFile.jsDocDiagnostics) { 6268 sourceFile.jsDocDiagnostics = []; 6269 } 6270 sourceFile.jsDocDiagnostics.push(...parseDiagnostics); 6271 } 6272 currentToken = saveToken; 6273 parseDiagnostics.length = saveParseDiagnosticsLength; 6274 parseErrorBeforeNextFinishedNode = saveParseErrorBeforeNextFinishedNode; 6275 6276 return comment; 6277 } 6278 6279 const enum JSDocState { 6280 BeginningOfLine, 6281 SawAsterisk, 6282 SavingComments, 6283 } 6284 6285 const enum PropertyLikeParse { 6286 Property, 6287 Parameter, 6288 } 6289 6290 export function parseJSDocCommentWorker(start: number, length: number): JSDoc { 6291 const content = sourceText; 6292 start = start || 0; 6293 const end = length === undefined ? content.length : start + length; 6294 length = end - start; 6295 6296 Debug.assert(start >= 0); 6297 Debug.assert(start <= end); 6298 Debug.assert(end <= content.length); 6299 6300 let tags: JSDocTag[]; 6301 let tagsPos: number; 6302 let tagsEnd: number; 6303 const comments: string[] = []; 6304 let result: JSDoc; 6305 6306 // Check for /** (JSDoc opening part) 6307 if (!isJsDocStart(content, start)) { 6308 return result; 6309 } 6310 6311 // + 3 for leading /**, - 5 in total for /** */ 6312 scanner.scanRange(start + 3, length - 5, () => { 6313 // Initially we can parse out a tag. We also have seen a starting asterisk. 6314 // This is so that /** * @type */ doesn't parse. 6315 let state = JSDocState.SawAsterisk; 6316 let margin: number | undefined = undefined; 6317 // + 4 for leading '/** ' 6318 let indent = start - Math.max(content.lastIndexOf("\n", start), 0) + 4; 6319 function pushComment(text: string) { 6320 if (!margin) { 6321 margin = indent; 6322 } 6323 comments.push(text); 6324 indent += text.length; 6325 } 6326 6327 let t = nextJSDocToken(); 6328 while (t === SyntaxKind.WhitespaceTrivia) { 6329 t = nextJSDocToken(); 6330 } 6331 if (t === SyntaxKind.NewLineTrivia) { 6332 state = JSDocState.BeginningOfLine; 6333 indent = 0; 6334 t = nextJSDocToken(); 6335 } 6336 loop: while (true) { 6337 switch (t) { 6338 case SyntaxKind.AtToken: 6339 if (state === JSDocState.BeginningOfLine || state === JSDocState.SawAsterisk) { 6340 removeTrailingNewlines(comments); 6341 parseTag(indent); 6342 // NOTE: According to usejsdoc.org, a tag goes to end of line, except the last tag. 6343 // Real-world comments may break this rule, so "BeginningOfLine" will not be a real line beginning 6344 // for malformed examples like `/** @param {string} x @returns {number} the length */` 6345 state = JSDocState.BeginningOfLine; 6346 margin = undefined; 6347 indent++; 6348 } 6349 else { 6350 pushComment(scanner.getTokenText()); 6351 } 6352 break; 6353 case SyntaxKind.NewLineTrivia: 6354 comments.push(scanner.getTokenText()); 6355 state = JSDocState.BeginningOfLine; 6356 indent = 0; 6357 break; 6358 case SyntaxKind.AsteriskToken: 6359 const asterisk = scanner.getTokenText(); 6360 if (state === JSDocState.SawAsterisk || state === JSDocState.SavingComments) { 6361 // If we've already seen an asterisk, then we can no longer parse a tag on this line 6362 state = JSDocState.SavingComments; 6363 pushComment(asterisk); 6364 } 6365 else { 6366 // Ignore the first asterisk on a line 6367 state = JSDocState.SawAsterisk; 6368 indent += asterisk.length; 6369 } 6370 break; 6371 case SyntaxKind.Identifier: 6372 // Anything else is doc comment text. We just save it. Because it 6373 // wasn't a tag, we can no longer parse a tag on this line until we hit the next 6374 // line break. 6375 pushComment(scanner.getTokenText()); 6376 state = JSDocState.SavingComments; 6377 break; 6378 case SyntaxKind.WhitespaceTrivia: 6379 // only collect whitespace if we're already saving comments or have just crossed the comment indent margin 6380 const whitespace = scanner.getTokenText(); 6381 if (state === JSDocState.SavingComments) { 6382 comments.push(whitespace); 6383 } 6384 else if (margin !== undefined && indent + whitespace.length > margin) { 6385 comments.push(whitespace.slice(margin - indent - 1)); 6386 } 6387 indent += whitespace.length; 6388 break; 6389 case SyntaxKind.EndOfFileToken: 6390 break loop; 6391 default: 6392 // anything other than whitespace or asterisk at the beginning of the line starts the comment text 6393 state = JSDocState.SavingComments; 6394 pushComment(scanner.getTokenText()); 6395 break; 6396 } 6397 t = nextJSDocToken(); 6398 } 6399 removeLeadingNewlines(comments); 6400 removeTrailingNewlines(comments); 6401 result = createJSDocComment(); 6402 6403 }); 6404 6405 return result; 6406 6407 function removeLeadingNewlines(comments: string[]) { 6408 while (comments.length && (comments[0] === "\n" || comments[0] === "\r")) { 6409 comments.shift(); 6410 } 6411 } 6412 6413 function removeTrailingNewlines(comments: string[]) { 6414 while (comments.length && (comments[comments.length - 1] === "\n" || comments[comments.length - 1] === "\r")) { 6415 comments.pop(); 6416 } 6417 } 6418 6419 function isJsDocStart(content: string, start: number) { 6420 return content.charCodeAt(start) === CharacterCodes.slash && 6421 content.charCodeAt(start + 1) === CharacterCodes.asterisk && 6422 content.charCodeAt(start + 2) === CharacterCodes.asterisk && 6423 content.charCodeAt(start + 3) !== CharacterCodes.asterisk; 6424 } 6425 6426 function createJSDocComment(): JSDoc { 6427 const result = <JSDoc>createNode(SyntaxKind.JSDocComment, start); 6428 result.tags = tags && createNodeArray(tags, tagsPos, tagsEnd); 6429 result.comment = comments.length ? comments.join("") : undefined; 6430 return finishNode(result, end); 6431 } 6432 6433 function skipWhitespace(): void { 6434 while (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) { 6435 nextJSDocToken(); 6436 } 6437 } 6438 6439 function parseTag(indent: number) { 6440 Debug.assert(token() === SyntaxKind.AtToken); 6441 const atToken = <AtToken>createNode(SyntaxKind.AtToken, scanner.getTokenPos()); 6442 atToken.end = scanner.getTextPos(); 6443 nextJSDocToken(); 6444 6445 const tagName = parseJSDocIdentifierName(); 6446 skipWhitespace(); 6447 if (!tagName) { 6448 return; 6449 } 6450 6451 let tag: JSDocTag; 6452 if (tagName) { 6453 switch (tagName.escapedText) { 6454 case "augments": 6455 case "extends": 6456 tag = parseAugmentsTag(atToken, tagName); 6457 break; 6458 case "class": 6459 case "constructor": 6460 tag = parseClassTag(atToken, tagName); 6461 break; 6462 case "arg": 6463 case "argument": 6464 case "param": 6465 tag = parseParameterOrPropertyTag(atToken, tagName, PropertyLikeParse.Parameter); 6466 break; 6467 case "return": 6468 case "returns": 6469 tag = parseReturnTag(atToken, tagName); 6470 break; 6471 case "template": 6472 tag = parseTemplateTag(atToken, tagName); 6473 break; 6474 case "type": 6475 tag = parseTypeTag(atToken, tagName); 6476 break; 6477 case "typedef": 6478 tag = parseTypedefTag(atToken, tagName); 6479 break; 6480 default: 6481 tag = parseUnknownTag(atToken, tagName); 6482 break; 6483 } 6484 } 6485 else { 6486 tag = parseUnknownTag(atToken, tagName); 6487 } 6488 6489 if (!tag) { 6490 // a badly malformed tag should not be added to the list of tags 6491 return; 6492 } 6493 tag.comment = parseTagComments(indent + tag.end - tag.pos); 6494 addTag(tag); 6495 } 6496 6497 function parseTagComments(indent: number): string | undefined { 6498 const comments: string[] = []; 6499 let state = JSDocState.BeginningOfLine; 6500 let margin: number | undefined; 6501 function pushComment(text: string) { 6502 if (!margin) { 6503 margin = indent; 6504 } 6505 comments.push(text); 6506 indent += text.length; 6507 } 6508 let tok = token() as JsDocSyntaxKind; 6509 loop: while (true) { 6510 switch (tok) { 6511 case SyntaxKind.NewLineTrivia: 6512 if (state >= JSDocState.SawAsterisk) { 6513 state = JSDocState.BeginningOfLine; 6514 comments.push(scanner.getTokenText()); 6515 } 6516 indent = 0; 6517 break; 6518 case SyntaxKind.AtToken: 6519 scanner.setTextPos(scanner.getTextPos() - 1); 6520 // falls through 6521 case SyntaxKind.EndOfFileToken: 6522 // Done 6523 break loop; 6524 case SyntaxKind.WhitespaceTrivia: 6525 if (state === JSDocState.SavingComments) { 6526 pushComment(scanner.getTokenText()); 6527 } 6528 else { 6529 const whitespace = scanner.getTokenText(); 6530 // if the whitespace crosses the margin, take only the whitespace that passes the margin 6531 if (margin !== undefined && indent + whitespace.length > margin) { 6532 comments.push(whitespace.slice(margin - indent - 1)); 6533 } 6534 indent += whitespace.length; 6535 } 6536 break; 6537 case SyntaxKind.AsteriskToken: 6538 if (state === JSDocState.BeginningOfLine) { 6539 // leading asterisks start recording on the *next* (non-whitespace) token 6540 state = JSDocState.SawAsterisk; 6541 indent += 1; 6542 break; 6543 } 6544 // record the * as a comment 6545 // falls through 6546 default: 6547 state = JSDocState.SavingComments; // leading identifiers start recording as well 6548 pushComment(scanner.getTokenText()); 6549 break; 6550 } 6551 tok = nextJSDocToken(); 6552 } 6553 6554 removeLeadingNewlines(comments); 6555 removeTrailingNewlines(comments); 6556 return comments.length === 0 ? undefined : comments.join(""); 6557 } 6558 6559 function parseUnknownTag(atToken: AtToken, tagName: Identifier) { 6560 const result = <JSDocTag>createNode(SyntaxKind.JSDocTag, atToken.pos); 6561 result.atToken = atToken; 6562 result.tagName = tagName; 6563 return finishNode(result); 6564 } 6565 6566 function addTag(tag: JSDocTag): void { 6567 if (!tags) { 6568 tags = [tag]; 6569 tagsPos = tag.pos; 6570 } 6571 else { 6572 tags.push(tag); 6573 } 6574 tagsEnd = tag.end; 6575 } 6576 6577 function tryParseTypeExpression(): JSDocTypeExpression | undefined { 6578 skipWhitespace(); 6579 return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined; 6580 } 6581 6582 function parseBracketNameInPropertyAndParamTag(): { name: EntityName, isBracketed: boolean } { 6583 // Looking for something like '[foo]', 'foo', '[foo.bar]' or 'foo.bar' 6584 const isBracketed = parseOptional(SyntaxKind.OpenBracketToken); 6585 const name = parseJSDocEntityName(); 6586 if (isBracketed) { 6587 skipWhitespace(); 6588 6589 // May have an optional default, e.g. '[foo = 42]' 6590 if (parseOptionalToken(SyntaxKind.EqualsToken)) { 6591 parseExpression(); 6592 } 6593 6594 parseExpected(SyntaxKind.CloseBracketToken); 6595 } 6596 6597 return { name, isBracketed }; 6598 } 6599 6600 function isObjectOrObjectArrayTypeReference(node: TypeNode): boolean { 6601 switch (node.kind) { 6602 case SyntaxKind.ObjectKeyword: 6603 return true; 6604 case SyntaxKind.ArrayType: 6605 return isObjectOrObjectArrayTypeReference((node as ArrayTypeNode).elementType); 6606 default: 6607 return isTypeReferenceNode(node) && ts.isIdentifier(node.typeName) && node.typeName.escapedText === "Object"; 6608 } 6609 } 6610 6611 function parseParameterOrPropertyTag(atToken: AtToken, tagName: Identifier, target: PropertyLikeParse): JSDocParameterTag | JSDocPropertyTag { 6612 let typeExpression = tryParseTypeExpression(); 6613 let isNameFirst = !typeExpression; 6614 skipWhitespace(); 6615 6616 const { name, isBracketed } = parseBracketNameInPropertyAndParamTag(); 6617 skipWhitespace(); 6618 6619 if (isNameFirst) { 6620 typeExpression = tryParseTypeExpression(); 6621 } 6622 6623 const result = target === PropertyLikeParse.Parameter ? 6624 <JSDocParameterTag>createNode(SyntaxKind.JSDocParameterTag, atToken.pos) : 6625 <JSDocPropertyTag>createNode(SyntaxKind.JSDocPropertyTag, atToken.pos); 6626 const nestedTypeLiteral = parseNestedTypeLiteral(typeExpression, name); 6627 if (nestedTypeLiteral) { 6628 typeExpression = nestedTypeLiteral; 6629 isNameFirst = true; 6630 } 6631 result.atToken = atToken; 6632 result.tagName = tagName; 6633 result.typeExpression = typeExpression; 6634 result.name = name; 6635 result.isNameFirst = isNameFirst; 6636 result.isBracketed = isBracketed; 6637 return finishNode(result); 6638 } 6639 6640 function parseNestedTypeLiteral(typeExpression: JSDocTypeExpression, name: EntityName) { 6641 if (typeExpression && isObjectOrObjectArrayTypeReference(typeExpression.type)) { 6642 const typeLiteralExpression = <JSDocTypeExpression>createNode(SyntaxKind.JSDocTypeExpression, scanner.getTokenPos()); 6643 let child: JSDocParameterTag | false; 6644 let jsdocTypeLiteral: JSDocTypeLiteral; 6645 const start = scanner.getStartPos(); 6646 let children: JSDocParameterTag[]; 6647 while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.Parameter, name))) { 6648 children = append(children, child); 6649 } 6650 if (children) { 6651 jsdocTypeLiteral = <JSDocTypeLiteral>createNode(SyntaxKind.JSDocTypeLiteral, start); 6652 jsdocTypeLiteral.jsDocPropertyTags = children; 6653 if (typeExpression.type.kind === SyntaxKind.ArrayType) { 6654 jsdocTypeLiteral.isArrayType = true; 6655 } 6656 typeLiteralExpression.type = finishNode(jsdocTypeLiteral); 6657 return finishNode(typeLiteralExpression); 6658 } 6659 } 6660 } 6661 6662 function parseReturnTag(atToken: AtToken, tagName: Identifier): JSDocReturnTag { 6663 if (forEach(tags, t => t.kind === SyntaxKind.JSDocReturnTag)) { 6664 parseErrorAtPosition(tagName.pos, scanner.getTokenPos() - tagName.pos, Diagnostics._0_tag_already_specified, tagName.escapedText); 6665 } 6666 6667 const result = <JSDocReturnTag>createNode(SyntaxKind.JSDocReturnTag, atToken.pos); 6668 result.atToken = atToken; 6669 result.tagName = tagName; 6670 result.typeExpression = tryParseTypeExpression(); 6671 return finishNode(result); 6672 } 6673 6674 function parseTypeTag(atToken: AtToken, tagName: Identifier): JSDocTypeTag { 6675 if (forEach(tags, t => t.kind === SyntaxKind.JSDocTypeTag)) { 6676 parseErrorAtPosition(tagName.pos, scanner.getTokenPos() - tagName.pos, Diagnostics._0_tag_already_specified, tagName.escapedText); 6677 } 6678 6679 const result = <JSDocTypeTag>createNode(SyntaxKind.JSDocTypeTag, atToken.pos); 6680 result.atToken = atToken; 6681 result.tagName = tagName; 6682 result.typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); 6683 return finishNode(result); 6684 } 6685 6686 function parseAugmentsTag(atToken: AtToken, tagName: Identifier): JSDocAugmentsTag { 6687 const result = <JSDocAugmentsTag>createNode(SyntaxKind.JSDocAugmentsTag, atToken.pos); 6688 result.atToken = atToken; 6689 result.tagName = tagName; 6690 result.class = parseExpressionWithTypeArgumentsForAugments(); 6691 return finishNode(result); 6692 } 6693 6694 function parseExpressionWithTypeArgumentsForAugments(): ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression } { 6695 const usedBrace = parseOptional(SyntaxKind.OpenBraceToken); 6696 const node = createNode(SyntaxKind.ExpressionWithTypeArguments) as ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression }; 6697 node.expression = parsePropertyAccessEntityNameExpression(); 6698 node.typeArguments = tryParseTypeArguments(); 6699 const res = finishNode(node); 6700 if (usedBrace) { 6701 parseExpected(SyntaxKind.CloseBraceToken); 6702 } 6703 return res; 6704 } 6705 6706 function parsePropertyAccessEntityNameExpression() { 6707 let node: Identifier | PropertyAccessEntityNameExpression = parseJSDocIdentifierName(/*createIfMissing*/ true); 6708 while (parseOptional(SyntaxKind.DotToken)) { 6709 const prop: PropertyAccessEntityNameExpression = createNode(SyntaxKind.PropertyAccessExpression, node.pos) as PropertyAccessEntityNameExpression; 6710 prop.expression = node; 6711 prop.name = parseJSDocIdentifierName(); 6712 node = finishNode(prop); 6713 } 6714 return node; 6715 } 6716 6717 function parseClassTag(atToken: AtToken, tagName: Identifier): JSDocClassTag { 6718 const tag = <JSDocClassTag>createNode(SyntaxKind.JSDocClassTag, atToken.pos); 6719 tag.atToken = atToken; 6720 tag.tagName = tagName; 6721 return finishNode(tag); 6722 } 6723 6724 function parseTypedefTag(atToken: AtToken, tagName: Identifier): JSDocTypedefTag { 6725 const typeExpression = tryParseTypeExpression(); 6726 skipWhitespace(); 6727 6728 const typedefTag = <JSDocTypedefTag>createNode(SyntaxKind.JSDocTypedefTag, atToken.pos); 6729 typedefTag.atToken = atToken; 6730 typedefTag.tagName = tagName; 6731 typedefTag.fullName = parseJSDocTypeNameWithNamespace(/*flags*/ 0); 6732 if (typedefTag.fullName) { 6733 let rightNode = typedefTag.fullName; 6734 while (true) { 6735 if (rightNode.kind === SyntaxKind.Identifier || !rightNode.body) { 6736 // if node is identifier - use it as name 6737 // otherwise use name of the rightmost part that we were able to parse 6738 typedefTag.name = rightNode.kind === SyntaxKind.Identifier ? rightNode : rightNode.name; 6739 break; 6740 } 6741 rightNode = rightNode.body; 6742 } 6743 } 6744 skipWhitespace(); 6745 6746 typedefTag.typeExpression = typeExpression; 6747 if (!typeExpression || isObjectOrObjectArrayTypeReference(typeExpression.type)) { 6748 let child: JSDocTypeTag | JSDocPropertyTag | false; 6749 let jsdocTypeLiteral: JSDocTypeLiteral; 6750 let childTypeTag: JSDocTypeTag; 6751 const start = scanner.getStartPos(); 6752 while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.Property))) { 6753 if (!jsdocTypeLiteral) { 6754 jsdocTypeLiteral = <JSDocTypeLiteral>createNode(SyntaxKind.JSDocTypeLiteral, start); 6755 } 6756 if (child.kind === SyntaxKind.JSDocTypeTag) { 6757 if (childTypeTag) { 6758 break; 6759 } 6760 else { 6761 childTypeTag = child; 6762 } 6763 } 6764 else { 6765 jsdocTypeLiteral.jsDocPropertyTags = append(jsdocTypeLiteral.jsDocPropertyTags as MutableNodeArray<JSDocPropertyTag>, child); 6766 } 6767 } 6768 if (jsdocTypeLiteral) { 6769 if (typeExpression && typeExpression.type.kind === SyntaxKind.ArrayType) { 6770 jsdocTypeLiteral.isArrayType = true; 6771 } 6772 typedefTag.typeExpression = childTypeTag && childTypeTag.typeExpression && !isObjectOrObjectArrayTypeReference(childTypeTag.typeExpression.type) ? 6773 childTypeTag.typeExpression : 6774 finishNode(jsdocTypeLiteral); 6775 } 6776 } 6777 6778 return finishNode(typedefTag); 6779 6780 function parseJSDocTypeNameWithNamespace(flags: NodeFlags) { 6781 const pos = scanner.getTokenPos(); 6782 const typeNameOrNamespaceName = parseJSDocIdentifierName(); 6783 6784 if (typeNameOrNamespaceName && parseOptional(SyntaxKind.DotToken)) { 6785 const jsDocNamespaceNode = <JSDocNamespaceDeclaration>createNode(SyntaxKind.ModuleDeclaration, pos); 6786 jsDocNamespaceNode.flags |= flags; 6787 jsDocNamespaceNode.name = typeNameOrNamespaceName; 6788 jsDocNamespaceNode.body = parseJSDocTypeNameWithNamespace(NodeFlags.NestedNamespace); 6789 return finishNode(jsDocNamespaceNode); 6790 } 6791 6792 if (typeNameOrNamespaceName && flags & NodeFlags.NestedNamespace) { 6793 typeNameOrNamespaceName.isInJSDocNamespace = true; 6794 } 6795 return typeNameOrNamespaceName; 6796 } 6797 } 6798 6799 function escapedTextsEqual(a: EntityName, b: EntityName): boolean { 6800 while (!ts.isIdentifier(a) || !ts.isIdentifier(b)) { 6801 if (!ts.isIdentifier(a) && !ts.isIdentifier(b) && a.right.escapedText === b.right.escapedText) { 6802 a = a.left; 6803 b = b.left; 6804 } 6805 else { 6806 return false; 6807 } 6808 } 6809 return a.escapedText === b.escapedText; 6810 } 6811 6812 function parseChildParameterOrPropertyTag(target: PropertyLikeParse.Property): JSDocTypeTag | JSDocPropertyTag | false; 6813 function parseChildParameterOrPropertyTag(target: PropertyLikeParse.Parameter, name: EntityName): JSDocParameterTag | false; 6814 function parseChildParameterOrPropertyTag(target: PropertyLikeParse, name?: EntityName): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false { 6815 let canParseTag = true; 6816 let seenAsterisk = false; 6817 while (true) { 6818 switch (nextJSDocToken()) { 6819 case SyntaxKind.AtToken: 6820 if (canParseTag) { 6821 const child = tryParseChildTag(target); 6822 if (child && child.kind === SyntaxKind.JSDocParameterTag && 6823 (ts.isIdentifier(child.name) || !escapedTextsEqual(name, child.name.left))) { 6824 return false; 6825 } 6826 return child; 6827 } 6828 seenAsterisk = false; 6829 break; 6830 case SyntaxKind.NewLineTrivia: 6831 canParseTag = true; 6832 seenAsterisk = false; 6833 break; 6834 case SyntaxKind.AsteriskToken: 6835 if (seenAsterisk) { 6836 canParseTag = false; 6837 } 6838 seenAsterisk = true; 6839 break; 6840 case SyntaxKind.Identifier: 6841 canParseTag = false; 6842 break; 6843 case SyntaxKind.EndOfFileToken: 6844 return false; 6845 } 6846 } 6847 } 6848 6849 function tryParseChildTag(target: PropertyLikeParse): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false { 6850 Debug.assert(token() === SyntaxKind.AtToken); 6851 const atToken = <AtToken>createNode(SyntaxKind.AtToken); 6852 atToken.end = scanner.getTextPos(); 6853 nextJSDocToken(); 6854 6855 const tagName = parseJSDocIdentifierName(); 6856 skipWhitespace(); 6857 if (!tagName) { 6858 return false; 6859 } 6860 let t: PropertyLikeParse; 6861 switch (tagName.escapedText) { 6862 case "type": 6863 return target === PropertyLikeParse.Property && parseTypeTag(atToken, tagName); 6864 case "prop": 6865 case "property": 6866 t = PropertyLikeParse.Property; 6867 break; 6868 case "arg": 6869 case "argument": 6870 case "param": 6871 t = PropertyLikeParse.Parameter; 6872 break; 6873 default: 6874 return false; 6875 } 6876 if (target !== t) { 6877 return false; 6878 } 6879 const tag = parseParameterOrPropertyTag(atToken, tagName, target); 6880 tag.comment = parseTagComments(tag.end - tag.pos); 6881 return tag; 6882 } 6883 6884 function parseTemplateTag(atToken: AtToken, tagName: Identifier): JSDocTemplateTag | undefined { 6885 if (some(tags, isJSDocTemplateTag)) { 6886 parseErrorAtPosition(tagName.pos, scanner.getTokenPos() - tagName.pos, Diagnostics._0_tag_already_specified, tagName.escapedText); 6887 } 6888 6889 // Type parameter list looks like '@template T,U,V' 6890 const typeParameters = []; 6891 const typeParametersPos = getNodePos(); 6892 6893 while (true) { 6894 const typeParameter = <TypeParameterDeclaration>createNode(SyntaxKind.TypeParameter); 6895 const name = parseJSDocIdentifierNameWithOptionalBraces(); 6896 skipWhitespace(); 6897 if (!name) { 6898 parseErrorAtPosition(scanner.getStartPos(), 0, Diagnostics.Identifier_expected); 6899 return undefined; 6900 } 6901 6902 typeParameter.name = name; 6903 finishNode(typeParameter); 6904 6905 typeParameters.push(typeParameter); 6906 6907 if (token() === SyntaxKind.CommaToken) { 6908 nextJSDocToken(); 6909 skipWhitespace(); 6910 } 6911 else { 6912 break; 6913 } 6914 } 6915 6916 const result = <JSDocTemplateTag>createNode(SyntaxKind.JSDocTemplateTag, atToken.pos); 6917 result.atToken = atToken; 6918 result.tagName = tagName; 6919 result.typeParameters = createNodeArray(typeParameters, typeParametersPos); 6920 finishNode(result); 6921 return result; 6922 } 6923 6924 function parseJSDocIdentifierNameWithOptionalBraces(): Identifier | undefined { 6925 const parsedBrace = parseOptional(SyntaxKind.OpenBraceToken); 6926 const res = parseJSDocIdentifierName(); 6927 if (parsedBrace) { 6928 parseExpected(SyntaxKind.CloseBraceToken); 6929 } 6930 return res; 6931 } 6932 6933 function nextJSDocToken(): JsDocSyntaxKind { 6934 return currentToken = scanner.scanJSDocToken(); 6935 } 6936 6937 function parseJSDocEntityName(): EntityName { 6938 let entity: EntityName = parseJSDocIdentifierName(/*createIfMissing*/ true); 6939 if (parseOptional(SyntaxKind.OpenBracketToken)) { 6940 parseExpected(SyntaxKind.CloseBracketToken); 6941 // Note that y[] is accepted as an entity name, but the postfix brackets are not saved for checking. 6942 // Technically usejsdoc.org requires them for specifying a property of a type equivalent to Array<{ x: ...}> 6943 // but it's not worth it to enforce that restriction. 6944 } 6945 while (parseOptional(SyntaxKind.DotToken)) { 6946 const name = parseJSDocIdentifierName(/*createIfMissing*/ true); 6947 if (parseOptional(SyntaxKind.OpenBracketToken)) { 6948 parseExpected(SyntaxKind.CloseBracketToken); 6949 } 6950 entity = createQualifiedName(entity, name); 6951 } 6952 return entity; 6953 } 6954 6955 function parseJSDocIdentifierName(): Identifier | undefined; 6956 function parseJSDocIdentifierName(createIfMissing: true): Identifier; 6957 function parseJSDocIdentifierName(createIfMissing = false): Identifier | undefined { 6958 if (!tokenIsIdentifierOrKeyword(token())) { 6959 if (createIfMissing) { 6960 return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected); 6961 } 6962 else { 6963 parseErrorAtCurrentToken(Diagnostics.Identifier_expected); 6964 return undefined; 6965 } 6966 } 6967 6968 const pos = scanner.getTokenPos(); 6969 const end = scanner.getTextPos(); 6970 const result = <Identifier>createNode(SyntaxKind.Identifier, pos); 6971 result.escapedText = escapeLeadingUnderscores(content.substring(pos, end)); 6972 finishNode(result, end); 6973 6974 nextJSDocToken(); 6975 return result; 6976 } 6977 } 6978 } 6979 } 6980 6981 namespace IncrementalParser { 6982 export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean): SourceFile { 6983 aggressiveChecks = aggressiveChecks || Debug.shouldAssert(AssertionLevel.Aggressive); 6984 6985 checkChangeRange(sourceFile, newText, textChangeRange, aggressiveChecks); 6986 if (textChangeRangeIsUnchanged(textChangeRange)) { 6987 // if the text didn't change, then we can just return our current source file as-is. 6988 return sourceFile; 6989 } 6990 6991 if (sourceFile.statements.length === 0) { 6992 // If we don't have any statements in the current source file, then there's no real 6993 // way to incrementally parse. So just do a full parse instead. 6994 return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setParentNodes*/ true, sourceFile.scriptKind); 6995 } 6996 6997 // Make sure we're not trying to incrementally update a source file more than once. Once 6998 // we do an update the original source file is considered unusable from that point onwards. 6999 // 7000 // This is because we do incremental parsing in-place. i.e. we take nodes from the old 7001 // tree and give them new positions and parents. From that point on, trusting the old 7002 // tree at all is not possible as far too much of it may violate invariants. 7003 const incrementalSourceFile = <IncrementalNode><Node>sourceFile; 7004 Debug.assert(!incrementalSourceFile.hasBeenIncrementallyParsed); 7005 incrementalSourceFile.hasBeenIncrementallyParsed = true; 7006 7007 const oldText = sourceFile.text; 7008 const syntaxCursor = createSyntaxCursor(sourceFile); 7009 7010 // Make the actual change larger so that we know to reparse anything whose lookahead 7011 // might have intersected the change. 7012 const changeRange = extendToAffectedRange(sourceFile, textChangeRange); 7013 checkChangeRange(sourceFile, newText, changeRange, aggressiveChecks); 7014 7015 // Ensure that extending the affected range only moved the start of the change range 7016 // earlier in the file. 7017 Debug.assert(changeRange.span.start <= textChangeRange.span.start); 7018 Debug.assert(textSpanEnd(changeRange.span) === textSpanEnd(textChangeRange.span)); 7019 Debug.assert(textSpanEnd(textChangeRangeNewSpan(changeRange)) === textSpanEnd(textChangeRangeNewSpan(textChangeRange))); 7020 7021 // The is the amount the nodes after the edit range need to be adjusted. It can be 7022 // positive (if the edit added characters), negative (if the edit deleted characters) 7023 // or zero (if this was a pure overwrite with nothing added/removed). 7024 const delta = textChangeRangeNewSpan(changeRange).length - changeRange.span.length; 7025 7026 // If we added or removed characters during the edit, then we need to go and adjust all 7027 // the nodes after the edit. Those nodes may move forward (if we inserted chars) or they 7028 // may move backward (if we deleted chars). 7029 // 7030 // Doing this helps us out in two ways. First, it means that any nodes/tokens we want 7031 // to reuse are already at the appropriate position in the new text. That way when we 7032 // reuse them, we don't have to figure out if they need to be adjusted. Second, it makes 7033 // it very easy to determine if we can reuse a node. If the node's position is at where 7034 // we are in the text, then we can reuse it. Otherwise we can't. If the node's position 7035 // is ahead of us, then we'll need to rescan tokens. If the node's position is behind 7036 // us, then we'll need to skip it or crumble it as appropriate 7037 // 7038 // We will also adjust the positions of nodes that intersect the change range as well. 7039 // By doing this, we ensure that all the positions in the old tree are consistent, not 7040 // just the positions of nodes entirely before/after the change range. By being 7041 // consistent, we can then easily map from positions to nodes in the old tree easily. 7042 // 7043 // Also, mark any syntax elements that intersect the changed span. We know, up front, 7044 // that we cannot reuse these elements. 7045 updateTokenPositionsAndMarkElements(incrementalSourceFile, 7046 changeRange.span.start, textSpanEnd(changeRange.span), textSpanEnd(textChangeRangeNewSpan(changeRange)), delta, oldText, newText, aggressiveChecks); 7047 7048 // Now that we've set up our internal incremental state just proceed and parse the 7049 // source file in the normal fashion. When possible the parser will retrieve and 7050 // reuse nodes from the old tree. 7051 // 7052 // Note: passing in 'true' for setNodeParents is very important. When incrementally 7053 // parsing, we will be reusing nodes from the old tree, and placing it into new 7054 // parents. If we don't set the parents now, we'll end up with an observably 7055 // inconsistent tree. Setting the parents on the new tree should be very fast. We 7056 // will immediately bail out of walking any subtrees when we can see that their parents 7057 // are already correct. 7058 const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /*setParentNodes*/ true, sourceFile.scriptKind); 7059 7060 return result; 7061 } 7062 7063 function moveElementEntirelyPastChangeRange(element: IncrementalElement, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) { 7064 if (isArray) { 7065 visitArray(<IncrementalNodeArray>element); 7066 } 7067 else { 7068 visitNode(<IncrementalNode>element); 7069 } 7070 return; 7071 7072 function visitNode(node: IncrementalNode) { 7073 let text = ""; 7074 if (aggressiveChecks && shouldCheckNode(node)) { 7075 text = oldText.substring(node.pos, node.end); 7076 } 7077 7078 // Ditch any existing LS children we may have created. This way we can avoid 7079 // moving them forward. 7080 if (node._children) { 7081 node._children = undefined; 7082 } 7083 7084 node.pos += delta; 7085 node.end += delta; 7086 7087 if (aggressiveChecks && shouldCheckNode(node)) { 7088 Debug.assert(text === newText.substring(node.pos, node.end)); 7089 } 7090 7091 forEachChild(node, visitNode, visitArray); 7092 if (hasJSDocNodes(node)) { 7093 for (const jsDocComment of node.jsDoc) { 7094 forEachChild(jsDocComment, visitNode, visitArray); 7095 } 7096 } 7097 checkNodePositions(node, aggressiveChecks); 7098 } 7099 7100 function visitArray(array: IncrementalNodeArray) { 7101 array._children = undefined; 7102 array.pos += delta; 7103 array.end += delta; 7104 7105 for (const node of array) { 7106 visitNode(node); 7107 } 7108 } 7109 } 7110 7111 function shouldCheckNode(node: Node) { 7112 switch (node.kind) { 7113 case SyntaxKind.StringLiteral: 7114 case SyntaxKind.NumericLiteral: 7115 case SyntaxKind.Identifier: 7116 return true; 7117 } 7118 7119 return false; 7120 } 7121 7122 function adjustIntersectingElement(element: IncrementalElement, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number) { 7123 Debug.assert(element.end >= changeStart, "Adjusting an element that was entirely before the change range"); 7124 Debug.assert(element.pos <= changeRangeOldEnd, "Adjusting an element that was entirely after the change range"); 7125 Debug.assert(element.pos <= element.end); 7126 7127 // We have an element that intersects the change range in some way. It may have its 7128 // start, or its end (or both) in the changed range. We want to adjust any part 7129 // that intersects such that the final tree is in a consistent state. i.e. all 7130 // children have spans within the span of their parent, and all siblings are ordered 7131 // properly. 7132 7133 // We may need to update both the 'pos' and the 'end' of the element. 7134 7135 // If the 'pos' is before the start of the change, then we don't need to touch it. 7136 // If it isn't, then the 'pos' must be inside the change. How we update it will 7137 // depend if delta is positive or negative. If delta is positive then we have 7138 // something like: 7139 // 7140 // -------------------AAA----------------- 7141 // -------------------BBBCCCCCCC----------------- 7142 // 7143 // In this case, we consider any node that started in the change range to still be 7144 // starting at the same position. 7145 // 7146 // however, if the delta is negative, then we instead have something like this: 7147 // 7148 // -------------------XXXYYYYYYY----------------- 7149 // -------------------ZZZ----------------- 7150 // 7151 // In this case, any element that started in the 'X' range will keep its position. 7152 // However any element that started after that will have their pos adjusted to be 7153 // at the end of the new range. i.e. any node that started in the 'Y' range will 7154 // be adjusted to have their start at the end of the 'Z' range. 7155 // 7156 // The element will keep its position if possible. Or Move backward to the new-end 7157 // if it's in the 'Y' range. 7158 element.pos = Math.min(element.pos, changeRangeNewEnd); 7159 7160 // If the 'end' is after the change range, then we always adjust it by the delta 7161 // amount. However, if the end is in the change range, then how we adjust it 7162 // will depend on if delta is positive or negative. If delta is positive then we 7163 // have something like: 7164 // 7165 // -------------------AAA----------------- 7166 // -------------------BBBCCCCCCC----------------- 7167 // 7168 // In this case, we consider any node that ended inside the change range to keep its 7169 // end position. 7170 // 7171 // however, if the delta is negative, then we instead have something like this: 7172 // 7173 // -------------------XXXYYYYYYY----------------- 7174 // -------------------ZZZ----------------- 7175 // 7176 // In this case, any element that ended in the 'X' range will keep its position. 7177 // However any element that ended after that will have their pos adjusted to be 7178 // at the end of the new range. i.e. any node that ended in the 'Y' range will 7179 // be adjusted to have their end at the end of the 'Z' range. 7180 if (element.end >= changeRangeOldEnd) { 7181 // Element ends after the change range. Always adjust the end pos. 7182 element.end += delta; 7183 } 7184 else { 7185 // Element ends in the change range. The element will keep its position if 7186 // possible. Or Move backward to the new-end if it's in the 'Y' range. 7187 element.end = Math.min(element.end, changeRangeNewEnd); 7188 } 7189 7190 Debug.assert(element.pos <= element.end); 7191 if (element.parent) { 7192 Debug.assert(element.pos >= element.parent.pos); 7193 Debug.assert(element.end <= element.parent.end); 7194 } 7195 } 7196 7197 function checkNodePositions(node: Node, aggressiveChecks: boolean) { 7198 if (aggressiveChecks) { 7199 let pos = node.pos; 7200 forEachChild(node, child => { 7201 Debug.assert(child.pos >= pos); 7202 pos = child.end; 7203 }); 7204 Debug.assert(pos <= node.end); 7205 } 7206 } 7207 7208 function updateTokenPositionsAndMarkElements( 7209 sourceFile: IncrementalNode, 7210 changeStart: number, 7211 changeRangeOldEnd: number, 7212 changeRangeNewEnd: number, 7213 delta: number, 7214 oldText: string, 7215 newText: string, 7216 aggressiveChecks: boolean): void { 7217 7218 visitNode(sourceFile); 7219 return; 7220 7221 function visitNode(child: IncrementalNode) { 7222 Debug.assert(child.pos <= child.end); 7223 if (child.pos > changeRangeOldEnd) { 7224 // Node is entirely past the change range. We need to move both its pos and 7225 // end, forward or backward appropriately. 7226 moveElementEntirelyPastChangeRange(child, /*isArray*/ false, delta, oldText, newText, aggressiveChecks); 7227 return; 7228 } 7229 7230 // Check if the element intersects the change range. If it does, then it is not 7231 // reusable. Also, we'll need to recurse to see what constituent portions we may 7232 // be able to use. 7233 const fullEnd = child.end; 7234 if (fullEnd >= changeStart) { 7235 child.intersectsChange = true; 7236 child._children = undefined; 7237 7238 // Adjust the pos or end (or both) of the intersecting element accordingly. 7239 adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); 7240 forEachChild(child, visitNode, visitArray); 7241 7242 checkNodePositions(child, aggressiveChecks); 7243 return; 7244 } 7245 7246 // Otherwise, the node is entirely before the change range. No need to do anything with it. 7247 Debug.assert(fullEnd < changeStart); 7248 } 7249 7250 function visitArray(array: IncrementalNodeArray) { 7251 Debug.assert(array.pos <= array.end); 7252 if (array.pos > changeRangeOldEnd) { 7253 // Array is entirely after the change range. We need to move it, and move any of 7254 // its children. 7255 moveElementEntirelyPastChangeRange(array, /*isArray*/ true, delta, oldText, newText, aggressiveChecks); 7256 return; 7257 } 7258 7259 // Check if the element intersects the change range. If it does, then it is not 7260 // reusable. Also, we'll need to recurse to see what constituent portions we may 7261 // be able to use. 7262 const fullEnd = array.end; 7263 if (fullEnd >= changeStart) { 7264 array.intersectsChange = true; 7265 array._children = undefined; 7266 7267 // Adjust the pos or end (or both) of the intersecting array accordingly. 7268 adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); 7269 for (const node of array) { 7270 visitNode(node); 7271 } 7272 return; 7273 } 7274 7275 // Otherwise, the array is entirely before the change range. No need to do anything with it. 7276 Debug.assert(fullEnd < changeStart); 7277 } 7278 } 7279 7280 function extendToAffectedRange(sourceFile: SourceFile, changeRange: TextChangeRange): TextChangeRange { 7281 // Consider the following code: 7282 // void foo() { /; } 7283 // 7284 // If the text changes with an insertion of / just before the semicolon then we end up with: 7285 // void foo() { //; } 7286 // 7287 // If we were to just use the changeRange a is, then we would not rescan the { token 7288 // (as it does not intersect the actual original change range). Because an edit may 7289 // change the token touching it, we actually need to look back *at least* one token so 7290 // that the prior token sees that change. 7291 const maxLookahead = 1; 7292 7293 let start = changeRange.span.start; 7294 7295 // the first iteration aligns us with the change start. subsequent iteration move us to 7296 // the left by maxLookahead tokens. We only need to do this as long as we're not at the 7297 // start of the tree. 7298 for (let i = 0; start > 0 && i <= maxLookahead; i++) { 7299 const nearestNode = findNearestNodeStartingBeforeOrAtPosition(sourceFile, start); 7300 Debug.assert(nearestNode.pos <= start); 7301 const position = nearestNode.pos; 7302 7303 start = Math.max(0, position - 1); 7304 } 7305 7306 const finalSpan = createTextSpanFromBounds(start, textSpanEnd(changeRange.span)); 7307 const finalLength = changeRange.newLength + (changeRange.span.start - start); 7308 7309 return createTextChangeRange(finalSpan, finalLength); 7310 } 7311 7312 function findNearestNodeStartingBeforeOrAtPosition(sourceFile: SourceFile, position: number): Node { 7313 let bestResult: Node = sourceFile; 7314 let lastNodeEntirelyBeforePosition: Node; 7315 7316 forEachChild(sourceFile, visit); 7317 7318 if (lastNodeEntirelyBeforePosition) { 7319 const lastChildOfLastEntireNodeBeforePosition = getLastChild(lastNodeEntirelyBeforePosition); 7320 if (lastChildOfLastEntireNodeBeforePosition.pos > bestResult.pos) { 7321 bestResult = lastChildOfLastEntireNodeBeforePosition; 7322 } 7323 } 7324 7325 return bestResult; 7326 7327 function getLastChild(node: Node): Node { 7328 while (true) { 7329 const lastChild = getLastChildWorker(node); 7330 if (lastChild) { 7331 node = lastChild; 7332 } 7333 else { 7334 return node; 7335 } 7336 } 7337 } 7338 7339 function getLastChildWorker(node: Node): Node | undefined { 7340 let last: Node = undefined; 7341 forEachChild(node, child => { 7342 if (nodeIsPresent(child)) { 7343 last = child; 7344 } 7345 }); 7346 return last; 7347 } 7348 7349 function visit(child: Node) { 7350 if (nodeIsMissing(child)) { 7351 // Missing nodes are effectively invisible to us. We never even consider them 7352 // When trying to find the nearest node before us. 7353 return; 7354 } 7355 7356 // If the child intersects this position, then this node is currently the nearest 7357 // node that starts before the position. 7358 if (child.pos <= position) { 7359 if (child.pos >= bestResult.pos) { 7360 // This node starts before the position, and is closer to the position than 7361 // the previous best node we found. It is now the new best node. 7362 bestResult = child; 7363 } 7364 7365 // Now, the node may overlap the position, or it may end entirely before the 7366 // position. If it overlaps with the position, then either it, or one of its 7367 // children must be the nearest node before the position. So we can just 7368 // recurse into this child to see if we can find something better. 7369 if (position < child.end) { 7370 // The nearest node is either this child, or one of the children inside 7371 // of it. We've already marked this child as the best so far. Recurse 7372 // in case one of the children is better. 7373 forEachChild(child, visit); 7374 7375 // Once we look at the children of this node, then there's no need to 7376 // continue any further. 7377 return true; 7378 } 7379 else { 7380 Debug.assert(child.end <= position); 7381 // The child ends entirely before this position. Say you have the following 7382 // (where $ is the position) 7383 // 7384 // <complex expr 1> ? <complex expr 2> $ : <...> <...> 7385 // 7386 // We would want to find the nearest preceding node in "complex expr 2". 7387 // To support that, we keep track of this node, and once we're done searching 7388 // for a best node, we recurse down this node to see if we can find a good 7389 // result in it. 7390 // 7391 // This approach allows us to quickly skip over nodes that are entirely 7392 // before the position, while still allowing us to find any nodes in the 7393 // last one that might be what we want. 7394 lastNodeEntirelyBeforePosition = child; 7395 } 7396 } 7397 else { 7398 Debug.assert(child.pos > position); 7399 // We're now at a node that is entirely past the position we're searching for. 7400 // This node (and all following nodes) could never contribute to the result, 7401 // so just skip them by returning 'true' here. 7402 return true; 7403 } 7404 } 7405 } 7406 7407 function checkChangeRange(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean) { 7408 const oldText = sourceFile.text; 7409 if (textChangeRange) { 7410 Debug.assert((oldText.length - textChangeRange.span.length + textChangeRange.newLength) === newText.length); 7411 7412 if (aggressiveChecks || Debug.shouldAssert(AssertionLevel.VeryAggressive)) { 7413 const oldTextPrefix = oldText.substr(0, textChangeRange.span.start); 7414 const newTextPrefix = newText.substr(0, textChangeRange.span.start); 7415 Debug.assert(oldTextPrefix === newTextPrefix); 7416 7417 const oldTextSuffix = oldText.substring(textSpanEnd(textChangeRange.span), oldText.length); 7418 const newTextSuffix = newText.substring(textSpanEnd(textChangeRangeNewSpan(textChangeRange)), newText.length); 7419 Debug.assert(oldTextSuffix === newTextSuffix); 7420 } 7421 } 7422 } 7423 7424 interface IncrementalElement extends TextRange { 7425 parent?: Node; 7426 intersectsChange: boolean; 7427 length?: number; 7428 _children: Node[]; 7429 } 7430 7431 export interface IncrementalNode extends Node, IncrementalElement { 7432 hasBeenIncrementallyParsed: boolean; 7433 } 7434 7435 interface IncrementalNodeArray extends NodeArray<IncrementalNode>, IncrementalElement { 7436 length: number; 7437 } 7438 7439 // Allows finding nodes in the source file at a certain position in an efficient manner. 7440 // The implementation takes advantage of the calling pattern it knows the parser will 7441 // make in order to optimize finding nodes as quickly as possible. 7442 export interface SyntaxCursor { 7443 currentNode(position: number): IncrementalNode; 7444 } 7445 7446 function createSyntaxCursor(sourceFile: SourceFile): SyntaxCursor { 7447 let currentArray: NodeArray<Node> = sourceFile.statements; 7448 let currentArrayIndex = 0; 7449 7450 Debug.assert(currentArrayIndex < currentArray.length); 7451 let current = currentArray[currentArrayIndex]; 7452 let lastQueriedPosition = InvalidPosition.Value; 7453 7454 return { 7455 currentNode(position: number) { 7456 // Only compute the current node if the position is different than the last time 7457 // we were asked. The parser commonly asks for the node at the same position 7458 // twice. Once to know if can read an appropriate list element at a certain point, 7459 // and then to actually read and consume the node. 7460 if (position !== lastQueriedPosition) { 7461 // Much of the time the parser will need the very next node in the array that 7462 // we just returned a node from.So just simply check for that case and move 7463 // forward in the array instead of searching for the node again. 7464 if (current && current.end === position && currentArrayIndex < (currentArray.length - 1)) { 7465 currentArrayIndex++; 7466 current = currentArray[currentArrayIndex]; 7467 } 7468 7469 // If we don't have a node, or the node we have isn't in the right position, 7470 // then try to find a viable node at the position requested. 7471 if (!current || current.pos !== position) { 7472 findHighestListElementThatStartsAtPosition(position); 7473 } 7474 } 7475 7476 // Cache this query so that we don't do any extra work if the parser calls back 7477 // into us. Note: this is very common as the parser will make pairs of calls like 7478 // 'isListElement -> parseListElement'. If we were unable to find a node when 7479 // called with 'isListElement', we don't want to redo the work when parseListElement 7480 // is called immediately after. 7481 lastQueriedPosition = position; 7482 7483 // Either we don'd have a node, or we have a node at the position being asked for. 7484 Debug.assert(!current || current.pos === position); 7485 return <IncrementalNode>current; 7486 } 7487 }; 7488 7489 // Finds the highest element in the tree we can find that starts at the provided position. 7490 // The element must be a direct child of some node list in the tree. This way after we 7491 // return it, we can easily return its next sibling in the list. 7492 function findHighestListElementThatStartsAtPosition(position: number) { 7493 // Clear out any cached state about the last node we found. 7494 currentArray = undefined; 7495 currentArrayIndex = InvalidPosition.Value; 7496 current = undefined; 7497 7498 // Recurse into the source file to find the highest node at this position. 7499 forEachChild(sourceFile, visitNode, visitArray); 7500 return; 7501 7502 function visitNode(node: Node) { 7503 if (position >= node.pos && position < node.end) { 7504 // Position was within this node. Keep searching deeper to find the node. 7505 forEachChild(node, visitNode, visitArray); 7506 7507 // don't proceed any further in the search. 7508 return true; 7509 } 7510 7511 // position wasn't in this node, have to keep searching. 7512 return false; 7513 } 7514 7515 function visitArray(array: NodeArray<Node>) { 7516 if (position >= array.pos && position < array.end) { 7517 // position was in this array. Search through this array to see if we find a 7518 // viable element. 7519 for (let i = 0; i < array.length; i++) { 7520 const child = array[i]; 7521 if (child) { 7522 if (child.pos === position) { 7523 // Found the right node. We're done. 7524 currentArray = array; 7525 currentArrayIndex = i; 7526 current = child; 7527 return true; 7528 } 7529 else { 7530 if (child.pos < position && position < child.end) { 7531 // Position in somewhere within this child. Search in it and 7532 // stop searching in this array. 7533 forEachChild(child, visitNode, visitArray); 7534 return true; 7535 } 7536 } 7537 } 7538 } 7539 } 7540 7541 // position wasn't in this array, have to keep searching. 7542 return false; 7543 } 7544 } 7545 } 7546 7547 const enum InvalidPosition { 7548 Value = -1 7549 } 7550 } 7551 7552 function isDeclarationFileName(fileName: string): boolean { 7553 return fileExtensionIs(fileName, Extension.Dts); 7554 } 7555} 7556