testrumenter
Version:
Command-line utility to test JavaScript code instrumenter
1 lines • 1.28 MB
JavaScript
var compiler_input = "//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\nmodule TypeScript {\n export class AstLogger {\n\n constructor (public logger: ILogger) { }\n\n public logScript(script: TypeScript.Script): void {\n this.logLinemap(script.locationInfo.lineMap);\n\n var stack: AST[]= [];\n\n var pre = (cur: TypeScript.AST, parent: TypeScript.AST) => {\n stack.push(cur);\n var indent = (stack.length - 1) * 2;\n this.logComments(script, cur.preComments, indent);\n this.logNode(script, cur, indent);\n this.logComments(script, cur.postComments, indent);\n return cur;\n }\n\n var post = (cur: TypeScript.AST, parent: TypeScript.AST) => {\n stack.pop();\n return cur;\n }\n\n TypeScript.getAstWalkerFactory().walk(script, pre, post);\n }\n\n\n public logNode(script: TypeScript.Script, cur: TypeScript.AST, indent: number) {\n var msg = this.addPadding(\"\", indent, \"| \", true);\n\n msg = msg.concat(\"+ \" + cur.treeViewLabel());\n msg = this.addPadding(msg, 70, \" \", false);\n\n msg = msg + this.addLineColumn(script, cur.minChar);\n msg = this.addPadding(msg, 80, \" \", false);\n\n msg = msg + \"=> \";\n msg = msg + this.addLineColumn(script, cur.limChar);\n msg = this.addPadding(msg, 102, \" \", false);\n\n msg = msg.concat(\"[\" + this.addPadding(cur.minChar.toString(), 1, \" \", true) + \", \" + this.addPadding(cur.limChar.toString(), 1, \" \", true) + \"]\");\n\n msg = this.addPadding(msg, 115, \" \", false);\n msg = msg.concat(\"sym=\" + (<any>cur).sym);\n\n msg = this.addPadding(msg, 135, \" \", false);\n msg = msg.concat(\"type=\" + (cur.type === null ? \"null\" : cur.type.getTypeName()));\n this.logger.log(msg);\n }\n\n private logComments(script: TypeScript.Script, comments: TypeScript.AST[], indent: number) {\n if (comments == null)\n return;\n\n for (var i = 0; i < comments.length; i++) {\n this.logNode(script, comments[i], indent);\n }\n }\n\n public logLinemap(linemap: number[]) {\n var result = \"[\";\n for (var i = 0; i < linemap.length; i++) {\n if (i > 0)\n result += \",\";\n result += linemap[i];\n }\n result += \"]\";\n this.logger.log(\"linemap: \" + result);\n }\n\n private addPadding(s: string, targetLength: number, paddingString: string, leftPadding: bool): string {\n var result = (leftPadding ? \"\" : s);\n for (var i = s.length; i < targetLength; i++) {\n result = result + paddingString;\n }\n result = result + (leftPadding ? s : \"\");\n return result;\n }\n\n private addLineColumn(script: TypeScript.Script, position: number): string {\n // just for calling getSourceLineColFromMap\n var lineInfo = {\n line: -1,\n col: -1\n }\n TypeScript.getSourceLineColFromMap(lineInfo, position, script.locationInfo.lineMap);\n\n if (lineInfo.col !== -1) {\n lineInfo.col++; //TODO: function above seems to consider line as 1-based, and column as 0-based\n }\n\n return \"(\" + lineInfo.line + \", \" + lineInfo.col + \")\";\n }\n }\n}\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n///<reference path='typescript.ts' />\n\nmodule TypeScript {\n export function lastOf(items: any[]): any {\n return (items === null || items.length === 0) ? null : items[items.length - 1];\n }\n\n export function max(a: number, b: number): number {\n return a >= b ? a : b;\n }\n\n export function min(a: number, b: number): number {\n return a <= b ? a : b;\n }\n\n //\n // Helper class representing a path from a root ast node to a (grand)child ast node.\n // This is helpful as our tree don't have parents.\n //\n export class AstPath {\n public asts: TypeScript.AST[] = [];\n public top: number = -1;\n\n static reverseIndexOf(items: any[], index: number): any {\n return (items === null || items.length <= index) ? null : items[items.length - index - 1];\n }\n\n public clone(): AstPath {\n var clone = new AstPath();\n clone.asts = this.asts.map((value) => { return value; });\n clone.top = this.top;\n return clone;\n }\n\n public pop(): TypeScript.AST {\n var head = this.ast();\n this.up();\n\n while (this.asts.length > this.count()) {\n this.asts.pop();\n }\n return head;\n }\n\n public push(ast: TypeScript.AST) {\n while (this.asts.length > this.count()) {\n this.asts.pop();\n }\n this.top = this.asts.length;\n this.asts.push(ast);\n }\n\n public up() {\n if (this.top <= -1)\n throw new Error(\"Invalid call to 'up'\");\n this.top--;\n }\n\n public down() {\n if (this.top == this.ast.length - 1)\n throw new Error(\"Invalid call to 'down'\");\n this.top++;\n }\n\n public nodeType(): TypeScript.NodeType {\n if (this.ast() == null)\n return TypeScript.NodeType.None;\n return this.ast().nodeType;\n }\n\n public ast() {\n return <TypeScript.AST>AstPath.reverseIndexOf(this.asts, this.asts.length - (this.top + 1));\n }\n\n public parent() {\n return <TypeScript.AST>AstPath.reverseIndexOf(this.asts, this.asts.length - this.top);\n }\n\n public count() {\n return this.top + 1;\n }\n\n public get(index: number): TypeScript.AST {\n return this.asts[index];\n }\n\n public isNameOfClass(): bool {\n if (this.ast() === null || this.parent() === null)\n return false;\n\n return (this.ast().nodeType === TypeScript.NodeType.Name) &&\n (this.parent().nodeType === TypeScript.NodeType.ClassDeclaration) &&\n ((<TypeScript.InterfaceDeclaration>this.parent()).name === this.ast());\n }\n\n public isNameOfInterface(): bool {\n if (this.ast() === null || this.parent() === null)\n return false;\n\n return (this.ast().nodeType === TypeScript.NodeType.Name) &&\n (this.parent().nodeType === TypeScript.NodeType.InterfaceDeclaration) &&\n ((<TypeScript.InterfaceDeclaration>this.parent()).name === this.ast());\n }\n\n public isNameOfArgument(): bool {\n if (this.ast() === null || this.parent() === null)\n return false;\n\n return (this.ast().nodeType === TypeScript.NodeType.Name) &&\n (this.parent().nodeType === TypeScript.NodeType.ArgDecl) &&\n ((<TypeScript.ArgDecl>this.parent()).id === this.ast());\n }\n\n public isNameOfVariable(): bool {\n if (this.ast() === null || this.parent() === null)\n return false;\n\n return (this.ast().nodeType === TypeScript.NodeType.Name) &&\n (this.parent().nodeType === TypeScript.NodeType.VarDecl) &&\n ((<TypeScript.VarDecl>this.parent()).id === this.ast());\n }\n\n public isNameOfModule(): bool {\n if (this.ast() === null || this.parent() === null)\n return false;\n\n return (this.ast().nodeType === TypeScript.NodeType.Name) &&\n (this.parent().nodeType === TypeScript.NodeType.ModuleDeclaration) &&\n ((<TypeScript.ModuleDeclaration>this.parent()).name === this.ast());\n }\n\n public isNameOfFunction(): bool {\n if (this.ast() === null || this.parent() === null)\n return false;\n\n return (this.ast().nodeType === TypeScript.NodeType.Name) &&\n (this.parent().nodeType === TypeScript.NodeType.FuncDecl) &&\n ((<TypeScript.FuncDecl>this.parent()).name === this.ast());\n }\n\n public isChildOfScript(): bool {\n var ast = lastOf(this.asts);\n return this.count() >= 3 &&\n this.asts[this.top] === ast &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.List &&\n this.asts[this.top - 2].nodeType === TypeScript.NodeType.Script;\n }\n\n public isChildOfModule(): bool {\n var ast = lastOf(this.asts);\n return this.count() >= 3 &&\n this.asts[this.top] === ast &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.List &&\n this.asts[this.top - 2].nodeType === TypeScript.NodeType.ModuleDeclaration;\n }\n\n public isChildOfClass(): bool {\n var ast = lastOf(this.asts);\n return this.count() >= 3 &&\n this.asts[this.top] === ast &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.List &&\n this.asts[this.top - 2].nodeType === TypeScript.NodeType.ClassDeclaration;\n }\n\n public isArgumentOfClassConstructor(): bool {\n var ast = lastOf(this.asts);\n return this.count() >= 5 &&\n this.asts[this.top] === ast &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.List &&\n this.asts[this.top - 2].nodeType === TypeScript.NodeType.FuncDecl &&\n this.asts[this.top - 3].nodeType === TypeScript.NodeType.List &&\n this.asts[this.top - 4].nodeType === TypeScript.NodeType.ClassDeclaration &&\n ((<TypeScript.FuncDecl>this.asts[this.top - 2]).isConstructor) &&\n ((<TypeScript.FuncDecl>this.asts[this.top - 2]).arguments === this.asts[this.top - 1]) &&\n ((<TypeScript.ClassDeclaration>this.asts[this.top - 4]).constructorDecl === this.asts[this.top - 2]);\n }\n\n public isChildOfInterface(): bool {\n var ast = lastOf(this.asts);\n return this.count() >= 3 &&\n this.asts[this.top] === ast &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.List &&\n this.asts[this.top - 2].nodeType === TypeScript.NodeType.InterfaceDeclaration;\n }\n\n public isTopLevelImplicitModule() {\n return this.count() >= 1 &&\n this.asts[this.top].nodeType === TypeScript.NodeType.ModuleDeclaration &&\n TypeScript.hasFlag((<TypeScript.ModuleDeclaration>this.asts[this.top]).modFlags, TypeScript.ModuleFlags.IsWholeFile);\n }\n\n public isBodyOfTopLevelImplicitModule() {\n return this.count() >= 2 &&\n this.asts[this.top - 0].nodeType === TypeScript.NodeType.List &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.ModuleDeclaration &&\n (<TypeScript.ModuleDeclaration>this.asts[this.top - 1]).members == this.asts[this.top - 0] &&\n TypeScript.hasFlag((<TypeScript.ModuleDeclaration>this.asts[this.top - 1]).modFlags, TypeScript.ModuleFlags.IsWholeFile);\n }\n\n public isBodyOfScript(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.Script &&\n (<TypeScript.Script>this.asts[this.top - 1]).bod == this.asts[this.top - 0];\n }\n\n public isBodyOfSwitch(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.Switch &&\n (<TypeScript.SwitchStatement>this.asts[this.top - 1]).caseList == this.asts[this.top - 0];\n }\n\n public isBodyOfModule(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.ModuleDeclaration &&\n (<TypeScript.ModuleDeclaration>this.asts[this.top - 1]).members == this.asts[this.top - 0];\n }\n\n public isBodyOfClass(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.ClassDeclaration &&\n (<TypeScript.ClassDeclaration>this.asts[this.top - 1]).members == this.asts[this.top - 0];\n }\n\n public isBodyOfFunction(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.FuncDecl &&\n (<TypeScript.FuncDecl>this.asts[this.top - 1]).bod == this.asts[this.top - 0];\n }\n\n public isBodyOfInterface(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.InterfaceDeclaration &&\n (<TypeScript.InterfaceDeclaration>this.asts[this.top - 1]).members == this.asts[this.top - 0];\n }\n\n public isBodyOfBlock(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.Block &&\n (<TypeScript.Block>this.asts[this.top - 1]).statements == this.asts[this.top - 0];\n }\n\n public isBodyOfFor(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.For &&\n (<TypeScript.ForStatement>this.asts[this.top - 1]).body == this.asts[this.top - 0];\n }\n\n public isBodyOfCase(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.Case &&\n (<TypeScript.CaseStatement>this.asts[this.top - 1]).body == this.asts[this.top - 0];\n }\n\n public isBodyOfTry(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.Try &&\n (<TypeScript.Try>this.asts[this.top - 1]).body == this.asts[this.top - 0];\n }\n\n public isBodyOfCatch(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.Catch &&\n (<TypeScript.Catch>this.asts[this.top - 1]).body == this.asts[this.top - 0];\n }\n\n public isBodyOfDoWhile(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.DoWhile &&\n (<TypeScript.DoWhileStatement>this.asts[this.top - 1]).body == this.asts[this.top - 0];\n }\n\n public isBodyOfWhile(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.While &&\n (<TypeScript.WhileStatement>this.asts[this.top - 1]).body == this.asts[this.top - 0];\n }\n\n public isBodyOfForIn(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.ForIn &&\n (<TypeScript.ForInStatement>this.asts[this.top - 1]).body == this.asts[this.top - 0];\n }\n\n public isBodyOfWith(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.With &&\n (<TypeScript.WithStatement>this.asts[this.top - 1]).body == this.asts[this.top - 0];\n }\n\n public isBodyOfFinally(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.Finally &&\n (<TypeScript.Finally>this.asts[this.top - 1]).body == this.asts[this.top - 0];\n }\n\n public isCaseOfSwitch(): bool {\n return this.count() >= 3 &&\n this.asts[this.top - 2].nodeType === TypeScript.NodeType.Switch &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.List &&\n (<TypeScript.SwitchStatement>this.asts[this.top - 2]).caseList == this.asts[this.top - 1];\n }\n\n public isDefaultCaseOfSwitch(): bool {\n return this.count() >= 3 &&\n this.asts[this.top - 2].nodeType === TypeScript.NodeType.Switch &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.List &&\n (<TypeScript.SwitchStatement>this.asts[this.top - 2]).caseList == this.asts[this.top - 1] &&\n (<TypeScript.SwitchStatement>this.asts[this.top - 2]).defaultCase == this.asts[this.top - 0];\n }\n\n public isListOfObjectLit(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.ObjectLit &&\n this.asts[this.top - 0].nodeType === TypeScript.NodeType.List &&\n (<TypeScript.UnaryExpression>this.asts[this.top - 1]).operand == this.asts[this.top - 0];\n }\n\n public isBodyOfObjectLit(): bool {\n return this.isListOfObjectLit();\n }\n\n public isEmptyListOfObjectLit(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.ObjectLit &&\n this.asts[this.top - 0].nodeType === TypeScript.NodeType.List &&\n (<TypeScript.UnaryExpression>this.asts[this.top - 1]).operand == this.asts[this.top - 0] &&\n (<TypeScript.ASTList>this.asts[this.top - 0]).members.length == 0;\n }\n\n public isMemberOfObjectLit(): bool {\n return this.count() >= 3 &&\n this.asts[this.top - 2].nodeType === TypeScript.NodeType.ObjectLit &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.List &&\n this.asts[this.top - 0].nodeType === TypeScript.NodeType.Member &&\n (<TypeScript.UnaryExpression>this.asts[this.top - 2]).operand == this.asts[this.top - 1];\n }\n\n public isNameOfMemberOfObjectLit(): bool {\n return this.count() >= 4 &&\n this.asts[this.top - 3].nodeType === TypeScript.NodeType.ObjectLit &&\n this.asts[this.top - 2].nodeType === TypeScript.NodeType.List &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.Member &&\n this.asts[this.top - 0].nodeType === TypeScript.NodeType.Name &&\n (<TypeScript.UnaryExpression>this.asts[this.top - 3]).operand == this.asts[this.top - 2];\n }\n\n public isListOfArrayLit(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.ArrayLit &&\n this.asts[this.top - 0].nodeType === TypeScript.NodeType.List &&\n (<TypeScript.UnaryExpression>this.asts[this.top - 1]).operand == this.asts[this.top - 0];\n }\n\n public isTargetOfMember(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.Member &&\n (<TypeScript.BinaryExpression>this.asts[this.top - 1]).operand1 === this.asts[this.top - 0];\n }\n\n public isMemberOfMember(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.Member &&\n (<TypeScript.BinaryExpression>this.asts[this.top - 1]).operand2 === this.asts[this.top - 0];\n }\n\n public isItemOfList(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.List;\n //(<Tools.ASTList>this.asts[this.top - 1]).operand2 === this.asts[this.top - 0];\n }\n\n public isThenOfIf(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.If &&\n (<TypeScript.IfStatement>this.asts[this.top - 1]).thenBod == this.asts[this.top - 0];\n }\n\n public isElseOfIf(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.If &&\n (<TypeScript.IfStatement>this.asts[this.top - 1]).elseBod == this.asts[this.top - 0];\n }\n\n public isBodyOfDefaultCase(): bool {\n return this.isBodyOfCase();\n }\n\n public isSingleStatementList(): bool {\n return this.count() >= 1 &&\n this.asts[this.top].nodeType === TypeScript.NodeType.List &&\n (<TypeScript.ASTList>this.asts[this.top]).members.length === 1;\n }\n\n public isArgumentListOfFunction(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 0].nodeType === TypeScript.NodeType.List &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.FuncDecl &&\n (<TypeScript.FuncDecl>this.asts[this.top - 1]).arguments === this.asts[this.top - 0];\n }\n\n public isArgumentOfFunction(): bool {\n return this.count() >= 3 &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.List &&\n this.asts[this.top - 2].nodeType === TypeScript.NodeType.FuncDecl &&\n (<TypeScript.FuncDecl>this.asts[this.top - 2]).arguments === this.asts[this.top - 1];\n }\n\n public isArgumentListOfCall(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 0].nodeType === TypeScript.NodeType.List &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.Call &&\n (<TypeScript.CallExpression>this.asts[this.top - 1]).arguments === this.asts[this.top - 0];\n }\n\n public isArgumentListOfNew(): bool {\n return this.count() >= 2 &&\n this.asts[this.top - 0].nodeType === TypeScript.NodeType.List &&\n this.asts[this.top - 1].nodeType === TypeScript.NodeType.New &&\n (<TypeScript.CallExpression>this.asts[this.top - 1]).arguments === this.asts[this.top - 0];\n }\n\n public isSynthesizedBlock(): bool {\n return this.count() >= 1 &&\n this.asts[this.top - 0].nodeType === TypeScript.NodeType.Block &&\n (<TypeScript.Block>this.asts[this.top - 0]).isStatementBlock === false;\n }\n }\n\n export function isValidAstNode(ast: TypeScript.ASTSpan): bool {\n if (ast === null)\n return false;\n\n if (ast.minChar === -1 || ast.limChar === -1)\n return false;\n\n return true;\n }\n\n export class AstPathContext {\n public path = new TypeScript.AstPath();\n }\n\n export enum GetAstPathOptions {\n Default = 0,\n EdgeInclusive = 1,\n //We need this options dealing with an AST coming from an incomplete AST. For example:\n // class foo { // r\n // If we ask for the AST at the position after the \"r\" character, we won't see we are \n // inside a comment, because the \"class\" AST node has a limChar corresponding to the position of \n // the \"{\" character, meaning we don't traverse the tree down to the stmt list of the class, meaning\n // we don't find the \"precomment\" attached to the errorneous empty stmt.\n //TODO: It would be nice to be able to get rid of this.\n DontPruneSearchBasedOnPosition = 1 << 1,\n }\n\n ///\n /// Return the stack of AST nodes containing \"position\"\n ///\n export function getAstPathToPosition(script: TypeScript.AST, pos: number, options = GetAstPathOptions.Default): TypeScript.AstPath {\n var lookInComments = (comments: TypeScript.Comment[]) => {\n if (comments && comments.length > 0) {\n for (var i = 0; i < comments.length; i++) {\n var minChar = comments[i].minChar;\n var limChar = comments[i].limChar;\n if (!comments[i].isBlockComment) {\n limChar++; // For single line comments, include 1 more character (for the newline)\n }\n if (pos >= minChar && pos < limChar) {\n ctx.path.push(comments[i]);\n }\n }\n }\n }\n\n var pre = function (cur: TypeScript.AST, parent: TypeScript.AST, walker: IAstWalker) {\n if (isValidAstNode(cur)) {\n\n // Add \"cur\" to the stack if it contains our position\n // For \"identifier\" nodes, we need a special case: A position equal to \"limChar\" is\n // valid, since the position corresponds to a caret position (in between characters)\n // For example:\n // bar\n // 0123\n // If \"position == 3\", the caret is at the \"right\" of the \"r\" character, which should be considered valid\n var inclusive =\n hasFlag(options, GetAstPathOptions.EdgeInclusive) ||\n cur.nodeType === TypeScript.NodeType.Name ||\n pos === script.limChar; // Special \"EOF\" case\n\n var minChar = cur.minChar;\n var limChar = cur.limChar + (inclusive ? 1 : 0)\n if (pos >= minChar && pos < limChar) {\n\n // TODO: Since AST is sometimes not correct wrt to position, only add \"cur\" if it's better\n // than top of the stack.\n var previous = ctx.path.ast();\n if (previous == null || (cur.minChar >= previous.minChar && cur.limChar <= previous.limChar)) {\n ctx.path.push(cur);\n }\n else {\n //logger.log(\"TODO: Ignoring node because minChar, limChar not better than previous node in stack\");\n }\n }\n\n // The AST walker skips comments, but we might be in one, so check the pre/post comments for this node manually\n if (pos < limChar) {\n lookInComments(cur.preComments);\n }\n if (pos >= minChar) {\n lookInComments(cur.postComments);\n }\n\n if (!hasFlag(options, GetAstPathOptions.DontPruneSearchBasedOnPosition)) {\n // Don't go further down the tree if pos is outside of [minChar, limChar]\n walker.options.goChildren = (minChar <= pos && pos <= limChar);\n }\n }\n return cur;\n }\n\n var ctx = new AstPathContext();\n TypeScript.getAstWalkerFactory().walk(script, pre, null, null, ctx);\n return ctx.path;\n }\n\n //\n // Find a source text offset that is safe for lexing tokens at the given position.\n // This is used when \"position\" might be inside a comment or string, etc.\n //\n export function getTokenizationOffset(script: TypeScript.Script, position: number): number {\n var bestOffset = 0;\n var pre = (cur: TypeScript.AST, parent: TypeScript.AST, walker: TypeScript.IAstWalker): TypeScript.AST => {\n if (TypeScript.isValidAstNode(cur)) {\n // Did we find a closer offset?\n if (cur.minChar <= position) {\n bestOffset = max(bestOffset, cur.minChar);\n }\n\n // Stop the walk if this node is not related to \"minChar\"\n if (cur.minChar > position || cur.limChar < bestOffset) {\n walker.options.goChildren = false;\n }\n }\n\n return cur;\n }\n\n TypeScript.getAstWalkerFactory().walk(script, pre);\n return bestOffset;\n }\n\n ///\n /// Simple function to Walk an AST using a simple callback function.\n ///\n export function walkAST(ast: TypeScript.AST, callback: (path: AstPath, walker: TypeScript.IAstWalker) => void ): void {\n var pre = function (cur: TypeScript.AST, parent: TypeScript.AST, walker: TypeScript.IAstWalker) {\n var path: TypeScript.AstPath = walker.state;\n path.push(cur);\n callback(path, walker);\n return cur;\n }\n var post = function (cur: TypeScript.AST, parent: TypeScript.AST, walker: TypeScript.IAstWalker) {\n var path: TypeScript.AstPath = walker.state;\n path.pop();\n return cur;\n }\n\n var path = new AstPath();\n TypeScript.getAstWalkerFactory().walk(ast, pre, post, null, path);\n }\n}\n//\n// Copyright (c) Microsoft Corporation. All rights reserved.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n///<reference path='typescript.ts' />\n\nmodule TypeScript {\n export class ASTSpan {\n public minChar: number = -1; // -1 = \"undefined\" or \"compiler generated\"\n public limChar: number = -1; // -1 = \"undefined\" or \"compiler generated\" \n }\n\n export class AST extends ASTSpan {\n public type: Type = null;\n public flags = ASTFlags.Writeable;\n\n // REVIEW: for diagnostic purposes\n public passCreated: number = CompilerDiagnostics.analysisPass;\n\n public preComments: Comment[] = null;\n public postComments: Comment[] = null;\n private docComments: Comment[] = null;\n\n public isParenthesized = false;\n\n constructor (public nodeType: NodeType) {\n super();\n }\n\n public isExpression() { return false; }\n\n public isStatementOrExpression() { return false; }\n\n public isCompoundStatement() { return false; }\n\n public isLeaf() { return this.isStatementOrExpression() && (!this.isCompoundStatement()); }\n \n public isDeclaration() { return false; }\n\n public typeCheck(typeFlow: TypeFlow) {\n switch (this.nodeType) {\n case NodeType.Error:\n case NodeType.EmptyExpr:\n this.type = typeFlow.anyType;\n break;\n case NodeType.This:\n return typeFlow.typeCheckThis(this);\n case NodeType.Null:\n this.type = typeFlow.nullType;\n break;\n case NodeType.False:\n case NodeType.True:\n this.type = typeFlow.booleanType;\n break;\n case NodeType.Super:\n return typeFlow.typeCheckSuper(this);\n case NodeType.EndCode:\n case NodeType.Empty:\n case NodeType.Void:\n this.type = typeFlow.voidType;\n break;\n default:\n throw new Error(\"please implement in derived class\");\n }\n return this;\n }\n\n public emit(emitter: Emitter, tokenId: TokenID, startLine: bool) {\n emitter.emitParensAndCommentsInPlace(this, true);\n switch (this.nodeType) {\n case NodeType.This:\n emitter.recordSourceMappingStart(this);\n if (emitter.thisFnc && (hasFlag(emitter.thisFnc.fncFlags, FncFlags.IsFatArrowFunction))) {\n emitter.writeToOutput(\"_this\");\n }\n else {\n emitter.writeToOutput(\"this\");\n }\n emitter.recordSourceMappingEnd(this);\n break;\n case NodeType.Null:\n emitter.recordSourceMappingStart(this);\n emitter.writeToOutput(\"null\");\n emitter.recordSourceMappingEnd(this);\n break;\n case NodeType.False:\n emitter.recordSourceMappingStart(this);\n emitter.writeToOutput(\"false\");\n emitter.recordSourceMappingEnd(this);\n break;\n case NodeType.True:\n emitter.recordSourceMappingStart(this);\n emitter.writeToOutput(\"true\");\n emitter.recordSourceMappingEnd(this);\n break;\n case NodeType.Super:\n emitter.recordSourceMappingStart(this);\n emitter.emitSuperReference();\n emitter.recordSourceMappingEnd(this);\n break;\n case NodeType.EndCode:\n case NodeType.Error:\n case NodeType.EmptyExpr:\n break;\n case NodeType.Empty:\n emitter.recordSourceMappingStart(this);\n emitter.recordSourceMappingEnd(this);\n break;\n case NodeType.Void:\n emitter.recordSourceMappingStart(this);\n emitter.writeToOutput(\"void \");\n emitter.recordSourceMappingEnd(this);\n break;\n default:\n throw new Error(\"please implement in derived class\");\n }\n emitter.emitParensAndCommentsInPlace(this, false);\n }\n\n public print(context: PrintContext) {\n context.startLine();\n var lineCol = { line: -1, col: -1 };\n var limLineCol = { line: -1, col: -1 };\n if (context.parser !== null) {\n context.parser.getSourceLineCol(lineCol, this.minChar);\n context.parser.getSourceLineCol(limLineCol, this.limChar);\n context.write(\"(\" + lineCol.line + \",\" + lineCol.col + \")--\" +\n \"(\" + limLineCol.line + \",\" + limLineCol.col + \"): \");\n }\n var lab = this.printLabel();\n if (hasFlag(this.flags, ASTFlags.Error)) {\n lab += \" (Error)\";\n }\n context.writeLine(lab);\n }\n\n public printLabel() {\n if (nodeTypeTable[this.nodeType] !== undefined) {\n return nodeTypeTable[this.nodeType];\n }\n else {\n return (<any>NodeType)._map[this.nodeType];\n }\n }\n\n public addToControlFlow(context: ControlFlowContext): void {\n // by default, AST adds itself to current basic block and does not check its children\n context.walker.options.goChildren = false;\n context.addContent(this);\n }\n\n public netFreeUses(container: Symbol, freeUses: StringHashTable) {\n }\n\n public treeViewLabel() {\n return (<any>NodeType)._map[this.nodeType];\n }\n\n public static getResolvedIdentifierName(name: string): string {\n if (!name) return \"\";\n\n var resolved = \"\";\n var start = 0;\n var i = 0;\n while(i <= name.length - 6) {\n // Look for escape sequence \\uxxxx\n if (name.charAt(i) == '\\\\' && name.charAt(i+1) == 'u') {\n var charCode = parseInt(name.substr(i + 2, 4), 16);\n resolved += name.substr(start, i - start);\n resolved += String.fromCharCode(charCode);\n i += 6;\n start = i;\n continue;\n } \n i++;\n }\n // Append remaining string\n resolved += name.substring(start);\n return resolved;\n }\n\n public getDocComments() : Comment[] {\n if (!this.isDeclaration() || !this.preComments || this.preComments.length == 0) {\n return [];\n }\n\n if (!this.docComments) {\n var preCommentsLength = this.preComments.length;\n var docComments: Comment[] = [];\n for (var i = preCommentsLength - 1; i >= 0; i--) {\n if (this.preComments[i].isDocComment()) {\n var prevDocComment = docComments.length > 0 ? docComments[docComments.length - 1] : null;\n if (prevDocComment == null || // If the help comments were not yet set then this is the comment\n (this.preComments[i].limLine == prevDocComment.minLine ||\n this.preComments[i].limLine + 1 == prevDocComment.minLine)) { // On same line or next line\n docComments.push(this.preComments[i]);\n continue;\n }\n }\n break;\n }\n\n this.docComments = docComments.reverse();\n }\n\n return this.docComments;\n }\n }\n\n export class IncompleteAST extends AST {\n constructor (min: number, lim: number) {\n super(NodeType.Error);\n\n this.minChar = min;\n this.limChar = lim;\n }\n }\n\n export class ASTList extends AST {\n public enclosingScope: SymbolScope = null;\n public members: AST[] = new AST[];\n\n constructor () {\n super(NodeType.List);\n }\n\n public addToControlFlow(context: ControlFlowContext) {\n var len = this.members.length;\n for (var i = 0; i < len; i++) {\n if (context.noContinuation) {\n context.addUnreachable(this.members[i]);\n break;\n }\n else {\n this.members[i] = context.walk(this.members[i], this);\n }\n }\n context.walker.options.goChildren = false;\n }\n\n public append(ast: AST) {\n this.members[this.members.length] = ast;\n return this;\n }\n\n public appendAll(ast: AST) {\n if (ast.nodeType == NodeType.List) {\n var list = <ASTList>ast;\n for (var i = 0, len = list.members.length; i < len; i++) {\n this.append(list.members[i]);\n }\n }\n else {\n this.append(ast);\n }\n return this;\n }\n\n public emit(emitter: Emitter, tokenId: TokenID, startLine: bool) {\n emitter.recordSourceMappingStart(this);\n emitter.emitJavascriptList(this, null, TokenID.Semicolon, startLine, false, false);\n emitter.recordSourceMappingEnd(this);\n }\n\n public typeCheck(typeFlow: TypeFlow) {\n var len = this.members.length;\n typeFlow.nestingLevel++;\n for (var i = 0; i < len; i++) {\n if (this.members[i]) {\n this.members[i] = this.members[i].typeCheck(typeFlow);\n }\n }\n typeFlow.nestingLevel--;\n return this;\n }\n }\n\n export class Identifier extends AST {\n public sym: Symbol = null;\n public cloId = -1;\n public text: string;\n\n // 'actualText' is the text that the user has entered for the identifier. the text might \n // include any Unicode escape sequences (e.g.: \\u0041 for 'A'). 'text', however, contains \n // the resolved value of any escape sequences in the actual text; so in the previous \n // example, actualText = '\\u0041', text = 'A'.\n //\n // For purposes of finding a symbol, use text, as this will allow you to match all \n // variations of the variable text. For full-fidelity translation of the user input, such\n // as emitting, use the actualText field.\n // \n // Note: \n // To change text, and to avoid running into a situation where 'actualText' does not \n // match 'text', always use setText.\n constructor (public actualText: string, public hasEscapeSequence?: bool) {\n super(NodeType.Name);\n this.setText(actualText, hasEscapeSequence);\n }\n\n public setText(actualText: string, hasEscapeSequence?: bool) {\n this.actualText = actualText;\n if (hasEscapeSequence) {\n this.text = AST.getResolvedIdentifierName(actualText);\n }\n else {\n this.text = actualText;\n }\n }\n\n public isMissing() { return false; }\n public isLeaf() { return true; }\n\n public treeViewLabel() {\n return \"id: \" + this.actualText;\n }\n\n public printLabel() {\n if (this.actualText) {\n return \"id: \" + this.actualText;\n }\n else {\n return \"name node\";\n }\n }\n\n public typeCheck(typeFlow: TypeFlow) {\n return typeFlow.typeCheckName(this);\n }\n\n public emit(emitter: Emitter, tokenId: TokenID, startLine: bool) {\n emitter.emitJavascriptName(this, true);\n }\n\n public static fromToken(token: Token): Identifier {\n return new Identifier(token.getText(), (<IdentifierToken>token).hasEscapeSequence);\n }\n }\n\n export class MissingIdentifier extends Identifier {\n constructor () {\n super(\"__missing\");\n }\n\n public isMissing() {\n return true;\n }\n\n public emit(emitter: Emitter, tokenId: TokenID, startLine: bool) {\n // Emit nothing for a missing ID\n }\n }\n\n export class Label extends AST {\n constructor (public id: Identifier) {\n super(NodeType.Label);\n }\n\n public printLabel() { return this.id.actualText + \":\"; }\n\n public typeCheck(typeFlow: TypeFlow) {\n this.type = typeFlow.voidType;\n return this;\n }\n\n public emit(emitter: Emitter, tokenId: TokenID, startLine: bool) {\n emitter.emitParensAndCommentsInPlace(this, true);\n emitter.recordSourceMappingStart(this);\n emitter.recordSourceMappingStart(this.id);\n emitter.writeToOutput(this.id.actualText);\n emitter.recordSourceMappingEnd(this.id);\n emitter.writeLineToOutput(\":\");\n emitter.recordSourceMappingEnd(this);\n emitter.emitParensAndCommentsInPlace(this, false);\n }\n }\n\n export class Expression extends AST {\n constructor (nodeType: NodeType) {\n super(nodeType);\n }\n\n public isExpression() { return true; }\n\n public isStatementOrExpression() { return true; }\n }\n\n export class UnaryExpression extends Expression {\n public targetType: Type = null; // Target type for an object literal (null if no target type)\n public castTerm: AST = null;\n\n constructor (nodeType: NodeType, public operand: AST) {\n super(nodeType);\n }\n\n public addToControlFlow(context: ControlFlowContext): void {\n super.addToControlFlow(context);\n // TODO: add successor as catch block/finally block if present\n if (this.nodeType == NodeType.Throw) {\n context.returnStmt();\n }\n }\n\n public typeCheck(typeFlow: TypeFlow) {\n switch (this.nodeType) {\n case NodeType.Not:\n return typeFlow.typeCheckBitNot(this);\n\n case NodeType.LogNot:\n return typeFlow.typeCheckLogNot(this);\n\n case NodeType.Pos:\n case NodeType.Neg:\n return typeFlow.typeCheckUnaryNumberOperator(this);\n\n case NodeType.IncPost:\n case NodeType.IncPre:\n case NodeType.DecPost:\n case NodeType.DecPre:\n return typeFlow.typeCheckIncOrDec(this);\n\n case NodeType.ArrayLit:\n typeFlow.typeCheckArrayLit(this);\n return this;\n\n case NodeType.ObjectLit:\n typeFlow.typeCheckObjectLit(this);\n return this;\n\n case NodeType.Throw:\n this.operand = typeFlow.typeCheck(this.operand);\n this.type = typeFlow.voidType;\n return this;\n\n case NodeType.Typeof:\n this.operand = typeFlow.typeCheck(this.operand);\n this.type = typeFlow.stringType;\n return this;\n\n case NodeType.Delete:\n this.operand = typeFlow.typeCheck(this.operand);\n this.type = typeFlow.booleanType;\n break;\n\n case NodeType.TypeAssertion:\n this.castTerm = typeFlow.typeCheck(this.castTerm);\n var applyTargetType = !this.operand.isParenthesized;\n\n var targetType = applyTargetType ? this.castTerm.type : null;\n\n typeFlow.checker.typeCheckWithContextualType(targetType, typeFlow.checker.inProvisionalTypecheckMode(), true, this.operand);\n typeFlow.castWithCoercion(this.operand, this.castTerm.type, false, true);\n this.type = this.castTerm.type;\n return this;\n\n case NodeType.Void:\n // REVIEW - Although this is good to do for completeness's sake,\n // this shouldn't be strictly necessary from the void operator's\n // point of view\n this.operand = typeFlow.typeCheck(this.operand);\n this.type = typeFlow.checker.undefinedType;\n break;\n\n default:\n throw new Error(\"please implement in derived class\");\n }\n return this;\n }\n\n public emit(emitter: Emitter, tokenId: TokenID, startLine: bool) {\n emitter.emitParensAndCommentsInPlace(this, true);\n emitter.recordSourceMappingStart(this);\n switch (this.nodeType) {\n case NodeType.IncPost:\n emitter.emitJavascript(this.operand, TokenID.PlusPlus, false);\n emitter.writeToOutput(\"++\");\n break;\n case NodeType.LogNot:\n emitter.writeToOutput(\"!\");\n emitter.emitJavascript(this.operand, TokenID.Exclamation, false);\n break;\n case NodeType.DecPost:\n emitter.emitJavascript(this.operand, TokenID.MinusMinus, false);\n emitter.writeToOutput(\"--\");\n break;\n case NodeType.ObjectLit:\n emitter.emitObjectLiteral(<ASTList>this.operand);\n break;\n case NodeType.ArrayLit:\n emitter.emitArrayLiteral(<ASTList>this.operand);\n break;\n case NodeType.Not:\n emitter.writeToOutput(\"~\");\n emitter.emitJavascript(this.operand, TokenID.Tilde, false);\n break;\n case NodeType.Neg:\n emitter.writeToOutput(\"-\");\n