diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 00cd54b94eb..b70c4a7a1d5 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -12,43 +12,50 @@ module ts { return new (getNodeConstructor(kind))(); } + function visitNode(cbNode: (node: Node) => T, node: Node): T { + if (node) { + return cbNode(node); + } + } + + function visitNodeArray(cbNodes: (nodes: Node[]) => T, nodes: Node[]) { + if (nodes) { + return cbNodes(nodes); + } + } + + function visitEachNode(cbNode: (node: Node) => T, nodes: Node[]) { + if (nodes) { + for (var i = 0, len = nodes.length; i < len; i++) { + var result = cbNode(nodes[i]); + if (result) { + return result; + } + } + } + } + // Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes // stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise, // embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns // a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned. - export function forEachChild(node: Node, cbNode: (node: Node) => T, cbNodes?: (nodes: Node[]) => T): T { - function child(node: Node): T { - if (node) { - return cbNode(node); - } - } - function children(nodes: Node[]) { - if (nodes) { - if (cbNodes) { - return cbNodes(nodes); - } - - for (var i = 0, len = nodes.length; i < len; i++) { - var result = cbNode(nodes[i]) - if (result) { - return result; - } - } - - return undefined; - } - } + export function forEachChild(node: Node, cbNode: (node: Node) => T, cbNodeArray?: (nodes: Node[]) => T): T { if (!node) { return; } + // The visitXXX functions could be written as local functions that close over the cbNode and cbNodeArray + // callback parameters, but that causes a closure allocation for each invocation with noticeable effects + // on performance. + var visitNodes: (cb: (node: Node | Node[]) => T, nodes: Node[]) => T = cbNodeArray ? visitNodeArray : visitEachNode; + var cbNodes = cbNodeArray || cbNode; switch (node.kind) { case SyntaxKind.QualifiedName: - return child((node).left) || - child((node).right); + return visitNode(cbNode, (node).left) || + visitNode(cbNode, (node).right); case SyntaxKind.TypeParameter: - return child((node).name) || - child((node).constraint) || - child((node).expression); + return visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).constraint) || + visitNode(cbNode, (node).expression); case SyntaxKind.Parameter: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: @@ -56,22 +63,22 @@ module ts { case SyntaxKind.ShorthandPropertyAssignment: case SyntaxKind.VariableDeclaration: case SyntaxKind.BindingElement: - return children(node.modifiers) || - child((node).propertyName) || - child((node).dotDotDotToken) || - child((node).name) || - child((node).questionToken) || - child((node).type) || - child((node).initializer); + return visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).propertyName) || + visitNode(cbNode, (node).dotDotDotToken) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).questionToken) || + visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).initializer); case SyntaxKind.FunctionType: case SyntaxKind.ConstructorType: case SyntaxKind.CallSignature: case SyntaxKind.ConstructSignature: case SyntaxKind.IndexSignature: - return children(node.modifiers) || - children((node).typeParameters) || - children((node).parameters) || - child((node).type); + return visitNodes(cbNodes, node.modifiers) || + visitNodes(cbNodes, (node).typeParameters) || + visitNodes(cbNodes, (node).parameters) || + visitNode(cbNode, (node).type); case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: case SyntaxKind.Constructor: @@ -80,182 +87,182 @@ module ts { case SyntaxKind.FunctionExpression: case SyntaxKind.FunctionDeclaration: case SyntaxKind.ArrowFunction: - return children(node.modifiers) || - child((node).asteriskToken) || - child((node).name) || - child((node).questionToken) || - children((node).typeParameters) || - children((node).parameters) || - child((node).type) || - child((node).body); + return visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).asteriskToken) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).questionToken) || + visitNodes(cbNodes, (node).typeParameters) || + visitNodes(cbNodes, (node).parameters) || + visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).body); case SyntaxKind.TypeReference: - return child((node).typeName) || - children((node).typeArguments); + return visitNode(cbNode, (node).typeName) || + visitNodes(cbNodes, (node).typeArguments); case SyntaxKind.TypeQuery: - return child((node).exprName); + return visitNode(cbNode, (node).exprName); case SyntaxKind.TypeLiteral: - return children((node).members); + return visitNodes(cbNodes, (node).members); case SyntaxKind.ArrayType: - return child((node).elementType); + return visitNode(cbNode, (node).elementType); case SyntaxKind.TupleType: - return children((node).elementTypes); + return visitNodes(cbNodes, (node).elementTypes); case SyntaxKind.UnionType: - return children((node).types); + return visitNodes(cbNodes, (node).types); case SyntaxKind.ParenthesizedType: - return child((node).type); + return visitNode(cbNode, (node).type); case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: - return children((node).elements); + return visitNodes(cbNodes, (node).elements); case SyntaxKind.ArrayLiteralExpression: - return children((node).elements); + return visitNodes(cbNodes, (node).elements); case SyntaxKind.ObjectLiteralExpression: - return children((node).properties); + return visitNodes(cbNodes, (node).properties); case SyntaxKind.PropertyAccessExpression: - return child((node).expression) || - child((node).name); + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).name); case SyntaxKind.ElementAccessExpression: - return child((node).expression) || - child((node).argumentExpression); + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).argumentExpression); case SyntaxKind.CallExpression: case SyntaxKind.NewExpression: - return child((node).expression) || - children((node).typeArguments) || - children((node).arguments); + return visitNode(cbNode, (node).expression) || + visitNodes(cbNodes, (node).typeArguments) || + visitNodes(cbNodes, (node).arguments); case SyntaxKind.TaggedTemplateExpression: - return child((node).tag) || - child((node).template); + return visitNode(cbNode, (node).tag) || + visitNode(cbNode, (node).template); case SyntaxKind.TypeAssertionExpression: - return child((node).type) || - child((node).expression); + return visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).expression); case SyntaxKind.ParenthesizedExpression: - return child((node).expression); + return visitNode(cbNode, (node).expression); case SyntaxKind.DeleteExpression: - return child((node).expression); + return visitNode(cbNode, (node).expression); case SyntaxKind.TypeOfExpression: - return child((node).expression); + return visitNode(cbNode, (node).expression); case SyntaxKind.VoidExpression: - return child((node).expression); + return visitNode(cbNode, (node).expression); case SyntaxKind.PrefixUnaryExpression: - return child((node).operand); + return visitNode(cbNode, (node).operand); case SyntaxKind.YieldExpression: - return child((node).asteriskToken) || - child((node).expression); + return visitNode(cbNode, (node).asteriskToken) || + visitNode(cbNode, (node).expression); case SyntaxKind.PostfixUnaryExpression: - return child((node).operand); + return visitNode(cbNode, (node).operand); case SyntaxKind.BinaryExpression: - return child((node).left) || - child((node).right); + return visitNode(cbNode, (node).left) || + visitNode(cbNode, (node).right); case SyntaxKind.ConditionalExpression: - return child((node).condition) || - child((node).whenTrue) || - child((node).whenFalse); + return visitNode(cbNode, (node).condition) || + visitNode(cbNode, (node).whenTrue) || + visitNode(cbNode, (node).whenFalse); case SyntaxKind.SpreadElementExpression: - return child((node).expression); + return visitNode(cbNode, (node).expression); case SyntaxKind.Block: case SyntaxKind.ModuleBlock: - return children((node).statements); + return visitNodes(cbNodes, (node).statements); case SyntaxKind.SourceFile: - return children((node).statements) || - child((node).endOfFileToken); + return visitNodes(cbNodes, (node).statements) || + visitNode(cbNode, (node).endOfFileToken); case SyntaxKind.VariableStatement: - return children(node.modifiers) || - child((node).declarationList); + return visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).declarationList); case SyntaxKind.VariableDeclarationList: - return children((node).declarations); + return visitNodes(cbNodes, (node).declarations); case SyntaxKind.ExpressionStatement: - return child((node).expression); + return visitNode(cbNode, (node).expression); case SyntaxKind.IfStatement: - return child((node).expression) || - child((node).thenStatement) || - child((node).elseStatement); + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).thenStatement) || + visitNode(cbNode, (node).elseStatement); case SyntaxKind.DoStatement: - return child((node).statement) || - child((node).expression); + return visitNode(cbNode, (node).statement) || + visitNode(cbNode, (node).expression); case SyntaxKind.WhileStatement: - return child((node).expression) || - child((node).statement); + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).statement); case SyntaxKind.ForStatement: - return child((node).initializer) || - child((node).condition) || - child((node).iterator) || - child((node).statement); + return visitNode(cbNode, (node).initializer) || + visitNode(cbNode, (node).condition) || + visitNode(cbNode, (node).iterator) || + visitNode(cbNode, (node).statement); case SyntaxKind.ForInStatement: - return child((node).initializer) || - child((node).expression) || - child((node).statement); + return visitNode(cbNode, (node).initializer) || + visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).statement); case SyntaxKind.ContinueStatement: case SyntaxKind.BreakStatement: - return child((node).label); + return visitNode(cbNode, (node).label); case SyntaxKind.ReturnStatement: - return child((node).expression); + return visitNode(cbNode, (node).expression); case SyntaxKind.WithStatement: - return child((node).expression) || - child((node).statement); + return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).statement); case SyntaxKind.SwitchStatement: - return child((node).expression) || - children((node).clauses); + return visitNode(cbNode, (node).expression) || + visitNodes(cbNodes, (node).clauses); case SyntaxKind.CaseClause: - return child((node).expression) || - children((node).statements); + return visitNode(cbNode, (node).expression) || + visitNodes(cbNodes, (node).statements); case SyntaxKind.DefaultClause: - return children((node).statements); + return visitNodes(cbNodes, (node).statements); case SyntaxKind.LabeledStatement: - return child((node).label) || - child((node).statement); + return visitNode(cbNode, (node).label) || + visitNode(cbNode, (node).statement); case SyntaxKind.ThrowStatement: - return child((node).expression); + return visitNode(cbNode, (node).expression); case SyntaxKind.TryStatement: - return child((node).tryBlock) || - child((node).catchClause) || - child((node).finallyBlock); + return visitNode(cbNode, (node).tryBlock) || + visitNode(cbNode, (node).catchClause) || + visitNode(cbNode, (node).finallyBlock); case SyntaxKind.CatchClause: - return child((node).name) || - child((node).type) || - child((node).block); + return visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).block); case SyntaxKind.ClassDeclaration: - return children(node.modifiers) || - child((node).name) || - children((node).typeParameters) || - children((node).heritageClauses) || - children((node).members); + return visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNodes(cbNodes, (node).typeParameters) || + visitNodes(cbNodes, (node).heritageClauses) || + visitNodes(cbNodes, (node).members); case SyntaxKind.InterfaceDeclaration: - return children(node.modifiers) || - child((node).name) || - children((node).typeParameters) || - children((node).heritageClauses) || - children((node).members); + return visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNodes(cbNodes, (node).typeParameters) || + visitNodes(cbNodes, (node).heritageClauses) || + visitNodes(cbNodes, (node).members); case SyntaxKind.TypeAliasDeclaration: - return children(node.modifiers) || - child((node).name) || - child((node).type); + return visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).type); case SyntaxKind.EnumDeclaration: - return children(node.modifiers) || - child((node).name) || - children((node).members); + return visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNodes(cbNodes, (node).members); case SyntaxKind.EnumMember: - return child((node).name) || - child((node).initializer); + return visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).initializer); case SyntaxKind.ModuleDeclaration: - return children(node.modifiers) || - child((node).name) || - child((node).body); + return visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).body); case SyntaxKind.ImportDeclaration: - return children(node.modifiers) || - child((node).name) || - child((node).moduleReference); + return visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).moduleReference); case SyntaxKind.ExportAssignment: - return children(node.modifiers) || - child((node).exportName); + return visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).exportName); case SyntaxKind.TemplateExpression: - return child((node).head) || children((node).templateSpans); + return visitNode(cbNode, (node).head) || visitNodes(cbNodes, (node).templateSpans); case SyntaxKind.TemplateSpan: - return child((node).expression) || child((node).literal); + return visitNode(cbNode, (node).expression) || visitNode(cbNode, (node).literal); case SyntaxKind.ComputedPropertyName: - return child((node).expression); + return visitNode(cbNode, (node).expression); case SyntaxKind.HeritageClause: - return children((node).types); + return visitNodes(cbNodes, (node).types); case SyntaxKind.ExternalModuleReference: - return child((node).expression); + return visitNode(cbNode, (node).expression); } }