From 253273820d47d1a4f278e374e1c5a2cbe1919dff Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Fri, 18 Jul 2014 16:55:11 -0700 Subject: [PATCH 01/59] initial change --- src/services/braceMatcher.ts | 116 + src/services/breakpoints.ts | 1088 ++++ src/services/classifier.ts | 194 + src/services/compiler/ast.ts | 53 + src/services/compiler/astHelpers.ts | 755 +++ src/services/compiler/astWalker.ts | 716 +++ src/services/compiler/base64.ts | 96 + src/services/compiler/bloomFilter.ts | 131 + src/services/compiler/declarationEmitter.ts | 1138 +++++ src/services/compiler/diagnostics.ts | 47 + src/services/compiler/document.ts | 151 + src/services/compiler/emitter.ts | 3797 ++++++++++++++ src/services/compiler/enumerator.ts | 6 + src/services/compiler/flags.ts | 0 src/services/compiler/hashTable.ts | 187 + src/services/compiler/identifierWalker.ts | 11 + src/services/compiler/io.ts | 64 + src/services/compiler/optionsParser.ts | 266 + src/services/compiler/pathUtils.ts | 193 + src/services/compiler/precompile.ts | 196 + src/services/compiler/process.ts | 17 + src/services/compiler/referenceResolution.ts | 28 + src/services/compiler/referenceResolver.ts | 255 + src/services/compiler/references.ts | 37 + src/services/compiler/settings.ts | 15 + src/services/compiler/sourceMapping.ts | 270 + src/services/compiler/tsc.ts | 736 +++ src/services/compiler/types.ts | 102 + src/services/compiler/typescript.ts | 1528 ++++++ src/services/compiler/walkContext.ts | 31 + src/services/compilerState.ts | 472 ++ src/services/completionHelpers.ts | 193 + src/services/completionSession.ts | 68 + src/services/core/arrayUtilities.ts | 205 + src/services/core/bitMatrix.ts | 82 + src/services/core/bitVector.ts | 210 + src/services/core/cancellationToken.ts | 3 + src/services/core/cancellationTokenSource.ts | 7 + src/services/core/constants.ts | 9 + src/services/core/debug.ts | 32 + src/services/core/diagnosticCategory.ts | 10 + src/services/core/diagnosticCore.ts | 200 + src/services/core/diagnosticInfo.ts | 9 + src/services/core/environment.ts | 505 ++ src/services/core/errors.ts | 29 + src/services/core/hash.ts | 112 + src/services/core/indexable.ts | 7 + src/services/core/integerUtilities.ts | 28 + src/services/core/iterator.ts | 8 + src/services/core/lineAndCharacter.ts | 8 + src/services/core/lineMap.ts | 82 + src/services/core/linePosition.ts | 35 + src/services/core/mathPrototype.ts | 13 + src/services/core/references.ts | 24 + src/services/core/require.ts | 5 + src/services/core/stringTable.ts | 159 + src/services/core/stringUtilities.ts | 21 + src/services/core/timer.ts | 52 + src/services/coreServices.ts | 74 + src/services/diagnosticServices.ts | 7 + src/services/diagnosticsParser.ts | 363 ++ src/services/document.ts | 6 + src/services/es5compat.ts | 354 ++ src/services/findReferenceHelpers.ts | 152 + src/services/formatting/formatter.ts | 320 ++ src/services/formatting/formatting.ts | 40 + src/services/formatting/formattingContext.ts | 116 + src/services/formatting/formattingManager.ts | 125 + .../formatting/formattingRequestKind.ts | 27 + .../formatting/indentationNodeContext.ts | 103 + .../formatting/indentationNodeContextPool.ts | 43 + .../formatting/indentationTrackingWalker.ts | 349 ++ .../formatting/multipleTokenIndenter.ts | 206 + src/services/formatting/rule.ts | 32 + src/services/formatting/ruleAction.ts | 25 + src/services/formatting/ruleDescriptor.ts | 46 + src/services/formatting/ruleFlag.ts | 23 + src/services/formatting/ruleOperation.ts | 44 + .../formatting/ruleOperationContext.ts | 47 + src/services/formatting/rules.ts | 678 +++ src/services/formatting/rulesMap.ts | 189 + src/services/formatting/rulesProvider.ts | 117 + .../formatting/singleTokenIndenter.ts | 46 + src/services/formatting/snapshotPoint.ts | 30 + src/services/formatting/textEditInfo.ts | 28 + src/services/formatting/textSnapshot.ts | 84 + src/services/formatting/textSnapshotLine.ts | 80 + src/services/formatting/tokenRange.ts | 152 + src/services/formatting/tokenSpan.ts | 25 + .../getScriptLexicalStructureWalker.ts | 352 ++ src/services/indentation.ts | 155 + src/services/indenter.ts | 207 + src/services/keywordCompletions.ts | 73 + src/services/languageService.ts | 345 ++ src/services/languageServiceCopy.ts | 342 ++ src/services/outliningElementsCollector.ts | 109 + src/services/pullLanguageService.ts | 733 +++ src/services/references.ts | 26 + .../resources/diagnosticCode.generated.ts | 445 ++ .../diagnosticInformationMap.generated.ts | 446 ++ .../resources/diagnosticMessages.json | 1766 +++++++ src/services/resources/references.ts | 2 + src/services/shims.ts | 796 ++- src/services/signatureInfoHelpers.ts | 348 ++ src/services/syntax/SyntaxGenerator.d.ts | 1139 +++++ src/services/syntax/characterInfo.ts | 70 + src/services/syntax/constants.ts | 26 + .../syntax/defaultSyntaxVisitor.generated.ts | 353 ++ src/services/syntax/depthLimitedWalker.ts | 21 + src/services/syntax/emitter.ts | 1246 +++++ src/services/syntax/formattingOptions.ts | 13 + src/services/syntax/incrementalParser.ts | 865 ++++ src/services/syntax/languageVersion.ts | 3 + src/services/syntax/parser.ts | 4385 +++++++++++++++++ src/services/syntax/prettyPrinter.ts | 1007 ++++ src/services/syntax/references.ts | 49 + src/services/syntax/scanner.ts | 1678 +++++++ .../syntax/scannerUtilities.generated.ts | 142 + src/services/syntax/slidingWindow.ts | 189 + src/services/syntax/syntax.ts | 283 ++ src/services/syntax/syntaxDedenter.ts | 193 + src/services/syntax/syntaxElement.ts | 557 +++ src/services/syntax/syntaxFacts.ts | 301 ++ src/services/syntax/syntaxFacts2.ts | 29 + src/services/syntax/syntaxGenerator.ts | 2883 +++++++++++ src/services/syntax/syntaxIndenter.ts | 164 + .../syntax/syntaxInterfaces.generated.ts | 499 ++ src/services/syntax/syntaxKind.ts | 337 ++ src/services/syntax/syntaxList.ts | 95 + src/services/syntax/syntaxNode.ts | 19 + .../syntax/syntaxNodeInvariantsChecker.ts | 39 + src/services/syntax/syntaxNodeOrToken.ts | 6 + .../syntax/syntaxNodes.abstract.generated.ts | 1194 +++++ .../syntax/syntaxNodes.concrete.generated.ts | 1424 ++++++ .../syntaxNodes.interfaces.generated.ts | 573 +++ src/services/syntax/syntaxToken.ts | 547 ++ src/services/syntax/syntaxTree.ts | 1615 ++++++ src/services/syntax/syntaxTrivia.ts | 178 + src/services/syntax/syntaxTriviaList.ts | 246 + src/services/syntax/syntaxUtilities.ts | 336 ++ .../syntax/syntaxVisitor.generated.ts | 190 + src/services/syntax/syntaxWalker.generated.ts | 618 +++ src/services/syntax/testUtilities.ts | 209 + src/services/syntax/unicode.ts | 107 + src/services/syntaxRewriter.generated.ts | 708 +++ src/services/syntaxUtilities.generated.ts | 395 ++ src/services/text/characterCodes.ts | 138 + src/services/text/lineMap.ts | 17 + src/services/text/references.ts | 12 + src/services/text/scriptSnapshot.ts | 57 + src/services/text/text.ts | 21 + src/services/text/textChangeRange.ts | 168 + src/services/text/textFactory.ts | 66 + src/services/text/textSpan.ts | 141 + src/services/text/textUtilities.ts | 94 + src/services/typescriptServices.ts | 243 + 156 files changed, 50722 insertions(+), 54 deletions(-) create mode 100644 src/services/braceMatcher.ts create mode 100644 src/services/breakpoints.ts create mode 100644 src/services/classifier.ts create mode 100644 src/services/compiler/ast.ts create mode 100644 src/services/compiler/astHelpers.ts create mode 100644 src/services/compiler/astWalker.ts create mode 100644 src/services/compiler/base64.ts create mode 100644 src/services/compiler/bloomFilter.ts create mode 100644 src/services/compiler/declarationEmitter.ts create mode 100644 src/services/compiler/diagnostics.ts create mode 100644 src/services/compiler/document.ts create mode 100644 src/services/compiler/emitter.ts create mode 100644 src/services/compiler/enumerator.ts create mode 100644 src/services/compiler/flags.ts create mode 100644 src/services/compiler/hashTable.ts create mode 100644 src/services/compiler/identifierWalker.ts create mode 100644 src/services/compiler/io.ts create mode 100644 src/services/compiler/optionsParser.ts create mode 100644 src/services/compiler/pathUtils.ts create mode 100644 src/services/compiler/precompile.ts create mode 100644 src/services/compiler/process.ts create mode 100644 src/services/compiler/referenceResolution.ts create mode 100644 src/services/compiler/referenceResolver.ts create mode 100644 src/services/compiler/references.ts create mode 100644 src/services/compiler/settings.ts create mode 100644 src/services/compiler/sourceMapping.ts create mode 100644 src/services/compiler/tsc.ts create mode 100644 src/services/compiler/types.ts create mode 100644 src/services/compiler/typescript.ts create mode 100644 src/services/compiler/walkContext.ts create mode 100644 src/services/compilerState.ts create mode 100644 src/services/completionHelpers.ts create mode 100644 src/services/completionSession.ts create mode 100644 src/services/core/arrayUtilities.ts create mode 100644 src/services/core/bitMatrix.ts create mode 100644 src/services/core/bitVector.ts create mode 100644 src/services/core/cancellationToken.ts create mode 100644 src/services/core/cancellationTokenSource.ts create mode 100644 src/services/core/constants.ts create mode 100644 src/services/core/debug.ts create mode 100644 src/services/core/diagnosticCategory.ts create mode 100644 src/services/core/diagnosticCore.ts create mode 100644 src/services/core/diagnosticInfo.ts create mode 100644 src/services/core/environment.ts create mode 100644 src/services/core/errors.ts create mode 100644 src/services/core/hash.ts create mode 100644 src/services/core/indexable.ts create mode 100644 src/services/core/integerUtilities.ts create mode 100644 src/services/core/iterator.ts create mode 100644 src/services/core/lineAndCharacter.ts create mode 100644 src/services/core/lineMap.ts create mode 100644 src/services/core/linePosition.ts create mode 100644 src/services/core/mathPrototype.ts create mode 100644 src/services/core/references.ts create mode 100644 src/services/core/require.ts create mode 100644 src/services/core/stringTable.ts create mode 100644 src/services/core/stringUtilities.ts create mode 100644 src/services/core/timer.ts create mode 100644 src/services/coreServices.ts create mode 100644 src/services/diagnosticServices.ts create mode 100644 src/services/diagnosticsParser.ts create mode 100644 src/services/document.ts create mode 100644 src/services/es5compat.ts create mode 100644 src/services/findReferenceHelpers.ts create mode 100644 src/services/formatting/formatter.ts create mode 100644 src/services/formatting/formatting.ts create mode 100644 src/services/formatting/formattingContext.ts create mode 100644 src/services/formatting/formattingManager.ts create mode 100644 src/services/formatting/formattingRequestKind.ts create mode 100644 src/services/formatting/indentationNodeContext.ts create mode 100644 src/services/formatting/indentationNodeContextPool.ts create mode 100644 src/services/formatting/indentationTrackingWalker.ts create mode 100644 src/services/formatting/multipleTokenIndenter.ts create mode 100644 src/services/formatting/rule.ts create mode 100644 src/services/formatting/ruleAction.ts create mode 100644 src/services/formatting/ruleDescriptor.ts create mode 100644 src/services/formatting/ruleFlag.ts create mode 100644 src/services/formatting/ruleOperation.ts create mode 100644 src/services/formatting/ruleOperationContext.ts create mode 100644 src/services/formatting/rules.ts create mode 100644 src/services/formatting/rulesMap.ts create mode 100644 src/services/formatting/rulesProvider.ts create mode 100644 src/services/formatting/singleTokenIndenter.ts create mode 100644 src/services/formatting/snapshotPoint.ts create mode 100644 src/services/formatting/textEditInfo.ts create mode 100644 src/services/formatting/textSnapshot.ts create mode 100644 src/services/formatting/textSnapshotLine.ts create mode 100644 src/services/formatting/tokenRange.ts create mode 100644 src/services/formatting/tokenSpan.ts create mode 100644 src/services/getScriptLexicalStructureWalker.ts create mode 100644 src/services/indentation.ts create mode 100644 src/services/indenter.ts create mode 100644 src/services/keywordCompletions.ts create mode 100644 src/services/languageService.ts create mode 100644 src/services/languageServiceCopy.ts create mode 100644 src/services/outliningElementsCollector.ts create mode 100644 src/services/pullLanguageService.ts create mode 100644 src/services/references.ts create mode 100644 src/services/resources/diagnosticCode.generated.ts create mode 100644 src/services/resources/diagnosticInformationMap.generated.ts create mode 100644 src/services/resources/diagnosticMessages.json create mode 100644 src/services/resources/references.ts create mode 100644 src/services/signatureInfoHelpers.ts create mode 100644 src/services/syntax/SyntaxGenerator.d.ts create mode 100644 src/services/syntax/characterInfo.ts create mode 100644 src/services/syntax/constants.ts create mode 100644 src/services/syntax/defaultSyntaxVisitor.generated.ts create mode 100644 src/services/syntax/depthLimitedWalker.ts create mode 100644 src/services/syntax/emitter.ts create mode 100644 src/services/syntax/formattingOptions.ts create mode 100644 src/services/syntax/incrementalParser.ts create mode 100644 src/services/syntax/languageVersion.ts create mode 100644 src/services/syntax/parser.ts create mode 100644 src/services/syntax/prettyPrinter.ts create mode 100644 src/services/syntax/references.ts create mode 100644 src/services/syntax/scanner.ts create mode 100644 src/services/syntax/scannerUtilities.generated.ts create mode 100644 src/services/syntax/slidingWindow.ts create mode 100644 src/services/syntax/syntax.ts create mode 100644 src/services/syntax/syntaxDedenter.ts create mode 100644 src/services/syntax/syntaxElement.ts create mode 100644 src/services/syntax/syntaxFacts.ts create mode 100644 src/services/syntax/syntaxFacts2.ts create mode 100644 src/services/syntax/syntaxGenerator.ts create mode 100644 src/services/syntax/syntaxIndenter.ts create mode 100644 src/services/syntax/syntaxInterfaces.generated.ts create mode 100644 src/services/syntax/syntaxKind.ts create mode 100644 src/services/syntax/syntaxList.ts create mode 100644 src/services/syntax/syntaxNode.ts create mode 100644 src/services/syntax/syntaxNodeInvariantsChecker.ts create mode 100644 src/services/syntax/syntaxNodeOrToken.ts create mode 100644 src/services/syntax/syntaxNodes.abstract.generated.ts create mode 100644 src/services/syntax/syntaxNodes.concrete.generated.ts create mode 100644 src/services/syntax/syntaxNodes.interfaces.generated.ts create mode 100644 src/services/syntax/syntaxToken.ts create mode 100644 src/services/syntax/syntaxTree.ts create mode 100644 src/services/syntax/syntaxTrivia.ts create mode 100644 src/services/syntax/syntaxTriviaList.ts create mode 100644 src/services/syntax/syntaxUtilities.ts create mode 100644 src/services/syntax/syntaxVisitor.generated.ts create mode 100644 src/services/syntax/syntaxWalker.generated.ts create mode 100644 src/services/syntax/testUtilities.ts create mode 100644 src/services/syntax/unicode.ts create mode 100644 src/services/syntaxRewriter.generated.ts create mode 100644 src/services/syntaxUtilities.generated.ts create mode 100644 src/services/text/characterCodes.ts create mode 100644 src/services/text/lineMap.ts create mode 100644 src/services/text/references.ts create mode 100644 src/services/text/scriptSnapshot.ts create mode 100644 src/services/text/text.ts create mode 100644 src/services/text/textChangeRange.ts create mode 100644 src/services/text/textFactory.ts create mode 100644 src/services/text/textSpan.ts create mode 100644 src/services/text/textUtilities.ts create mode 100644 src/services/typescriptServices.ts diff --git a/src/services/braceMatcher.ts b/src/services/braceMatcher.ts new file mode 100644 index 00000000000..0cb336d4dc2 --- /dev/null +++ b/src/services/braceMatcher.ts @@ -0,0 +1,116 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services { + export class BraceMatcher { + + // Given a script name and position in the script, return a pair of text range if the + // position corresponds to a "brace matchin" characters (e.g. "{" or "(", etc.) + // If the position is not on any range, return an empty set. + public static getMatchSpans(syntaxTree: TypeScript.SyntaxTree, position: number): TypeScript.TextSpan[] { + var result: TypeScript.TextSpan[] = []; + + var currentToken = findToken(syntaxTree.sourceUnit(), position); + + BraceMatcher.getMatchingCloseBrace(currentToken, position, result); + BraceMatcher.getMatchingOpenBrace(currentToken, position, result); + + return result; + } + + private static getMatchingCloseBrace(currentToken: TypeScript.ISyntaxToken, position: number, result: TypeScript.TextSpan[]) { + if (start(currentToken) === position) { + var closingBraceKind = BraceMatcher.getMatchingCloseBraceTokenKind(currentToken); + if (closingBraceKind !== null) { + var parentElement = currentToken.parent + var currentPosition = fullStart(currentToken.parent); + for (var i = 0, n = childCount(parentElement); i < n; i++) { + var element = childAt(parentElement, i); + if (element !== null && fullWidth(element) > 0) { + if (element.kind() === closingBraceKind) { + var range1 = new TypeScript.TextSpan(position, width(currentToken)); + var range2 = new TypeScript.TextSpan(currentPosition + leadingTriviaWidth(element), width(element)); + result.push(range1, range2); + break; + } + + currentPosition += fullWidth(element); + } + } + } + } + } + + private static getMatchingOpenBrace(currentToken: TypeScript.ISyntaxToken, position: number, result: TypeScript.TextSpan[]) { + // Check if the current token to the left is a close brace + if (currentToken.fullStart() === position) { + currentToken = previousToken(currentToken); + } + + if (currentToken !== null && start(currentToken) === (position - 1)) { + var openBraceKind = BraceMatcher.getMatchingOpenBraceTokenKind(currentToken); + if (openBraceKind !== null) { + var parentElement = currentToken.parent; + var currentPosition = fullStart(currentToken.parent) + fullWidth(parentElement); + for (var i = childCount(parentElement) - 1 ; i >= 0; i--) { + var element = childAt(parentElement, i); + if (element !== null && fullWidth(element) > 0) { + if (element.kind() === openBraceKind) { + var range1 = new TypeScript.TextSpan(position - 1, width(currentToken)); + var range2 = new TypeScript.TextSpan(currentPosition - lastToken(element).trailingTriviaWidth() - width(element), width(element)); + result.push(range1, range2); + break; + } + + currentPosition -= fullWidth(element); + } + } + } + } + } + + private static getMatchingCloseBraceTokenKind(positionedElement: TypeScript.ISyntaxElement): TypeScript.SyntaxKind { + var element = positionedElement !== null && positionedElement; + switch (element.kind()) { + case TypeScript.SyntaxKind.OpenBraceToken: + return TypeScript.SyntaxKind.CloseBraceToken + case TypeScript.SyntaxKind.OpenParenToken: + return TypeScript.SyntaxKind.CloseParenToken; + case TypeScript.SyntaxKind.OpenBracketToken: + return TypeScript.SyntaxKind.CloseBracketToken; + case TypeScript.SyntaxKind.LessThanToken: + return TypeScript.SyntaxUtilities.isAngleBracket(positionedElement) ? TypeScript.SyntaxKind.GreaterThanToken : null; + } + return null; + } + + private static getMatchingOpenBraceTokenKind(positionedElement: TypeScript.ISyntaxElement): TypeScript.SyntaxKind { + var element = positionedElement !== null && positionedElement; + switch (element.kind()) { + case TypeScript.SyntaxKind.CloseBraceToken: + return TypeScript.SyntaxKind.OpenBraceToken + case TypeScript.SyntaxKind.CloseParenToken: + return TypeScript.SyntaxKind.OpenParenToken; + case TypeScript.SyntaxKind.CloseBracketToken: + return TypeScript.SyntaxKind.OpenBracketToken; + case TypeScript.SyntaxKind.GreaterThanToken: + return TypeScript.SyntaxUtilities.isAngleBracket(positionedElement) ? TypeScript.SyntaxKind.LessThanToken : null; + } + return null; + } + } +} diff --git a/src/services/breakpoints.ts b/src/services/breakpoints.ts new file mode 100644 index 00000000000..c1e3535d432 --- /dev/null +++ b/src/services/breakpoints.ts @@ -0,0 +1,1088 @@ +// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0. +// See LICENSE.txt in the project root for complete license information. + +/// + +module TypeScript.Services.Breakpoints { + function createBreakpointSpanInfo(parentElement: TypeScript.ISyntaxElement, ...childElements: TypeScript.ISyntaxElement[]): SpanInfo { + if (!parentElement) { + return null; + } + + if (childElements.length == 0) { + return new SpanInfo(TypeScript.start(parentElement), TypeScript.end(parentElement)); + } + + var start: number; + var end: number; + for (var i = 0; i < childElements.length; i++) { + var element = childElements[i]; + if (element && !isShared(element)) { + if (start == undefined) { + start = TypeScript.start(element); + } + end = TypeScript.end(element); + } + } + + return new SpanInfo(start, end); + } + + function createBreakpointSpanInfoWithLimChar(startElement: TypeScript.ISyntaxElement, limChar: number): SpanInfo { + return new SpanInfo(start(startElement), limChar); + } + + class BreakpointResolver { + constructor(private posLine: number, private lineMap: TypeScript.LineMap) { + } + + private breakpointSpanOfToken(positionedToken: TypeScript.ISyntaxToken): SpanInfo { + switch (positionedToken.kind()) { + case TypeScript.SyntaxKind.OpenBraceToken: + return this.breakpointSpanOfOpenBrace(positionedToken); + + case TypeScript.SyntaxKind.CloseBraceToken: + return this.breakpointSpanOfCloseBrace(positionedToken); + + case TypeScript.SyntaxKind.CommaToken: + return this.breakpointSpanOfComma(positionedToken); + + case TypeScript.SyntaxKind.SemicolonToken: + case TypeScript.SyntaxKind.EndOfFileToken: + return this.breakpointSpanIfStartsOnSameLine(previousToken(positionedToken)); + + case TypeScript.SyntaxKind.CloseParenToken: + return this.breakpointSpanOfCloseParen(positionedToken); + + case TypeScript.SyntaxKind.DoKeyword: + var parentElement = positionedToken.parent; + if (parentElement && parentElement.kind() == TypeScript.SyntaxKind.DoStatement) { + return this.breakpointSpanIfStartsOnSameLine(nextToken(positionedToken)); + } + break; + } + + return this.breakpointSpanOfContainingNode(positionedToken); + } + + private breakpointSpanOfOpenBrace(openBraceToken: TypeScript.ISyntaxToken): SpanInfo { + var container = Syntax.containingNode(openBraceToken); + if (container) { + var originalContainer = container; + if (container && container.kind() == TypeScript.SyntaxKind.Block) { + // We have to check the parent and decide what to do with the breakpoint + container = Syntax.containingNode(container); + if (!container) { + container = originalContainer; + } + } + + switch (container.kind()) { + case TypeScript.SyntaxKind.Block: + if (!this.canHaveBreakpointInBlock(container)) { + return null; + } + return this.breakpointSpanOfFirstStatementInBlock(container); + break; + + case TypeScript.SyntaxKind.ModuleDeclaration: + case TypeScript.SyntaxKind.ClassDeclaration: + case TypeScript.SyntaxKind.FunctionDeclaration: + case TypeScript.SyntaxKind.ConstructorDeclaration: + case TypeScript.SyntaxKind.MemberFunctionDeclaration: + case TypeScript.SyntaxKind.GetAccessor: + case TypeScript.SyntaxKind.SetAccessor: + case TypeScript.SyntaxKind.FunctionExpression: + case TypeScript.SyntaxKind.ParenthesizedArrowFunctionExpression: + case TypeScript.SyntaxKind.SimpleArrowFunctionExpression: + if (!this.canHaveBreakpointInDeclaration(container)) { + return null; + } + if (this.posLine != this.lineMap.getLineNumberFromPosition(start(container))) { + return this.breakpointSpanOfFirstChildOfSyntaxList(this.getSyntaxListOfDeclarationWithElements(container)); + } + else { + return this.breakpointSpanOf(container); + } + + case TypeScript.SyntaxKind.EnumDeclaration: + if (!this.canHaveBreakpointInDeclaration(container)) { + return null; + } + if (this.posLine != this.lineMap.getLineNumberFromPosition(start(container))) { + return this.breakpointSpanOfFirstEnumElement(container); + } + else { + return this.breakpointSpanOf(container); + } + + case TypeScript.SyntaxKind.IfStatement: + case TypeScript.SyntaxKind.ForInStatement: + case TypeScript.SyntaxKind.WhileStatement: + case TypeScript.SyntaxKind.CatchClause: + if (this.posLine != this.lineMap.getLineNumberFromPosition(start(container))) { + return this.breakpointSpanOfFirstStatementInBlock(originalContainer); + } + else { + return this.breakpointSpanOf(container); + } + + case TypeScript.SyntaxKind.DoStatement: + return this.breakpointSpanOfFirstStatementInBlock(originalContainer); + + case TypeScript.SyntaxKind.ForStatement: + if (this.posLine != this.lineMap.getLineNumberFromPosition(start(container))) { + return this.breakpointSpanOfFirstStatementInBlock(originalContainer); + } + else { + return this.breakpointSpanOf(previousToken(openBraceToken)); + } + + case TypeScript.SyntaxKind.ElseClause: + case TypeScript.SyntaxKind.CaseSwitchClause: + case TypeScript.SyntaxKind.DefaultSwitchClause: + case TypeScript.SyntaxKind.WithStatement: + case TypeScript.SyntaxKind.TryStatement: + case TypeScript.SyntaxKind.FinallyClause: + return this.breakpointSpanOfFirstStatementInBlock(originalContainer); + + case TypeScript.SyntaxKind.SwitchStatement: + if (this.posLine != this.lineMap.getLineNumberFromPosition(start(container))) { + return this.breakpointSpanOfFirstStatementOfFirstCaseClause(container); + } + else { + return this.breakpointSpanOf(container); + } + } + } + + return null; + } + + private breakpointSpanOfCloseBrace(closeBraceToken: TypeScript.ISyntaxToken): SpanInfo { + var container = Syntax.containingNode(closeBraceToken); + if (container) { + var originalContainer = container; + if (container.kind() == TypeScript.SyntaxKind.Block) { + // We have to check the parent and decide what to do with the breakpoint + container = Syntax.containingNode(container); + if (!container) { + container = originalContainer; + } + } + + switch (container.kind()) { + case TypeScript.SyntaxKind.Block: + if (!this.canHaveBreakpointInBlock(container)) { + return null; + } + return this.breakpointSpanOfLastStatementInBlock(container); + break; + + case TypeScript.SyntaxKind.ModuleDeclaration: + if (!this.canHaveBreakpointInDeclaration(container)) { + return null; + } + var moduleSyntax = container; + if (moduleSyntax.moduleElements && moduleSyntax.moduleElements.length > 0) { + return createBreakpointSpanInfo(closeBraceToken); + } + else { + return null; + } + + case TypeScript.SyntaxKind.ClassDeclaration: + case TypeScript.SyntaxKind.FunctionDeclaration: + case TypeScript.SyntaxKind.ConstructorDeclaration: + case TypeScript.SyntaxKind.MemberFunctionDeclaration: + case TypeScript.SyntaxKind.GetAccessor: + case TypeScript.SyntaxKind.SetAccessor: + case TypeScript.SyntaxKind.FunctionExpression: + if (!this.canHaveBreakpointInDeclaration(container)) { + return null; + } + return createBreakpointSpanInfo(closeBraceToken); + + case TypeScript.SyntaxKind.EnumDeclaration: + if (!this.canHaveBreakpointInDeclaration(container)) { + return null; + } + return createBreakpointSpanInfo(closeBraceToken); + + case TypeScript.SyntaxKind.IfStatement: + case TypeScript.SyntaxKind.ElseClause: + case TypeScript.SyntaxKind.ForInStatement: + case TypeScript.SyntaxKind.ForStatement: + case TypeScript.SyntaxKind.WhileStatement: + case TypeScript.SyntaxKind.DoStatement: + case TypeScript.SyntaxKind.CaseSwitchClause: + case TypeScript.SyntaxKind.DefaultSwitchClause: + case TypeScript.SyntaxKind.WithStatement: + case TypeScript.SyntaxKind.TryStatement: + case TypeScript.SyntaxKind.CatchClause: + case TypeScript.SyntaxKind.FinallyClause: + case TypeScript.SyntaxKind.ParenthesizedArrowFunctionExpression: + case TypeScript.SyntaxKind.SimpleArrowFunctionExpression: + return this.breakpointSpanOfLastStatementInBlock(originalContainer); + + case TypeScript.SyntaxKind.SwitchStatement: + return this.breakpointSpanOfLastStatementOfLastCaseClause(container); + } + } + + return null; + } + + + private breakpointSpanOfComma(commaToken: TypeScript.ISyntaxToken): SpanInfo { + var commaParent = commaToken.parent; + if (isSeparatedList(commaParent)) { + var grandParent = commaParent.parent; + if (grandParent) { + switch (grandParent.kind()) { + case TypeScript.SyntaxKind.VariableDeclaration: + case TypeScript.SyntaxKind.EnumDeclaration: + case TypeScript.SyntaxKind.ParameterList: + var index = Syntax.childIndex(commaParent, commaToken); + // Use the previous child + if (index > 0) { + var child = childAt(commaParent, index - 1); + return this.breakpointSpanOf(child); + } + + // If we cant set breakpoint on enum element, just dont set breakpoint + if (grandParent.kind() == TypeScript.SyntaxKind.EnumDeclaration) { + return null; + } + break; + } + } + } + + return this.breakpointSpanOfContainingNode(commaToken); + } + + private breakpointSpanOfCloseParen(closeParenToken: TypeScript.ISyntaxToken): SpanInfo { + var closeParenParent = closeParenToken.parent; + if (closeParenParent) { + switch (closeParenParent.kind()) { + case TypeScript.SyntaxKind.ForStatement: + case TypeScript.SyntaxKind.ParameterList: + return this.breakpointSpanOf(previousToken(closeParenToken)); + } + } + + return this.breakpointSpanOfContainingNode(closeParenToken); + } + + private canHaveBreakpointInBlock(blockNode: TypeScript.ISyntaxNode) { + if (!blockNode || TypeScript.SyntaxUtilities.isAmbientDeclarationSyntax(blockNode)) { + return false; + } + + var blockSyntax = blockNode; + return blockSyntax.statements && blockSyntax.statements.length != 0; + } + + private breakpointSpanOfFirstStatementInBlock(blockNode: TypeScript.ISyntaxNode): SpanInfo { + if (!blockNode) { + return null; + } + + var blockSyntax = blockNode; + var statementsNode = blockSyntax.statements; + if (!statementsNode || statementsNode.length == 0) { + return null; + } + + var firstStatement = childAt(statementsNode, 0); + if (firstStatement && firstStatement.kind() == TypeScript.SyntaxKind.Block) { + if (this.canHaveBreakpointInBlock(firstStatement)) { + return this.breakpointSpanOfFirstStatementInBlock(firstStatement); + } + return null; + } + else { + return this.breakpointSpanOf(firstStatement); + } + } + + private breakpointSpanOfLastStatementInBlock(blockNode: TypeScript.ISyntaxNode): SpanInfo { + if (!blockNode) { + return null; + } + + var blockSyntax = blockNode; + var statementsNode = blockSyntax.statements; + if (!statementsNode || statementsNode.length == 0) { + return null; + } + + var lastStatement = childAt(statementsNode, statementsNode.length - 1); + if (lastStatement && lastStatement.kind() == TypeScript.SyntaxKind.Block) { + if (this.canHaveBreakpointInBlock(lastStatement)) { + return this.breakpointSpanOfLastStatementInBlock(lastStatement); + } + return null; + } + else { + return this.breakpointSpanOf(lastStatement); + } + } + + private breakpointSpanOfFirstChildOfSyntaxList(positionedList: TypeScript.ISyntaxNodeOrToken[]): SpanInfo { + if (!positionedList) { + return null; + } + + // Find the first syntax element + var listSyntax = positionedList; + if (listSyntax.length == 0) { + return null; + } + + var firstStatement = childAt(positionedList, 0); + if (firstStatement && firstStatement.kind() == TypeScript.SyntaxKind.Block) { + if (this.canHaveBreakpointInBlock(firstStatement)) { + return this.breakpointSpanOfFirstStatementInBlock(firstStatement); + } + + return null; + } + else { + return this.breakpointSpanOf(firstStatement); + } + } + + private breakpointSpanOfLastChildOfSyntaxList(positionedList: TypeScript.ISyntaxNodeOrToken[]): SpanInfo { + if (!positionedList) { + return null; + } + + // Find the first syntax element + var listSyntax = positionedList; + if (listSyntax.length == 0) { + return null; + } + var lastStatement = childAt(positionedList, 0); + if (lastStatement && lastStatement.kind() == TypeScript.SyntaxKind.Block) { + if (this.canHaveBreakpointInBlock(lastStatement)) { + return this.breakpointSpanOfLastStatementInBlock(lastStatement); + } + return null; + } + else { + return this.breakpointSpanOf(lastStatement); + } + } + + private breakpointSpanOfNode(positionedNode: TypeScript.ISyntaxNode): SpanInfo { + var node = positionedNode; + switch (node.kind()) { + // Declarations with elements + case TypeScript.SyntaxKind.ModuleDeclaration: + case TypeScript.SyntaxKind.ClassDeclaration: + case TypeScript.SyntaxKind.FunctionDeclaration: + case TypeScript.SyntaxKind.ConstructorDeclaration: + case TypeScript.SyntaxKind.MemberFunctionDeclaration: + case TypeScript.SyntaxKind.GetAccessor: + case TypeScript.SyntaxKind.SetAccessor: + case TypeScript.SyntaxKind.FunctionExpression: + return this.breakpointSpanOfDeclarationWithElements(positionedNode); + + // Var, parameter and member variable declaration syntax + case TypeScript.SyntaxKind.VariableDeclarator: + return this.breakpointSpanOfVariableDeclarator(positionedNode); + + case TypeScript.SyntaxKind.VariableDeclaration: + return this.breakpointSpanOfVariableDeclaration(positionedNode); + + case TypeScript.SyntaxKind.VariableStatement: + return this.breakpointSpanOfVariableStatement(positionedNode); + + case TypeScript.SyntaxKind.Parameter: + return this.breakpointSpanOfParameter(positionedNode); + + case TypeScript.SyntaxKind.MemberVariableDeclaration: + return this.breakpointSpanOfMemberVariableDeclaration(positionedNode); + + case TypeScript.SyntaxKind.ImportDeclaration: + return this.breakpointSpanOfImportDeclaration(positionedNode); + + case TypeScript.SyntaxKind.EnumDeclaration: + return this.breakpointSpanOfEnumDeclaration(positionedNode); + + case TypeScript.SyntaxKind.EnumElement: + return this.breakpointSpanOfEnumElement(positionedNode); + + // Statements + case TypeScript.SyntaxKind.IfStatement: + return this.breakpointSpanOfIfStatement(positionedNode); + case TypeScript.SyntaxKind.ElseClause: + return this.breakpointSpanOfElseClause(positionedNode); + case TypeScript.SyntaxKind.ForInStatement: + return this.breakpointSpanOfForInStatement(positionedNode); + case TypeScript.SyntaxKind.ForStatement: + return this.breakpointSpanOfForStatement(positionedNode); + case TypeScript.SyntaxKind.WhileStatement: + return this.breakpointSpanOfWhileStatement(positionedNode); + case TypeScript.SyntaxKind.DoStatement: + return this.breakpointSpanOfDoStatement(positionedNode); + case TypeScript.SyntaxKind.SwitchStatement: + return this.breakpointSpanOfSwitchStatement(positionedNode); + case TypeScript.SyntaxKind.CaseSwitchClause: + return this.breakpointSpanOfCaseSwitchClause(positionedNode); + case TypeScript.SyntaxKind.DefaultSwitchClause: + return this.breakpointSpanOfDefaultSwitchClause(positionedNode); + case TypeScript.SyntaxKind.WithStatement: + return this.breakpointSpanOfWithStatement(positionedNode); + case TypeScript.SyntaxKind.TryStatement: + return this.breakpointSpanOfTryStatement(positionedNode); + case TypeScript.SyntaxKind.CatchClause: + return this.breakpointSpanOfCatchClause(positionedNode); + case TypeScript.SyntaxKind.FinallyClause: + return this.breakpointSpanOfFinallyClause(positionedNode); + + // Arrow expressions + case TypeScript.SyntaxKind.ParenthesizedArrowFunctionExpression: + return this.breakpointSpanOfParenthesizedArrowFunctionExpression(positionedNode); + + case TypeScript.SyntaxKind.SimpleArrowFunctionExpression: + return this.breakpointSpanOfSimpleArrowFunctionExpression(positionedNode); + + // Expressions or statements + default: + if (SyntaxUtilities.isStatement(node)) { + return this.breakpointSpanOfStatement(positionedNode); + } + else { + return this.breakpointOfExpression(positionedNode); + } + } + } + + private isExpressionOfArrowExpressions(expression: ISyntaxElement): boolean { + if (!expression) { + return false; + } + + var expressionParent = expression.parent; + if (expressionParent) { + if (expressionParent.kind() == TypeScript.SyntaxKind.ParenthesizedArrowFunctionExpression) { + var parenthesizedArrowExpression = expressionParent; + var expressionOfParenthesizedArrowExpression = parenthesizedArrowExpression.expression; + return expressionOfParenthesizedArrowExpression == expression; + } + else if (expressionParent.kind() == TypeScript.SyntaxKind.SimpleArrowFunctionExpression) { + var simpleArrowExpression = expressionParent; + var expressionOfSimpleArrowExpression = simpleArrowExpression.expression; + return expressionOfSimpleArrowExpression == expression; + } + else if (expressionParent.kind() == TypeScript.SyntaxKind.CommaExpression) { + return this.isExpressionOfArrowExpressions(expressionParent); + } + } + return false; + } + + private isInitializerOfForStatement(expressionNode: TypeScript.ISyntaxNode): boolean { + if (!expressionNode) { + return false; + } + + var expressionParent = expressionNode.parent; + if (expressionParent && expressionParent.kind() == TypeScript.SyntaxKind.ForStatement) { + + var expression = expressionNode; + var forStatement = expressionParent; + var initializer = forStatement.initializer; + return initializer === expression; + } + else if (expressionParent && expressionParent.kind() == TypeScript.SyntaxKind.CommaExpression) { + return this.isInitializerOfForStatement(expressionParent); + } + + return false; + } + + private isConditionOfForStatement(expressionNode: TypeScript.ISyntaxNode): boolean { + if (!expressionNode) { + return false; + } + + var expressionParent = expressionNode.parent; + if (expressionParent && expressionParent.kind() == TypeScript.SyntaxKind.ForStatement) { + var expression = expressionNode; + var forStatement = expressionParent; + var condition = forStatement.condition; + return condition === expression; + } + else if (expressionParent && expressionParent.kind() == TypeScript.SyntaxKind.CommaExpression) { + return this.isConditionOfForStatement(expressionParent); + } + + return false; + } + + private isIncrememtorOfForStatement(expressionNode: TypeScript.ISyntaxNode): boolean { + if (!expressionNode) { + return false; + } + + var expressionParent = expressionNode.parent; + if (expressionParent && expressionParent.kind() == TypeScript.SyntaxKind.ForStatement) { + var expression = expressionNode; + var forStatement = expressionParent; + var incrementor = forStatement.incrementor; + return incrementor === expression; + } + else if (expressionParent && expressionParent.kind() == TypeScript.SyntaxKind.CommaExpression) { + return this.isIncrememtorOfForStatement(expressionParent); + } + + return false; + } + + private breakpointOfLeftOfCommaExpression(commaExpressionNode: TypeScript.ISyntaxNode): SpanInfo { + var commaExpression = commaExpressionNode; + return this.breakpointSpanOf(commaExpression.left); + } + + private breakpointOfExpression(expressionNode: TypeScript.ISyntaxNode): SpanInfo { + if (this.isInitializerOfForStatement(expressionNode) || + this.isConditionOfForStatement(expressionNode) || + this.isIncrememtorOfForStatement(expressionNode)) { + if (expressionNode.kind() == TypeScript.SyntaxKind.CommaExpression) { + return this.breakpointOfLeftOfCommaExpression(expressionNode); + } + return createBreakpointSpanInfo(expressionNode); + } + + if (this.isExpressionOfArrowExpressions(expressionNode)) { + if (expressionNode.kind() == TypeScript.SyntaxKind.CommaExpression) { + return this.breakpointOfLeftOfCommaExpression(expressionNode); + } + return createBreakpointSpanInfo(expressionNode); + } + + if (expressionNode.kind() == TypeScript.SyntaxKind.ExportAssignment) { + var exportAssignmentSyntax = expressionNode; + return createBreakpointSpanInfo(expressionNode, exportAssignmentSyntax.exportKeyword, exportAssignmentSyntax.equalsToken, exportAssignmentSyntax.identifier); + } + + return this.breakpointSpanOfContainingNode(expressionNode); + } + + private breakpointSpanOfStatement(statementNode: TypeScript.ISyntaxNode): SpanInfo { + var statement = statementNode; + if (statement.kind() == TypeScript.SyntaxKind.EmptyStatement) { + return null; + } + + var containingNode = Syntax.containingNode(statementNode); + if (SyntaxUtilities.isStatement(containingNode)) { + // Check if not the declarations and the compound statements + var useNodeForBreakpoint = false; + switch (containingNode.kind()) { + // Declarations + case TypeScript.SyntaxKind.ModuleDeclaration: + case TypeScript.SyntaxKind.ClassDeclaration: + case TypeScript.SyntaxKind.FunctionDeclaration: + case TypeScript.SyntaxKind.ConstructorDeclaration: + case TypeScript.SyntaxKind.MemberFunctionDeclaration: + case TypeScript.SyntaxKind.GetAccessor: + case TypeScript.SyntaxKind.SetAccessor: + case TypeScript.SyntaxKind.Block: + + // Compound Statements + case TypeScript.SyntaxKind.IfStatement: + case TypeScript.SyntaxKind.ElseClause: + case TypeScript.SyntaxKind.ForInStatement: + case TypeScript.SyntaxKind.ForStatement: + case TypeScript.SyntaxKind.WhileStatement: + case TypeScript.SyntaxKind.DoStatement: + case TypeScript.SyntaxKind.SwitchStatement: + case TypeScript.SyntaxKind.CaseSwitchClause: + case TypeScript.SyntaxKind.DefaultSwitchClause: + case TypeScript.SyntaxKind.WithStatement: + case TypeScript.SyntaxKind.TryStatement: + case TypeScript.SyntaxKind.CatchClause: + case TypeScript.SyntaxKind.FinallyClause: + case TypeScript.SyntaxKind.Block: + useNodeForBreakpoint = true; + } + + if (!useNodeForBreakpoint) { + return this.breakpointSpanOfContainingNode(statementNode); + } + } + + switch (statement.kind()) { + case TypeScript.SyntaxKind.ExpressionStatement: + var expressionSyntax = statement; + return createBreakpointSpanInfo(expressionSyntax.expression); + + case TypeScript.SyntaxKind.ReturnStatement: + var returnStatementSyntax = statement; + return createBreakpointSpanInfo(statementNode, returnStatementSyntax.returnKeyword, returnStatementSyntax.expression); + + case TypeScript.SyntaxKind.ThrowStatement: + var throwStatementSyntax = statement; + return createBreakpointSpanInfo(statementNode, throwStatementSyntax.throwKeyword, throwStatementSyntax.expression); + + case TypeScript.SyntaxKind.BreakStatement: + var breakStatementSyntax = statement; + return createBreakpointSpanInfo(statementNode, breakStatementSyntax.breakKeyword, breakStatementSyntax.identifier); + + case TypeScript.SyntaxKind.ContinueStatement: + var continueStatementSyntax = statement; + return createBreakpointSpanInfo(statementNode, continueStatementSyntax.continueKeyword, continueStatementSyntax.identifier); + + case TypeScript.SyntaxKind.DebuggerStatement: + var debuggerStatementSyntax = statement; + return createBreakpointSpanInfo(debuggerStatementSyntax.debuggerKeyword); + + case TypeScript.SyntaxKind.LabeledStatement: + var labeledStatementSyntax = statement; + return this.breakpointSpanOf(labeledStatementSyntax.statement); + } + + return null; + } + + private getSyntaxListOfDeclarationWithElements(positionedNode: TypeScript.ISyntaxNode) { + var node = positionedNode; + var elementsList: TypeScript.ISyntaxNodeOrToken[]; + var block: TypeScript.BlockSyntax; + + switch (node.kind()) { + case TypeScript.SyntaxKind.ModuleDeclaration: + elementsList = (node).moduleElements; + break; + + case TypeScript.SyntaxKind.ClassDeclaration: + elementsList = (node).classElements; + break; + + case TypeScript.SyntaxKind.FunctionDeclaration: + block = (node).block; + break; + + case TypeScript.SyntaxKind.ConstructorDeclaration: + block = (node).block; + break; + + case TypeScript.SyntaxKind.MemberFunctionDeclaration: + block = (node).block; + break; + + case TypeScript.SyntaxKind.GetAccessor: + block = (node).block; + break; + + case TypeScript.SyntaxKind.SetAccessor: + block = (node).block; + break; + + case TypeScript.SyntaxKind.FunctionExpression: + block = (node).block; + break; + + case TypeScript.SyntaxKind.ParenthesizedArrowFunctionExpression: + block = (node).block; + break; + + case TypeScript.SyntaxKind.SimpleArrowFunctionExpression: + block = (node).block; + break; + + default: + throw TypeScript.Errors.argument('positionNode', 'unknown node kind in getSyntaxListOfDeclarationWithElements'); + } + + var parentElement: TypeScript.ISyntaxElement = positionedNode; + if (block) { + parentElement = block; + elementsList = block.statements; + } + + return elementsList; + } + + private canHaveBreakpointInDeclaration(positionedNode: TypeScript.ISyntaxNode) { + return positionedNode && !TypeScript.SyntaxUtilities.isAmbientDeclarationSyntax(positionedNode); + } + + private breakpointSpanOfDeclarationWithElements(positionedNode: TypeScript.ISyntaxNode): SpanInfo { + if (!this.canHaveBreakpointInDeclaration(positionedNode)) { + return null; + } + + // If inside another module the whole declaration is debuggable + var node = positionedNode; + var moduleSyntax = positionedNode; + if ((SyntaxUtilities.isModuleElement(node) && Syntax.containingNode(positionedNode).kind() != TypeScript.SyntaxKind.SourceUnit) || + SyntaxUtilities.isClassElement(node) || + (moduleSyntax.kind() == TypeScript.SyntaxKind.ModuleDeclaration && moduleSyntax.name + && moduleSyntax.name.kind() == TypeScript.SyntaxKind.QualifiedName)) { + return createBreakpointSpanInfo(positionedNode); + } + else { + // Try to get the breakpoint in first element declaration + return this.breakpointSpanOfFirstChildOfSyntaxList(this.getSyntaxListOfDeclarationWithElements(positionedNode)); + } + } + + private canHaveBreakpointInVariableDeclarator(varDeclaratorNode: TypeScript.ISyntaxNode) { + if (!varDeclaratorNode || TypeScript.SyntaxUtilities.isAmbientDeclarationSyntax(varDeclaratorNode)) { + return false; + } + + var varDeclaratorSyntax = varDeclaratorNode; + return !!varDeclaratorSyntax.equalsValueClause; + } + + private breakpointSpanOfVariableDeclarator(varDeclaratorNode: TypeScript.ISyntaxNode): SpanInfo { + if (!this.canHaveBreakpointInVariableDeclarator(varDeclaratorNode)) { + return null; + } + + var container = Syntax.containingNode(varDeclaratorNode); + if (container && container.kind() == TypeScript.SyntaxKind.VariableDeclaration) { + var parentDeclaratorsList = varDeclaratorNode.parent; + // If this is the first declarator in the list use the declaration instead + if (parentDeclaratorsList && childAt(parentDeclaratorsList, 0) == varDeclaratorNode) { + return this.breakpointSpanOfVariableDeclaration(container); + } + + // Create breakpoint on this var declarator + if (this.canHaveBreakpointInVariableDeclarator(varDeclaratorNode)) { + return createBreakpointSpanInfo(varDeclaratorNode); + } + else { + return null; + } + } + else if (container) { + // Member Variable syntax + return this.breakpointSpanOfMemberVariableDeclaration(container); + } + + return null; + } + + private canHaveBreakpointInVariableDeclaration(varDeclarationNode: TypeScript.ISyntaxNode) { + if (!varDeclarationNode || TypeScript.SyntaxUtilities.isAmbientDeclarationSyntax(varDeclarationNode)) { + return false; + } + + var varDeclarationSyntax = varDeclarationNode; + var containerChildren = varDeclarationSyntax.variableDeclarators; + if (!containerChildren || childCount(containerChildren) == 0) { + return false; + } + + var child = childAt(containerChildren, 0); + if (isNode(child)) { + return this.canHaveBreakpointInVariableDeclarator(child); + } + + return false; + } + + private breakpointSpanOfVariableDeclaration(varDeclarationNode: TypeScript.ISyntaxNode): SpanInfo { + if (!this.canHaveBreakpointInDeclaration(varDeclarationNode)) { + return null; + } + + var container = Syntax.containingNode(varDeclarationNode); + var varDeclarationSyntax = varDeclarationNode; + var varDeclarators = varDeclarationSyntax.variableDeclarators; + var varDeclaratorsCount = childCount(varDeclarators); // varDeclarators has to be non null because its checked in canHaveBreakpoint + + if (container && container.kind() == TypeScript.SyntaxKind.VariableStatement) { + return this.breakpointSpanOfVariableStatement(container); + } + + if (this.canHaveBreakpointInVariableDeclaration(varDeclarationNode)) { + return createBreakpointSpanInfoWithLimChar(varDeclarationNode, end(childAt(varDeclarators, 0))); + } + else { + return null; + } + } + + private canHaveBreakpointInVariableStatement(varStatementNode: TypeScript.ISyntaxNode) { + if (!varStatementNode || TypeScript.SyntaxUtilities.isAmbientDeclarationSyntax(varStatementNode)) { + return false; + } + + var variableStatement = varStatementNode; + return this.canHaveBreakpointInVariableDeclaration(variableStatement.variableDeclaration); + } + + private breakpointSpanOfVariableStatement(varStatementNode: TypeScript.ISyntaxNode): SpanInfo { + if (!this.canHaveBreakpointInVariableStatement(varStatementNode)) { + return null; + } + + var variableStatement = varStatementNode; + var variableDeclaration = variableStatement.variableDeclaration; + var varDeclarationSyntax = variableDeclaration; + var varDeclarators = varDeclarationSyntax.variableDeclarators; + return createBreakpointSpanInfoWithLimChar(varStatementNode, end(childAt(varDeclarators, 0))); + } + + private breakpointSpanOfParameter(parameterNode: TypeScript.ISyntaxNode): SpanInfo { + if (parameterNode.parent.kind() === SyntaxKind.SimpleArrowFunctionExpression) { + return this.breakpointSpanOfNode(parameterNode.parent); + } + + if (TypeScript.SyntaxUtilities.isAmbientDeclarationSyntax(parameterNode)) { + return null; + } + + var parameterSyntax = parameterNode; + if (parameterSyntax.dotDotDotToken || parameterSyntax.equalsValueClause || parameterSyntax.modifiers.length > 0) { + return createBreakpointSpanInfo(parameterNode); + } + else { + return null; + } + } + + private breakpointSpanOfMemberVariableDeclaration(memberVarDeclarationNode: TypeScript.ISyntaxNode): SpanInfo { + if (TypeScript.SyntaxUtilities.isAmbientDeclarationSyntax(memberVarDeclarationNode)) { + return null; + } + + var memberVariableDeclaration = memberVarDeclarationNode; + if (this.canHaveBreakpointInVariableDeclarator(memberVariableDeclaration.variableDeclarator)) { + return createBreakpointSpanInfo(memberVarDeclarationNode, memberVariableDeclaration.modifiers, memberVariableDeclaration.variableDeclarator); + } + else { + return null; + } + } + + private breakpointSpanOfImportDeclaration(importDeclarationNode: TypeScript.ISyntaxNode): SpanInfo { + if (TypeScript.SyntaxUtilities.isAmbientDeclarationSyntax(importDeclarationNode)) { + return null; + } + + var importSyntax = importDeclarationNode; + return createBreakpointSpanInfo(importDeclarationNode, importSyntax.modifiers, importSyntax.importKeyword, importSyntax.identifier, importSyntax.equalsToken, importSyntax.moduleReference); + } + + private breakpointSpanOfEnumDeclaration(enumDeclarationNode: TypeScript.ISyntaxNode): SpanInfo { + if (!this.canHaveBreakpointInDeclaration(enumDeclarationNode)) { + return null; + } + + return createBreakpointSpanInfo(enumDeclarationNode); + } + + private breakpointSpanOfFirstEnumElement(enumDeclarationNode: TypeScript.ISyntaxNode): SpanInfo { + var enumDeclarationSyntax = enumDeclarationNode; + var enumElements = enumDeclarationSyntax.enumElements; + if (enumElements && childCount(enumElements)) { + return this.breakpointSpanOf(childAt(enumElements, 0)); + } + + return null; + } + + private breakpointSpanOfEnumElement(enumElementNode: TypeScript.ISyntaxNode): SpanInfo { + if (TypeScript.SyntaxUtilities.isAmbientDeclarationSyntax(enumElementNode)) { + return null; + } + + return createBreakpointSpanInfo(enumElementNode); + } + + private breakpointSpanOfIfStatement(ifStatementNode: TypeScript.ISyntaxNode): SpanInfo { + var ifStatement = ifStatementNode; + return createBreakpointSpanInfo(ifStatementNode, ifStatement.ifKeyword, ifStatement.openParenToken, ifStatement.condition, ifStatement.closeParenToken); + } + + private breakpointSpanOfElseClause(elseClauseNode: TypeScript.ISyntaxNode): SpanInfo { + var elseClause = elseClauseNode; + return this.breakpointSpanOf(elseClause.statement); + } + + private breakpointSpanOfForInStatement(forInStatementNode: TypeScript.ISyntaxNode): SpanInfo { + var forInStatement = forInStatementNode; + return createBreakpointSpanInfo(forInStatementNode, forInStatement.forKeyword, forInStatement.openParenToken, forInStatement.variableDeclaration, + forInStatement.left, forInStatement.inKeyword, forInStatement.expression, forInStatement.closeParenToken); + } + + private breakpointSpanOfForStatement(forStatementNode: TypeScript.ISyntaxNode): SpanInfo { + var forStatement = forStatementNode; + return this.breakpointSpanOf(forStatement.variableDeclaration + ? forStatement.variableDeclaration + : forStatement.initializer); + } + + private breakpointSpanOfWhileStatement(whileStatementNode: TypeScript.ISyntaxNode): SpanInfo { + var whileStatement = whileStatementNode; + return createBreakpointSpanInfo(whileStatementNode, whileStatement.whileKeyword, whileStatement.openParenToken, whileStatement.condition, whileStatement.closeParenToken); + } + + private breakpointSpanOfDoStatement(doStatementNode: TypeScript.ISyntaxNode): SpanInfo { + var doStatement = doStatementNode; + return createBreakpointSpanInfo(doStatementNode, doStatement.whileKeyword, doStatement.openParenToken, doStatement.condition, doStatement.closeParenToken); + } + + private breakpointSpanOfSwitchStatement(switchStatementNode: TypeScript.ISyntaxNode): SpanInfo { + var switchStatement = switchStatementNode; + return createBreakpointSpanInfo(switchStatementNode, switchStatement.switchKeyword, switchStatement.openParenToken, switchStatement.expression, switchStatement.closeParenToken); + } + + private breakpointSpanOfFirstStatementOfFirstCaseClause(switchStatementNode: TypeScript.ISyntaxNode): SpanInfo { + var switchStatement = switchStatementNode; + if (switchStatement.switchClauses && switchStatement.switchClauses.length == 0) { + return null; + } + + var switchClauses = switchStatement.switchClauses; + if (switchClauses.length == 0) { + return null; + } + + var firstCaseClause = switchClauses[0]; + var statements = firstCaseClause.statements; + + return this.breakpointSpanOfFirstChildOfSyntaxList(statements); + } + + private breakpointSpanOfLastStatementOfLastCaseClause(switchStatementNode: TypeScript.ISyntaxNode): SpanInfo { + var switchStatement = switchStatementNode; + if (switchStatement.switchClauses && switchStatement.switchClauses.length == 0) { + return null; + } + + var switchClauses = switchStatement.switchClauses; + if (switchClauses.length == 0) { + return null; + } + + var lastClauseNode = switchClauses[switchClauses.length - 1]; + var statements = lastClauseNode.statements; + + return this.breakpointSpanOfLastChildOfSyntaxList(statements); + } + + private breakpointSpanOfCaseSwitchClause(caseClauseNode: TypeScript.ISyntaxNode): SpanInfo { + var caseSwitchClause = caseClauseNode; + return this.breakpointSpanOfFirstChildOfSyntaxList(caseSwitchClause.statements); + } + + private breakpointSpanOfDefaultSwitchClause(defaultSwithClauseNode: TypeScript.ISyntaxNode): SpanInfo { + var defaultSwitchClause = defaultSwithClauseNode; + return this.breakpointSpanOfFirstChildOfSyntaxList(defaultSwitchClause.statements); + } + + private breakpointSpanOfWithStatement(withStatementNode: TypeScript.ISyntaxNode): SpanInfo { + var withStatement = withStatementNode; + return this.breakpointSpanOf(withStatement.statement); + } + + private breakpointSpanOfTryStatement(tryStatementNode: TypeScript.ISyntaxNode): SpanInfo { + var tryStatement = tryStatementNode; + return this.breakpointSpanOfFirstStatementInBlock(tryStatement.block); + } + + private breakpointSpanOfCatchClause(catchClauseNode: TypeScript.ISyntaxNode): SpanInfo { + var catchClause = catchClauseNode; + return createBreakpointSpanInfo(catchClauseNode, catchClause.catchKeyword, catchClause.openParenToken, catchClause.identifier, catchClause.typeAnnotation, catchClause.closeParenToken); + } + + private breakpointSpanOfFinallyClause(finallyClauseNode: TypeScript.ISyntaxNode): SpanInfo { + var finallyClause = finallyClauseNode; + return this.breakpointSpanOfFirstStatementInBlock(finallyClause.block); + } + + private breakpointSpanOfParenthesizedArrowFunctionExpression(arrowFunctionExpression: ParenthesizedArrowFunctionExpressionSyntax): SpanInfo { + if (arrowFunctionExpression.block) { + return this.breakpointSpanOfFirstStatementInBlock(arrowFunctionExpression.block); + } + else { + return this.breakpointSpanOf(arrowFunctionExpression.expression); + } + } + + private breakpointSpanOfSimpleArrowFunctionExpression(arrowFunctionExpression: SimpleArrowFunctionExpressionSyntax): SpanInfo { + if (arrowFunctionExpression.block) { + return this.breakpointSpanOfFirstStatementInBlock(arrowFunctionExpression.block); + } + else { + return this.breakpointSpanOf(arrowFunctionExpression.expression); + } + } + + private breakpointSpanOfContainingNode(positionedElement: ISyntaxElement): SpanInfo { + var current = positionedElement.parent; + while (!isNode(current)) { + current = current.parent; + } + + return this.breakpointSpanOf(current); + } + + private breakpointSpanIfStartsOnSameLine(positionedElement: TypeScript.ISyntaxElement): SpanInfo { + if (positionedElement && this.posLine == this.lineMap.getLineNumberFromPosition(start(positionedElement))) { + return this.breakpointSpanOf(positionedElement); + } + + return null; + } + + public breakpointSpanOf(positionedElement: TypeScript.ISyntaxElement): SpanInfo { + if (!positionedElement) { + return null; + } + + for (var containingNode = Syntax.containingNode(positionedElement); containingNode != null; containingNode = Syntax.containingNode(containingNode)) { + if (containingNode.kind() == TypeScript.SyntaxKind.TypeAnnotation) { + return this.breakpointSpanIfStartsOnSameLine(containingNode); + } + } + + var element = positionedElement; + + // Syntax node + if (isNode(element)) { + return this.breakpointSpanOfNode(positionedElement); + } + + // Token + if (isToken(element)) { + return this.breakpointSpanOfToken(positionedElement); + } + + // List + // Separated List + return this.breakpointSpanOfContainingNode(positionedElement); + } + } + + export function getBreakpointLocation(syntaxTree: TypeScript.SyntaxTree, askedPos: number): SpanInfo { + // Cannot set breakpoint in dts file + if (TypeScript.isDTSFile(syntaxTree.fileName())) { + return null; + } + + var sourceUnit = syntaxTree.sourceUnit(); + var positionedToken = TypeScript.findToken(sourceUnit, askedPos); + + var lineMap = syntaxTree.lineMap(); + var posLine = lineMap.getLineNumberFromPosition(askedPos); + var tokenStartLine = lineMap.getLineNumberFromPosition(start(positionedToken)); + if (posLine < tokenStartLine) { + return null; + } + + var breakpointResolver = new BreakpointResolver(posLine, lineMap); + return breakpointResolver.breakpointSpanOf(positionedToken); + } +} \ No newline at end of file diff --git a/src/services/classifier.ts b/src/services/classifier.ts new file mode 100644 index 00000000000..e5e68f06296 --- /dev/null +++ b/src/services/classifier.ts @@ -0,0 +1,194 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services { + export enum EndOfLineState { + Start, + InMultiLineCommentTrivia, + InSingleQuoteStringLiteral, + InDoubleQuoteStringLiteral, + } + + export enum TokenClass { + Punctuation, + Keyword, + Operator, + Comment, + Whitespace, + Identifier, + NumberLiteral, + StringLiteral, + RegExpLiteral, + } + + var noRegexTable: boolean[] = []; + noRegexTable[TypeScript.SyntaxKind.IdentifierName] = true; + noRegexTable[TypeScript.SyntaxKind.StringLiteral] = true; + noRegexTable[TypeScript.SyntaxKind.NumericLiteral] = true; + noRegexTable[TypeScript.SyntaxKind.RegularExpressionLiteral] = true; + noRegexTable[TypeScript.SyntaxKind.ThisKeyword] = true; + noRegexTable[TypeScript.SyntaxKind.PlusPlusToken] = true; + noRegexTable[TypeScript.SyntaxKind.MinusMinusToken] = true; + noRegexTable[TypeScript.SyntaxKind.CloseParenToken] = true; + noRegexTable[TypeScript.SyntaxKind.CloseBracketToken] = true; + noRegexTable[TypeScript.SyntaxKind.CloseBraceToken] = true; + noRegexTable[TypeScript.SyntaxKind.TrueKeyword] = true; + noRegexTable[TypeScript.SyntaxKind.FalseKeyword] = true; + + export class Classifier { + private scanner: TypeScript.Scanner.IScanner; + private lastDiagnosticKey: string = null; + private reportDiagnostic = (position: number, fullWidth: number, key: string, args: any[]) => { + this.lastDiagnosticKey = key; + }; + + constructor(public host: IClassifierHost) { + } + + /// COLORIZATION + public getClassificationsForLine(text: string, lexState: EndOfLineState): ClassificationResult { + var offset = 0; + if (lexState !== EndOfLineState.Start) { + // If we're in a string literal, then prepend: "\ + // (and a newline). That way when we lex we'll think we're still in a string literal. + // + // If we're in a multiline comment, then prepend: /* + // (and a newline). That way when we lex we'll think we're still in a multiline comment. + if (lexState === EndOfLineState.InDoubleQuoteStringLiteral) { + text = '"\\\n' + text; + } + else if (lexState === EndOfLineState.InSingleQuoteStringLiteral) { + text = "'\\\n" + text; + } + else if (lexState === EndOfLineState.InMultiLineCommentTrivia) { + text = "/*\n" + text; + } + + offset = 3; + } + + var result = new ClassificationResult(); + var simpleText = TypeScript.SimpleText.fromString(text); + this.scanner = Scanner.createScanner(ts.ScriptTarget.ES5, simpleText, this.reportDiagnostic); + + var lastTokenKind = TypeScript.SyntaxKind.None; + var token: ISyntaxToken = null; + do { + this.lastDiagnosticKey = null; + + token = this.scanner.scan(!noRegexTable[lastTokenKind]); + lastTokenKind = token.kind(); + + this.processToken(text, simpleText, offset, token, result); + } + while (token.kind() !== SyntaxKind.EndOfFileToken); + + this.lastDiagnosticKey = null; + return result; + } + + private processToken(text: string, simpleText: ISimpleText, offset: number, token: TypeScript.ISyntaxToken, result: ClassificationResult): void { + this.processTriviaList(text, offset, token.leadingTrivia(simpleText), result); + this.addResult(text, offset, result, width(token), token.kind()); + this.processTriviaList(text, offset, token.trailingTrivia(simpleText), result); + + if (fullEnd(token) >= text.length) { + // We're at the end. + if (this.lastDiagnosticKey === TypeScript.DiagnosticCode.AsteriskSlash_expected) { + result.finalLexState = EndOfLineState.InMultiLineCommentTrivia; + return; + } + + if (token.kind() === TypeScript.SyntaxKind.StringLiteral) { + var tokenText = token.text(); + if (tokenText.length > 0 && tokenText.charCodeAt(tokenText.length - 1) === TypeScript.CharacterCodes.backslash) { + var quoteChar = tokenText.charCodeAt(0); + result.finalLexState = quoteChar === TypeScript.CharacterCodes.doubleQuote + ? EndOfLineState.InDoubleQuoteStringLiteral + : EndOfLineState.InSingleQuoteStringLiteral; + return; + } + } + } + } + + private processTriviaList(text: string, offset: number, triviaList: TypeScript.ISyntaxTriviaList, result: ClassificationResult): void { + for (var i = 0, n = triviaList.count(); i < n; i++) { + var trivia = triviaList.syntaxTriviaAt(i); + this.addResult(text, offset, result, trivia.fullWidth(), trivia.kind()); + } + } + + private addResult(text: string, offset: number, result: ClassificationResult, length: number, kind: TypeScript.SyntaxKind): void { + if (length > 0) { + // If this is the first classification we're adding to the list, then remove any + // offset we have if we were continuing a construct from the previous line. + if (result.entries.length === 0) { + length -= offset; + } + + result.entries.push(new ClassificationInfo(length, this.classFromKind(kind))); + } + } + + private classFromKind(kind: TypeScript.SyntaxKind) { + if (TypeScript.SyntaxFacts.isAnyKeyword(kind)) { + return TokenClass.Keyword; + } + else if (TypeScript.SyntaxFacts.isBinaryExpressionOperatorToken(kind) || + TypeScript.SyntaxFacts.isPrefixUnaryExpressionOperatorToken(kind)) { + return TokenClass.Operator; + } + else if (TypeScript.SyntaxFacts.isAnyPunctuation(kind)) { + return TokenClass.Punctuation; + } + + switch (kind) { + case TypeScript.SyntaxKind.WhitespaceTrivia: + return TokenClass.Whitespace; + case TypeScript.SyntaxKind.MultiLineCommentTrivia: + case TypeScript.SyntaxKind.SingleLineCommentTrivia: + return TokenClass.Comment; + case TypeScript.SyntaxKind.NumericLiteral: + return TokenClass.NumberLiteral; + case TypeScript.SyntaxKind.StringLiteral: + return TokenClass.StringLiteral; + case TypeScript.SyntaxKind.RegularExpressionLiteral: + return TokenClass.RegExpLiteral; + case TypeScript.SyntaxKind.IdentifierName: + default: + return TokenClass.Identifier; + } + } + } + + export interface IClassifierHost extends TypeScript.ILogger { + } + + export class ClassificationResult { + public finalLexState: EndOfLineState = EndOfLineState.Start; + public entries: ClassificationInfo[] = []; + + constructor() { + } + } + + export class ClassificationInfo { + constructor(public length: number, public classification: TokenClass) { + } + } +} diff --git a/src/services/compiler/ast.ts b/src/services/compiler/ast.ts new file mode 100644 index 00000000000..76b4903768d --- /dev/null +++ b/src/services/compiler/ast.ts @@ -0,0 +1,53 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript { + export class Comment { + constructor(private _trivia: ISyntaxTrivia, + public endsLine: boolean, + public _start: number, + public _end: number) { + } + + public start(): number { + return this._start; + } + + public end(): number { + return this._end; + } + + public fullText(): string { + return this._trivia.fullText(); + } + + public kind(): SyntaxKind { + return this._trivia.kind(); + } + + public structuralEquals(ast: Comment, includingPosition: boolean): boolean { + if (includingPosition) { + if (this.start() !== ast.start() || this.end() !== ast.end()) { + return false; + } + } + + return this._trivia.fullText() === ast._trivia.fullText() && + this.endsLine === ast.endsLine; + } + } +} \ No newline at end of file diff --git a/src/services/compiler/astHelpers.ts b/src/services/compiler/astHelpers.ts new file mode 100644 index 00000000000..589e4fad503 --- /dev/null +++ b/src/services/compiler/astHelpers.ts @@ -0,0 +1,755 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.ASTHelpers { + //export function scriptIsElided(sourceUnit: SourceUnitSyntax): boolean { + // return isDTSFile(sourceUnit.syntaxTree.fileName()) || moduleMembersAreElided(sourceUnit.moduleElements); + //} + + //export function moduleIsElided(declaration: ModuleDeclarationSyntax): boolean { + // return hasModifier(declaration.modifiers, PullElementFlags.Ambient) || moduleMembersAreElided(declaration.moduleElements); + //} + + //function moduleMembersAreElided(members: IModuleElementSyntax[]): boolean { + // for (var i = 0, n = members.length; i < n; i++) { + // var member = members[i]; + + // // We should emit *this* module if it contains any non-interface types. + // // Caveat: if we have contain a module, then we should be emitted *if we want to + // // emit that inner module as well. + // if (member.kind() === SyntaxKind.ModuleDeclaration) { + // if (!moduleIsElided(member)) { + // return false; + // } + // } + // else if (member.kind() !== SyntaxKind.InterfaceDeclaration) { + // return false; + // } + // } + + // return true; + //} + + //export function enumIsElided(declaration: EnumDeclarationSyntax): boolean { + // if (hasModifier(declaration.modifiers, PullElementFlags.Ambient)) { + // return true; + // } + + // return false; + //} + + export function isValidAstNode(ast: ISyntaxElement): boolean { + return ast && !isShared(ast) && start(ast) !== -1 && end(ast) !== -1; + } + + export function isValidSpan(ast: ISpan): boolean { + if (!ast) + return false; + + if (ast.start() === -1 || ast.end() === -1) + return false; + + return true; + } + + /// + /// Return the ISyntaxElement containing "position" + /// + export function getAstAtPosition(script: ISyntaxElement, pos: number, useTrailingTriviaAsLimChar: boolean = true, forceInclusive: boolean = false): ISyntaxElement { + var top: ISyntaxElement = null; + + var pre = function (cur: ISyntaxElement, walker: IAstWalker) { + if (!isShared(cur) && isValidAstNode(cur)) { + var isInvalid1 = cur.kind() === SyntaxKind.ExpressionStatement && width(cur) === 0; + + if (isInvalid1) { + walker.options.goChildren = false; + } + else { + // Add "cur" to the stack if it contains our position + // For "identifier" nodes, we need a special case: A position equal to "limChar" is + // valid, since the position corresponds to a caret position (in between characters) + // For example: + // bar + // 0123 + // If "position === 3", the caret is at the "right" of the "r" character, which should be considered valid + var inclusive = + forceInclusive || + cur.kind() === SyntaxKind.IdentifierName || + cur.kind() === SyntaxKind.MemberAccessExpression || + cur.kind() === SyntaxKind.QualifiedName || + //cur.kind() === SyntaxKind.TypeRef || + cur.kind() === SyntaxKind.VariableDeclaration || + cur.kind() === SyntaxKind.VariableDeclarator || + cur.kind() === SyntaxKind.InvocationExpression || + pos === end(script) + lastToken(script).trailingTriviaWidth(); // Special "EOF" case + + var minChar = start(cur); + var limChar = end(cur) + (useTrailingTriviaAsLimChar ? trailingTriviaWidth(cur) : 0) + (inclusive ? 1 : 0); + if (pos >= minChar && pos < limChar) { + + // Ignore empty lists + if ((cur.kind() !== SyntaxKind.List && cur.kind() !== SyntaxKind.SeparatedList) || end(cur) > start(cur)) { + // TODO: Since ISyntaxElement is sometimes not correct wrt to position, only add "cur" if it's better + // than top of the stack. + if (top === null) { + top = cur; + } + else if (start(cur) >= start(top) && + (end(cur) + (useTrailingTriviaAsLimChar ? trailingTriviaWidth(cur) : 0)) <= (end(top) + (useTrailingTriviaAsLimChar ? trailingTriviaWidth(top) : 0))) { + // this new node appears to be better than the one we're + // storing. Make this the new node. + + // However, If the current top is a missing identifier, we + // don't want to replace it with another missing identifier. + // We want to return the first missing identifier found in a + // depth first walk of the tree. + if (width(top) !== 0 || width(cur) !== 0) { + top = cur; + } + } + } + } + + // Don't go further down the tree if pos is outside of [minChar, limChar] + walker.options.goChildren = (minChar <= pos && pos <= limChar); + } + } + }; + + getAstWalkerFactory().walk(script, pre); + return top; + } + + export function getExtendsHeritageClause(clauses: HeritageClauseSyntax[]): HeritageClauseSyntax { + return getHeritageClause(clauses, SyntaxKind.ExtendsHeritageClause); + } + + export function getImplementsHeritageClause(clauses: HeritageClauseSyntax[]): HeritageClauseSyntax { + return getHeritageClause(clauses, SyntaxKind.ImplementsHeritageClause); + } + + function getHeritageClause(clauses: HeritageClauseSyntax[], kind: SyntaxKind): HeritageClauseSyntax { + if (clauses) { + for (var i = 0, n = clauses.length; i < n; i++) { + var child = clauses[i]; + + if (child.typeNames.length > 0 && child.kind() === kind) { + return child; + } + } + } + + return null; + } + + export function isCallExpression(ast: ISyntaxElement): boolean { + return (ast && ast.kind() === SyntaxKind.InvocationExpression) || + (ast && ast.kind() === SyntaxKind.ObjectCreationExpression); + } + + export function isCallExpressionTarget(ast: ISyntaxElement): boolean { + return !!getCallExpressionTarget(ast); + } + + export function getCallExpressionTarget(ast: ISyntaxElement): ISyntaxElement { + if (!ast) { + return null; + } + + var current = ast; + + while (current && current.parent) { + if (current.parent.kind() === SyntaxKind.MemberAccessExpression && + (current.parent).name === current) { + current = current.parent; + continue; + } + + break; + } + + if (current && current.parent) { + if (current.parent.kind() === SyntaxKind.InvocationExpression || current.parent.kind() === SyntaxKind.ObjectCreationExpression) { + return current === (current.parent).expression ? current : null; + } + } + return null; + } + + function isNameOfSomeDeclaration(ast: ISyntaxElement) { + if (ast === null || ast.parent === null) { + return false; + } + if (ast.kind() !== SyntaxKind.IdentifierName) { + return false; + } + + switch (ast.parent.kind()) { + case SyntaxKind.ClassDeclaration: + return (ast.parent).identifier === ast; + case SyntaxKind.InterfaceDeclaration: + return (ast.parent).identifier === ast; + case SyntaxKind.EnumDeclaration: + return (ast.parent).identifier === ast; + case SyntaxKind.ModuleDeclaration: + return (ast.parent).name === ast || (ast.parent).stringLiteral === ast; + case SyntaxKind.VariableDeclarator: + return (ast.parent).propertyName === ast; + case SyntaxKind.FunctionDeclaration: + return (ast.parent).identifier === ast; + case SyntaxKind.MemberFunctionDeclaration: + return (ast.parent).propertyName === ast; + case SyntaxKind.Parameter: + return (ast.parent).identifier === ast; + case SyntaxKind.TypeParameter: + return (ast.parent).identifier === ast; + case SyntaxKind.SimplePropertyAssignment: + return (ast.parent).propertyName === ast; + case SyntaxKind.FunctionPropertyAssignment: + return (ast.parent).propertyName === ast; + case SyntaxKind.EnumElement: + return (ast.parent).propertyName === ast; + case SyntaxKind.ImportDeclaration: + return (ast.parent).identifier === ast; + case SyntaxKind.MethodSignature: + return (ast.parent).propertyName === ast; + case SyntaxKind.PropertySignature: + return (ast.parent).propertyName === ast; + } + + return false; + } + + export function isDeclarationASTOrDeclarationNameAST(ast: ISyntaxElement) { + return isNameOfSomeDeclaration(ast) || ASTHelpers.isDeclarationAST(ast); + } + + export function getEnclosingParameterForInitializer(ast: ISyntaxElement): ParameterSyntax { + var current = ast; + while (current) { + switch (current.kind()) { + case SyntaxKind.EqualsValueClause: + if (current.parent && current.parent.kind() === SyntaxKind.Parameter) { + return current.parent; + } + break; + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.ModuleDeclaration: + // exit early + return null; + } + + current = current.parent; + } + return null; + } + + export function getEnclosingMemberDeclaration(ast: ISyntaxElement): ISyntaxElement { + var current = ast; + + while (current) { + switch (current.kind()) { + case SyntaxKind.MemberVariableDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.MemberFunctionDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return current; + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.ModuleDeclaration: + // exit early + return null; + } + current = current.parent; + } + + return null; + } + + export function isNameOfFunction(ast: ISyntaxElement) { + return ast + && ast.parent + && ast.kind() === SyntaxKind.IdentifierName + && ast.parent.kind() === SyntaxKind.FunctionDeclaration + && (ast.parent).identifier === ast; + } + + export function isNameOfMemberFunction(ast: ISyntaxElement) { + return ast + && ast.parent + && ast.kind() === SyntaxKind.IdentifierName + && ast.parent.kind() === SyntaxKind.MemberFunctionDeclaration + && (ast.parent).propertyName === ast; + } + + export function isNameOfMemberAccessExpression(ast: ISyntaxElement) { + if (ast && + ast.parent && + ast.parent.kind() === SyntaxKind.MemberAccessExpression && + (ast.parent).name === ast) { + + return true; + } + + return false; + } + + export function isRightSideOfQualifiedName(ast: ISyntaxElement) { + if (ast && + ast.parent && + ast.parent.kind() === SyntaxKind.QualifiedName && + (ast.parent).right === ast) { + + return true; + } + + return false; + } + + export function parentIsModuleDeclaration(ast: ISyntaxElement) { + return ast.parent && ast.parent.kind() === SyntaxKind.ModuleDeclaration; + } + + export function isDeclarationAST(ast: ISyntaxElement): boolean { + switch (ast.kind()) { + case SyntaxKind.VariableDeclarator: + return getVariableStatement(ast) !== null; + + case SyntaxKind.ImportDeclaration: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.Parameter: + case SyntaxKind.SimpleArrowFunctionExpression: + case SyntaxKind.ParenthesizedArrowFunctionExpression: + case SyntaxKind.IndexSignature: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.ArrayType: + case SyntaxKind.ObjectType: + case SyntaxKind.TypeParameter: + case SyntaxKind.ConstructorDeclaration: + case SyntaxKind.MemberFunctionDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.MemberVariableDeclaration: + case SyntaxKind.IndexMemberDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.EnumElement: + case SyntaxKind.SimplePropertyAssignment: + case SyntaxKind.FunctionPropertyAssignment: + case SyntaxKind.FunctionExpression: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.MethodSignature: + case SyntaxKind.PropertySignature: + return true; + default: + return false; + } + } + + export function preComments(element: ISyntaxElement, text: ISimpleText): Comment[]{ + if (element) { + switch (element.kind()) { + case SyntaxKind.VariableStatement: + case SyntaxKind.ExpressionStatement: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ImportDeclaration: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.IfStatement: + case SyntaxKind.SimplePropertyAssignment: + case SyntaxKind.MemberFunctionDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.ReturnStatement: + case SyntaxKind.ConstructorDeclaration: + case SyntaxKind.MemberVariableDeclaration: + case SyntaxKind.EnumElement: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.IndexSignature: + case SyntaxKind.PropertySignature: + case SyntaxKind.MethodSignature: + case SyntaxKind.FunctionPropertyAssignment: + case SyntaxKind.Parameter: + return convertNodeLeadingComments(element, text); + } + } + + return null; + } + + export function postComments(element: ISyntaxElement, text: ISimpleText): Comment[] { + if (element) { + switch (element.kind()) { + case SyntaxKind.ExpressionStatement: + return convertNodeTrailingComments(element, text, /*allowWithNewLine:*/ true); + case SyntaxKind.VariableStatement: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ImportDeclaration: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.IfStatement: + case SyntaxKind.SimplePropertyAssignment: + case SyntaxKind.MemberFunctionDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.ReturnStatement: + case SyntaxKind.ConstructorDeclaration: + case SyntaxKind.MemberVariableDeclaration: + case SyntaxKind.EnumElement: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.IndexSignature: + case SyntaxKind.PropertySignature: + case SyntaxKind.MethodSignature: + case SyntaxKind.FunctionPropertyAssignment: + case SyntaxKind.Parameter: + return convertNodeTrailingComments(element, text); + } + } + + return null; + } + + function convertNodeTrailingComments(node: ISyntaxElement, text: ISimpleText, allowWithNewLine = false): Comment[]{ + // Bail out quickly before doing any expensive math computation. + var _lastToken = lastToken(node); + if (_lastToken === null || !_lastToken.hasTrailingTrivia()) { + return null; + } + + if (!allowWithNewLine && SyntaxUtilities.isLastTokenOnLine(_lastToken, text)) { + return null; + } + + return convertComments(_lastToken.trailingTrivia(text), fullStart(node) + fullWidth(node) - _lastToken.trailingTriviaWidth(text)); + } + + function convertNodeLeadingComments(element: ISyntaxElement, text: ISimpleText): Comment[]{ + if (element) { + return convertTokenLeadingComments(firstToken(element), text); + } + + return null; + } + + export function convertTokenLeadingComments(token: ISyntaxToken, text: ISimpleText): Comment[]{ + if (token === null) { + return null; + } + + return token.hasLeadingTrivia() + ? convertComments(token.leadingTrivia(text), token.fullStart()) + : null; + } + + export function convertTokenTrailingComments(token: ISyntaxToken, text: ISimpleText): Comment[] { + if (token === null) { + return null; + } + + return token.hasTrailingTrivia() + ? convertComments(token.trailingTrivia(text), fullEnd(token) - token.trailingTriviaWidth(text)) + : null; + } + + function convertComments(triviaList: ISyntaxTriviaList, commentStartPosition: number): Comment[]{ + var result: Comment[] = null; + + for (var i = 0, n = triviaList.count(); i < n; i++) { + var trivia = triviaList.syntaxTriviaAt(i); + + if (trivia.isComment()) { + var hasTrailingNewLine = ((i + 1) < n) && triviaList.syntaxTriviaAt(i + 1).isNewLine(); + result = result || []; + result.push(convertComment(trivia, commentStartPosition, hasTrailingNewLine)); + } + + commentStartPosition += trivia.fullWidth(); + } + + return result; + } + + function convertComment(trivia: ISyntaxTrivia, commentStartPosition: number, hasTrailingNewLine: boolean): Comment { + var comment = new Comment(trivia, hasTrailingNewLine, commentStartPosition, commentStartPosition + trivia.fullWidth()); + + return comment; + } + + export function docComments(ast: ISyntaxElement, text: ISimpleText): Comment[] { + if (isDeclarationAST(ast)) { + var comments: Comment[] = null; + + if (ast.kind() === SyntaxKind.VariableDeclarator) { + // Get the doc comments for a variable off of the variable statement. That's what + // they'll be attached to in the tree. + comments = TypeScript.ASTHelpers.preComments(getVariableStatement(ast), text); + } + else if (ast.kind() === SyntaxKind.Parameter) { + // First check if the parameter was written like so: + // ( + // /** blah */ a, + // /** blah */ b); + comments = TypeScript.ASTHelpers.preComments(ast, text); + if (!comments) { + // Now check if it was written like so: + // (/** blah */ a, /** blah */ b); + // In this case, the comment will belong to the preceding token. + var previousToken = findToken(syntaxTree(ast).sourceUnit(), firstToken(ast).fullStart() - 1); + if (previousToken && (previousToken.kind() === SyntaxKind.OpenParenToken || previousToken.kind() === SyntaxKind.CommaToken)) { + comments = convertTokenTrailingComments(previousToken, text); + } + } + } + else { + comments = TypeScript.ASTHelpers.preComments(ast, text); + } + + if (comments && comments.length > 0) { + return comments.filter(c => isDocComment(c)); + } + } + + return sentinelEmptyArray; + } + + export function isDocComment(comment: Comment) { + if (comment.kind() === SyntaxKind.MultiLineCommentTrivia) { + var fullText = comment.fullText(); + return fullText.charAt(2) === "*" && fullText.charAt(3) !== "/"; + } + + return false; + } + + export function getParameterList(ast: ISyntaxElement): ParameterListSyntax { + if (ast) { + switch (ast.kind()) { + case SyntaxKind.ConstructorDeclaration: + return getParameterList((ast).callSignature); + case SyntaxKind.FunctionDeclaration: + return getParameterList((ast).callSignature); + case SyntaxKind.ParenthesizedArrowFunctionExpression: + return getParameterList((ast).callSignature); + case SyntaxKind.ConstructSignature: + return getParameterList((ast).callSignature); + case SyntaxKind.MemberFunctionDeclaration: + return getParameterList((ast).callSignature); + case SyntaxKind.FunctionPropertyAssignment: + return getParameterList((ast).callSignature); + case SyntaxKind.FunctionExpression: + return getParameterList((ast).callSignature); + case SyntaxKind.MethodSignature: + return getParameterList((ast).callSignature); + case SyntaxKind.ConstructorType: + return (ast).parameterList; + case SyntaxKind.FunctionType: + return (ast).parameterList; + case SyntaxKind.CallSignature: + return (ast).parameterList; + case SyntaxKind.GetAccessor: + return getParameterList((ast).callSignature); + case SyntaxKind.SetAccessor: + return getParameterList((ast).callSignature); + } + } + + return null; + } + + export function getType(ast: ISyntaxElement): ITypeSyntax { + if (ast) { + switch (ast.kind()) { + case SyntaxKind.FunctionDeclaration: + return getType((ast).callSignature); + case SyntaxKind.ParenthesizedArrowFunctionExpression: + return getType((ast).callSignature); + case SyntaxKind.ConstructSignature: + return getType((ast).callSignature); + case SyntaxKind.MemberFunctionDeclaration: + return getType((ast).callSignature); + case SyntaxKind.FunctionPropertyAssignment: + return getType((ast).callSignature); + case SyntaxKind.FunctionExpression: + return getType((ast).callSignature); + case SyntaxKind.MethodSignature: + return getType((ast).callSignature); + case SyntaxKind.CallSignature: + return getType((ast).typeAnnotation); + case SyntaxKind.IndexSignature: + return getType((ast).typeAnnotation); + case SyntaxKind.PropertySignature: + return getType((ast).typeAnnotation); + case SyntaxKind.GetAccessor: + return getType((ast).callSignature); + case SyntaxKind.Parameter: + return getType((ast).typeAnnotation); + case SyntaxKind.MemberVariableDeclaration: + return getType((ast).variableDeclarator); + case SyntaxKind.VariableDeclarator: + return getType((ast).typeAnnotation); + case SyntaxKind.CatchClause: + return getType((ast).typeAnnotation); + case SyntaxKind.ConstructorType: + return (ast).type; + case SyntaxKind.FunctionType: + return (ast).type; + case SyntaxKind.TypeAnnotation: + return (ast).type; + } + } + + return null; + } + + function getVariableStatement(variableDeclarator: VariableDeclaratorSyntax): VariableStatementSyntax { + if (variableDeclarator && variableDeclarator.parent && variableDeclarator.parent.parent && variableDeclarator.parent.parent.parent && + variableDeclarator.parent.kind() === SyntaxKind.SeparatedList && + variableDeclarator.parent.parent.kind() === SyntaxKind.VariableDeclaration && + variableDeclarator.parent.parent.parent.kind() === SyntaxKind.VariableStatement) { + + return variableDeclarator.parent.parent.parent; + } + + return null; + } + + export function getVariableDeclaratorModifiers(variableDeclarator: VariableDeclaratorSyntax): ISyntaxToken[] { + var variableStatement = getVariableStatement(variableDeclarator); + return variableStatement ? variableStatement.modifiers : Syntax.emptyList(); + } + + export function isIntegerLiteralAST(expression: ISyntaxElement): boolean { + if (expression) { + switch (expression.kind()) { + case SyntaxKind.PlusExpression: + case SyntaxKind.NegateExpression: + // Note: if there is a + or - sign, we can only allow a normal integer following + // (and not a hex integer). i.e. -0xA is a legal expression, but it is not a + // *literal*. + expression = (expression).operand; + return expression.kind() === SyntaxKind.NumericLiteral && IntegerUtilities.isInteger((expression).text()); + + case SyntaxKind.NumericLiteral: + // If it doesn't have a + or -, then either an integer literal or a hex literal + // is acceptable. + var text = (expression).text(); + return IntegerUtilities.isInteger(text) || IntegerUtilities.isHexInteger(text); + } + } + + return false; + } + + export function getEnclosingModuleDeclaration(ast: ISyntaxElement): ModuleDeclarationSyntax { + while (ast) { + if (ast.kind() === SyntaxKind.ModuleDeclaration) { + return ast; + } + + ast = ast.parent; + } + + return null; + } + + function isEntireNameOfModuleDeclaration(nameAST: ISyntaxElement) { + return parentIsModuleDeclaration(nameAST) && (nameAST.parent).name === nameAST; + } + + export function getModuleDeclarationFromNameAST(ast: ISyntaxElement): ModuleDeclarationSyntax { + if (ast) { + switch (ast.kind()) { + case SyntaxKind.StringLiteral: + if (parentIsModuleDeclaration(ast) && (ast.parent).stringLiteral === ast) { + return ast.parent; + } + return null; + + case SyntaxKind.IdentifierName: + case SyntaxKind.QualifiedName: + if (isEntireNameOfModuleDeclaration(ast)) { + return ast.parent; + } + break; + + default: + return null; + } + + // Only qualified names can be name of module declaration if they didnt satisfy above conditions + for (ast = ast.parent; ast && ast.kind() === SyntaxKind.QualifiedName; ast = ast.parent) { + if (isEntireNameOfModuleDeclaration(ast)) { + return ast.parent; + } + } + } + + return null; + } + + export function isLastNameOfModule(ast: ModuleDeclarationSyntax, astName: ISyntaxElement): boolean { + if (ast) { + if (ast.stringLiteral) { + return astName === ast.stringLiteral; + } + else if (ast.name.kind() === SyntaxKind.QualifiedName) { + return astName === (ast.name).right; + } + else { + return astName === ast.name; + } + } + + return false; + } + + export function getNameOfIdenfierOrQualifiedName(name: ISyntaxElement): string { + if (name.kind() === SyntaxKind.IdentifierName) { + return (name).text(); + } + else { + Debug.assert(name.kind() == SyntaxKind.QualifiedName); + var dotExpr = name; + return getNameOfIdenfierOrQualifiedName(dotExpr.left) + "." + getNameOfIdenfierOrQualifiedName(dotExpr.right); + } + } + + export function getModuleNames(name: ISyntaxElement, result?: ISyntaxToken[]): ISyntaxToken[] { + result = result || []; + + if (name.kind() === SyntaxKind.QualifiedName) { + getModuleNames((name).left, result); + result.push((name).right); + } + else { + result.push(name); + } + + return result; + } +} \ No newline at end of file diff --git a/src/services/compiler/astWalker.ts b/src/services/compiler/astWalker.ts new file mode 100644 index 00000000000..53d22142cbb --- /dev/null +++ b/src/services/compiler/astWalker.ts @@ -0,0 +1,716 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript { + function walkListChildren(preAst: ISyntaxNodeOrToken[], walker: AstWalker): void { + for (var i = 0, n = preAst.length; i < n; i++) { + walker.walk(preAst[i]); + } + } + + function walkThrowStatementChildren(preAst: ThrowStatementSyntax, walker: AstWalker): void { + walker.walk(preAst.expression); + } + + function walkPrefixUnaryExpressionChildren(preAst: PrefixUnaryExpressionSyntax, walker: AstWalker): void { + walker.walk(preAst.operand); + } + + function walkPostfixUnaryExpressionChildren(preAst: PostfixUnaryExpressionSyntax, walker: AstWalker): void { + walker.walk(preAst.operand); + } + + function walkDeleteExpressionChildren(preAst: DeleteExpressionSyntax, walker: AstWalker): void { + walker.walk(preAst.expression); + } + + function walkTypeArgumentListChildren(preAst: TypeArgumentListSyntax, walker: AstWalker): void { + walker.walk(preAst.typeArguments); + } + + function walkTypeOfExpressionChildren(preAst: TypeOfExpressionSyntax, walker: AstWalker): void { + walker.walk(preAst.expression); + } + + function walkVoidExpressionChildren(preAst: VoidExpressionSyntax, walker: AstWalker): void { + walker.walk(preAst.expression); + } + + function walkArgumentListChildren(preAst: ArgumentListSyntax, walker: AstWalker): void { + walker.walk(preAst.typeArgumentList); + walker.walk(preAst.arguments); + } + + function walkArrayLiteralExpressionChildren(preAst: ArrayLiteralExpressionSyntax, walker: AstWalker): void { + walker.walk(preAst.expressions); + } + + function walkSimplePropertyAssignmentChildren(preAst: SimplePropertyAssignmentSyntax, walker: AstWalker): void { + walker.walk(preAst.propertyName); + walker.walk(preAst.expression); + } + + function walkFunctionPropertyAssignmentChildren(preAst: FunctionPropertyAssignmentSyntax, walker: AstWalker): void { + walker.walk(preAst.propertyName); + walker.walk(preAst.callSignature); + walker.walk(preAst.block); + } + + function walkGetAccessorChildren(preAst: GetAccessorSyntax, walker: AstWalker): void { + walker.walk(preAst.propertyName); + walker.walk(preAst.callSignature); + walker.walk(preAst.block); + } + + function walkSeparatedListChildren(preAst: ISyntaxNodeOrToken[], walker: AstWalker): void { + for (var i = 0, n = preAst.length; i < n; i++) { + walker.walk(preAst[i]); + } + } + + function walkSetAccessorChildren(preAst: SetAccessorSyntax, walker: AstWalker): void { + walker.walk(preAst.propertyName); + walker.walk(preAst.callSignature); + walker.walk(preAst.block); + } + + function walkObjectLiteralExpressionChildren(preAst: ObjectLiteralExpressionSyntax, walker: AstWalker): void { + walker.walk(preAst.propertyAssignments); + } + + function walkCastExpressionChildren(preAst: CastExpressionSyntax, walker: AstWalker): void { + walker.walk(preAst.type); + walker.walk(preAst.expression); + } + + function walkParenthesizedExpressionChildren(preAst: ParenthesizedExpressionSyntax, walker: AstWalker): void { + walker.walk(preAst.expression); + } + + function walkElementAccessExpressionChildren(preAst: ElementAccessExpressionSyntax, walker: AstWalker): void { + walker.walk(preAst.expression); + walker.walk(preAst.argumentExpression); + } + + function walkMemberAccessExpressionChildren(preAst: MemberAccessExpressionSyntax, walker: AstWalker): void { + walker.walk(preAst.expression); + walker.walk(preAst.name); + } + + function walkQualifiedNameChildren(preAst: QualifiedNameSyntax, walker: AstWalker): void { + walker.walk(preAst.left); + walker.walk(preAst.right); + } + + function walkBinaryExpressionChildren(preAst: BinaryExpressionSyntax, walker: AstWalker): void { + walker.walk(preAst.left); + walker.walk(preAst.right); + } + + function walkEqualsValueClauseChildren(preAst: EqualsValueClauseSyntax, walker: AstWalker): void { + walker.walk(preAst.value); + } + + function walkTypeParameterChildren(preAst: TypeParameterSyntax, walker: AstWalker): void { + walker.walk(preAst.identifier); + walker.walk(preAst.constraint); + } + + function walkTypeParameterListChildren(preAst: TypeParameterListSyntax, walker: AstWalker): void { + walker.walk(preAst.typeParameters); + } + + function walkGenericTypeChildren(preAst: GenericTypeSyntax, walker: AstWalker): void { + walker.walk(preAst.name); + walker.walk(preAst.typeArgumentList); + } + + function walkTypeAnnotationChildren(preAst: TypeAnnotationSyntax, walker: AstWalker): void { + walker.walk(preAst.type); + } + + function walkTypeQueryChildren(preAst: TypeQuerySyntax, walker: AstWalker): void { + walker.walk(preAst.name); + } + + function walkInvocationExpressionChildren(preAst: InvocationExpressionSyntax, walker: AstWalker): void { + walker.walk(preAst.expression); + walker.walk(preAst.argumentList); + } + + function walkObjectCreationExpressionChildren(preAst: ObjectCreationExpressionSyntax, walker: AstWalker): void { + walker.walk(preAst.expression); + walker.walk(preAst.argumentList); + } + + function walkTrinaryExpressionChildren(preAst: ConditionalExpressionSyntax, walker: AstWalker): void { + walker.walk(preAst.condition); + walker.walk(preAst.whenTrue); + walker.walk(preAst.whenFalse); + } + + function walkFunctionExpressionChildren(preAst: FunctionExpressionSyntax, walker: AstWalker): void { + walker.walk(preAst.identifier); + walker.walk(preAst.callSignature); + walker.walk(preAst.block); + } + + function walkFunctionTypeChildren(preAst: FunctionTypeSyntax, walker: AstWalker): void { + walker.walk(preAst.typeParameterList); + walker.walk(preAst.parameterList); + walker.walk(preAst.type); + } + + function walkParenthesizedArrowFunctionExpressionChildren(preAst: ParenthesizedArrowFunctionExpressionSyntax, walker: AstWalker): void { + walker.walk(preAst.callSignature); + walker.walk(preAst.block); + walker.walk(preAst.expression); + } + + function walkSimpleArrowFunctionExpressionChildren(preAst: SimpleArrowFunctionExpressionSyntax, walker: AstWalker): void { + walker.walk(preAst.parameter); + walker.walk(preAst.block); + walker.walk(preAst.expression); + } + + function walkMemberFunctionDeclarationChildren(preAst: MemberFunctionDeclarationSyntax, walker: AstWalker): void { + walker.walk(preAst.propertyName); + walker.walk(preAst.callSignature); + walker.walk(preAst.block); + } + + function walkFuncDeclChildren(preAst: FunctionDeclarationSyntax, walker: AstWalker): void { + walker.walk(preAst.identifier); + walker.walk(preAst.callSignature); + walker.walk(preAst.block); + } + + function walkIndexMemberDeclarationChildren(preAst: IndexMemberDeclarationSyntax, walker: AstWalker): void { + walker.walk(preAst.indexSignature); + } + + function walkIndexSignatureChildren(preAst: IndexSignatureSyntax, walker: AstWalker): void { + walker.walk(preAst.parameters); + walker.walk(preAst.typeAnnotation); + } + + function walkCallSignatureChildren(preAst: CallSignatureSyntax, walker: AstWalker): void { + walker.walk(preAst.typeParameterList); + walker.walk(preAst.parameterList); + walker.walk(preAst.typeAnnotation); + } + + function walkConstraintChildren(preAst: ConstraintSyntax, walker: AstWalker): void { + walker.walk(preAst.typeOrExpression); + } + + function walkConstructorDeclarationChildren(preAst: ConstructorDeclarationSyntax, walker: AstWalker): void { + walker.walk(preAst.callSignature); + walker.walk(preAst.block); + } + + function walkConstructorTypeChildren(preAst: FunctionTypeSyntax, walker: AstWalker): void { + walker.walk(preAst.typeParameterList); + walker.walk(preAst.parameterList); + walker.walk(preAst.type); + } + + function walkConstructSignatureChildren(preAst: ConstructSignatureSyntax, walker: AstWalker): void { + walker.walk(preAst.callSignature); + } + + function walkParameterChildren(preAst: ParameterSyntax, walker: AstWalker): void { + walker.walk(preAst.identifier); + walker.walk(preAst.typeAnnotation); + walker.walk(preAst.equalsValueClause); + } + + function walkParameterListChildren(preAst: ParameterListSyntax, walker: AstWalker): void { + walker.walk(preAst.parameters); + } + + function walkPropertySignatureChildren(preAst: PropertySignatureSyntax, walker: AstWalker): void { + walker.walk(preAst.propertyName); + walker.walk(preAst.typeAnnotation); + } + + function walkVariableDeclaratorChildren(preAst: VariableDeclaratorSyntax, walker: AstWalker): void { + walker.walk(preAst.propertyName); + walker.walk(preAst.typeAnnotation); + walker.walk(preAst.equalsValueClause); + } + + function walkMemberVariableDeclarationChildren(preAst: MemberVariableDeclarationSyntax, walker: AstWalker): void { + walker.walk(preAst.variableDeclarator); + } + + function walkMethodSignatureChildren(preAst: MethodSignatureSyntax, walker: AstWalker): void { + walker.walk(preAst.propertyName); + walker.walk(preAst.callSignature); + } + + function walkReturnStatementChildren(preAst: ReturnStatementSyntax, walker: AstWalker): void { + walker.walk(preAst.expression); + } + + function walkForStatementChildren(preAst: ForStatementSyntax, walker: AstWalker): void { + walker.walk(preAst.variableDeclaration); + walker.walk(preAst.initializer); + walker.walk(preAst.condition); + walker.walk(preAst.incrementor); + walker.walk(preAst.statement); + } + + function walkForInStatementChildren(preAst: ForInStatementSyntax, walker: AstWalker): void { + walker.walk(preAst.variableDeclaration); + walker.walk(preAst.left); + walker.walk(preAst.expression); + walker.walk(preAst.statement); + } + + function walkIfStatementChildren(preAst: IfStatementSyntax, walker: AstWalker): void { + walker.walk(preAst.condition); + walker.walk(preAst.statement); + walker.walk(preAst.elseClause); + } + + function walkElseClauseChildren(preAst: ElseClauseSyntax, walker: AstWalker): void { + walker.walk(preAst.statement); + } + + function walkWhileStatementChildren(preAst: WhileStatementSyntax, walker: AstWalker): void { + walker.walk(preAst.condition); + walker.walk(preAst.statement); + } + + function walkDoStatementChildren(preAst: DoStatementSyntax, walker: AstWalker): void { + walker.walk(preAst.condition); + walker.walk(preAst.statement); + } + + function walkBlockChildren(preAst: BlockSyntax, walker: AstWalker): void { + walker.walk(preAst.statements); + } + + function walkVariableDeclarationChildren(preAst: VariableDeclarationSyntax, walker: AstWalker): void { + walker.walk(preAst.variableDeclarators); + } + + function walkCaseSwitchClauseChildren(preAst: CaseSwitchClauseSyntax, walker: AstWalker): void { + walker.walk(preAst.expression); + walker.walk(preAst.statements); + } + + function walkDefaultSwitchClauseChildren(preAst: DefaultSwitchClauseSyntax, walker: AstWalker): void { + walker.walk(preAst.statements); + } + + function walkSwitchStatementChildren(preAst: SwitchStatementSyntax, walker: AstWalker): void { + walker.walk(preAst.expression); + walker.walk(preAst.switchClauses); + } + + function walkTryStatementChildren(preAst: TryStatementSyntax, walker: AstWalker): void { + walker.walk(preAst.block); + walker.walk(preAst.catchClause); + walker.walk(preAst.finallyClause); + } + + function walkCatchClauseChildren(preAst: CatchClauseSyntax, walker: AstWalker): void { + walker.walk(preAst.identifier); + walker.walk(preAst.typeAnnotation); + walker.walk(preAst.block); + } + + function walkExternalModuleReferenceChildren(preAst: ExternalModuleReferenceSyntax, walker: AstWalker): void { + walker.walk(preAst.stringLiteral); + } + + function walkFinallyClauseChildren(preAst: FinallyClauseSyntax, walker: AstWalker): void { + walker.walk(preAst.block); + } + + function walkClassDeclChildren(preAst: ClassDeclarationSyntax, walker: AstWalker): void { + walker.walk(preAst.identifier); + walker.walk(preAst.typeParameterList); + walker.walk(preAst.heritageClauses); + walker.walk(preAst.classElements); + } + + function walkScriptChildren(preAst: SourceUnitSyntax, walker: AstWalker): void { + walker.walk(preAst.moduleElements); + } + + function walkHeritageClauseChildren(preAst: HeritageClauseSyntax, walker: AstWalker): void { + walker.walk(preAst.typeNames); + } + + function walkInterfaceDeclerationChildren(preAst: InterfaceDeclarationSyntax, walker: AstWalker): void { + walker.walk(preAst.identifier); + walker.walk(preAst.typeParameterList); + walker.walk(preAst.heritageClauses); + walker.walk(preAst.body); + } + + function walkObjectTypeChildren(preAst: ObjectTypeSyntax, walker: AstWalker): void { + walker.walk(preAst.typeMembers); + } + + function walkArrayTypeChildren(preAst: ArrayTypeSyntax, walker: AstWalker): void { + walker.walk(preAst.type); + } + + function walkModuleDeclarationChildren(preAst: ModuleDeclarationSyntax, walker: AstWalker): void { + walker.walk(preAst.name); + walker.walk(preAst.stringLiteral); + walker.walk(preAst.moduleElements); + } + + function walkModuleNameModuleReferenceChildren(preAst: ModuleNameModuleReferenceSyntax, walker: AstWalker): void { + walker.walk(preAst.moduleName); + } + + function walkEnumDeclarationChildren(preAst: EnumDeclarationSyntax, walker: AstWalker): void { + walker.walk(preAst.identifier); + walker.walk(preAst.enumElements); + } + + function walkEnumElementChildren(preAst: EnumElementSyntax, walker: AstWalker): void { + walker.walk(preAst.propertyName); + walker.walk(preAst.equalsValueClause); + } + + function walkImportDeclarationChildren(preAst: ImportDeclarationSyntax, walker: AstWalker): void { + walker.walk(preAst.identifier); + walker.walk(preAst.moduleReference); + } + + function walkExportAssignmentChildren(preAst: ExportAssignmentSyntax, walker: AstWalker): void { + walker.walk(preAst.identifier); + } + + function walkWithStatementChildren(preAst: WithStatementSyntax, walker: AstWalker): void { + walker.walk(preAst.condition); + walker.walk(preAst.statement); + } + + function walkExpressionStatementChildren(preAst: ExpressionStatementSyntax, walker: AstWalker): void { + walker.walk(preAst.expression); + } + + function walkLabeledStatementChildren(preAst: LabeledStatementSyntax, walker: AstWalker): void { + walker.walk(preAst.identifier); + walker.walk(preAst.statement); + } + + function walkVariableStatementChildren(preAst: VariableStatementSyntax, walker: AstWalker): void { + walker.walk(preAst.variableDeclaration); + } + + var childrenWalkers: IAstWalkChildren[] = new Array(SyntaxKind.LastNode + 1); + + // Tokens/trivia can't ever be walked into. + for (var i = SyntaxKind.FirstToken, n = SyntaxKind.LastToken; i <= n; i++) { + childrenWalkers[i] = null; + } + for (var i = SyntaxKind.FirstTrivia, n = SyntaxKind.LastTrivia; i <= n; i++) { + childrenWalkers[i] = null; + } + + childrenWalkers[SyntaxKind.AddAssignmentExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.AddExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.AndAssignmentExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.AnyKeyword] = null; + childrenWalkers[SyntaxKind.ArgumentList] = walkArgumentListChildren; + childrenWalkers[SyntaxKind.ArrayLiteralExpression] = walkArrayLiteralExpressionChildren; + childrenWalkers[SyntaxKind.ArrayType] = walkArrayTypeChildren; + childrenWalkers[SyntaxKind.SimpleArrowFunctionExpression] = walkSimpleArrowFunctionExpressionChildren; + childrenWalkers[SyntaxKind.ParenthesizedArrowFunctionExpression] = walkParenthesizedArrowFunctionExpressionChildren; + childrenWalkers[SyntaxKind.AssignmentExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.BitwiseAndExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.BitwiseExclusiveOrExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.BitwiseNotExpression] = walkPrefixUnaryExpressionChildren; + childrenWalkers[SyntaxKind.BitwiseOrExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.Block] = walkBlockChildren; + childrenWalkers[SyntaxKind.BooleanKeyword] = null; + childrenWalkers[SyntaxKind.BreakStatement] = null; + childrenWalkers[SyntaxKind.CallSignature] = walkCallSignatureChildren; + childrenWalkers[SyntaxKind.CaseSwitchClause] = walkCaseSwitchClauseChildren; + childrenWalkers[SyntaxKind.CastExpression] = walkCastExpressionChildren; + childrenWalkers[SyntaxKind.CatchClause] = walkCatchClauseChildren; + childrenWalkers[SyntaxKind.ClassDeclaration] = walkClassDeclChildren; + childrenWalkers[SyntaxKind.CommaExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.ConditionalExpression] = walkTrinaryExpressionChildren; + childrenWalkers[SyntaxKind.Constraint] = walkConstraintChildren; + childrenWalkers[SyntaxKind.ConstructorDeclaration] = walkConstructorDeclarationChildren; + childrenWalkers[SyntaxKind.ConstructSignature] = walkConstructSignatureChildren; + childrenWalkers[SyntaxKind.ContinueStatement] = null; + childrenWalkers[SyntaxKind.ConstructorType] = walkConstructorTypeChildren; + childrenWalkers[SyntaxKind.DebuggerStatement] = null; + childrenWalkers[SyntaxKind.DefaultSwitchClause] = walkDefaultSwitchClauseChildren; + childrenWalkers[SyntaxKind.DeleteExpression] = walkDeleteExpressionChildren; + childrenWalkers[SyntaxKind.DivideAssignmentExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.DivideExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.DoStatement] = walkDoStatementChildren; + childrenWalkers[SyntaxKind.ElementAccessExpression] = walkElementAccessExpressionChildren; + childrenWalkers[SyntaxKind.ElseClause] = walkElseClauseChildren; + childrenWalkers[SyntaxKind.EmptyStatement] = null; + childrenWalkers[SyntaxKind.EnumDeclaration] = walkEnumDeclarationChildren; + childrenWalkers[SyntaxKind.EnumElement] = walkEnumElementChildren; + childrenWalkers[SyntaxKind.EqualsExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.EqualsValueClause] = walkEqualsValueClauseChildren; + childrenWalkers[SyntaxKind.EqualsWithTypeConversionExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.ExclusiveOrAssignmentExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.ExportAssignment] = walkExportAssignmentChildren; + childrenWalkers[SyntaxKind.ExpressionStatement] = walkExpressionStatementChildren; + childrenWalkers[SyntaxKind.ExtendsHeritageClause] = walkHeritageClauseChildren; + childrenWalkers[SyntaxKind.ExternalModuleReference] = walkExternalModuleReferenceChildren; + childrenWalkers[SyntaxKind.FalseKeyword] = null; + childrenWalkers[SyntaxKind.FinallyClause] = walkFinallyClauseChildren; + childrenWalkers[SyntaxKind.ForInStatement] = walkForInStatementChildren; + childrenWalkers[SyntaxKind.ForStatement] = walkForStatementChildren; + childrenWalkers[SyntaxKind.FunctionDeclaration] = walkFuncDeclChildren; + childrenWalkers[SyntaxKind.FunctionExpression] = walkFunctionExpressionChildren; + childrenWalkers[SyntaxKind.FunctionPropertyAssignment] = walkFunctionPropertyAssignmentChildren; + childrenWalkers[SyntaxKind.FunctionType] = walkFunctionTypeChildren; + childrenWalkers[SyntaxKind.GenericType] = walkGenericTypeChildren; + childrenWalkers[SyntaxKind.GetAccessor] = walkGetAccessorChildren; + childrenWalkers[SyntaxKind.GreaterThanExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.GreaterThanOrEqualExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.IfStatement] = walkIfStatementChildren; + childrenWalkers[SyntaxKind.ImplementsHeritageClause] = walkHeritageClauseChildren; + childrenWalkers[SyntaxKind.ImportDeclaration] = walkImportDeclarationChildren; + childrenWalkers[SyntaxKind.IndexMemberDeclaration] = walkIndexMemberDeclarationChildren; + childrenWalkers[SyntaxKind.IndexSignature] = walkIndexSignatureChildren; + childrenWalkers[SyntaxKind.InExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.InstanceOfExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.InterfaceDeclaration] = walkInterfaceDeclerationChildren; + childrenWalkers[SyntaxKind.InvocationExpression] = walkInvocationExpressionChildren; + childrenWalkers[SyntaxKind.LabeledStatement] = walkLabeledStatementChildren; + childrenWalkers[SyntaxKind.LeftShiftAssignmentExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.LeftShiftExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.LessThanExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.LessThanOrEqualExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.List] = walkListChildren; + childrenWalkers[SyntaxKind.LogicalAndExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.LogicalNotExpression] = walkPrefixUnaryExpressionChildren; + childrenWalkers[SyntaxKind.LogicalOrExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.MemberAccessExpression] = walkMemberAccessExpressionChildren; + childrenWalkers[SyntaxKind.MemberFunctionDeclaration] = walkMemberFunctionDeclarationChildren; + childrenWalkers[SyntaxKind.MemberVariableDeclaration] = walkMemberVariableDeclarationChildren; + childrenWalkers[SyntaxKind.MethodSignature] = walkMethodSignatureChildren; + childrenWalkers[SyntaxKind.ModuleDeclaration] = walkModuleDeclarationChildren; + childrenWalkers[SyntaxKind.ModuleNameModuleReference] = walkModuleNameModuleReferenceChildren; + childrenWalkers[SyntaxKind.ModuloAssignmentExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.ModuloExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.MultiplyAssignmentExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.MultiplyExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.IdentifierName] = null; + childrenWalkers[SyntaxKind.NegateExpression] = walkPrefixUnaryExpressionChildren; + childrenWalkers[SyntaxKind.None] = null; + childrenWalkers[SyntaxKind.NotEqualsExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.NotEqualsWithTypeConversionExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.NullKeyword] = null; + childrenWalkers[SyntaxKind.NumberKeyword] = null; + childrenWalkers[SyntaxKind.NumericLiteral] = null; + childrenWalkers[SyntaxKind.ObjectCreationExpression] = walkObjectCreationExpressionChildren; + childrenWalkers[SyntaxKind.ObjectLiteralExpression] = walkObjectLiteralExpressionChildren; + childrenWalkers[SyntaxKind.ObjectType] = walkObjectTypeChildren; + childrenWalkers[SyntaxKind.OmittedExpression] = null; + childrenWalkers[SyntaxKind.OrAssignmentExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.Parameter] = walkParameterChildren; + childrenWalkers[SyntaxKind.ParameterList] = walkParameterListChildren; + childrenWalkers[SyntaxKind.ParenthesizedExpression] = walkParenthesizedExpressionChildren; + childrenWalkers[SyntaxKind.PlusExpression] = walkPrefixUnaryExpressionChildren; + childrenWalkers[SyntaxKind.PostDecrementExpression] = walkPostfixUnaryExpressionChildren; + childrenWalkers[SyntaxKind.PostIncrementExpression] = walkPostfixUnaryExpressionChildren; + childrenWalkers[SyntaxKind.PreDecrementExpression] = walkPrefixUnaryExpressionChildren; + childrenWalkers[SyntaxKind.PreIncrementExpression] = walkPrefixUnaryExpressionChildren; + childrenWalkers[SyntaxKind.PropertySignature] = walkPropertySignatureChildren; + childrenWalkers[SyntaxKind.QualifiedName] = walkQualifiedNameChildren; + childrenWalkers[SyntaxKind.RegularExpressionLiteral] = null; + childrenWalkers[SyntaxKind.ReturnStatement] = walkReturnStatementChildren; + childrenWalkers[SyntaxKind.SourceUnit] = walkScriptChildren; + childrenWalkers[SyntaxKind.SeparatedList] = walkSeparatedListChildren; + childrenWalkers[SyntaxKind.SetAccessor] = walkSetAccessorChildren; + childrenWalkers[SyntaxKind.SignedRightShiftAssignmentExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.SignedRightShiftExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.SimplePropertyAssignment] = walkSimplePropertyAssignmentChildren; + childrenWalkers[SyntaxKind.StringLiteral] = null; + childrenWalkers[SyntaxKind.StringKeyword] = null; + childrenWalkers[SyntaxKind.SubtractAssignmentExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.SubtractExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.SuperKeyword] = null; + childrenWalkers[SyntaxKind.SwitchStatement] = walkSwitchStatementChildren; + childrenWalkers[SyntaxKind.ThisKeyword] = null; + childrenWalkers[SyntaxKind.ThrowStatement] = walkThrowStatementChildren; + childrenWalkers[SyntaxKind.TriviaList] = null; + childrenWalkers[SyntaxKind.TrueKeyword] = null; + childrenWalkers[SyntaxKind.TryStatement] = walkTryStatementChildren; + childrenWalkers[SyntaxKind.TypeAnnotation] = walkTypeAnnotationChildren; + childrenWalkers[SyntaxKind.TypeArgumentList] = walkTypeArgumentListChildren; + childrenWalkers[SyntaxKind.TypeOfExpression] = walkTypeOfExpressionChildren; + childrenWalkers[SyntaxKind.TypeParameter] = walkTypeParameterChildren; + childrenWalkers[SyntaxKind.TypeParameterList] = walkTypeParameterListChildren; + childrenWalkers[SyntaxKind.TypeQuery] = walkTypeQueryChildren; + childrenWalkers[SyntaxKind.UnsignedRightShiftAssignmentExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.UnsignedRightShiftExpression] = walkBinaryExpressionChildren; + childrenWalkers[SyntaxKind.VariableDeclaration] = walkVariableDeclarationChildren; + childrenWalkers[SyntaxKind.VariableDeclarator] = walkVariableDeclaratorChildren; + childrenWalkers[SyntaxKind.VariableStatement] = walkVariableStatementChildren; + childrenWalkers[SyntaxKind.VoidExpression] = walkVoidExpressionChildren; + childrenWalkers[SyntaxKind.VoidKeyword] = null; + childrenWalkers[SyntaxKind.WhileStatement] = walkWhileStatementChildren; + childrenWalkers[SyntaxKind.WithStatement] = walkWithStatementChildren; + + // Verify the code is up to date with the enum + for (var e in SyntaxKind) { + if (SyntaxKind.hasOwnProperty(e) && StringUtilities.isString(SyntaxKind[e])) { + TypeScript.Debug.assert(childrenWalkers[e] !== undefined, "Fix initWalkers: " + SyntaxKind[e]); + } + } + + export class AstWalkOptions { + public goChildren = true; + public stopWalking = false; + } + + interface IAstWalkChildren { + (preAst: ISyntaxElement, walker: AstWalker): void; + } + + export interface IAstWalker { + options: AstWalkOptions; + state: any + } + + interface AstWalker { + walk(ast: ISyntaxElement): void; + } + + class SimplePreAstWalker implements AstWalker { + public options: AstWalkOptions = new AstWalkOptions(); + + constructor( + private pre: (ast: ISyntaxElement, state: any) => void, + public state: any) { + } + + public walk(ast: ISyntaxElement): void { + if (!ast) { + return; + } + + this.pre(ast, this.state); + + var walker = childrenWalkers[ast.kind()]; + if (walker) { + walker(ast, this); + } + } + } + + class SimplePrePostAstWalker implements AstWalker { + public options: AstWalkOptions = new AstWalkOptions(); + + constructor( + private pre: (ast: ISyntaxElement, state: any) => void, + private post: (ast: ISyntaxElement, state: any) => void, + public state: any) { + } + + public walk(ast: ISyntaxElement): void { + if (!ast) { + return; + } + + this.pre(ast, this.state); + + var walker = childrenWalkers[ast.kind()]; + if (walker) { + walker(ast, this); + } + + this.post(ast, this.state); + } + } + + class NormalAstWalker implements AstWalker { + public options: AstWalkOptions = new AstWalkOptions(); + + constructor( + private pre: (ast: ISyntaxElement, walker: IAstWalker) => void, + private post: (ast: ISyntaxElement, walker: IAstWalker) => void, + public state: any) { + } + + public walk(ast: ISyntaxElement): void { + if (!ast) { + return; + } + + // If we're stopping, then bail out immediately. + if (this.options.stopWalking) { + return; + } + + this.pre(ast, this); + + // If we were asked to stop, then stop. + if (this.options.stopWalking) { + return; + } + + if (this.options.goChildren) { + // Call the "walkChildren" function corresponding to "nodeType". + var walker = childrenWalkers[ast.kind()]; + if (walker) { + walker(ast, this); + } + } + else { + // no go only applies to children of node issuing it + this.options.goChildren = true; + } + + if (this.post) { + this.post(ast, this); + } + } + } + + export class AstWalkerFactory { + public walk(ast: ISyntaxElement, pre: (ast: ISyntaxElement, walker: IAstWalker) => void, post?: (ast: ISyntaxElement, walker: IAstWalker) => void, state?: any): void { + new NormalAstWalker(pre, post, state).walk(ast); + } + + public simpleWalk(ast: ISyntaxElement, pre: (ast: ISyntaxElement, state: any) => void, post?: (ast: ISyntaxElement, state: any) => void, state?: any): void { + if (post) { + new SimplePrePostAstWalker(pre, post, state).walk(ast); + } + else { + new SimplePreAstWalker(pre, state).walk(ast); + } + } + } + + var globalAstWalkerFactory = new AstWalkerFactory(); + + export function getAstWalkerFactory(): AstWalkerFactory { + return globalAstWalkerFactory; + } +} \ No newline at end of file diff --git a/src/services/compiler/base64.ts b/src/services/compiler/base64.ts new file mode 100644 index 00000000000..06eac4f4b74 --- /dev/null +++ b/src/services/compiler/base64.ts @@ -0,0 +1,96 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +module TypeScript { + class Base64Format { + static encodedValues = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + static encode(inValue: number) { + if (inValue < 64) { + return Base64Format.encodedValues.charAt(inValue); + } + throw TypeError(inValue + ": not a 64 based value"); + } + + static decodeChar(inChar: string) { + if (inChar.length === 1) { + return Base64Format.encodedValues.indexOf(inChar); + } + else { + throw TypeError('"' + inChar + '" must have length 1'); + } + } + } + + export class Base64VLQFormat { + static encode(inValue: number) { + // Add a new least significant bit that has the sign of the value. + // if negative number the least significant bit that gets added to the number has value 1 + // else least significant bit value that gets added is 0 + // eg. -1 changes to binary : 01 [1] => 3 + // +1 changes to binary : 01 [0] => 2 + if (inValue < 0) { + inValue = ((-inValue) << 1) + 1; + } + else { + inValue = inValue << 1; + } + + // Encode 5 bits at a time starting from least significant bits + var encodedStr = ""; + do { + var currentDigit = inValue & 31; // 11111 + inValue = inValue >> 5; + if (inValue > 0) { + // There are still more digits to decode, set the msb (6th bit) + currentDigit = currentDigit | 32; + } + encodedStr = encodedStr + Base64Format.encode(currentDigit); + } while (inValue > 0); + + return encodedStr; + } + + static decode(inString: string) { + var result = 0; + var negative = false; + + var shift = 0; + for (var i = 0; i < inString.length; i++) { + var byte = Base64Format.decodeChar(inString[i]); + if (i === 0) { + // Sign bit appears in the LSBit of the first value + if ((byte & 1) === 1) { + negative = true; + } + result = (byte >> 1) & 15; // 1111x + } + else { + result = result | ((byte & 31) << shift); // 11111 + } + + shift += (i === 0) ? 4 : 5; + + if ((byte & 32) === 32) { + // Continue + } + else { + return { value: negative ? -(result) : result, rest: inString.substr(i + 1) }; + } + } + + throw new Error(getDiagnosticMessage(DiagnosticCode.Base64_value_0_finished_with_a_continuation_bit, [inString])); + } + } +} diff --git a/src/services/compiler/bloomFilter.ts b/src/services/compiler/bloomFilter.ts new file mode 100644 index 00000000000..fe841b6f7a3 --- /dev/null +++ b/src/services/compiler/bloomFilter.ts @@ -0,0 +1,131 @@ +/// + +module TypeScript { + + export class BloomFilter { + private bitArray: boolean[]; + private hashFunctionCount: number; + + public static falsePositiveProbability: number = 0.0001; + + /* + * From the bloom filter calculator here: http://hur.st/bloomfilter?n=4&p=1.0E-20 + * + * 1) n = Number of items in the filter + * + * 2) p = Probability of false positives, (a double between 0 and 1). + * + * 3) m = Number of bits in the filter + * + * 4) k = Number of hash functions + * + * m = ceil((n * log(p)) / log(1.0 / (pow(2.0, log(2.0))))) + * + * k = round(log(2.0) * m / n) + * + */ + constructor(expectedCount: number) { + var m: number = Math.max(1, BloomFilter.computeM(expectedCount)); + var k: number = Math.max(1, BloomFilter.computeK(expectedCount));; + + // We must have size in even bytes, so that when we deserialize from bytes we get a bit array with the same count. + // The count is used by the hash functions. + var sizeInEvenBytes = (m + 7) & ~7; + + this.bitArray = []; + for (var i = 0, len = sizeInEvenBytes; i < len; i++) { + this.bitArray[i] = false; + } + this.hashFunctionCount = k; + } + + // m = ceil((n * log(p)) / log(1.0 / (pow(2.0, log(2.0))))) + static computeM(expectedCount: number): number { + var p: number = BloomFilter.falsePositiveProbability; + var n: number = expectedCount; + + var numerator = n * Math.log(p); + var denominator = Math.log(1.0 / Math.pow(2.0, Math.log(2.0))); + return Math.ceil(numerator / denominator); + } + + // k = round(log(2.0) * m / n) + static computeK(expectedCount: number): number { + var n: number = expectedCount; + var m: number = BloomFilter.computeM(expectedCount); + + var temp = Math.log(2.0) * m / n; + return Math.round(temp); + } + + /** Modification of the murmurhash2 algorithm. Code is simpler because it operates over + * strings instead of byte arrays. Because each string character is two bytes, it is known + * that the input will be an even number of bytes (though not necessarily a multiple of 4). + * + * This is needed over the normal 'string.GetHashCode()' because we need to be able to generate + * 'k' different well distributed hashes for any given string s. Also, we want to be able to + * generate these hashes without allocating any memory. My ideal solution would be to use an + * MD5 hash. However, there appears to be no way to do MD5 in .Net where you can: + * + * a) feed it individual values instead of a byte[] + * + * b) have the hash computed into a byte[] you provide instead of a newly allocated one + * + * Generating 'k' pieces of garbage on each insert and lookup seems very wasteful. So, + * instead, we use murmur hash since it provides well distributed values, allows for a + * seed, and allocates no memory. + * + * Murmur hash is public domain. Actual code is included below as reference. + */ + private computeHash(key: string, seed: number): number { + return Hash.computeMurmur2StringHashCode(key, seed); + } + + public addKeys(keys: IIndexable) { + for (var name in keys) { + if (keys[name]) { + this.add(name); + } + } + } + + public add(value: string) { + for (var i = 0; i < this.hashFunctionCount; i++) { + var hash = this.computeHash(value, i); + hash = hash % this.bitArray.length; + this.bitArray[Math.abs(hash)] = true; + } + } + + public probablyContains(value: string): boolean { + for (var i = 0; i < this.hashFunctionCount; i++) { + var hash = this.computeHash(value, i); + hash = hash % this.bitArray.length; + if (!this.bitArray[Math.abs(hash)]) { + return false; + } + } + + return true; + } + + public isEquivalent(filter: BloomFilter): boolean { + return BloomFilter.isEquivalent(this.bitArray, filter.bitArray) + && this.hashFunctionCount === filter.hashFunctionCount; + } + + static isEquivalent(array1: boolean[], array2: boolean[]): boolean { + if (array1.length !== array2.length) { + return false; + } + + for (var i = 0; i < array1.length; i++) { + if (array1[i] !== array2[i]) { + return false; + } + } + + return true; + } + } +} diff --git a/src/services/compiler/declarationEmitter.ts b/src/services/compiler/declarationEmitter.ts new file mode 100644 index 00000000000..d3052389cb0 --- /dev/null +++ b/src/services/compiler/declarationEmitter.ts @@ -0,0 +1,1138 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript { + export class TextWriter { + private contents = ""; + public onNewLine = true; + constructor(private name: string, private writeByteOrderMark: boolean, private outputFileType: OutputFileType) { + } + + public Write(s: string) { + this.contents += s; + this.onNewLine = false; + } + + public WriteLine(s: string) { + this.contents += s; + this.contents += TypeScript.newLine(); + this.onNewLine = true; + } + + public Close(): void { + } + + public getOutputFile(): OutputFile { + return new OutputFile(this.name, this.writeByteOrderMark, this.contents, this.outputFileType); + } + } + + export class DeclarationEmitter { + private declFile: TextWriter = null; + private indenter = new Indenter(); + private emittedReferencePaths = false; + + constructor(private emittingFileName: string, + public document: Document, + private compiler: TypeScriptCompiler, + private emitOptions: EmitOptions, + private semanticInfoChain: SemanticInfoChain) { + this.declFile = new TextWriter(emittingFileName, this.document.byteOrderMark !== ByteOrderMark.None, OutputFileType.Declaration); + } + + public getOutputFile(): OutputFile { + return this.declFile.getOutputFile(); + } + + public emitDeclarations(sourceUnit: SourceUnitSyntax) { + this.emitDeclarationsForSourceUnit(sourceUnit); + } + + private emitDeclarationsForList(list: ISyntaxNodeOrToken[]) { + for (var i = 0, n = list.length; i < n; i++) { + this.emitDeclarationsForAST(list[i]); + } + } + + private emitSeparatedList(list: ISyntaxNodeOrToken[]) { + for (var i = 0, n = list.length; i < n; i++) { + this.emitDeclarationsForAST(list[i]); + } + } + + private emitDeclarationsForAST(ast: ISyntaxElement) { + switch (ast.kind()) { + case SyntaxKind.VariableStatement: + return this.emitDeclarationsForVariableStatement(ast); + case SyntaxKind.PropertySignature: + return this.emitPropertySignature(ast); + case SyntaxKind.VariableDeclarator: + return this.emitVariableDeclarator(ast, true, true); + case SyntaxKind.MemberVariableDeclaration: + return this.emitDeclarationsForMemberVariableDeclaration(ast); + case SyntaxKind.ConstructorDeclaration: + return this.emitDeclarationsForConstructorDeclaration(ast); + case SyntaxKind.GetAccessor: + return this.emitDeclarationsForGetAccessor(ast); + case SyntaxKind.SetAccessor: + return this.emitDeclarationsForSetAccessor(ast); + case SyntaxKind.IndexMemberDeclaration: + return this.emitIndexMemberDeclaration(ast); + case SyntaxKind.IndexSignature: + return this.emitIndexSignature(ast); + case SyntaxKind.CallSignature: + return this.emitCallSignature(ast); + case SyntaxKind.ConstructSignature: + return this.emitConstructSignature(ast); + case SyntaxKind.MethodSignature: + return this.emitMethodSignature(ast); + case SyntaxKind.FunctionDeclaration: + return this.emitDeclarationsForFunctionDeclaration(ast); + case SyntaxKind.MemberFunctionDeclaration: + return this.emitMemberFunctionDeclaration(ast); + case SyntaxKind.ClassDeclaration: + return this.emitDeclarationsForClassDeclaration(ast); + case SyntaxKind.InterfaceDeclaration: + return this.emitDeclarationsForInterfaceDeclaration(ast); + case SyntaxKind.ImportDeclaration: + return this.emitDeclarationsForImportDeclaration(ast); + case SyntaxKind.ModuleDeclaration: + return this.emitDeclarationsForModuleDeclaration(ast); + case SyntaxKind.EnumDeclaration: + return this.emitDeclarationsForEnumDeclaration(ast); + case SyntaxKind.ExportAssignment: + return this.emitDeclarationsForExportAssignment(ast); + } + } + + private getIndentString(declIndent = false) { + return this.indenter.getIndent(); + } + + private emitIndent() { + this.declFile.Write(this.getIndentString()); + } + + private canEmitDeclarations(declAST: ISyntaxElement): boolean { + var container = DeclarationEmitter.getEnclosingContainer(declAST); + if (container.kind() === SyntaxKind.ModuleDeclaration || container.kind() === SyntaxKind.SourceUnit) { + var pullDecl = this.semanticInfoChain.getDeclForAST(declAST); + if (!hasFlag(pullDecl.flags, PullElementFlags.Exported)) { + var start = new Date().getTime(); + var declSymbol = this.semanticInfoChain.getSymbolForAST(declAST); + var result = declSymbol && declSymbol.isExternallyVisible(); + TypeScript.declarationEmitIsExternallyVisibleTime += new Date().getTime() - start; + + return result; + } + } + + return true; + } + + private getDeclFlagsString(pullDecl: PullDecl, typeString: string) { + var result = this.getIndentString(); + var pullFlags = pullDecl.flags; + + // Static/public/private/global declare + if (hasFlag(pullFlags, PullElementFlags.Static)) { + if (hasFlag(pullFlags, PullElementFlags.Private)) { + result += "private "; + } + result += "static "; + } + else { + if (hasFlag(pullFlags, PullElementFlags.Private)) { + result += "private "; + } + else if (hasFlag(pullFlags, PullElementFlags.Public)) { + result += "public "; + } + else { + var emitDeclare = !hasFlag(pullFlags, PullElementFlags.Exported); + + var declAST = this.semanticInfoChain.getASTForDecl(pullDecl); + var container = DeclarationEmitter.getEnclosingContainer(declAST); + + var isExternalModule = container.kind() === SyntaxKind.SourceUnit && this.document.syntaxTree().isExternalModule(); + + // Emit export only for global export statements. + // The container for this would be dynamic module which is whole file + if (isExternalModule && hasFlag(pullFlags, PullElementFlags.Exported)) { + result += "export "; + emitDeclare = true; + } + + // Emit declare only in global context + if (isExternalModule || container.kind() === SyntaxKind.SourceUnit) { + // Emit declare if not interface declaration or import declaration && is not from module + if (emitDeclare && typeString !== "interface" && typeString !== "import") { + result += "declare "; + } + } + + result += typeString + " "; + } + } + + return result; + } + + private emitDeclFlags(declarationAST: ISyntaxElement, typeString: string) { + this.declFile.Write(this.getDeclFlagsString(this.semanticInfoChain.getDeclForAST(declarationAST), typeString)); + } + + private emitTypeNamesMember(memberName: MemberName, emitIndent: boolean = false) { + if (memberName.prefix === "{ ") { + if (emitIndent) { + this.emitIndent(); + } + + this.declFile.WriteLine("{"); + this.indenter.increaseIndent(); + emitIndent = true; + } + else if (memberName.prefix !== "") { + if (emitIndent) { + this.emitIndent(); + } + + this.declFile.Write(memberName.prefix); + emitIndent = false; + } + + if (memberName.isString()) { + if (emitIndent) { + this.emitIndent(); + } + + this.declFile.Write((memberName).text); + } + else if (memberName.isArray()) { + var ar = memberName; + for (var index = 0; index < ar.entries.length; index++) { + this.emitTypeNamesMember(ar.entries[index], emitIndent); + if (ar.delim === "; ") { + this.declFile.WriteLine(";"); + } + } + } + + if (memberName.suffix === "}") { + this.indenter.decreaseIndent(); + this.emitIndent(); + this.declFile.Write(memberName.suffix); + } + else { + this.declFile.Write(memberName.suffix); + } + } + + private emitTypeSignature(ast: ISyntaxElement, type: PullTypeSymbol) { + var declarationContainerAst = DeclarationEmitter.getEnclosingContainer(ast); + + var start = new Date().getTime(); + var declarationContainerDecl = this.semanticInfoChain.getDeclForAST(declarationContainerAst); + + var declarationPullSymbol = declarationContainerDecl.getSymbol(this.semanticInfoChain); + TypeScript.declarationEmitTypeSignatureTime += new Date().getTime() - start; + + var isNotAGenericType = ast.kind() !== SyntaxKind.GenericType; + + var typeNameMembers = type.getScopedNameEx( + declarationPullSymbol, + /*skipTypeParametersInName?*/ false, + /*useConstraintInName?*/ false, + /*getPrettyTypeName?*/ false, + /*getTypeParamMarkerInfo?*/ false, + /*skipInternalAliasName?*/ false, + /*shouldAllowArrayType:*/ isNotAGenericType); + this.emitTypeNamesMember(typeNameMembers); + } + + private emitComment(comment: Comment) { + var text = getTrimmedTextLines(comment); + if (this.declFile.onNewLine) { + this.emitIndent(); + } + else if (comment.kind() !== SyntaxKind.MultiLineCommentTrivia) { + this.declFile.WriteLine(""); + this.emitIndent(); + } + + this.declFile.Write(text[0]); + + for (var i = 1; i < text.length; i++) { + this.declFile.WriteLine(""); + this.emitIndent(); + this.declFile.Write(text[i]); + } + + if (comment.endsLine || comment.kind() !== SyntaxKind.MultiLineCommentTrivia) { + this.declFile.WriteLine(""); + } + else { + this.declFile.Write(" "); + } + } + + private text() { + return this.document.syntaxTree().text; + } + + private emitDeclarationComments(ast: ISyntaxElement, endLine?: boolean): void; + private emitDeclarationComments(astOrSymbol: any, endLine = true) { + if (this.emitOptions.compilationSettings().removeComments()) { + return; + } + + var declComments: Comment[] = astOrSymbol.docComments ? astOrSymbol.docComments() : ASTHelpers.docComments(astOrSymbol, this.text()); + this.writeDeclarationComments(declComments, endLine); + } + + private writeDeclarationComments(declComments: Comment[], endLine = true) { + if (declComments) { + var wroteComment = false; + for (var i = 0; i < declComments.length; i++) { + if (ASTHelpers.isDocComment(declComments[i])) { + this.emitComment(declComments[i]); + wroteComment = true; + } + } + + if (wroteComment) { + if (endLine) { + if (!this.declFile.onNewLine) { + this.declFile.WriteLine(""); + } + } + else { + if (this.declFile.onNewLine) { + this.emitIndent(); + } + } + } + } + } + + private emitTypeOfVariableDeclaratorOrParameter(boundDecl: ISyntaxElement) { + var start = new Date().getTime(); + var decl = this.semanticInfoChain.getDeclForAST(boundDecl); + var pullSymbol = decl.getSymbol(this.semanticInfoChain); + TypeScript.declarationEmitGetBoundDeclTypeTime += new Date().getTime() - start; + + var type = pullSymbol.type; + Debug.assert(type); + + this.declFile.Write(": "); + this.emitTypeSignature(boundDecl, type); + } + + private emitPropertySignature(varDecl: PropertySignatureSyntax): void { + this.emitDeclarationComments(varDecl); + this.emitIndent(); + this.declFile.Write(varDecl.propertyName.text()); + if (varDecl.questionToken) { + this.declFile.Write("?"); + } + + this.emitTypeOfVariableDeclaratorOrParameter(varDecl); + + this.declFile.WriteLine(";"); + } + + private emitVariableDeclarator(varDecl: VariableDeclaratorSyntax, isFirstVarInList: boolean, isLastVarInList: boolean) { + if (this.canEmitDeclarations(varDecl)) { + this.emitDeclarationComments(varDecl); + // If it is var list of form var a, b, c = emit it only if count > 0 - which will be when emitting first var + // If it is var list of form var a = varList count will be 0 + if (isFirstVarInList) { + this.emitDeclFlags(varDecl, "var"); + } + + this.declFile.Write(varDecl.propertyName.text()); + + if (!hasModifier(ASTHelpers.getVariableDeclaratorModifiers(varDecl), PullElementFlags.Private)) { + this.emitTypeOfVariableDeclaratorOrParameter(varDecl); + } + + // Write ; or , + if (isLastVarInList) { + this.declFile.WriteLine(";"); + } + else { + this.declFile.Write(", "); + } + } + } + + private emitClassElementModifiers(modifiers: ISyntaxToken[]): void { + if (hasModifier(modifiers, PullElementFlags.Static)) { + if (hasModifier(modifiers, PullElementFlags.Private)) { + this.declFile.Write("private "); + } + this.declFile.Write("static "); + } + else { + if (hasModifier(modifiers, PullElementFlags.Private)) { + this.declFile.Write("private "); + } + else { + this.declFile.Write("public "); + } + } + } + + private emitDeclarationsForMemberVariableDeclaration(varDecl: MemberVariableDeclarationSyntax) { + if (this.canEmitDeclarations(varDecl)) { + this.emitDeclarationComments(varDecl); + + this.declFile.Write(this.getIndentString()); + this.emitClassElementModifiers(varDecl.modifiers);; + + this.declFile.Write(varDecl.variableDeclarator.propertyName.text()); + + if (!hasModifier(varDecl.modifiers, PullElementFlags.Private)) { + this.emitTypeOfVariableDeclaratorOrParameter(varDecl); + } + + this.declFile.WriteLine(";"); + } + } + + private emitDeclarationsForVariableStatement(variableStatement: VariableStatementSyntax) { + this.emitDeclarationsForVariableDeclaration(variableStatement.variableDeclaration); + } + + private emitDeclarationsForVariableDeclaration(variableDeclaration: VariableDeclarationSyntax) { + var varListCount = variableDeclaration.variableDeclarators.length; + for (var i = 0; i < varListCount; i++) { + this.emitVariableDeclarator(variableDeclaration.variableDeclarators[i], i === 0, i === varListCount - 1); + } + } + + private parameterIsOptional(parameter: ParameterSyntax) { + return parameter.questionToken !== null || parameter.equalsValueClause !== null; + } + + private emitParameter(argDecl: ParameterSyntax, isPrivate: boolean) { + this.indenter.increaseIndent(); + + this.emitDeclarationComments(argDecl, false); + this.declFile.Write(argDecl.identifier.text()); + if (this.parameterIsOptional(argDecl)) { + this.declFile.Write("?"); + } + + this.indenter.decreaseIndent(); + + if (!isPrivate) { + this.emitTypeOfVariableDeclaratorOrParameter(argDecl); + } + } + + private isOverloadedCallSignature(funcDecl: ISyntaxElement) { + var start = new Date().getTime(); + var functionDecl = this.semanticInfoChain.getDeclForAST(funcDecl); + var funcSymbol = functionDecl.getSymbol(this.semanticInfoChain); + TypeScript.declarationEmitIsOverloadedCallSignatureTime += new Date().getTime() - start; + + var funcTypeSymbol = funcSymbol.type; + var signatures = funcTypeSymbol.getCallSignatures(); + var result = signatures && signatures.length > 1; + + return result; + } + + private emitDeclarationsForConstructorDeclaration(funcDecl: ConstructorDeclarationSyntax) { + var start = new Date().getTime(); + var funcSymbol = this.semanticInfoChain.getSymbolForAST(funcDecl); + + TypeScript.declarationEmitFunctionDeclarationGetSymbolTime += new Date().getTime() - start; + + var funcTypeSymbol = funcSymbol.type; + if (funcDecl.block) { + var constructSignatures = funcTypeSymbol.getConstructSignatures(); + if (constructSignatures && constructSignatures.length > 1) { + return; + } + //else if (this.isOverloadedCallSignature(funcDecl)) { + // // This means its implementation of overload signature. do not emit + // return; + //} + } + + var funcPullDecl = this.semanticInfoChain.getDeclForAST(funcDecl); + var funcSignature = funcPullDecl.getSignatureSymbol(this.semanticInfoChain); + this.emitDeclarationComments(funcDecl); + + this.emitIndent(); + this.declFile.Write("constructor"); + + this.emitParameterList(/*isPrivate:*/ false, funcDecl.callSignature.parameterList); + + this.declFile.WriteLine(";"); + } + + private emitParameterList(isPrivate: boolean, parameterList: ParameterListSyntax): void { + this.declFile.Write("("); + this.emitParameters(isPrivate, parameterList.parameters); + this.declFile.Write(")"); + } + + private emitParameters(isPrivate: boolean, parameterList: ParameterSyntax[]): void { + var hasLastParameterRestParameter = lastParameterIsRest(parameterList); + var argsLen = parameterList.length; + if (hasLastParameterRestParameter) { + argsLen--; + } + + for (var i = 0; i < argsLen; i++) { + this.emitParameter(parameterList[i], isPrivate); + if (i < (argsLen - 1)) { + this.declFile.Write(", "); + } + } + + if (hasLastParameterRestParameter) { + if (parameterList.length > 1) { + this.declFile.Write(", ..."); + } + else { + this.declFile.Write("..."); + } + + var index = parameterList.length - 1; + this.emitParameter(parameterList[index], isPrivate); + } + } + + private emitMemberFunctionDeclaration(funcDecl: MemberFunctionDeclarationSyntax) { + var start = new Date().getTime(); + var funcSymbol = this.semanticInfoChain.getSymbolForAST(funcDecl); + + TypeScript.declarationEmitFunctionDeclarationGetSymbolTime += new Date().getTime() - start; + + var funcTypeSymbol = funcSymbol.type; + if (funcDecl.block) { + var constructSignatures = funcTypeSymbol.getConstructSignatures(); + if (constructSignatures && constructSignatures.length > 1) { + return; + } + else if (this.isOverloadedCallSignature(funcDecl)) { + // This means its implementation of overload signature. do not emit + return; + } + } + else if (hasModifier(funcDecl.modifiers, PullElementFlags.Private) && this.isOverloadedCallSignature(funcDecl)) { + // Print only first overload of private function + var callSignatures = funcTypeSymbol.getCallSignatures(); + Debug.assert(callSignatures && callSignatures.length > 1); + var firstSignature = callSignatures[0].isDefinition() ? callSignatures[1] : callSignatures[0]; + var firstSignatureDecl = firstSignature.getDeclarations()[0]; + var firstFuncDecl = this.semanticInfoChain.getASTForDecl(firstSignatureDecl); + if (firstFuncDecl !== funcDecl) { + return; + } + } + + if (!this.canEmitDeclarations(funcDecl)) { + return; + } + + var funcPullDecl = this.semanticInfoChain.getDeclForAST(funcDecl); + var funcSignature = funcPullDecl.getSignatureSymbol(this.semanticInfoChain); + this.emitDeclarationComments(funcDecl); + + this.emitDeclFlags(funcDecl, "function"); + var id = funcDecl.propertyName.text(); + this.declFile.Write(id); + this.emitTypeParameters(funcDecl.callSignature.typeParameterList, funcSignature); + + var isPrivate = hasModifier(funcDecl.modifiers, PullElementFlags.Private); + + this.emitParameterList(isPrivate, funcDecl.callSignature.parameterList); + + if (!isPrivate) { + var returnType = funcSignature.returnType; + this.declFile.Write(": "); + this.emitTypeSignature(funcDecl, returnType); + } + + this.declFile.WriteLine(";"); + } + + private emitCallSignature(funcDecl: CallSignatureSyntax): void { + var funcPullDecl = this.semanticInfoChain.getDeclForAST(funcDecl); + + this.emitDeclarationComments(funcDecl); + + var funcSignature = funcPullDecl.getSignatureSymbol(this.semanticInfoChain); + this.emitTypeParameters(funcDecl.typeParameterList, funcSignature); + + this.emitIndent(); + + this.emitParameterList(/*isPrivate:*/ false, funcDecl.parameterList); + + var returnType = funcSignature.returnType; + this.declFile.Write(": "); + if (returnType) { + this.emitTypeSignature(funcDecl, returnType); + } + else { + this.declFile.Write("any"); + } + + this.declFile.WriteLine(";"); + } + + private emitConstructSignature(funcDecl: ConstructSignatureSyntax) { + var funcPullDecl = this.semanticInfoChain.getDeclForAST(funcDecl); + + var start = new Date().getTime(); + var funcSymbol = this.semanticInfoChain.getSymbolForAST(funcDecl); + + TypeScript.declarationEmitFunctionDeclarationGetSymbolTime += new Date().getTime() - start; + + this.emitDeclarationComments(funcDecl); + + this.emitIndent(); + this.declFile.Write("new"); + + var funcSignature = funcPullDecl.getSignatureSymbol(this.semanticInfoChain); + this.emitTypeParameters(funcDecl.callSignature.typeParameterList, funcSignature); + + this.emitParameterList(/*isPrivate:*/ false, funcDecl.callSignature.parameterList); + + var returnType = funcSignature.returnType; + this.declFile.Write(": "); + if (returnType) { + this.emitTypeSignature(funcDecl, returnType); + } + else { + this.declFile.Write("any"); + } + + this.declFile.WriteLine(";"); + } + + private emitMethodSignature(funcDecl: MethodSignatureSyntax) { + var funcPullDecl = this.semanticInfoChain.getDeclForAST(funcDecl); + + var start = new Date().getTime(); + var funcSymbol = this.semanticInfoChain.getSymbolForAST(funcDecl); + + TypeScript.declarationEmitFunctionDeclarationGetSymbolTime += new Date().getTime() - start; + + this.emitDeclarationComments(funcDecl); + + this.emitIndent(); + this.declFile.Write(funcDecl.propertyName.text()); + if (funcDecl.questionToken) { + this.declFile.Write("? "); + } + + var funcSignature = funcPullDecl.getSignatureSymbol(this.semanticInfoChain); + this.emitTypeParameters(funcDecl.callSignature.typeParameterList, funcSignature); + + this.emitParameterList(/*isPrivate:*/ false, funcDecl.callSignature.parameterList); + + var returnType = funcSignature.returnType; + this.declFile.Write(": "); + if (returnType) { + this.emitTypeSignature(funcDecl, returnType); + } + else { + this.declFile.Write("any"); + } + + this.declFile.WriteLine(";"); + } + + private emitDeclarationsForFunctionDeclaration(funcDecl: FunctionDeclarationSyntax) { + var funcPullDecl = this.semanticInfoChain.getDeclForAST(funcDecl); + + var start = new Date().getTime(); + var funcSymbol = this.semanticInfoChain.getSymbolForAST(funcDecl); + + TypeScript.declarationEmitFunctionDeclarationGetSymbolTime += new Date().getTime() - start; + + if (funcDecl.block) { + var funcTypeSymbol = funcSymbol.type; + var constructSignatures = funcTypeSymbol.getConstructSignatures(); + if (constructSignatures && constructSignatures.length > 1) { + return; + } + else if (this.isOverloadedCallSignature(funcDecl)) { + // This means its implementation of overload signature. do not emit + return; + } + } + + if (!this.canEmitDeclarations(funcDecl)) { + return; + } + + this.emitDeclarationComments(funcDecl); + + var id = funcDecl.identifier.text(); + this.emitDeclFlags(funcDecl, "function"); + if (id !== "" || !funcDecl.identifier || funcDecl.identifier.text().length > 0) { + this.declFile.Write(id); + } + else if (funcPullDecl.kind === PullElementKind.ConstructSignature) { + this.declFile.Write("new"); + } + + var funcSignature = funcPullDecl.getSignatureSymbol(this.semanticInfoChain); + this.emitTypeParameters(funcDecl.callSignature.typeParameterList, funcSignature); + + this.emitParameterList(/*isPrivate:*/ false, funcDecl.callSignature.parameterList); + + var returnType = funcSignature.returnType; + this.declFile.Write(": "); + if (returnType) { + this.emitTypeSignature(funcDecl, returnType); + } + else { + this.declFile.Write("any"); + } + + this.declFile.WriteLine(";"); + } + + private emitIndexMemberDeclaration(funcDecl: IndexMemberDeclarationSyntax) { + this.emitDeclarationsForAST(funcDecl.indexSignature); + } + + private emitIndexSignature(funcDecl: IndexSignatureSyntax) { + if (!this.canEmitDeclarations(funcDecl)) { + return; + } + + this.emitDeclarationComments(funcDecl); + + this.emitIndent(); + this.declFile.Write("["); + this.emitParameters(/*isPrivate:*/ false, funcDecl.parameters); + this.declFile.Write("]"); + + var funcPullDecl = this.semanticInfoChain.getDeclForAST(funcDecl); + var funcSignature = funcPullDecl.getSignatureSymbol(this.semanticInfoChain); + var returnType = funcSignature.returnType; + this.declFile.Write(": "); + this.emitTypeSignature(funcDecl, returnType); + + this.declFile.WriteLine(";"); + } + + private emitBaseList(bases: INameSyntax[], useExtendsList: boolean) { + if (bases && (bases.length > 0)) { + var qual = useExtendsList ? "extends" : "implements"; + this.declFile.Write(" " + qual + " "); + var basesLen = bases.length; + for (var i = 0; i < basesLen; i++) { + if (i > 0) { + this.declFile.Write(", "); + } + var base = bases[i]; + var baseType = this.semanticInfoChain.getSymbolForAST(base); + this.emitTypeSignature(base, baseType); + } + } + } + + private emitAccessorDeclarationComments(funcDecl: ISyntaxElement) { + if (this.emitOptions.compilationSettings().removeComments()) { + return; + } + + var start = new Date().getTime(); + var accessors = PullHelpers.getGetterAndSetterFunction(funcDecl, this.semanticInfoChain); + TypeScript.declarationEmitGetAccessorFunctionTime += new Date().getTime(); + + var comments: Comment[] = []; + if (accessors.getter) { + comments = comments.concat(ASTHelpers.docComments(accessors.getter, this.text())); + } + if (accessors.setter) { + comments = comments.concat(ASTHelpers.docComments(accessors.setter, this.text())); + } + + this.writeDeclarationComments(comments); + } + + private emitDeclarationsForGetAccessor(funcDecl: GetAccessorSyntax): void { + this.emitMemberAccessorDeclaration(funcDecl, funcDecl.modifiers, funcDecl.propertyName); + } + + private emitDeclarationsForSetAccessor(funcDecl: SetAccessorSyntax): void { + this.emitMemberAccessorDeclaration(funcDecl, funcDecl.modifiers, funcDecl.propertyName); + } + + private emitMemberAccessorDeclaration(funcDecl: ISyntaxElement, modifiers: ISyntaxToken[], name: ISyntaxToken) { + var start = new Date().getTime(); + var accessorSymbol = PullHelpers.getAccessorSymbol(funcDecl, this.semanticInfoChain); + TypeScript.declarationEmitGetAccessorFunctionTime += new Date().getTime(); + + if (funcDecl.kind() === SyntaxKind.SetAccessor && accessorSymbol.getGetter()) { + // Setter is being used to emit the type info. + return; + } + + var isPrivate = hasModifier(modifiers, PullElementFlags.Private); + this.emitAccessorDeclarationComments(funcDecl); + this.declFile.Write(this.getIndentString()); + this.emitClassElementModifiers(modifiers); + this.declFile.Write(name.text()); + if (!isPrivate) { + this.declFile.Write(" : "); + var type = accessorSymbol.type; + this.emitTypeSignature(funcDecl, type); + } + this.declFile.WriteLine(";"); + } + + private emitClassMembersFromConstructorDefinition(funcDecl: ConstructorDeclarationSyntax) { + var argsLen = funcDecl.callSignature.parameterList.parameters.length; + if (lastParameterIsRest(funcDecl.callSignature.parameterList.parameters)) { + argsLen--; + } + + for (var i = 0; i < argsLen; i++) { + var parameter = funcDecl.callSignature.parameterList.parameters[i]; + var parameterDecl = this.semanticInfoChain.getDeclForAST(parameter); + if (hasFlag(parameterDecl.flags, PullElementFlags.PropertyParameter)) { + var funcPullDecl = this.semanticInfoChain.getDeclForAST(funcDecl); + this.emitDeclarationComments(parameter); + this.declFile.Write(this.getIndentString()); + this.emitClassElementModifiers(parameter.modifiers); + this.declFile.Write(parameter.identifier.text()); + + if (!hasModifier(parameter.modifiers, PullElementFlags.Private)) { + this.emitTypeOfVariableDeclaratorOrParameter(parameter); + } + this.declFile.WriteLine(";"); + } + } + } + + private emitDeclarationsForClassDeclaration(classDecl: ClassDeclarationSyntax) { + if (!this.canEmitDeclarations(classDecl)) { + return; + } + + var className = classDecl.identifier.text(); + this.emitDeclarationComments(classDecl); + var classPullDecl = this.semanticInfoChain.getDeclForAST(classDecl); + this.emitDeclFlags(classDecl, "class"); + this.declFile.Write(className); + + this.emitTypeParameters(classDecl.typeParameterList); + this.emitHeritageClauses(classDecl.heritageClauses); + this.declFile.WriteLine(" {"); + + this.indenter.increaseIndent(); + var constructorDecl = getLastConstructor(classDecl); + if (constructorDecl) { + this.emitClassMembersFromConstructorDefinition(constructorDecl); + } + + this.emitDeclarationsForList(classDecl.classElements); + + this.indenter.decreaseIndent(); + + this.emitIndent(); + this.declFile.WriteLine("}"); + } + + private emitHeritageClauses(clauses: HeritageClauseSyntax[]): void { + if (clauses) { + for (var i = 0, n = clauses.length; i < n; i++) { + this.emitHeritageClause(clauses[i]); + } + } + } + + private emitHeritageClause(clause: HeritageClauseSyntax) { + this.emitBaseList(clause.typeNames, clause.kind() === SyntaxKind.ExtendsHeritageClause); + } + + static getEnclosingContainer(ast: ISyntaxElement): ISyntaxElement { + // If the passed in as is the 'name' portion of an module declaration. + // If so, we want the actual container of *that* module declaration. + var enclosingModule = ASTHelpers.getModuleDeclarationFromNameAST(ast); + ast = enclosingModule || ast; + + ast = ast.parent; + while (ast) { + if (ast.kind() === SyntaxKind.ClassDeclaration || + ast.kind() === SyntaxKind.InterfaceDeclaration || + ast.kind() === SyntaxKind.ModuleDeclaration || + ast.kind() === SyntaxKind.SourceUnit) { + + return ast; + } + + ast = ast.parent; + } + + return null; + } + + private emitTypeParameters(typeParams: TypeParameterListSyntax, funcSignature?: PullSignatureSymbol) { + if (!typeParams || !typeParams.typeParameters.length) { + return; + } + + this.declFile.Write("<"); + var containerAst = DeclarationEmitter.getEnclosingContainer(typeParams); + + var start = new Date().getTime(); + var containerDecl = this.semanticInfoChain.getDeclForAST(containerAst); + var containerSymbol = containerDecl.getSymbol(this.semanticInfoChain); + TypeScript.declarationEmitGetTypeParameterSymbolTime += new Date().getTime() - start; + + var typars: PullTypeSymbol[]; + if (funcSignature) { + typars = funcSignature.getTypeParameters(); + } + else { + typars = containerSymbol.getTypeArgumentsOrTypeParameters(); + } + + for (var i = 0; i < typars.length; i++) { + if (i) { + this.declFile.Write(", "); + } + + var memberName = typars[i].getScopedNameEx(containerSymbol, /*skipTypeParametersInName*/ false, /*useConstraintInName:*/ true); + this.emitTypeNamesMember(memberName); + } + + this.declFile.Write(">"); + } + + private emitDeclarationsForInterfaceDeclaration(interfaceDecl: InterfaceDeclarationSyntax) { + if (!this.canEmitDeclarations(interfaceDecl)) { + return; + } + + var interfaceName = interfaceDecl.identifier.text(); + this.emitDeclarationComments(interfaceDecl); + var interfacePullDecl = this.semanticInfoChain.getDeclForAST(interfaceDecl); + this.emitDeclFlags(interfaceDecl, "interface"); + this.declFile.Write(interfaceName); + + this.emitTypeParameters(interfaceDecl.typeParameterList); + this.emitHeritageClauses(interfaceDecl.heritageClauses); + this.declFile.WriteLine(" {"); + + this.indenter.increaseIndent(); + + this.emitSeparatedList(interfaceDecl.body.typeMembers); + + this.indenter.decreaseIndent(); + + this.emitIndent(); + this.declFile.WriteLine("}"); + } + + private emitDeclarationsForImportDeclaration(importDeclAST: ImportDeclarationSyntax) { + var importDecl = this.semanticInfoChain.getDeclForAST(importDeclAST); + var importSymbol = importDecl.getSymbol(this.semanticInfoChain); + var isExportedImportDecl = hasModifier(importDeclAST.modifiers, PullElementFlags.Exported); + + if (isExportedImportDecl || importSymbol.typeUsedExternally() || PullContainerSymbol.usedAsSymbol(importSymbol.getContainer(), importSymbol)) { + this.emitDeclarationComments(importDeclAST); + this.emitIndent(); + if (isExportedImportDecl) { + this.declFile.Write("export "); + } + this.declFile.Write("import "); + this.declFile.Write(importDeclAST.identifier.text() + " = "); + if (importDeclAST.moduleReference.kind() === SyntaxKind.ExternalModuleReference) { + this.declFile.WriteLine("require(" + (importDeclAST.moduleReference).stringLiteral.text() + ");"); + } + else { + this.declFile.WriteLine(ASTHelpers.getNameOfIdenfierOrQualifiedName((importDeclAST.moduleReference).moduleName) + ";"); + } + } + } + + private emitDeclarationsForEnumDeclaration(moduleDecl: EnumDeclarationSyntax): void { + if (!this.canEmitDeclarations(moduleDecl)) { + return; + } + + this.emitDeclarationComments(moduleDecl); + var modulePullDecl = this.semanticInfoChain.getDeclForAST(moduleDecl); + this.emitDeclFlags(moduleDecl, "enum"); + this.declFile.WriteLine(moduleDecl.identifier.text() + " {"); + + this.indenter.increaseIndent(); + var membersLen = moduleDecl.enumElements.length; + for (var j = 0; j < membersLen; j++) { + var enumElement = moduleDecl.enumElements[j]; + var enumElementDecl = this.semanticInfoChain.getDeclForAST(enumElement); + this.emitDeclarationComments(enumElement); + this.emitIndent(); + this.declFile.Write(enumElement.propertyName.text()); + if (enumElementDecl.constantValue !== null) { + this.declFile.Write(" = " + enumElementDecl.constantValue); + } + this.declFile.WriteLine(","); + } + this.indenter.decreaseIndent(); + + this.emitIndent(); + this.declFile.WriteLine("}"); + } + + private emitDeclarationsForModuleDeclaration(moduleDecl: ModuleDeclarationSyntax) { + // If module is defined as A.B.C + // The whole moduleDecl will have the pullDecl corresponding to innermost + // Which would always be exported and hence would need to be emitted + // But we really want to check if module A needs to be emitted and hence use + // the leftmost name to determine if this needs to be emitted + // Since the module name will have the correct decl, it is always used to determine + // if this ast needs to be emitted or not + var name: ISyntaxElement = moduleDecl.stringLiteral || ArrayUtilities.first(ASTHelpers.getModuleNames(moduleDecl.name)); + if (!this.canEmitDeclarations(name)) { + return; + } + + this.emitDeclarationComments(moduleDecl); + this.emitDeclFlags(name, "module"); + + if (moduleDecl.stringLiteral) { + this.declFile.Write(moduleDecl.stringLiteral.text()); + } + else { + this.declFile.Write(ASTHelpers.getNameOfIdenfierOrQualifiedName(moduleDecl.name)); + } + + this.declFile.WriteLine(" {"); + this.indenter.increaseIndent(); + + this.emitDeclarationsForList(moduleDecl.moduleElements); + + this.indenter.decreaseIndent(); + this.emitIndent(); + this.declFile.WriteLine("}"); + } + + private emitDeclarationsForExportAssignment(ast: ExportAssignmentSyntax) { + this.emitIndent(); + this.declFile.Write("export = "); + this.declFile.Write(ast.identifier.text()); + this.declFile.WriteLine(";"); + } + + private resolveScriptReference(document: Document, reference: string) { + if (!this.emitOptions.compilationSettings().noResolve() || isRooted(reference)) { + return reference; + } + + var documentDir = convertToDirectoryPath(switchToForwardSlashes(getRootFilePath(document.fileName))); + var resolvedReferencePath = this.emitOptions.resolvePath(documentDir + reference); + return resolvedReferencePath; + } + + private emitReferencePaths(sourceUnit: SourceUnitSyntax) { + // In case of shared handler we collect all the references and emit them + if (this.emittedReferencePaths) { + return; + } + + // Collect all the documents that need to be emitted as reference + var documents: Document[] = []; + if (this.document.emitToOwnOutputFile()) { + // Emit only from this file + var scriptReferences = this.document.referencedFiles; + var addedGlobalDocument = false; + for (var j = 0; j < scriptReferences.length; j++) { + var currentReference = this.resolveScriptReference(this.document, scriptReferences[j]); + var document = this.compiler.getDocument(currentReference); + // All the references that are not going to be part of same file + + if (document && + (document.emitToOwnOutputFile() || document.isDeclareFile() || !addedGlobalDocument)) { + + documents = documents.concat(document); + + if (!document.isDeclareFile() && document.syntaxTree().isExternalModule()) { + addedGlobalDocument = true; + } + } + } + } + else { + // Collect from all the references and emit + var fileNames = this.compiler.fileNames(); + for (var i = 0; i < fileNames.length; i++) { + var doc = this.compiler.getDocument(fileNames[i]); + if (!doc.isDeclareFile() && !doc.syntaxTree().isExternalModule()) { + // Check what references need to be added + var scriptReferences = doc.referencedFiles; + for (var j = 0; j < scriptReferences.length; j++) { + var currentReference = this.resolveScriptReference(doc, scriptReferences[j]); + var document = this.compiler.getDocument(currentReference); + // All the references that are not going to be part of same file + if (document && + (document.isDeclareFile() || document.syntaxTree().isExternalModule())) { + for (var k = 0; k < documents.length; k++) { + if (documents[k] === document) { + break; + } + } + + if (k === documents.length) { + documents = documents.concat(document); + } + } + } + } + } + } + + // Emit the references + var emittingFilePath = documents.length ? getRootFilePath(this.emittingFileName) : null; + for (var i = 0; i < documents.length; i++) { + var document = documents[i]; + var declFileName: string; + if (document.isDeclareFile()) { + declFileName = document.fileName; + } + else { + declFileName = this.compiler.mapOutputFileName(document, this.emitOptions, TypeScriptCompiler.mapToDTSFileName); + } + + // Get the relative path + declFileName = getRelativePathToFixedPath(emittingFilePath, declFileName, false); + this.declFile.WriteLine('/// '); + } + + this.emittedReferencePaths = true; + } + + private emitDeclarationsForSourceUnit(sourceUnit: SourceUnitSyntax) { + this.emitReferencePaths(sourceUnit); + this.emitDeclarationsForList(sourceUnit.moduleElements); + } + } +} \ No newline at end of file diff --git a/src/services/compiler/diagnostics.ts b/src/services/compiler/diagnostics.ts new file mode 100644 index 00000000000..75d7bfd5a78 --- /dev/null +++ b/src/services/compiler/diagnostics.ts @@ -0,0 +1,47 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript { + export interface ILogger { + information(): boolean; + debug(): boolean; + warning(): boolean; + error(): boolean; + fatal(): boolean; + log(s: string): void; + } + + export class NullLogger implements ILogger { + public information(): boolean { return false; } + public debug(): boolean { return false; } + public warning(): boolean { return false; } + public error(): boolean { return false; } + public fatal(): boolean { return false; } + public log(s: string): void { + } + } + + export function timeFunction(logger: ILogger, funcDescription: string, func: () => any): any { + var start = (new Date()).getTime(); + var result = func(); + var end = (new Date()).getTime(); + if (logger.information()) { + logger.log(funcDescription + " completed in " + (end - start) + " msec"); + } + return result; + } +} \ No newline at end of file diff --git a/src/services/compiler/document.ts b/src/services/compiler/document.ts new file mode 100644 index 00000000000..e8a2f89df68 --- /dev/null +++ b/src/services/compiler/document.ts @@ -0,0 +1,151 @@ +/// + +module TypeScript { + export interface IncrementalParse { + (oldSyntaxTree: SyntaxTree, textChangeRange: TextChangeRange, newText: ISimpleText): SyntaxTree + } + + + export class Document { + private _bloomFilter: BloomFilter = null; + + // By default, our Document class doesn't support incremental update of its contents. + // However, we enable other layers (like teh services layer) to inject the capability + // into us by setting this function. + public static incrementalParse: IncrementalParse = null; + + constructor(private compilationSettings: ts.CompilerOptions, + public filename: string, + public referencedFiles: string[], + private _scriptSnapshot: IScriptSnapshot, + public byteOrderMark: ByteOrderMark, + public version: number, + public isOpen: boolean, + private _syntaxTree: SyntaxTree, + private _soruceFile: ts.SourceFile) { + } + + public isDeclareFile(): boolean { + return isDTSFile(this.filename); + } + + public sourceUnit(): SourceUnitSyntax { + // If we don't have a script, create one from our parse tree. + return this.syntaxTree().sourceUnit(); + } + + public diagnostics(): Diagnostic[] { + return this.syntaxTree().diagnostics(); + } + + public lineMap(): LineMap { + return this.syntaxTree().lineMap(); + } + + public syntaxTree(): SyntaxTree { + if (!this._syntaxTree) { + var start = new Date().getTime(); + + this._syntaxTree = Parser.parse( + this.filename, SimpleText.fromScriptSnapshot(this._scriptSnapshot), this.compilationSettings.target, this.isDeclareFile()); + + var time = new Date().getTime() - start; + + //TypeScript.syntaxTreeParseTime += time; + } + + return this._syntaxTree; + } + + public sourceFile(): ts.SourceFile { + if (!this._soruceFile) { + var start = new Date().getTime(); + + this._soruceFile = ts.createSourceFile(this.filename, this._scriptSnapshot.getText(0, this._scriptSnapshot.getLength()), this.compilationSettings.target); + + var time = new Date().getTime() - start; + + //TypeScript.astParseTime += time; + } + + return this._soruceFile; + } + + public bloomFilter(): BloomFilter { + if (!this._bloomFilter) { + var identifiers = createIntrinsicsObject(); + var pre = function (cur: TypeScript.ISyntaxElement) { + if (ASTHelpers.isValidAstNode(cur)) { + if (cur.kind() === SyntaxKind.IdentifierName) { + var nodeText = tokenValueText((cur)); + + identifiers[nodeText] = true; + } + } + }; + + TypeScript.getAstWalkerFactory().simpleWalk(this.sourceUnit(), pre, null, identifiers); + + var identifierCount = 0; + for (var name in identifiers) { + if (identifiers[name]) { + identifierCount++; + } + } + + this._bloomFilter = new BloomFilter(identifierCount); + this._bloomFilter.addKeys(identifiers); + } + return this._bloomFilter; + } + + // Returns true if this file should get emitted into its own unique output file. + // Otherwise, it should be written into a single output file along with the rest of hte + // documents in the compilation. + public emitToOwnOutputFile(): boolean { + // If we haven't specified an output file in our settings, then we're definitely + // emitting to our own file. Also, if we're an external module, then we're + // definitely emitting to our own file. + return !this.compilationSettings.out || this.syntaxTree().isExternalModule(); + } + + public update(scriptSnapshot: IScriptSnapshot, version: number, isOpen: boolean, textChangeRange: TextChangeRange): Document { + // See if we are currently holding onto a syntax tree. We may not be because we're + // either a closed file, or we've just been lazy and haven't had to create the syntax + // tree yet. Access the field instead of the method so we don't accidently realize + // the old syntax tree. + var oldSyntaxTree = this._syntaxTree; + + if (textChangeRange !== null && Debug.shouldAssert(AssertionLevel.Normal)) { + var oldText = this._scriptSnapshot; + var newText = scriptSnapshot; + + TypeScript.Debug.assert((oldText.getLength() - textChangeRange.span().length() + textChangeRange.newLength()) === newText.getLength()); + + if (Debug.shouldAssert(AssertionLevel.VeryAggressive)) { + var oldTextPrefix = oldText.getText(0, textChangeRange.span().start()); + var newTextPrefix = newText.getText(0, textChangeRange.span().start()); + TypeScript.Debug.assert(oldTextPrefix === newTextPrefix); + + var oldTextSuffix = oldText.getText(textChangeRange.span().end(), oldText.getLength()); + var newTextSuffix = newText.getText(textChangeRange.newSpan().end(), newText.getLength()); + TypeScript.Debug.assert(oldTextSuffix === newTextSuffix); + } + } + + var text = SimpleText.fromScriptSnapshot(scriptSnapshot); + + // If we don't have a text change, or we don't have an old syntax tree, then do a full + // parse. Otherwise, do an incremental parse. + var newSyntaxTree = textChangeRange === null || oldSyntaxTree === null || Document.incrementalParse === null + ? TypeScript.Parser.parse(this.filename, text, this.compilationSettings.target, TypeScript.isDTSFile(this.filename)) + : Document.incrementalParse(oldSyntaxTree, textChangeRange, text); + + return new Document(this.compilationSettings, this.filename, this.referencedFiles, scriptSnapshot, this.byteOrderMark, version, isOpen, newSyntaxTree, /*soruceFile*/ null); + } + + public static create(compilationSettings: ts.CompilerOptions, fileName: string, scriptSnapshot: IScriptSnapshot, byteOrderMark: ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]): Document { + return new Document(compilationSettings, fileName, referencedFiles, scriptSnapshot, byteOrderMark, version, isOpen, /*syntaxTree:*/ null, /*soruceFile*/ null); + } + } +} \ No newline at end of file diff --git a/src/services/compiler/emitter.ts b/src/services/compiler/emitter.ts new file mode 100644 index 00000000000..8de5e64dbba --- /dev/null +++ b/src/services/compiler/emitter.ts @@ -0,0 +1,3797 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript { + export enum EmitContainer { + Prog, + Module, + DynamicModule, + Class, + Constructor, + Function, + Args, + Interface, + } + + export class EmitState { + public column: number; + public line: number; + public container: EmitContainer; + + constructor() { + this.column = 0; + this.line = 0; + this.container = EmitContainer.Prog; + } + } + + export class EmitOptions { + private _diagnostic: Diagnostic = null; + + private _settings: ImmutableCompilationSettings = null; + private _commonDirectoryPath = ""; + private _sharedOutputFile = ""; + private _sourceRootDirectory = ""; + private _sourceMapRootDirectory = ""; + private _outputDirectory = ""; + + public diagnostic(): Diagnostic { return this._diagnostic; } + + public commonDirectoryPath() { return this._commonDirectoryPath; } + public sharedOutputFile() { return this._sharedOutputFile; } + public sourceRootDirectory() { return this._sourceRootDirectory; } + public sourceMapRootDirectory() { return this._sourceMapRootDirectory; } + public outputDirectory() { return this._outputDirectory; } + + public compilationSettings() { return this._settings; } + + constructor(compiler: TypeScriptCompiler, public resolvePath: (path: string) => string) { + var settings = compiler.compilationSettings(); + this._settings = settings; + + // If the document is an external module, then report if the the user has not + // provided the right command line option. + if (settings.moduleGenTarget() === ModuleGenTarget.Unspecified) { + var fileNames = compiler.fileNames(); + for (var i = 0, n = fileNames.length; i < n; i++) { + var document = compiler.getDocument(fileNames[i]); + if (!document.isDeclareFile() && document.syntaxTree().isExternalModule()) { + var errorSpan = externalModuleIndicatorSpan(document.syntaxTree()); + this._diagnostic = new Diagnostic(document.fileName, document.lineMap(), errorSpan.start(), errorSpan.length(), + DiagnosticCode.Cannot_compile_external_modules_unless_the_module_flag_is_provided); + + return; + } + } + } + + if (!settings.mapSourceFiles()) { + // Error to specify --mapRoot or --sourceRoot without mapSourceFiles + if (settings.mapRoot()) { + if (settings.sourceRoot()) { + this._diagnostic = new Diagnostic(null, null, 0, 0, DiagnosticCode.Options_mapRoot_and_sourceRoot_cannot_be_specified_without_specifying_sourcemap_option, null); + return; + } + else { + this._diagnostic = new Diagnostic(null, null, 0, 0, DiagnosticCode.Option_mapRoot_cannot_be_specified_without_specifying_sourcemap_option, null); + return; + } + } + else if (settings.sourceRoot()) { + this._diagnostic = new Diagnostic(null, null, 0, 0, DiagnosticCode.Option_sourceRoot_cannot_be_specified_without_specifying_sourcemap_option, null); + return; + } + } + + this._sourceMapRootDirectory = convertToDirectoryPath(switchToForwardSlashes(settings.mapRoot())); + this._sourceRootDirectory = convertToDirectoryPath(switchToForwardSlashes(settings.sourceRoot())); + + if (settings.outFileOption() || + settings.outDirOption() || + settings.mapRoot() || + settings.sourceRoot()) { + + if (settings.outFileOption()) { + this._sharedOutputFile = switchToForwardSlashes(resolvePath(settings.outFileOption())); + } + + if (settings.outDirOption()) { + this._outputDirectory = convertToDirectoryPath(switchToForwardSlashes(resolvePath(settings.outDirOption()))); + } + + // Parse the directory structure + if (this._outputDirectory || this._sourceMapRootDirectory || this.sourceRootDirectory) { + this.determineCommonDirectoryPath(compiler); + } + } + } + + private determineCommonDirectoryPath(compiler: TypeScriptCompiler): void { + var commonComponents: string[] = []; + var commonComponentsLength = -1; + + var fileNames = compiler.fileNames(); + for (var i = 0, len = fileNames.length; i < len; i++) { + var fileName = fileNames[i]; + var document = compiler.getDocument(fileNames[i]); + var sourceUnit = document.sourceUnit(); + + if (!document.isDeclareFile()) { + var fileComponents = filePathComponents(fileName); + if (commonComponentsLength === -1) { + // First time at finding common path + // So common path = directory of file + commonComponents = fileComponents; + commonComponentsLength = commonComponents.length; + } + else { + var updatedPath = false; + for (var j = 0; j < commonComponentsLength && j < fileComponents.length; j++) { + if (commonComponents[j] !== fileComponents[j]) { + // The new components = 0 ... j -1 + commonComponentsLength = j; + updatedPath = true; + + if (j === 0) { + var isDynamicModuleCompilation = ArrayUtilities.any(fileNames, fileName => { + document = compiler.getDocument(fileName); + return !document.isDeclareFile() && document.syntaxTree().isExternalModule(); + }); + + if (this._outputDirectory || // there is --outDir specified + this._sourceRootDirectory || // there is --sourceRoot specified + (this._sourceMapRootDirectory && // there is --map Specified and there would be multiple js files generated + (!this._sharedOutputFile || isDynamicModuleCompilation))) { + // Its error to not have common path + this._diagnostic = new Diagnostic(null, null, 0, 0, DiagnosticCode.Cannot_find_the_common_subdirectory_path_for_the_input_files, null); + return; + } + + return; + } + + break; + } + } + + // If the fileComponent path completely matched and less than already found update the length + if (!updatedPath && fileComponents.length < commonComponentsLength) { + commonComponentsLength = fileComponents.length; + } + } + } + } + + this._commonDirectoryPath = commonComponents.slice(0, commonComponentsLength).join("/") + "/"; + } + } + + export class Indenter { + static indentStep: number = 4; + static indentStepString: string = " "; + static indentStrings: string[] = []; + public indentAmt: number = 0; + + public increaseIndent() { + this.indentAmt += Indenter.indentStep; + } + + public decreaseIndent() { + this.indentAmt -= Indenter.indentStep; + } + + public getIndent() { + var indentString = Indenter.indentStrings[this.indentAmt]; + if (indentString === undefined) { + indentString = ""; + for (var i = 0; i < this.indentAmt; i = i + Indenter.indentStep) { + indentString += Indenter.indentStepString; + } + Indenter.indentStrings[this.indentAmt] = indentString; + } + return indentString; + } + } + + export function lastParameterIsRest(parameters: ParameterSyntax[]): boolean { + return parameters.length > 0 && (parameters[parameters.length - 1]).dotDotDotToken !== null; + } + + export class Emitter { + public globalThisCapturePrologueEmitted = false; + public extendsPrologueEmitted = false; + public thisClassNode: ClassDeclarationSyntax = null; + public inArrowFunction: boolean = false; + public moduleName = ""; + public emitState = new EmitState(); + public indenter = new Indenter(); + public sourceMapper: SourceMapper = null; + public captureThisStmtString = "var _this = this;"; + private currentVariableDeclaration: VariableDeclarationSyntax; + private declStack: PullDecl[] = []; + private exportAssignment: ExportAssignmentSyntax = null; + private inWithBlock = false; + + public document: Document = null; + + // If we choose to detach comments from an element (for example, the Copyright comments), + // then keep track of that element so that we don't emit all on the comments on it when + // we visit it. + private detachedCommentsElement: ISyntaxElement = null; + + constructor(public emittingFileName: string, + public outfile: TextWriter, + public emitOptions: EmitOptions, + private semanticInfoChain: SemanticInfoChain) { + } + + private pushDecl(decl: PullDecl) { + if (decl) { + this.declStack[this.declStack.length] = decl; + } + } + + private popDecl(decl: PullDecl) { + if (decl) { + this.declStack.length--; + } + } + + private getEnclosingDecl() { + var declStackLen = this.declStack.length; + var enclosingDecl = declStackLen > 0 ? this.declStack[declStackLen - 1] : null; + return enclosingDecl; + } + + public setExportAssignment(exportAssignment: ExportAssignmentSyntax) { + this.exportAssignment = exportAssignment; + } + + public getExportAssignment() { + return this.exportAssignment; + } + + public setDocument(document: Document) { + this.document = document; + } + + public shouldEmitImportDeclaration(importDeclAST: ImportDeclarationSyntax) { + var isExternalModuleReference = importDeclAST.moduleReference.kind() === SyntaxKind.ExternalModuleReference; + var importDecl = this.semanticInfoChain.getDeclForAST(importDeclAST); + var isExported = hasFlag(importDecl.flags, PullElementFlags.Exported); + var isAmdCodeGen = this.emitOptions.compilationSettings().moduleGenTarget() === ModuleGenTarget.Asynchronous; + + // 1) Any internal reference needs to check if the emit can happen + // 2) External module reference with export modifier always needs to be emitted + // 3) commonjs needs the var declaration for the import declaration + if (isExternalModuleReference && !isExported && isAmdCodeGen) { + return false; + } + + var importSymbol = importDecl.getSymbol(this.semanticInfoChain); + if (importSymbol.isUsedAsValue()) { + return true; + } + + if (importDeclAST.moduleReference.kind() !== SyntaxKind.ExternalModuleReference) { + var canBeUsedExternally = isExported || importSymbol.typeUsedExternally() || importSymbol.isUsedInExportedAlias(); + if (!canBeUsedExternally && !this.document.syntaxTree().isExternalModule()) { + // top level import in non-external module are visible across the whole global module + canBeUsedExternally = hasFlag(importDecl.getParentDecl().kind, PullElementKind.Script | PullElementKind.DynamicModule); + } + + if (canBeUsedExternally) { + if (importSymbol.getExportAssignedValueSymbol()) { + return true; + } + + var containerSymbol = importSymbol.getExportAssignedContainerSymbol(); + if (containerSymbol && containerSymbol.getInstanceSymbol()) { + return true; + } + } + } + + return false; + } + + public emitImportDeclaration(importDeclAST: ImportDeclarationSyntax) { + var isExternalModuleReference = importDeclAST.moduleReference.kind() === SyntaxKind.ExternalModuleReference; + var importDecl = this.semanticInfoChain.getDeclForAST(importDeclAST); + var isExported = hasFlag(importDecl.flags, PullElementFlags.Exported); + var isAmdCodeGen = this.emitOptions.compilationSettings().moduleGenTarget() === ModuleGenTarget.Asynchronous; + + this.emitComments(importDeclAST, true); + + var importSymbol = importDecl.getSymbol(this.semanticInfoChain); + + var parentSymbol = importSymbol.getContainer(); + var parentKind = parentSymbol ? parentSymbol.kind : PullElementKind.None; + var associatedParentSymbol = parentSymbol ? parentSymbol.getAssociatedContainerType() : null; + var associatedParentSymbolKind = associatedParentSymbol ? associatedParentSymbol.kind : PullElementKind.None; + + var needsPropertyAssignment = false; + var usePropertyAssignmentInsteadOfVarDecl = false; + var moduleNamePrefix: string; + + if (isExported && + (parentKind === PullElementKind.Container || + parentKind === PullElementKind.DynamicModule || + associatedParentSymbolKind === PullElementKind.Container || + associatedParentSymbolKind === PullElementKind.DynamicModule)) { + if (importSymbol.getExportAssignedTypeSymbol() || importSymbol.getExportAssignedContainerSymbol()) { + // Type or container assignment that is exported + needsPropertyAssignment = true; + } + else { + var valueSymbol = importSymbol.getExportAssignedValueSymbol(); + if (valueSymbol && + (valueSymbol.kind === PullElementKind.Method || valueSymbol.kind === PullElementKind.Function)) { + needsPropertyAssignment = true; + } + else { + usePropertyAssignmentInsteadOfVarDecl = true; + } + } + + // Calculate what name prefix to use + if (this.emitState.container === EmitContainer.DynamicModule) { + moduleNamePrefix = "exports." + } + else { + moduleNamePrefix = this.moduleName + "."; + } + } + + if (isAmdCodeGen && isExternalModuleReference) { + // For amdCode gen of exported external module reference, do not emit var declaration + // Emit the property assignment since it is exported + needsPropertyAssignment = true; + } + else { + this.recordSourceMappingStart(importDeclAST); + if (usePropertyAssignmentInsteadOfVarDecl) { + this.writeToOutput(moduleNamePrefix); + } + else { + this.writeToOutput("var "); + } + this.writeToOutput(importDeclAST.identifier.text() + " = "); + var aliasAST = importDeclAST.moduleReference; + + if (isExternalModuleReference) { + this.writeToOutput("require(" + (aliasAST).stringLiteral.text() + ")"); + } + else { + this.emitJavascript((aliasAST).moduleName, false); + } + + this.recordSourceMappingEnd(importDeclAST); + this.writeToOutput(";"); + + if (needsPropertyAssignment) { + this.writeLineToOutput(""); + this.emitIndent(); + } + } + + if (needsPropertyAssignment) { + this.writeToOutputWithSourceMapRecord(moduleNamePrefix + importDeclAST.identifier.text() + " = " + importDeclAST.identifier.text(), importDeclAST); + this.writeToOutput(";"); + } + this.emitComments(importDeclAST, false); + } + + public createSourceMapper(document: Document, jsFileName: string, jsFile: TextWriter, sourceMapOut: TextWriter, resolvePath: (path: string) => string) { + this.sourceMapper = new SourceMapper(jsFile, sourceMapOut, document, jsFileName, this.emitOptions, resolvePath); + } + + public setSourceMapperNewSourceFile(document: Document) { + this.sourceMapper.setNewSourceFile(document, this.emitOptions); + } + + private updateLineAndColumn(s: string) { + var lineNumbers = TextUtilities.parseLineStarts(s); + if (lineNumbers.length > 1) { + // There are new lines in the string, update the line and column number accordingly + this.emitState.line += lineNumbers.length - 1; + this.emitState.column = s.length - lineNumbers[lineNumbers.length - 1]; + } + else { + // No new lines in the string + this.emitState.column += s.length; + } + } + + public writeToOutputWithSourceMapRecord(s: string, astSpan: ISyntaxElement) { + if (astSpan) { + this.recordSourceMappingStart(astSpan); + } + + this.writeToOutput(s); + + if (astSpan) { + this.recordSourceMappingEnd(astSpan); + } + } + + public writeToOutput(s: string) { + this.outfile.Write(s); + this.updateLineAndColumn(s); + } + + public writeLineToOutput(s: string, force = false) { + // No need to print a newline if we're already at the start of the line. + if (!force && s === "" && this.emitState.column === 0) { + return; + } + + this.outfile.WriteLine(s); + this.updateLineAndColumn(s); + this.emitState.column = 0; + this.emitState.line++; + } + + public writeCaptureThisStatement(ast: ISyntaxElement) { + this.emitIndent(); + this.writeToOutputWithSourceMapRecord(this.captureThisStmtString, ast); + this.writeLineToOutput(""); + } + + public setContainer(c: number): number { + var temp = this.emitState.container; + this.emitState.container = c; + return temp; + } + + private getIndentString() { + return this.indenter.getIndent(); + } + + public emitIndent() { + this.writeToOutput(this.getIndentString()); + } + + public emitComment(comment: Comment, trailing: boolean, first: boolean, noLeadingSpace = false) { + if (this.emitOptions.compilationSettings().removeComments()) { + return; + } + + var text = getTrimmedTextLines(comment); + var emitColumn = this.emitState.column; + + if (emitColumn === 0) { + this.emitIndent(); + } + else if (trailing && first && !noLeadingSpace) { + this.writeToOutput(" "); + } + + if (comment.kind() === SyntaxKind.MultiLineCommentTrivia) { + this.recordSourceMappingCommentStart(comment); + this.writeToOutput(text[0]); + + if (text.length > 1 || comment.endsLine) { + for (var i = 1; i < text.length; i++) { + this.writeLineToOutput(""); + this.emitIndent(); + this.writeToOutput(text[i]); + } + this.recordSourceMappingCommentEnd(comment); + this.writeLineToOutput(""); + // Fall through + } + else { + this.recordSourceMappingCommentEnd(comment); + this.writeToOutput(" "); + return; + } + } + else { + this.recordSourceMappingCommentStart(comment); + this.writeToOutput(text[0]); + this.recordSourceMappingCommentEnd(comment); + this.writeLineToOutput(""); + // Fall through + } + + if (!trailing && emitColumn !== 0) { + // If we were indented before, stay indented after. + this.emitIndent(); + } + } + + private text(): ISimpleText { + return this.document.syntaxTree().text; + } + + public emitComments(ast: ISyntaxElement, pre: boolean, onlyPinnedOrTripleSlashComments: boolean = false) { + // Emitting the comments for the exprssion inside an arrow function is handled specially + // in emitFunctionBodyStatements. We don't want to emit those comments a second time. + if (ast && !isShared(ast) && ast.kind() !== SyntaxKind.Block) { + if (ast.parent.kind() === SyntaxKind.SimpleArrowFunctionExpression || ast.parent.kind() === SyntaxKind.ParenthesizedArrowFunctionExpression) { + return; + } + } + + if (pre) { + var preComments = TypeScript.ASTHelpers.preComments(ast, this.text()); + + if (preComments && ast === this.detachedCommentsElement) { + // We're emitting the comments for the first script element. Skip any + // copyright comments, as we'll already have emitted those. + var detachedComments = this.getDetachedComments(ast); + preComments = preComments.slice(detachedComments.length); + this.detachedCommentsElement = null; + } + + // We're emitting comments on an elided element. Only keep the comment if it is + // a triple slash or pinned comment. + if (preComments && onlyPinnedOrTripleSlashComments) { + preComments = ArrayUtilities.where(preComments, c => this.isPinnedOrTripleSlash(c)); + } + + this.emitCommentsArray(preComments, /*trailing:*/ false); + } + else { + this.emitCommentsArray(ASTHelpers.postComments(ast, this.text()), /*trailing:*/ true); + } + } + + private isPinnedOrTripleSlash(comment: Comment): boolean { + var fullText = comment.fullText(); + if (fullText.match(tripleSlashReferenceRegExp)) { + return true; + } + else { + return fullText.indexOf("/*!") === 0; + } + } + + private emitCommentsArray(comments: Comment[], trailing: boolean, noLeadingSpace = false): void { + if (!this.emitOptions.compilationSettings().removeComments() && comments) { + for (var i = 0, n = comments.length; i < n; i++) { + this.emitComment(comments[i], trailing, /*first:*/ i === 0, noLeadingSpace); + } + } + } + + public emitObjectLiteralExpression(objectLiteral: ObjectLiteralExpressionSyntax) { + this.recordSourceMappingStart(objectLiteral); + + // Try to preserve the newlines between elements that the user had. + this.writeToken(objectLiteral.openBraceToken); + this.emitCommaSeparatedList(objectLiteral, objectLiteral.propertyAssignments, /*buffer:*/ " ", /*preserveNewLines:*/ true); + this.writeToken(objectLiteral.closeBraceToken); + + this.recordSourceMappingEnd(objectLiteral); + } + + public emitArrayLiteralExpression(arrayLiteral: ArrayLiteralExpressionSyntax) { + this.recordSourceMappingStart(arrayLiteral); + + // Try to preserve the newlines between elements that the user had. + this.writeToken(arrayLiteral.openBracketToken); + this.emitCommaSeparatedList(arrayLiteral, arrayLiteral.expressions, /*buffer:*/ "", /*preserveNewLines:*/ true); + this.writeToken(arrayLiteral.closeBracketToken); + + this.recordSourceMappingEnd(arrayLiteral); + } + + public emitObjectCreationExpression(objectCreationExpression: ObjectCreationExpressionSyntax) { + this.recordSourceMappingStart(objectCreationExpression); + this.writeToken(objectCreationExpression.newKeyword); + this.writeToOutput(" "); + var target = objectCreationExpression.expression; + + this.emit(target); + if (objectCreationExpression.argumentList) { + this.recordSourceMappingStart(objectCreationExpression.argumentList); + this.writeToken(objectCreationExpression.argumentList.openParenToken); + this.emitCommaSeparatedList(objectCreationExpression.argumentList, objectCreationExpression.argumentList.arguments, /*buffer:*/ "", /*preserveNewLines:*/ false); + this.writeToken(objectCreationExpression.argumentList.closeParenToken); + this.recordSourceMappingEnd(objectCreationExpression.argumentList); + } + + this.recordSourceMappingEnd(objectCreationExpression); + } + + public getConstantDecl(dotExpr: MemberAccessExpressionSyntax): PullEnumElementDecl { + var pullSymbol = this.semanticInfoChain.getSymbolForAST(dotExpr); + if (pullSymbol && pullSymbol.kind === PullElementKind.EnumMember) { + var pullDecls = pullSymbol.getDeclarations(); + if (pullDecls.length === 1) { + var pullDecl = pullDecls[0]; + if (pullDecl.kind === PullElementKind.EnumMember) { + return pullDecl; + } + } + } + + return null; + } + + public tryEmitConstant(dotExpr: MemberAccessExpressionSyntax) { + var propertyName = dotExpr.name; + var boundDecl = this.getConstantDecl(dotExpr); + if (boundDecl) { + var value = boundDecl.constantValue; + if (value !== null) { + this.recordSourceMappingStart(dotExpr); + this.writeToOutput(value.toString()); + var comment = " /* "; + comment += propertyName.text(); + comment += " */"; + this.writeToOutput(comment); + this.recordSourceMappingEnd(dotExpr); + return true; + } + } + + return false; + } + + public emitInvocationExpression(callNode: InvocationExpressionSyntax) { + this.recordSourceMappingStart(callNode); + var target = callNode.expression; + var args = callNode.argumentList.arguments; + + if (target.kind() === SyntaxKind.MemberAccessExpression && (target).expression.kind() === SyntaxKind.SuperKeyword) { + this.emit(target); + this.writeToOutput(".call"); + this.recordSourceMappingStart(args); + this.writeToken(callNode.argumentList.openParenToken); + this.emitThis(); + if (args && args.length > 0) { + this.writeToOutput(", "); + this.emitCommaSeparatedList(callNode.argumentList, args, /*buffer:*/ "", /*preserveNewLines:*/ false); + } + } + else { + if (callNode.expression.kind() === SyntaxKind.SuperKeyword && this.emitState.container === EmitContainer.Constructor) { + this.writeToOutput("_super.call"); + } + else { + this.emitJavascript(target, false); + } + this.recordSourceMappingStart(args); + this.writeToken(callNode.argumentList.openParenToken); + if (callNode.expression.kind() === SyntaxKind.SuperKeyword && this.emitState.container === EmitContainer.Constructor) { + this.writeToOutput("this"); + if (args && args.length > 0) { + this.writeToOutput(", "); + } + } + this.emitCommaSeparatedList(callNode.argumentList, args, /*buffer:*/ "", /*preserveNewLines:*/ false); + } + + this.writeToken(callNode.argumentList.closeParenToken); + this.recordSourceMappingEnd(args); + this.recordSourceMappingEnd(callNode); + } + + private emitParameterList(list: ParameterListSyntax): void { + this.writeToken(list.openParenToken); + this.emitCommentsArray(ASTHelpers.convertTokenTrailingComments(list.openParenToken, this.text()), /*trailing:*/ true, /*noLeadingSpace:*/ true); + this.emitFunctionParameters(list.parameters, list.parameters); + this.writeToken(list.closeParenToken); + } + + private emitFunctionParameters(ast: ISyntaxElement, parameters: ParameterSyntax[]): void { + var argsLen = 0; + + if (parameters) { + this.emitComments(ast, true); + + var tempContainer = this.setContainer(EmitContainer.Args); + argsLen = parameters.length; + var printLen = argsLen; + if (lastParameterIsRest(parameters)) { + printLen--; + } + for (var i = 0; i < printLen; i++) { + var arg = parameters[i]; + this.emit(arg); + + if (i < (printLen - 1)) { + this.writeToOutput(", "); + if (parameters) { + this.emitCommentsArray(ASTHelpers.convertTokenTrailingComments(parameters.separatorAt(i), this.text()), /*trailing:*/ true, /*noLeadingSpace:*/ true); + } + } + } + this.setContainer(tempContainer); + + this.emitComments(ast, false); + } + } + + private emitFunctionBodyStatements(name: string, funcDecl: ISyntaxElement, parameters: ParameterSyntax[], block: BlockSyntax, bodyExpression: ISyntaxElement): void { + this.writeLineToOutput(" {"); + if (name) { + this.recordSourceMappingNameStart(name); + } + + this.indenter.increaseIndent(); + + if (block) { + // We want any detached statements at the start of hte block to stay at the start. + // This is important for features like VSDoc which place their comments inside a + // block, but can't have them preceded by things like "var _this = this" when we + // emit. + + this.emitDetachedComments(block.statements); + } + + // Parameter list parameters with defaults could capture this + if (this.shouldCaptureThis(funcDecl)) { + this.writeCaptureThisStatement(funcDecl); + } + + if (parameters) { + this.emitDefaultValueAssignments(parameters); + this.emitRestParameterInitializer(parameters); + } + + if (block) { + this.emitList(block.statements); + this.emitCommentsArray(ASTHelpers.convertTokenLeadingComments(block.closeBraceToken, this.text()), /*trailing:*/ false); + } + else { + // Copy any comments before the body of the arrow function to the return statement. + // This is necessary for emitting correctness so we don't emit something like this: + // + // return + // // foo + // this.foo(); + // + // Because of ASI, this gets parsed as "return;" which is *not* what we want for + // proper semantics. + //var preComments = bodyExpression.preComments(); + //var postComments = bodyExpression.postComments(); + + //bodyExpression.setPreComments(null); + //bodyExpression.setPostComments(null); + + this.emitIndent(); + this.emitCommentsArray(ASTHelpers.preComments(bodyExpression, this.text()), /*trailing:*/ false); + this.writeToOutput("return "); + this.emit(bodyExpression); + this.writeLineToOutput(";"); + this.emitCommentsArray(ASTHelpers.preComments(bodyExpression, this.text()), /*trailing:*/ true); + + //bodyExpression.setPreComments(preComments); + //bodyExpression.setPostComments(postComments); + } + + this.indenter.decreaseIndent(); + this.emitIndent(); + + if (block) { + this.writeToken(block.closeBraceToken); + } + else { + this.writeToOutputWithSourceMapRecord("}", bodyExpression); + } + + if (name) { + this.recordSourceMappingNameEnd(); + } + } + + private emitDefaultValueAssignments(parameters: ParameterSyntax[]): void { + var n = parameters.length; + if (lastParameterIsRest(parameters)) { + n--; + } + + for (var i = 0; i < n; i++) { + var arg = parameters[i]; + var id = arg.identifier; + var equalsValueClause = arg.equalsValueClause; + if (equalsValueClause) { + this.emitIndent(); + this.recordSourceMappingStart(arg); + this.writeToOutput("if (typeof " + id.text() + " === \"undefined\") { ");// + this.writeToken(id); + this.emitJavascript(equalsValueClause, false); + this.writeLineToOutput("; }"); + this.recordSourceMappingEnd(arg); + } + } + } + + private emitRestParameterInitializer(parameters: ParameterSyntax[]): void { + if (lastParameterIsRest(parameters)) { + var n = parameters.length; + var lastArg = parameters[n - 1]; + var id = lastArg.identifier; + this.emitIndent(); + this.recordSourceMappingStart(lastArg); + this.writeToOutput("var "); + this.writeToken(id); + this.writeLineToOutput(" = [];"); + this.recordSourceMappingEnd(lastArg); + this.emitIndent(); + this.writeToOutput("for ("); + this.writeToOutputWithSourceMapRecord("var _i = 0;", lastArg); + this.writeToOutput(" "); + this.writeToOutputWithSourceMapRecord("_i < (arguments.length - " + (n - 1) + ")", lastArg); + this.writeToOutput("; "); + this.writeToOutputWithSourceMapRecord("_i++", lastArg); + this.writeLineToOutput(") {"); + this.indenter.increaseIndent(); + this.emitIndent(); + + this.writeToOutputWithSourceMapRecord(id.text() + "[_i] = arguments[_i + " + (n - 1) + "];", lastArg); + this.writeLineToOutput(""); + this.indenter.decreaseIndent(); + this.emitIndent(); + this.writeLineToOutput("}"); + } + } + + private getImportDecls(fileName: string): PullDecl[] { + var topLevelDecl = this.semanticInfoChain.topLevelDecl(this.document.fileName); + var result: PullDecl[] = []; + + var dynamicModuleDecl = topLevelDecl.getChildDecls()[0]; // Dynamic module declaration has to be present + var queue: PullDecl[] = dynamicModuleDecl.getChildDecls(); + + for (var i = 0, n = queue.length; i < n; i++) { + var decl = queue[i]; + + if (decl.kind & PullElementKind.TypeAlias) { + var importStatementAST = this.semanticInfoChain.getASTForDecl(decl); + if (importStatementAST.moduleReference.kind() === SyntaxKind.ExternalModuleReference) { // external module + var symbol = decl.getSymbol(this.semanticInfoChain); + var typeSymbol = symbol && symbol.type; + if (typeSymbol && typeSymbol !== this.semanticInfoChain.anyTypeSymbol && !typeSymbol.isError()) { + result.push(decl); + } + } + } + } + + return result; + } + + public getModuleImportAndDependencyList(sourceUnit: SourceUnitSyntax) { + var importList = ""; + var dependencyList = ""; + + var importDecls = this.getImportDecls(this.document.fileName); + + // all dependencies are quoted + if (importDecls.length) { + for (var i = 0; i < importDecls.length; i++) { + var importStatementDecl = importDecls[i]; + var importStatementSymbol = importStatementDecl.getSymbol(this.semanticInfoChain); + var importStatementAST = this.semanticInfoChain.getASTForDecl(importStatementDecl); + + if (importStatementSymbol.isUsedAsValue()) { + if (i <= importDecls.length - 1) { + dependencyList += ", "; + importList += ", "; + } + + importList += importStatementDecl.name; + dependencyList += (importStatementAST.moduleReference).stringLiteral.text(); + } + } + } + + // emit any potential amd dependencies + var amdDependencies = this.document.syntaxTree().amdDependencies(); + for (var i = 0; i < amdDependencies.length; i++) { + dependencyList += ", \"" + amdDependencies[i] + "\""; + } + + return { + importList: importList, + dependencyList: dependencyList + }; + } + + public shouldCaptureThis(ast: ISyntaxElement) { + if (ast.kind() === SyntaxKind.SourceUnit) { + var scriptDecl = this.semanticInfoChain.topLevelDecl(this.document.fileName); + return hasFlag(scriptDecl.flags, PullElementFlags.MustCaptureThis); + } + + var decl = this.semanticInfoChain.getDeclForAST(ast); + if (decl) { + return hasFlag(decl.flags, PullElementFlags.MustCaptureThis); + } + + return false; + } + + public emitEnum(moduleDecl: EnumDeclarationSyntax) { + var pullDecl = this.semanticInfoChain.getDeclForAST(moduleDecl); + this.pushDecl(pullDecl); + + var svModuleName = this.moduleName; + this.moduleName = moduleDecl.identifier.text(); + + var temp = this.setContainer(EmitContainer.Module); + var isExported = hasFlag(pullDecl.flags, PullElementFlags.Exported); + + if (!isExported) { + this.recordSourceMappingStart(moduleDecl); + this.writeToOutput("var "); + this.writeToOutputWithSourceMapRecord(this.moduleName, moduleDecl.identifier); + this.writeLineToOutput(";"); + this.recordSourceMappingEnd(moduleDecl); + this.emitIndent(); + } + + this.writeToOutput("("); + this.recordSourceMappingStart(moduleDecl); + this.writeToOutput("function ("); + this.writeToOutputWithSourceMapRecord(this.moduleName, moduleDecl.identifier); + this.writeLineToOutput(") {"); + + this.recordSourceMappingNameStart(this.moduleName); + + this.indenter.increaseIndent(); + + if (this.shouldCaptureThis(moduleDecl)) { + this.writeCaptureThisStatement(moduleDecl); + } + + this.emitSeparatedList(moduleDecl.enumElements); + this.indenter.decreaseIndent(); + this.emitIndent(); + + var parentIsDynamic = temp === EmitContainer.DynamicModule; + if (temp === EmitContainer.Prog && isExported) { + this.writeToOutput("}"); + this.recordSourceMappingNameEnd(); + this.writeToOutput(")(this." + this.moduleName + " || (this." + this.moduleName + " = {}));"); + } + else if (isExported || temp === EmitContainer.Prog) { + var dotMod = svModuleName !== "" ? (parentIsDynamic ? "exports" : svModuleName) + "." : svModuleName; + this.writeToOutput("}"); + this.recordSourceMappingNameEnd(); + this.writeToOutput(")(" + dotMod + this.moduleName + " || (" + dotMod + this.moduleName + " = {}));"); + } + else if (!isExported && temp !== EmitContainer.Prog) { + this.writeToOutput("}"); + this.recordSourceMappingNameEnd(); + this.writeToOutput(")(" + this.moduleName + " || (" + this.moduleName + " = {}));"); + } + else { + this.writeToOutput("}"); + this.recordSourceMappingNameEnd(); + this.writeToOutput(")();"); + } + + this.recordSourceMappingEnd(moduleDecl); + if (temp !== EmitContainer.Prog && isExported) { + this.recordSourceMappingStart(moduleDecl); + if (parentIsDynamic) { + this.writeLineToOutput(""); + this.emitIndent(); + this.writeToOutput("var " + this.moduleName + " = exports." + this.moduleName + ";"); + } + else { + this.writeLineToOutput(""); + this.emitIndent(); + this.writeToOutput("var " + this.moduleName + " = " + svModuleName + "." + this.moduleName + ";"); + } + this.recordSourceMappingEnd(moduleDecl); + } + + this.setContainer(temp); + this.moduleName = svModuleName; + + this.popDecl(pullDecl); + } + + private getModuleDeclToVerifyChildNameCollision(moduleDecl: PullDecl, changeNameIfAnyDeclarationInContext: boolean) { + if (ArrayUtilities.contains(this.declStack, moduleDecl)) { + // Given decl is in the scope, we would need to check for child name collision + return moduleDecl; + } + else if (changeNameIfAnyDeclarationInContext) { + // Check if any other declaration of the given symbol is in scope + // (eg. when emitting expression of type defined from different declaration in reopened module) + var symbol = moduleDecl.getSymbol(this.semanticInfoChain); + if (symbol) { + var otherDecls = symbol.getDeclarations(); + for (var i = 0; i < otherDecls.length; i++) { + // If the other decl is in the scope, use this decl to determine which name to display + if (ArrayUtilities.contains(this.declStack, otherDecls[i])) { + return otherDecls[i]; + } + } + } + } + + return null; + } + + private hasChildNameCollision(moduleName: string, parentDecl: PullDecl) { + var childDecls = parentDecl.getChildDecls(); + return ArrayUtilities.any(childDecls, (childDecl: PullDecl) => { + var childAST = this.semanticInfoChain.getASTForDecl(childDecl); + // Enum member it can never conflict with module name as it is property of the enum + // Only if this child would be emitted we need to look further in + if (childDecl.kind != PullElementKind.EnumMember && this.shouldEmit(childAST)) { + // same name child + if (childDecl.name === moduleName) { + // collision if the parent was not class + if (parentDecl.kind != PullElementKind.Class) { + return true; + } + + // If the parent was class, we would find name collision if this was not a property/method/accessor + if (!(childDecl.kind == PullElementKind.Method || + childDecl.kind == PullElementKind.Property || + childDecl.kind == PullElementKind.SetAccessor || + childDecl.kind == PullElementKind.GetAccessor)) { + return true; + } + } + + // Check if the name collision exists in any of the children + if (this.hasChildNameCollision(moduleName, childDecl)) { + return true; + } + } + return false; + }); + } + + // Get the moduleName to write in js file + // If changeNameIfAnyDeclarationInContext is true, verify if any of the declarations for the symbol would need rename. + private getModuleName(moduleDecl: PullDecl, changeNameIfAnyDeclarationInContext?: boolean) { + var moduleName = moduleDecl.name; + var moduleDisplayName = moduleDecl.getDisplayName(); + + // If the decl is in stack it may need name change in the js file + moduleDecl = this.getModuleDeclToVerifyChildNameCollision(moduleDecl, changeNameIfAnyDeclarationInContext); + if (moduleDecl && moduleDecl.kind != PullElementKind.Enum) { + // If there is any child that would be emitted with same name as module, js files would need to use rename for the module + while (this.hasChildNameCollision(moduleName, moduleDecl)) { + // there was name collision with member which could result in faulty codegen, try rename with prepend of '_' + moduleName = "_" + moduleName; + moduleDisplayName = "_" + moduleDisplayName; + } + } + + return moduleDisplayName; + } + + private emitModuleDeclarationWorker(moduleDecl: ModuleDeclarationSyntax) { + if (moduleDecl.stringLiteral) { + this.emitSingleModuleDeclaration(moduleDecl, moduleDecl.stringLiteral); + } + else { + var moduleNames = ASTHelpers.getModuleNames(moduleDecl.name); + this.emitSingleModuleDeclaration(moduleDecl, moduleNames[0]); + } + } + + private writeToken(token: ISyntaxToken) { + if (token) { + this.writeToOutputWithSourceMapRecord(token.text(), token); + } + } + + public emitSingleModuleDeclaration(moduleDecl: ModuleDeclarationSyntax, moduleName: ISyntaxToken) { + var isLastName = ASTHelpers.isLastNameOfModule(moduleDecl, moduleName); + + if (isLastName) { + // Doc Comments on the ast belong to the innermost module being emitted. + this.emitComments(moduleDecl, true); + } + + var pullDecl = this.semanticInfoChain.getDeclForAST(moduleName); + this.pushDecl(pullDecl); + + var svModuleName = this.moduleName; + + if (moduleDecl.stringLiteral) { + this.moduleName = tokenValueText(moduleDecl.stringLiteral); + if (isTSFile(this.moduleName)) { + this.moduleName = this.moduleName.substring(0, this.moduleName.length - ".ts".length); + } + } + else { + this.moduleName = moduleName.text(); + } + + var temp = this.setContainer(EmitContainer.Module); + var isExported = hasFlag(pullDecl.flags, PullElementFlags.Exported); + + // prologue + + if (!isExported) { + this.recordSourceMappingStart(moduleDecl); + this.writeToOutput("var "); + this.writeToOutputWithSourceMapRecord(this.moduleName, moduleName); + this.writeLineToOutput(";"); + this.recordSourceMappingEnd(moduleDecl); + this.emitIndent(); + } + + this.writeToOutput("("); + this.recordSourceMappingStart(moduleDecl); + this.writeToOutput("function ("); + // Use the name that doesnt conflict with its members, + // this.moduleName needs to be updated to make sure that export member declaration is emitted correctly + this.moduleName = this.getModuleName(pullDecl); + this.writeToOutputWithSourceMapRecord(this.moduleName, moduleName); + this.writeLineToOutput(") {"); + + this.recordSourceMappingNameStart(moduleName.text()); + + this.indenter.increaseIndent(); + + if (this.shouldCaptureThis(moduleDecl)) { + this.writeCaptureThisStatement(moduleDecl); + } + + if (moduleName === moduleDecl.stringLiteral) { + this.emitList(moduleDecl.moduleElements); + } + else { + var moduleNames = ASTHelpers.getModuleNames(moduleDecl.name); + var nameIndex = moduleNames.indexOf(moduleName); + + Debug.assert(nameIndex >= 0); + + if (isLastName) { + // If we're on the innermost module, we can emit the module elements. + this.emitList(moduleDecl.moduleElements); + } + else { + // otherwise, just recurse and emit the next module in the A.B.C module name. + this.emitIndent(); + this.emitSingleModuleDeclaration(moduleDecl, moduleNames[nameIndex + 1]); + this.writeLineToOutput(""); + } + } + + this.moduleName = moduleName.text(); + this.indenter.decreaseIndent(); + this.emitIndent(); + + // epilogue + var parentIsDynamic = temp === EmitContainer.DynamicModule; + this.recordSourceMappingStart(moduleDecl.closeBraceToken); + if (temp === EmitContainer.Prog && isExported) { + this.writeToOutput("}"); + this.recordSourceMappingNameEnd(); + this.recordSourceMappingEnd(moduleDecl.closeBraceToken); + this.writeToOutput(")(this." + this.moduleName + " || (this." + this.moduleName + " = {}));"); + } + else if (isExported || temp === EmitContainer.Prog) { + var dotMod = svModuleName !== "" ? (parentIsDynamic ? "exports" : svModuleName) + "." : svModuleName; + this.writeToOutput("}"); + this.recordSourceMappingNameEnd(); + this.recordSourceMappingEnd(moduleDecl.closeBraceToken); + this.writeToOutput(")(" + dotMod + this.moduleName + " || (" + dotMod + this.moduleName + " = {}));"); + } + else if (!isExported && temp !== EmitContainer.Prog) { + this.writeToOutput("}"); + this.recordSourceMappingNameEnd(); + this.recordSourceMappingEnd(moduleDecl.closeBraceToken); + this.writeToOutput(")(" + this.moduleName + " || (" + this.moduleName + " = {}));"); + } + else { + this.writeToOutput("}"); + this.recordSourceMappingNameEnd(); + this.recordSourceMappingEnd(moduleDecl.closeBraceToken); + this.writeToOutput(")();"); + } + + this.recordSourceMappingEnd(moduleDecl); + if (temp !== EmitContainer.Prog && isExported) { + this.recordSourceMappingStart(moduleDecl); + if (parentIsDynamic) { + this.writeLineToOutput(""); + this.emitIndent(); + this.writeToOutput("var " + this.moduleName + " = exports." + this.moduleName + ";"); + } + else { + this.writeLineToOutput(""); + this.emitIndent(); + this.writeToOutput("var " + this.moduleName + " = " + svModuleName + "." + this.moduleName + ";"); + } + this.recordSourceMappingEnd(moduleDecl); + } + + this.setContainer(temp); + this.moduleName = svModuleName; + + this.popDecl(pullDecl); + + if (isLastName) { + // Comments on the module ast belong to the innermost module being emitted. + this.emitComments(moduleDecl, false); + } + } + + public emitEnumElement(varDecl: EnumElementSyntax): void { + // [[""] = ] = ""; + var pullDecl = this.semanticInfoChain.getDeclForAST(varDecl); + Debug.assert(pullDecl && pullDecl.kind === PullElementKind.EnumMember); + + this.emitComments(varDecl, true); + this.recordSourceMappingStart(varDecl); + + var representation = (varDecl.propertyName.kind() === SyntaxKind.StringLiteral) + ? varDecl.propertyName.text() + : ('"' + tokenValueText(varDecl.propertyName) + '"'); + + this.writeToOutput(this.moduleName); + this.writeToOutput('['); + this.writeToOutput(this.moduleName); + this.writeToOutput('['); + this.writeToOutput(representation); + this.writeToOutput(']'); + + if (varDecl.equalsValueClause) { + this.emit(varDecl.equalsValueClause); + } + else if (pullDecl.constantValue !== null) { + this.writeToOutput(' = '); + this.writeToOutput(pullDecl.constantValue.toString()); + } + else { + this.writeToOutput(' = null'); + } + + this.writeToOutput('] = '); + this.writeToOutput(representation); + this.recordSourceMappingEnd(varDecl); + this.emitComments(varDecl, false); + this.writeToOutput(';'); + } + + public emitElementAccessExpression(expression: ElementAccessExpressionSyntax) { + this.recordSourceMappingStart(expression); + this.emit(expression.expression); + this.writeToken(expression.openBracketToken); + this.emit(expression.argumentExpression); + this.writeToken(expression.closeBracketToken); + this.recordSourceMappingEnd(expression); + } + + public emitSimpleArrowFunctionExpression(arrowFunction: SimpleArrowFunctionExpressionSyntax): void { + this.emitAnyArrowFunctionExpression(arrowFunction, arrowFunction.block, arrowFunction.expression); + } + + public emitParenthesizedArrowFunctionExpression(arrowFunction: ParenthesizedArrowFunctionExpressionSyntax): void { + this.emitAnyArrowFunctionExpression(arrowFunction, arrowFunction.block, arrowFunction.expression); + } + + private emitAnyArrowFunctionExpression(arrowFunction: ISyntaxElement, block: BlockSyntax, expression: ISyntaxElement): void { + var savedInArrowFunction = this.inArrowFunction; + this.inArrowFunction = true; + + var temp = this.setContainer(EmitContainer.Function); + + this.recordSourceMappingStart(arrowFunction); + + // Start + var pullDecl = this.semanticInfoChain.getDeclForAST(arrowFunction); + this.pushDecl(pullDecl); + + this.emitComments(arrowFunction, true); + + this.recordSourceMappingStart(arrowFunction); + this.writeToOutput("function "); + + var parameters: ParameterSyntax[] = null; + if (arrowFunction.kind() === SyntaxKind.ParenthesizedArrowFunctionExpression) { + var parenthesizedArrowFunction = arrowFunction; + + parameters = parenthesizedArrowFunction.callSignature.parameterList.parameters; + this.emitParameterList(parenthesizedArrowFunction.callSignature.parameterList); + } + else { + var parameter = (arrowFunction).parameter; + parameters = [parameter]; + this.writeToOutput("("); + this.emitFunctionParameters(parameter, parameters); + this.writeToOutput(")"); + } + + this.emitFunctionBodyStatements(/*funcName:*/ null, arrowFunction, parameters, block, expression); + + this.recordSourceMappingEnd(arrowFunction); + + // The extra call is to make sure the caller's funcDecl end is recorded, since caller wont be able to record it + this.recordSourceMappingEnd(arrowFunction); + + this.emitComments(arrowFunction, false); + + this.popDecl(pullDecl); + this.setContainer(temp); + this.inArrowFunction = savedInArrowFunction; + } + + public emitConstructor(funcDecl: ConstructorDeclarationSyntax) { + if (!funcDecl.block) { + return; + } + var temp = this.setContainer(EmitContainer.Constructor); + + this.recordSourceMappingStart(funcDecl); + + var pullDecl = this.semanticInfoChain.getDeclForAST(funcDecl); + this.pushDecl(pullDecl); + + this.emitComments(funcDecl, true); + + this.recordSourceMappingStart(funcDecl); + this.writeToOutput("function "); + this.writeToOutput(this.thisClassNode.identifier.text()); + + this.emitParameterList(funcDecl.callSignature.parameterList); + this.writeLineToOutput(" {"); + + this.recordSourceMappingNameStart("constructor"); + this.indenter.increaseIndent(); + + var parameters = funcDecl.callSignature.parameterList.parameters; + this.emitDefaultValueAssignments(parameters); + this.emitRestParameterInitializer(parameters); + + if (this.shouldCaptureThis(funcDecl)) { + this.writeCaptureThisStatement(funcDecl); + } + + this.emitConstructorStatements(funcDecl); + this.emitCommentsArray(ASTHelpers.convertTokenLeadingComments(funcDecl.block.closeBraceToken, this.text()), /*trailing:*/ false); + + this.indenter.decreaseIndent(); + this.emitIndent(); + this.writeToken(funcDecl.block.closeBraceToken); + + this.recordSourceMappingNameEnd(); + this.recordSourceMappingEnd(funcDecl); + + // The extra call is to make sure the caller's funcDecl end is recorded, since caller wont be able to record it + this.recordSourceMappingEnd(funcDecl); + + this.emitComments(funcDecl, false); + + this.popDecl(pullDecl); + this.setContainer(temp); + } + + public emitGetAccessor(accessor: GetAccessorSyntax): void { + this.recordSourceMappingStart(accessor); + this.writeToOutput("get "); + + var temp = this.setContainer(EmitContainer.Function); + + this.recordSourceMappingStart(accessor); + + var pullDecl = this.semanticInfoChain.getDeclForAST(accessor); + this.pushDecl(pullDecl); + + this.recordSourceMappingStart(accessor); + + var accessorSymbol = PullHelpers.getAccessorSymbol(accessor, this.semanticInfoChain); + var container = accessorSymbol.getContainer(); + var containerKind = container.kind; + + this.recordSourceMappingNameStart(accessor.propertyName.text()); + this.writeToOutput(accessor.propertyName.text()); + this.emitParameterList(accessor.callSignature.parameterList); + + this.emitFunctionBodyStatements(null, accessor, accessor.callSignature.parameterList.parameters, accessor.block, /*bodyExpression:*/ null); + + this.recordSourceMappingEnd(accessor); + + // The extra call is to make sure the caller's funcDecl end is recorded, since caller wont be able to record it + this.recordSourceMappingEnd(accessor); + + this.popDecl(pullDecl); + this.setContainer(temp); + this.recordSourceMappingEnd(accessor); + } + + public emitSetAccessor(accessor: SetAccessorSyntax): void { + this.recordSourceMappingStart(accessor); + this.writeToOutput("set "); + + var temp = this.setContainer(EmitContainer.Function); + + this.recordSourceMappingStart(accessor); + + var pullDecl = this.semanticInfoChain.getDeclForAST(accessor); + this.pushDecl(pullDecl); + + this.recordSourceMappingStart(accessor); + + var accessorSymbol = PullHelpers.getAccessorSymbol(accessor, this.semanticInfoChain); + var container = accessorSymbol.getContainer(); + var containerKind = container.kind; + + this.recordSourceMappingNameStart(accessor.propertyName.text()); + this.writeToOutput(accessor.propertyName.text()); + + this.emitParameterList(accessor.callSignature.parameterList); + + this.emitFunctionBodyStatements(null, accessor, accessor.callSignature.parameterList.parameters, accessor.block, /*bodyExpression:*/ null); + + this.recordSourceMappingEnd(accessor); + + // The extra call is to make sure the caller's funcDecl end is recorded, since caller wont be able to record it + this.recordSourceMappingEnd(accessor); + + this.popDecl(pullDecl); + this.setContainer(temp); + this.recordSourceMappingEnd(accessor); + } + + public emitFunctionExpression(funcDecl: FunctionExpressionSyntax): void { + var savedInArrowFunction = this.inArrowFunction; + this.inArrowFunction = false; + + var temp = this.setContainer(EmitContainer.Function); + + var funcName = funcDecl.identifier ? funcDecl.identifier.text() : null;//.getNameText(); + + this.recordSourceMappingStart(funcDecl); + + var pullDecl = this.semanticInfoChain.getDeclForAST(funcDecl); + this.pushDecl(pullDecl); + + this.recordSourceMappingStart(funcDecl); + this.writeToken(funcDecl.functionKeyword); + this.writeToOutput(" "); + + //var id = funcDecl.getNameText(); + if (funcDecl.identifier) { + this.writeToOutputWithSourceMapRecord(funcDecl.identifier.text(), funcDecl.identifier); + } + + this.emitParameterList(funcDecl.callSignature.parameterList); + this.emitFunctionBodyStatements(funcName, funcDecl, funcDecl.callSignature.parameterList.parameters, funcDecl.block, /*bodyExpression:*/ null); + + this.recordSourceMappingEnd(funcDecl); + + // The extra call is to make sure the caller's funcDecl end is recorded, since caller wont be able to record it + this.recordSourceMappingEnd(funcDecl); + + this.emitComments(funcDecl, false); + + this.popDecl(pullDecl); + + this.setContainer(temp); + this.inArrowFunction = savedInArrowFunction; + } + + public emitFunction(funcDecl: FunctionDeclarationSyntax) { + if (funcDecl.block === null) { + return; + } + var savedInArrowFunction = this.inArrowFunction; + this.inArrowFunction = false; + + var temp = this.setContainer(EmitContainer.Function); + + var funcName = funcDecl.identifier.text(); + + this.recordSourceMappingStart(funcDecl); + + var printName = funcDecl.identifier !== null + var pullDecl = this.semanticInfoChain.getDeclForAST(funcDecl); + this.pushDecl(pullDecl); + + this.emitComments(funcDecl, true); + + this.recordSourceMappingStart(funcDecl); + this.writeToken(funcDecl.functionKeyword); + this.writeToOutput(" "); + + if (printName) { + var id = funcDecl.identifier.text(); + if (id) { + if (funcDecl.identifier) { + this.recordSourceMappingStart(funcDecl.identifier); + } + this.writeToOutput(id); + if (funcDecl.identifier) { + this.recordSourceMappingEnd(funcDecl.identifier); + } + } + } + + this.emitParameterList(funcDecl.callSignature.parameterList); + + var parameters = funcDecl.callSignature.parameterList.parameters; + this.emitFunctionBodyStatements(funcDecl.identifier.text(), funcDecl, parameters, funcDecl.block, /*bodyExpression:*/ null); + + this.recordSourceMappingEnd(funcDecl); + + // The extra call is to make sure the caller's funcDecl end is recorded, since caller wont be able to record it + this.recordSourceMappingEnd(funcDecl); + + this.emitComments(funcDecl, false); + + this.popDecl(pullDecl); + + this.setContainer(temp); + this.inArrowFunction = savedInArrowFunction; + + if (funcDecl.block) { + var pullFunctionDecl = this.semanticInfoChain.getDeclForAST(funcDecl); + if ((this.emitState.container === EmitContainer.Module || this.emitState.container === EmitContainer.DynamicModule) && pullFunctionDecl && hasFlag(pullFunctionDecl.flags, PullElementFlags.Exported)) { + this.writeLineToOutput(""); + this.emitIndent(); + var modName = this.emitState.container === EmitContainer.Module ? this.moduleName : "exports"; + this.recordSourceMappingStart(funcDecl); + this.writeToOutput(modName + "." + funcName + " = " + funcName + ";"); + this.recordSourceMappingEnd(funcDecl); + } + } + } + + public emitAmbientVarDecl(varDecl: VariableDeclaratorSyntax) { + this.recordSourceMappingStart(this.currentVariableDeclaration); + if (varDecl.equalsValueClause) { + this.emitComments(varDecl, true); + this.recordSourceMappingStart(varDecl); + this.writeToOutputWithSourceMapRecord(varDecl.propertyName.text(), varDecl.propertyName); + this.emitJavascript(varDecl.equalsValueClause, false); + this.recordSourceMappingEnd(varDecl); + this.emitComments(varDecl, false); + } + } + + // Emits "var " if it is allowed + public emitVarDeclVar() { + if (this.currentVariableDeclaration) { + this.writeToOutput("var "); + } + } + + public emitVariableDeclaration(declaration: VariableDeclarationSyntax) { + var varDecl = declaration.variableDeclarators[0]; + + var symbol = this.semanticInfoChain.getSymbolForAST(varDecl); + + var parentSymbol = symbol ? symbol.getContainer() : null; + var parentKind = parentSymbol ? parentSymbol.kind : PullElementKind.None; + + this.emitComments(declaration, true); + + var pullVarDecl = this.semanticInfoChain.getDeclForAST(varDecl); + var isAmbientWithoutInit = pullVarDecl && hasFlag(pullVarDecl.flags, PullElementFlags.Ambient) && varDecl.equalsValueClause === null; + if (!isAmbientWithoutInit) { + var prevVariableDeclaration = this.currentVariableDeclaration; + this.currentVariableDeclaration = declaration; + + for (var i = 0, n = declaration.variableDeclarators.length; i < n; i++) { + var declarator = declaration.variableDeclarators[i]; + + if (i > 0) { + this.writeToOutput(", "); + } + + this.emit(declarator); + } + this.currentVariableDeclaration = prevVariableDeclaration; + + // Declarator emit would take care of emitting start of the variable declaration start + this.recordSourceMappingEnd(declaration); + } + + this.emitComments(declaration, false); + } + + private emitMemberVariableDeclaration(varDecl: MemberVariableDeclarationSyntax) { + Debug.assert(!hasModifier(varDecl.modifiers, PullElementFlags.Static) && varDecl.variableDeclarator.equalsValueClause); + + var pullDecl = this.semanticInfoChain.getDeclForAST(varDecl); + this.pushDecl(pullDecl); + + this.emitComments(varDecl, true); + this.recordSourceMappingStart(varDecl); + + var varDeclName = varDecl.variableDeclarator.propertyName.text(); + var quotedOrNumber = isQuoted(varDeclName) || varDecl.variableDeclarator.propertyName.kind() !== SyntaxKind.IdentifierName; + + var symbol = this.semanticInfoChain.getSymbolForAST(varDecl); + var parentSymbol = symbol ? symbol.getContainer() : null; + var parentDecl = pullDecl && pullDecl.getParentDecl(); + + if (quotedOrNumber) { + this.writeToOutput("this["); + } + else { + this.writeToOutput("this."); + } + + this.writeToOutputWithSourceMapRecord(varDecl.variableDeclarator.propertyName.text(), varDecl.variableDeclarator.propertyName); + + if (quotedOrNumber) { + this.writeToOutput("]"); + } + + if (varDecl.variableDeclarator.equalsValueClause) { + // Ensure we have a fresh var list count when recursing into the variable + // initializer. We don't want our current list of variables to affect how we + // emit nested variable lists. + var prevVariableDeclaration = this.currentVariableDeclaration; + this.emit(varDecl.variableDeclarator.equalsValueClause); + this.currentVariableDeclaration = prevVariableDeclaration; + } + + // class + if (this.emitState.container !== EmitContainer.Args) { + this.writeToOutput(";"); + } + + this.recordSourceMappingEnd(varDecl); + this.emitComments(varDecl, false); + + this.popDecl(pullDecl); + } + + public emitVariableDeclarator(varDecl: VariableDeclaratorSyntax) { + var pullDecl = this.semanticInfoChain.getDeclForAST(varDecl); + this.pushDecl(pullDecl); + if (pullDecl && (pullDecl.flags & PullElementFlags.Ambient) === PullElementFlags.Ambient) { + this.emitAmbientVarDecl(varDecl); + } + else { + this.emitComments(varDecl, true); + this.recordSourceMappingStart(this.currentVariableDeclaration); + this.recordSourceMappingStart(varDecl); + + var varDeclName = varDecl.propertyName.text(); + + var symbol = this.semanticInfoChain.getSymbolForAST(varDecl); + var parentSymbol = symbol ? symbol.getContainer() : null; + var parentDecl = pullDecl && pullDecl.getParentDecl(); + var parentIsModule = parentDecl && (parentDecl.flags & PullElementFlags.SomeInitializedModule); + + if (parentIsModule) { + // module + if (!hasFlag(pullDecl.flags, PullElementFlags.Exported)/* && !varDecl.isProperty() */) { + this.emitVarDeclVar(); + } + else { + if (this.emitState.container === EmitContainer.DynamicModule) { + this.writeToOutput("exports."); + } + else { + this.writeToOutput(this.moduleName + "."); + } + } + } + else { + this.emitVarDeclVar(); + } + + this.writeToOutputWithSourceMapRecord(varDecl.propertyName.text(), varDecl.propertyName); + + if (varDecl.equalsValueClause) { + // Ensure we have a fresh var list count when recursing into the variable + // initializer. We don't want our current list of variables to affect how we + // emit nested variable lists. + var prevVariableDeclaration = this.currentVariableDeclaration; + this.emit(varDecl.equalsValueClause); + this.currentVariableDeclaration = prevVariableDeclaration; + } + + this.recordSourceMappingEnd(varDecl); + this.emitComments(varDecl, false); + } + this.currentVariableDeclaration = undefined; + this.popDecl(pullDecl); + } + + private symbolIsUsedInItsEnclosingContainer(symbol: PullSymbol, dynamic = false) { + var symDecls = symbol.getDeclarations(); + + if (symDecls.length) { + var enclosingDecl = this.getEnclosingDecl(); + if (enclosingDecl) { + var parentDecl = symDecls[0].getParentDecl(); + if (parentDecl) { + var symbolDeclarationEnclosingContainer = parentDecl; + var enclosingContainer = enclosingDecl; + + // compute the closing container of the symbol's declaration + while (symbolDeclarationEnclosingContainer) { + if (symbolDeclarationEnclosingContainer.kind === (dynamic ? PullElementKind.DynamicModule : PullElementKind.Container)) { + break; + } + symbolDeclarationEnclosingContainer = symbolDeclarationEnclosingContainer.getParentDecl(); + } + + // if the symbol in question is not a global, compute the nearest + // enclosing declaration from the point of usage + if (symbolDeclarationEnclosingContainer) { + while (enclosingContainer) { + if (enclosingContainer.kind === (dynamic ? PullElementKind.DynamicModule : PullElementKind.Container)) { + break; + } + + enclosingContainer = enclosingContainer.getParentDecl(); + } + } + + if (symbolDeclarationEnclosingContainer && enclosingContainer) { + var same = symbolDeclarationEnclosingContainer === enclosingContainer; + + // initialized module object variables are bound to their parent's decls + if (!same && symbol.anyDeclHasFlag(PullElementFlags.InitializedModule)) { + same = symbolDeclarationEnclosingContainer === enclosingContainer.getParentDecl(); + } + + return same; + } + } + } + } + + return false; + } + + // In some cases, when emitting a name, the emitter needs to qualify a symbol + // name by first emitting its parent's name. This generally happens when the + // name referenced is in scope in TypeScript, but not in Javascript. This is true + // in any of the following 3 cases: + // - It is an enum member, even if accessed from within the enum declaration in which it is defined + // - It is an exported var, even if accessed from within the module declaration in which it is defined + // - It is an exported member of the current module, but is never defined in this particular module + // declaration (i.e. it is only defined in other components of the same merged module) + private shouldQualifySymbolNameWithParentName(symbol: PullSymbol): boolean { + var enclosingContextDeclPath = this.declStack; + var symbolDeclarations = symbol.getDeclarations(); + for (var i = 0; i < symbolDeclarations.length; i++) { + var currentDecl = symbolDeclarations[i]; + var declParent = currentDecl.getParentDecl(); + + if (currentDecl.kind === PullElementKind.EnumMember) { + return true; + } + + // All decls of the same symbol must agree on whether they are exported + // If one decl is not exported, none of them are, and it is safe to + // assume it is just a local + if (!hasFlag(currentDecl.flags, PullElementFlags.Exported)) { + return false; + } + + // Section 10.6: + // When a variable is exported, all references to the variable in the body of the + // module are replaced with + // .< VariableName> + if (currentDecl.kind === PullElementKind.Variable && !hasFlag(currentDecl.flags, PullElementFlags.ImplicitVariable)) { + return true; + } + + if (ArrayUtilities.contains(this.declStack, declParent)) { + return false; + } + } + + return true; + } + + // Get the symbol information to be used for emitting the ast + private getSymbolForEmit(ast: ISyntaxElement) { + var pullSymbol = this.semanticInfoChain.getSymbolForAST(ast); + var pullSymbolAlias = this.semanticInfoChain.getAliasSymbolForAST(ast); + if (pullSymbol && pullSymbolAlias) { + var symbolToCompare = isTypesOnlyLocation(ast) ? + pullSymbolAlias.getExportAssignedTypeSymbol() : + pullSymbolAlias.getExportAssignedValueSymbol(); + + if (pullSymbol === symbolToCompare) { + pullSymbol = pullSymbolAlias; + pullSymbolAlias = null; + } + } + return { symbol: pullSymbol, aliasSymbol: pullSymbolAlias }; + } + + public emitName(name: ISyntaxToken, addThis: boolean) { + this.emitComments(name, true); + this.recordSourceMappingStart(name); + if (name.text().length > 0) { + var symbolForEmit = this.getSymbolForEmit(name); + var pullSymbol = symbolForEmit.symbol; + if (!pullSymbol) { + pullSymbol = this.semanticInfoChain.anyTypeSymbol; + } + var pullSymbolAlias = symbolForEmit.aliasSymbol; + var pullSymbolKind = pullSymbol.kind; + var isLocalAlias = pullSymbolAlias && (pullSymbolAlias.getDeclarations()[0].getParentDecl() === this.getEnclosingDecl()); + if (addThis && (this.emitState.container !== EmitContainer.Args) && pullSymbol) { + var pullSymbolContainer = pullSymbol.getContainer(); + + if (pullSymbolContainer) { + var pullSymbolContainerKind = pullSymbolContainer.kind; + + if (PullHelpers.symbolIsModule(pullSymbolContainer) || pullSymbolContainerKind === PullElementKind.Enum || + pullSymbolContainer.anyDeclHasFlag(PullElementFlags.InitializedModule | PullElementFlags.Enum)) { + var needToEmitParentName = this.shouldQualifySymbolNameWithParentName(pullSymbol); + if (needToEmitParentName) { + var parentDecl = pullSymbol.getDeclarations()[0].getParentDecl(); + Debug.assert(parentDecl && !parentDecl.isRootDecl()); + this.writeToOutput(this.getModuleName(parentDecl, /* changeNameIfAnyDeclarationInContext */ true) + "."); + } + } + else if (pullSymbolContainerKind === PullElementKind.DynamicModule || + pullSymbolContainer.anyDeclHasFlag(PullElementFlags.InitializedDynamicModule)) { + if (pullSymbolKind === PullElementKind.Property) { + // If dynamic module + this.writeToOutput("exports."); + } + else if (pullSymbol.anyDeclHasFlag(PullElementFlags.Exported) && + !isLocalAlias && + !pullSymbol.anyDeclHasFlag(PullElementFlags.ImplicitVariable) && + pullSymbol.kind !== PullElementKind.ConstructorMethod && + pullSymbol.kind !== PullElementKind.Class && + pullSymbol.kind !== PullElementKind.Enum) { + this.writeToOutput("exports."); + } + } + } + } + + this.writeToOutput(name.text()); + } + + this.recordSourceMappingEnd(name); + this.emitComments(name, false); + } + + public recordSourceMappingNameStart(name: string) { + if (this.sourceMapper) { + var nameIndex = -1; + if (name) { + if (this.sourceMapper.currentNameIndex.length > 0) { + var parentNameIndex = this.sourceMapper.currentNameIndex[this.sourceMapper.currentNameIndex.length - 1]; + if (parentNameIndex !== -1) { + name = this.sourceMapper.names[parentNameIndex] + "." + name; + } + } + + // Look if there already exists name + var nameIndex = this.sourceMapper.names.length - 1; + for (nameIndex; nameIndex >= 0; nameIndex--) { + if (this.sourceMapper.names[nameIndex] === name) { + break; + } + } + + if (nameIndex === -1) { + nameIndex = this.sourceMapper.names.length; + this.sourceMapper.names.push(name); + } + } + this.sourceMapper.currentNameIndex.push(nameIndex); + } + } + + public recordSourceMappingNameEnd() { + if (this.sourceMapper) { + this.sourceMapper.currentNameIndex.pop(); + } + } + + private recordSourceMappingStart(ast: ISyntaxElement) { + if (this.sourceMapper && ASTHelpers.isValidAstNode(ast)) { + var text = this.text(); + this.recordSourceMappingSpanStart(ast, start(ast, text), end(ast, text)); + } + } + + private recordSourceMappingCommentStart(comment: Comment) { + this.recordSourceMappingSpanStart(comment, comment.start(), comment.end()); + } + + private recordSourceMappingSpanStart(ast: any, start: number, end: number) { + if (this.sourceMapper && ast && start !== -1 && end !== -1) { + var lineCol = { line: -1, character: -1 }; + var sourceMapping = new SourceMapping(); + sourceMapping.start.emittedColumn = this.emitState.column; + sourceMapping.start.emittedLine = this.emitState.line; + // REVIEW: check time consumed by this binary search (about two per leaf statement) + var lineMap = this.document.lineMap(); + lineMap.fillLineAndCharacterFromPosition(start, lineCol); + sourceMapping.start.sourceColumn = lineCol.character; + sourceMapping.start.sourceLine = lineCol.line + 1; + lineMap.fillLineAndCharacterFromPosition(end, lineCol); + sourceMapping.end.sourceColumn = lineCol.character; + sourceMapping.end.sourceLine = lineCol.line + 1; + + Debug.assert(!isNaN(sourceMapping.start.emittedColumn)); + Debug.assert(!isNaN(sourceMapping.start.emittedLine)); + Debug.assert(!isNaN(sourceMapping.start.sourceColumn)); + Debug.assert(!isNaN(sourceMapping.start.sourceLine)); + Debug.assert(!isNaN(sourceMapping.end.sourceColumn)); + Debug.assert(!isNaN(sourceMapping.end.sourceLine)); + + if (this.sourceMapper.currentNameIndex.length > 0) { + sourceMapping.nameIndex = this.sourceMapper.currentNameIndex[this.sourceMapper.currentNameIndex.length - 1]; + } + // Set parent and child relationship + var siblings = this.sourceMapper.currentMappings[this.sourceMapper.currentMappings.length - 1]; + siblings.push(sourceMapping); + this.sourceMapper.currentMappings.push(sourceMapping.childMappings); + this.sourceMapper.increaseMappingLevel(ast); + } + } + + private recordSourceMappingEnd(ast: ISyntaxElement) { + if (this.sourceMapper && ASTHelpers.isValidAstNode(ast)) { + var text = this.text(); + this.recordSourceMappingSpanEnd(ast, start(ast, text), end(ast, text)); + } + } + + private recordSourceMappingCommentEnd(ast: Comment) { + if (this.sourceMapper && ASTHelpers.isValidSpan(ast)) { + this.recordSourceMappingSpanEnd(ast, ast.start(), ast.end()); + } + } + + private recordSourceMappingSpanEnd(ast: any, start: number, end: number) { + if (this.sourceMapper && ast && start !== -1 && end !== -1) { + // Pop source mapping childs + this.sourceMapper.currentMappings.pop(); + + // Get the last source mapping from sibling list = which is the one we are recording end for + var siblings = this.sourceMapper.currentMappings[this.sourceMapper.currentMappings.length - 1]; + var sourceMapping = siblings[siblings.length - 1]; + + sourceMapping.end.emittedColumn = this.emitState.column; + sourceMapping.end.emittedLine = this.emitState.line; + + Debug.assert(!isNaN(sourceMapping.end.emittedColumn)); + Debug.assert(!isNaN(sourceMapping.end.emittedLine)); + + this.sourceMapper.decreaseMappingLevel(ast); + } + } + + // Note: may throw exception. + public getOutputFiles(): OutputFile[] { + // Output a source mapping. As long as we haven't gotten any errors yet. + var result: OutputFile[] = []; + if (this.sourceMapper !== null) { + this.sourceMapper.emitSourceMapping(); + result.push(this.sourceMapper.getOutputFile()); + } + + result.push(this.outfile.getOutputFile()); + return result; + } + + private emitParameterPropertyAndMemberVariableAssignments(): void { + // emit any parameter properties first + var constructorDecl = getLastConstructor(this.thisClassNode); + + if (constructorDecl) { + for (var i = 0, n = constructorDecl.callSignature.parameterList.parameters.length; i < n; i++) { + var parameter = constructorDecl.callSignature.parameterList.parameters[i]; + + var parameterDecl = this.semanticInfoChain.getDeclForAST(parameter); + if (hasFlag(parameterDecl.flags, PullElementFlags.PropertyParameter)) { + this.emitIndent(); + this.recordSourceMappingStart(parameter); + this.writeToOutputWithSourceMapRecord("this." + parameter.identifier.text(), parameter.identifier); + this.writeToOutput(" = "); + this.writeToOutputWithSourceMapRecord(parameter.identifier.text(), parameter.identifier); + this.writeLineToOutput(";"); + this.recordSourceMappingEnd(parameter); + } + } + } + + for (var i = 0, n = this.thisClassNode.classElements.length; i < n; i++) { + if (this.thisClassNode.classElements[i].kind() === SyntaxKind.MemberVariableDeclaration) { + var varDecl = this.thisClassNode.classElements[i]; + if (!hasModifier(varDecl.modifiers, PullElementFlags.Static) && varDecl.variableDeclarator.equalsValueClause) { + this.emitIndent(); + this.emitMemberVariableDeclaration(varDecl); + this.writeLineToOutput(""); + } + } + } + } + + private isOnSameLine(pos1: number, pos2: number): boolean { + if (pos1 < 0 || pos2 < 0) { + // Missing element. Assume it's on the same line as the other element. + return true; + } + + var lineMap = this.document.lineMap(); + return lineMap.getLineNumberFromPosition(pos1) === lineMap.getLineNumberFromPosition(pos2); + } + + private emitCommaSeparatedList(parent: ISyntaxElement, list: T[], buffer: string, preserveNewLines: boolean): void { + if (list === null || list.length === 0) { + return; + } + + // If the first element isn't on hte same line as the parent node, then we need to + // start with a newline. + var text = this.text(); + var startLine = preserveNewLines && !this.isOnSameLine(end(parent, text), end(list[0], text)); + + if (preserveNewLines) { + // Any elements on a new line will have to be indented. + this.indenter.increaseIndent(); + } + + // If we're starting on a newline, then emit an actual newline. Otherwise write out + // the buffer character before hte first element. + if (startLine) { + this.writeLineToOutput(""); + } + else { + this.writeToOutput(buffer); + } + + for (var i = 0, n = list.length; i < n; i++) { + var emitNode = list[i]; + + // Write out the element, emitting an indent if we're on a new line. + this.emitJavascript(emitNode, startLine); + + if (i < (n - 1)) { + // If the next element start on a different line than this element ended on, + // then we want to start on a newline. Emit the comma with a newline. + // Otherwise, emit the comma with the space. + startLine = preserveNewLines && !this.isOnSameLine(end(emitNode, text), start(list[i + 1], text)); + if (startLine) { + this.writeLineToOutput(","); + } + else { + this.writeToOutput(", "); + } + } + } + + if (preserveNewLines) { + // We're done with all the elements. Return the indent back to where it was. + this.indenter.decreaseIndent(); + } + + // If the last element isn't on the same line as the parent, then emit a newline + // after the last element and emit our indent so the list's terminator will be + // on the right line. Otherwise, emit the buffer string between the last value + // and the terminator. + if (preserveNewLines && !this.isOnSameLine(end(parent, text), end(list[list.length - 1], text))) { + this.writeLineToOutput(""); + this.emitIndent(); + } + else { + this.writeToOutput(buffer); + } + } + + public emitList(list: T[], useNewLineSeparator = true, startInclusive = 0, endExclusive = list.length) { + if (list === null) { + return; + } + + this.emitComments(list, true); + var lastEmittedNode: ISyntaxElement = null; + + for (var i = startInclusive; i < endExclusive; i++) { + var node = list[i]; + + if (this.shouldEmit(node)) { + this.emitSpaceBetweenConstructs(lastEmittedNode, node); + + this.emitJavascript(node, true); + if (useNewLineSeparator) { + this.writeLineToOutput(""); + } + + lastEmittedNode = node; + } + } + + this.emitComments(list, false); + } + + public emitSeparatedList(list: T[], useNewLineSeparator = true, startInclusive = 0, endExclusive = list.length) { + if (list === null) { + return; + } + + this.emitComments(list, true); + var lastEmittedNode: ISyntaxElement = null; + + for (var i = startInclusive; i < endExclusive; i++) { + var node = list[i]; + + if (this.shouldEmit(node)) { + this.emitSpaceBetweenConstructs(lastEmittedNode, node); + + this.emitJavascript(node, true); + if (useNewLineSeparator) { + this.writeLineToOutput(""); + } + + lastEmittedNode = node; + } + } + + this.emitComments(list, false); + } + + private isDirectivePrologueElement(node: ISyntaxElement) { + if (node.kind() === SyntaxKind.ExpressionStatement) { + var exprStatement = node; + return exprStatement.expression.kind() === SyntaxKind.StringLiteral; + } + + return false; + } + + // If these two constructs had more than one line between them originally, then emit at + // least one blank line between them. + public emitSpaceBetweenConstructs(node1: ISyntaxElement, node2: ISyntaxElement): void { + if (node1 === null || node2 === null) { + return; + } + + var text = this.text(); + if (start(node1, text) === -1 || end(node1, text) === -1 || start(node2, text) === -1 || end(node2, text) === -1) { + return; + } + + var lineMap = this.document.lineMap(); + var node1EndLine = lineMap.getLineNumberFromPosition(end(node1, text)); + var node2StartLine = lineMap.getLineNumberFromPosition(start(node2, text)); + + if ((node2StartLine - node1EndLine) > 1) { + this.writeLineToOutput("", /*force:*/ true); + } + } + + // We consider a sequence of comments to be a detached from an ast if there are no blank lines + // between them, and there is a blank line after the last one and the node they're attached + // to. + private getDetachedComments(element: ISyntaxElement): Comment[] { + var text = this.text(); + var preComments = TypeScript.ASTHelpers.preComments(element, text); + if (preComments) { + var lineMap = this.document.lineMap(); + + var detachedComments: Comment[] = []; + var lastComment: Comment = null; + + for (var i = 0, n = preComments.length; i < n; i++) { + var comment = preComments[i]; + + if (lastComment) { + var lastCommentLine = lineMap.getLineNumberFromPosition(lastComment.end()); + var commentLine = lineMap.getLineNumberFromPosition(comment.start()); + + if (commentLine >= lastCommentLine + 2) { + // There was a blank line between the last comment and this comment. This + // comment is not part of the copyright comments. Return what we have so + // far. + return detachedComments; + } + } + + detachedComments.push(comment); + lastComment = comment; + } + + // All comments look like they could have been part of the copyright header. Make + // sure there is at least one blank line between it and the node. If not, it's not + // a copyright header. + var lastCommentLine = lineMap.getLineNumberFromPosition(ArrayUtilities.last(detachedComments).end()); + var astLine = lineMap.getLineNumberFromPosition(start(element, text)); + if (astLine >= lastCommentLine + 2) { + return detachedComments; + } + } + + // No usable copyright comments found. + return []; + } + + private emitPossibleCopyrightHeaders(script: SourceUnitSyntax): void { + this.emitDetachedComments(script.moduleElements); + } + + private emitDetachedComments(list: ISyntaxNodeOrToken[]): void { + if (list.length > 0) { + var firstElement = childAt(list, 0); + + this.detachedCommentsElement = firstElement; + this.emitCommentsArray(this.getDetachedComments(this.detachedCommentsElement), /*trailing:*/ false); + } + } + + public emitScriptElements(sourceUnit: SourceUnitSyntax) { + var list = sourceUnit.moduleElements; + + this.emitPossibleCopyrightHeaders(sourceUnit); + + // First, emit all the prologue elements. + for (var i = 0, n = list.length; i < n; i++) { + var node = list[i]; + + if (!this.isDirectivePrologueElement(node)) { + break; + } + + this.emitJavascript(node, true); + this.writeLineToOutput(""); + } + + // Now emit __extends or a _this capture if necessary. + this.emitPrologue(sourceUnit); + + var isExternalModule = this.document.syntaxTree().isExternalModule(); + var isNonElidedExternalModule = isExternalModule && !ASTHelpers.scriptIsElided(sourceUnit); + if (isNonElidedExternalModule) { + this.recordSourceMappingStart(sourceUnit); + + if (this.emitOptions.compilationSettings().moduleGenTarget() === ModuleGenTarget.Asynchronous) { // AMD + var dependencyList = "[\"require\", \"exports\""; + var importList = "require, exports"; + + var importAndDependencyList = this.getModuleImportAndDependencyList(sourceUnit); + importList += importAndDependencyList.importList; + dependencyList += importAndDependencyList.dependencyList + "]"; + + this.writeLineToOutput("define(" + dependencyList + "," + " function(" + importList + ") {"); + } + } + + if (isExternalModule) { + var temp = this.setContainer(EmitContainer.DynamicModule); + + var svModuleName = this.moduleName; + this.moduleName = syntaxTree(sourceUnit).fileName(); + if (TypeScript.isTSFile(this.moduleName)) { + this.moduleName = this.moduleName.substring(0, this.moduleName.length - ".ts".length); + } + + // if the external module has an "export =" identifier, we'll + // set it in the ExportAssignment emit method + this.setExportAssignment(null); + + if(this.emitOptions.compilationSettings().moduleGenTarget() === ModuleGenTarget.Asynchronous) { + this.indenter.increaseIndent(); + } + + var externalModule = this.semanticInfoChain.getDeclForAST(this.document.sourceUnit()); + + if (hasFlag(externalModule.flags, PullElementFlags.MustCaptureThis)) { + this.writeCaptureThisStatement(sourceUnit); + } + + this.pushDecl(externalModule); + } + + this.emitList(list, /*useNewLineSeparator:*/ true, /*startInclusive:*/ i, /*endExclusive:*/ n); + + if (isExternalModule) { + if (this.emitOptions.compilationSettings().moduleGenTarget() === ModuleGenTarget.Asynchronous) { + this.indenter.decreaseIndent(); + } + + if (isNonElidedExternalModule) { + var exportAssignment = this.getExportAssignment(); + var exportAssignmentIdentifierText = exportAssignment ? exportAssignment.identifier.text() : null; + var exportAssignmentValueSymbol = (externalModule.getSymbol(this.semanticInfoChain)).getExportAssignedValueSymbol(); + + if (this.emitOptions.compilationSettings().moduleGenTarget() === ModuleGenTarget.Asynchronous) { // AMD + if (exportAssignmentIdentifierText && exportAssignmentValueSymbol && !(exportAssignmentValueSymbol.kind & PullElementKind.SomeTypeReference)) { + // indent was decreased for AMD above + this.indenter.increaseIndent(); + this.emitIndent(); + this.writeToOutputWithSourceMapRecord("return " + exportAssignmentIdentifierText, exportAssignment); + this.writeLineToOutput(";"); + this.indenter.decreaseIndent(); + } + this.writeToOutput("});"); + } + else if (exportAssignmentIdentifierText && exportAssignmentValueSymbol && !(exportAssignmentValueSymbol.kind & PullElementKind.SomeTypeReference)) { + this.emitIndent(); + this.writeToOutputWithSourceMapRecord("module.exports = " + exportAssignmentIdentifierText, exportAssignment); + this.writeToOutput(";"); + } + + this.recordSourceMappingEnd(sourceUnit); + this.writeLineToOutput(""); + } + + this.setContainer(temp); + this.moduleName = svModuleName; + this.popDecl(externalModule); + } + } + + public emitConstructorStatements(funcDecl: ConstructorDeclarationSyntax) { + var list = funcDecl.block.statements; + + if (list === null) { + return; + } + + this.emitComments(list, true); + + var emitPropertyAssignmentsAfterSuperCall = ASTHelpers.getExtendsHeritageClause(this.thisClassNode.heritageClauses) !== null; + var propertyAssignmentIndex = emitPropertyAssignmentsAfterSuperCall ? 1 : 0; + var lastEmittedNode: ISyntaxElement = null; + + for (var i = 0, n = list.length; i < n; i++) { + // In some circumstances, class property initializers must be emitted immediately after the 'super' constructor + // call which, in these cases, must be the first statement in the constructor body + if (i === propertyAssignmentIndex) { + this.emitParameterPropertyAndMemberVariableAssignments(); + } + + var node = list[i]; + + if (this.shouldEmit(node)) { + this.emitSpaceBetweenConstructs(lastEmittedNode, node); + + this.emitJavascript(node, true); + this.writeLineToOutput(""); + + lastEmittedNode = node; + } + } + + if (i === propertyAssignmentIndex) { + this.emitParameterPropertyAndMemberVariableAssignments(); + } + + this.emitComments(list, false); + } + + // tokenId is the id the preceding token + public emitJavascript(ast: ISyntaxElement, startLine: boolean) { + if (ast === null) { + return; + } + + if (startLine && + this.indenter.indentAmt > 0) { + + this.emitIndent(); + } + + this.emit(ast); + } + + public emitAccessorMemberDeclaration(funcDecl: ISyntaxElement, name: ISyntaxToken, className: string, isProto: boolean) { + if (funcDecl.kind() !== SyntaxKind.GetAccessor) { + var accessorSymbol = PullHelpers.getAccessorSymbol(funcDecl, this.semanticInfoChain); + if (accessorSymbol.getGetter()) { + return; + } + } + + this.emitIndent(); + this.recordSourceMappingStart(funcDecl); + + this.writeToOutput("Object.defineProperty(" + className); + if (isProto) { + this.writeToOutput(".prototype, "); + } + else { + this.writeToOutput(", "); + } + + var functionName = name.text(); + if (isQuoted(functionName)) { + this.writeToOutput(functionName); + } + else { + this.writeToOutput('"' + functionName + '"'); + } + + this.writeLineToOutput(", {"); + + this.indenter.increaseIndent(); + + var accessors = PullHelpers.getGetterAndSetterFunction(funcDecl, this.semanticInfoChain); + if (accessors.getter) { + this.emitIndent(); + this.recordSourceMappingStart(accessors.getter); + this.emitComments(accessors.getter, true); + this.writeToOutput("get: "); + this.emitAccessorBody(accessors.getter, accessors.getter.callSignature.parameterList, accessors.getter.block); + this.writeLineToOutput(","); + } + + if (accessors.setter) { + this.emitIndent(); + this.recordSourceMappingStart(accessors.setter); + this.emitComments(accessors.setter, true); + this.writeToOutput("set: "); + this.emitAccessorBody(accessors.setter, accessors.setter.callSignature.parameterList, accessors.setter.block); + this.writeLineToOutput(","); + } + + this.emitIndent(); + this.writeLineToOutput("enumerable: true,"); + this.emitIndent(); + this.writeLineToOutput("configurable: true"); + this.indenter.decreaseIndent(); + this.emitIndent(); + this.writeLineToOutput("});"); + this.recordSourceMappingEnd(funcDecl); + } + + private emitAccessorBody(funcDecl: ISyntaxElement, parameterList: ParameterListSyntax, block: BlockSyntax): void { + var pullDecl = this.semanticInfoChain.getDeclForAST(funcDecl); + this.pushDecl(pullDecl); + + this.recordSourceMappingStart(funcDecl); + this.writeToOutput("function "); + this.emitParameterList(parameterList); + + var parameters = parameterList.parameters; + this.emitFunctionBodyStatements(null, funcDecl, parameters, block, /*bodyExpression:*/ null); + + this.recordSourceMappingEnd(funcDecl); + + // The extra call is to make sure the caller's funcDecl end is recorded, since caller wont be able to record it + this.recordSourceMappingEnd(funcDecl); + this.popDecl(pullDecl); + } + + public emitClass(classDecl: ClassDeclarationSyntax) { + var pullDecl = this.semanticInfoChain.getDeclForAST(classDecl); + this.pushDecl(pullDecl); + + var svClassNode = this.thisClassNode; + this.thisClassNode = classDecl; + var className = classDecl.identifier.text(); + this.emitComments(classDecl, true); + var temp = this.setContainer(EmitContainer.Class); + + this.recordSourceMappingStart(classDecl); + this.writeToOutput("var " + className); + + var hasBaseClass = ASTHelpers.getExtendsHeritageClause(classDecl.heritageClauses) !== null; + var baseTypeReference: ISyntaxElement = null; + var varDecl: VariableDeclaratorSyntax = null; + + if (hasBaseClass) { + this.writeLineToOutput(" = (function (_super) {"); + } + else { + this.writeLineToOutput(" = (function () {"); + } + + this.recordSourceMappingNameStart(className); + this.indenter.increaseIndent(); + + if (hasBaseClass) { + baseTypeReference = ASTHelpers.getExtendsHeritageClause(classDecl.heritageClauses).typeNames[0]; + this.emitIndent(); + this.writeToOutputWithSourceMapRecord("__extends(" + className + ", _super)", baseTypeReference); + this.writeLineToOutput(";"); + } + + this.emitIndent(); + + var constrDecl = getLastConstructor(classDecl); + + // output constructor + if (constrDecl) { + // declared constructor + this.emit(constrDecl); + this.writeLineToOutput(""); + } + else { + this.recordSourceMappingStart(classDecl); + // default constructor + this.indenter.increaseIndent(); + this.writeLineToOutput("function " + classDecl.identifier.text() + "() {"); + this.recordSourceMappingNameStart("constructor"); + if (hasBaseClass) { + this.emitIndent(); + this.writeToOutputWithSourceMapRecord("_super.apply(this, arguments)", baseTypeReference); + this.writeLineToOutput(";"); + } + + if (this.shouldCaptureThis(classDecl)) { + this.writeCaptureThisStatement(classDecl); + } + + this.emitParameterPropertyAndMemberVariableAssignments(); + + this.indenter.decreaseIndent(); + this.emitIndent(); + this.writeToken(classDecl.closeBraceToken); + this.writeLineToOutput(""); + + this.recordSourceMappingNameEnd(); + this.recordSourceMappingEnd(classDecl); + } + + this.emitClassMembers(classDecl); + + this.emitIndent(); + this.writeToOutputWithSourceMapRecord("return " + className + ";", classDecl.closeBraceToken); + this.writeLineToOutput(""); + this.indenter.decreaseIndent(); + this.emitIndent(); + this.writeToken(classDecl.closeBraceToken); + this.recordSourceMappingNameEnd(); + this.recordSourceMappingStart(classDecl); + this.writeToOutput(")("); + if (hasBaseClass) { + this.emitJavascript(baseTypeReference, /*startLine:*/ false); + } + this.writeToOutput(");"); + this.recordSourceMappingEnd(classDecl); + + if ((temp === EmitContainer.Module || temp === EmitContainer.DynamicModule) && hasFlag(pullDecl.flags, PullElementFlags.Exported)) { + this.writeLineToOutput(""); + this.emitIndent(); + var modName = temp === EmitContainer.Module ? this.moduleName : "exports"; + this.writeToOutputWithSourceMapRecord(modName + "." + className + " = " + className + ";", classDecl); + } + + this.recordSourceMappingEnd(classDecl); + this.emitComments(classDecl, false); + this.setContainer(temp); + this.thisClassNode = svClassNode; + + this.popDecl(pullDecl); + } + + private emitClassMembers(classDecl: ClassDeclarationSyntax): void { + // First, emit all the functions. + var lastEmittedMember: ISyntaxElement = null; + + for (var i = 0, n = classDecl.classElements.length; i < n; i++) { + var memberDecl = classDecl.classElements[i]; + + if (memberDecl.kind() === SyntaxKind.GetAccessor) { + this.emitSpaceBetweenConstructs(lastEmittedMember, memberDecl); + var getter = memberDecl; + this.emitAccessorMemberDeclaration(getter, getter.propertyName, classDecl.identifier.text(), + !hasModifier(getter.modifiers, PullElementFlags.Static)); + lastEmittedMember = memberDecl; + } + else if (memberDecl.kind() === SyntaxKind.SetAccessor) { + this.emitSpaceBetweenConstructs(lastEmittedMember, memberDecl); + var setter = memberDecl; + this.emitAccessorMemberDeclaration(setter, setter.propertyName, classDecl.identifier.text(), + !hasModifier(setter.modifiers, PullElementFlags.Static)); + lastEmittedMember = memberDecl; + } + else if (memberDecl.kind() === SyntaxKind.MemberFunctionDeclaration) { + + var memberFunction = memberDecl; + + if (memberFunction.block) { + this.emitSpaceBetweenConstructs(lastEmittedMember, memberDecl); + + this.emitClassMemberFunctionDeclaration(classDecl, memberFunction); + lastEmittedMember = memberDecl; + } + } + } + + // Now emit all the statics. + for (var i = 0, n = classDecl.classElements.length; i < n; i++) { + var memberDecl = classDecl.classElements[i]; + + if (memberDecl.kind() === SyntaxKind.MemberVariableDeclaration) { + var varDecl = memberDecl; + + if (hasModifier(varDecl.modifiers, PullElementFlags.Static) && varDecl.variableDeclarator.equalsValueClause) { + this.emitSpaceBetweenConstructs(lastEmittedMember, varDecl); + + this.emitIndent(); + this.recordSourceMappingStart(varDecl); + + this.emitComments(varDecl, true); + var varDeclName = varDecl.variableDeclarator.propertyName.text(); + if (isQuoted(varDeclName) || varDecl.variableDeclarator.propertyName.kind() !== SyntaxKind.IdentifierName) { + this.writeToOutput(classDecl.identifier.text() + "[" + varDeclName + "]"); + } + else { + this.writeToOutput(classDecl.identifier.text() + "." + varDeclName); + } + + this.emit(varDecl.variableDeclarator.equalsValueClause); + + this.recordSourceMappingEnd(varDecl); + this.writeLineToOutput(";"); + + lastEmittedMember = varDecl; + } + } + } + } + + private emitClassMemberFunctionDeclaration(classDecl: ClassDeclarationSyntax, funcDecl: MemberFunctionDeclarationSyntax): void { + this.emitIndent(); + this.recordSourceMappingStart(funcDecl); + this.emitComments(funcDecl, true); + var functionName = funcDecl.propertyName.text(); + + this.writeToOutput(classDecl.identifier.text()); + + if (!hasModifier(funcDecl.modifiers, PullElementFlags.Static)) { + this.writeToOutput(".prototype"); + } + + if (isQuoted(functionName) || funcDecl.propertyName.kind() !== SyntaxKind.IdentifierName) { + this.writeToOutput("[" + functionName + "] = "); + } + else { + this.writeToOutput("." + functionName + " = "); + } + + var pullDecl = this.semanticInfoChain.getDeclForAST(funcDecl); + this.pushDecl(pullDecl); + + this.recordSourceMappingStart(funcDecl); + this.writeToOutput("function "); + + this.emitParameterList(funcDecl.callSignature.parameterList); + + var parameters = funcDecl.callSignature.parameterList.parameters; + this.emitFunctionBodyStatements(funcDecl.propertyName.text(), funcDecl, parameters, funcDecl.block, /*bodyExpression:*/ null); + + this.recordSourceMappingEnd(funcDecl); + + this.emitComments(funcDecl, false); + + this.recordSourceMappingEnd(funcDecl); + this.popDecl(pullDecl); + + this.writeLineToOutput(";"); + } + + private requiresExtendsBlock(moduleElements: IModuleElementSyntax[]): boolean { + for (var i = 0, n = moduleElements.length; i < n; i++) { + var moduleElement = moduleElements[i]; + + if (moduleElement.kind() === SyntaxKind.ModuleDeclaration) { + var moduleAST = moduleElement; + + if (!hasModifier(moduleAST.modifiers, PullElementFlags.Ambient) && this.requiresExtendsBlock(moduleAST.moduleElements)) { + return true; + } + } + else if (moduleElement.kind() === SyntaxKind.ClassDeclaration) { + var classDeclaration = moduleElement; + + if (!hasModifier(classDeclaration.modifiers, PullElementFlags.Ambient) && ASTHelpers.getExtendsHeritageClause(classDeclaration.heritageClauses) !== null) { + return true; + } + } + } + + return false; + } + + public emitPrologue(sourceUnit: SourceUnitSyntax) { + if (!this.extendsPrologueEmitted) { + if (this.requiresExtendsBlock(sourceUnit.moduleElements)) { + this.extendsPrologueEmitted = true; + this.writeLineToOutput("var __extends = this.__extends || function (d, b) {"); + this.writeLineToOutput(" for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];"); + this.writeLineToOutput(" function __() { this.constructor = d; }"); + this.writeLineToOutput(" __.prototype = b.prototype;"); + this.writeLineToOutput(" d.prototype = new __();"); + this.writeLineToOutput("};"); + } + } + + if (!this.globalThisCapturePrologueEmitted) { + if (this.shouldCaptureThis(sourceUnit)) { + this.globalThisCapturePrologueEmitted = true; + this.writeLineToOutput(this.captureThisStmtString); + } + } + } + + public emitThis() { + if (!this.inWithBlock && this.inArrowFunction) { + this.writeToOutput("_this"); + } + else { + this.writeToOutput("this"); + } + } + + public emitBlockOrStatement(node: ISyntaxElement): void { + if (node.kind() === SyntaxKind.Block) { + this.emit(node); + } + else { + this.writeLineToOutput(""); + this.indenter.increaseIndent(); + this.emitJavascript(node, true); + this.indenter.decreaseIndent(); + } + } + + public emitLiteralExpression(expression: ISyntaxToken): void { + switch (expression.kind()) { + case SyntaxKind.NullKeyword: + this.writeToken(expression); + break; + case SyntaxKind.FalseKeyword: + this.writeToken(expression); + break; + case SyntaxKind.TrueKeyword: + this.writeToken(expression); + break; + default: + throw Errors.abstract(); + } + } + + public emitThisExpression(expression: ISyntaxToken): void { + if (!this.inWithBlock && this.inArrowFunction) { + this.writeToOutputWithSourceMapRecord("_this", expression); + } + else { + this.writeToken(expression); + } + } + + public emitSuperExpression(expression: ISyntaxToken): void { + if (PullHelpers.isInStaticMemberContext(expression, this.semanticInfoChain)) { + this.writeToOutputWithSourceMapRecord("_super", expression); + } + else { + this.writeToOutputWithSourceMapRecord("_super.prototype", expression); + } + } + + private hasTrailingComment(token: ISyntaxToken) { + return token.hasTrailingTrivia() && token.trailingTrivia().hasComment(); + } + + public emitParenthesizedExpression(parenthesizedExpression: ParenthesizedExpressionSyntax): void { + var omitParentheses = false; + + if (parenthesizedExpression.expression.kind() === SyntaxKind.CastExpression && !this.hasTrailingComment(parenthesizedExpression.openParenToken)) { + var castedExpression = (parenthesizedExpression.expression).expression; + + // Make sure we consider all nested cast expressions, e.g.: + // (-A).x; + while (castedExpression.kind() == SyntaxKind.CastExpression) { + castedExpression = (castedExpression).expression; + } + + // We have an expression of the form: (SubExpr) + // Emitting this as (SubExpr) is really not desirable. Just emit the subexpr as is. + // We cannot generalize this rule however, as omitting the parentheses could cause change in the semantics of the generated + // code if the casted expression has a lower precedence than the rest of the expression, e.g.: + // (new A).foo should be emitted as (new A).foo and not new A.foo + // (typeof A).toString() should be emitted as (typeof A).toString() and not typeof A.toString() + // (function foo() { })() should be emitted as an IIF (function foo(){})() and not declaration function foo(){} () + // Parenthesis can be safelly removed from: + // Literals + // MemberAccessExpressions + // ElementAccessExpressions + // InvocationExpression, only if they are not part of an object creation (new) expression; e.g.: + // new (A()) removing the parentheses would result in calling A as a constructor, instead of calling the + // result of the function invocation A() as a constructor + switch (castedExpression.kind()) { + case SyntaxKind.ParenthesizedExpression: + case SyntaxKind.IdentifierName: + case SyntaxKind.NullKeyword: + case SyntaxKind.ThisKeyword: + case SyntaxKind.StringLiteral: + case SyntaxKind.NumericLiteral: + case SyntaxKind.RegularExpressionLiteral: + case SyntaxKind.TrueKeyword: + case SyntaxKind.FalseKeyword: + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.MemberAccessExpression: + case SyntaxKind.ElementAccessExpression: + omitParentheses = true; + break; + + case SyntaxKind.InvocationExpression: + if (parenthesizedExpression.parent.kind() !== SyntaxKind.ObjectCreationExpression) { + omitParentheses = true; + } + + break; + } + } + + if (omitParentheses) { + this.emit(parenthesizedExpression.expression); + } + else { + this.recordSourceMappingStart(parenthesizedExpression); + this.writeToken(parenthesizedExpression.openParenToken); + this.emitCommentsArray(ASTHelpers.convertTokenTrailingComments(parenthesizedExpression.openParenToken, this.text()), /*trailing:*/ false); + this.emit(parenthesizedExpression.expression); + this.writeToken(parenthesizedExpression.closeParenToken); + this.recordSourceMappingEnd(parenthesizedExpression); + } + } + + public emitCastExpression(expression: CastExpressionSyntax): void { + this.emit(expression.expression); + } + + public emitPrefixUnaryExpression(expression: PrefixUnaryExpressionSyntax): void { + var nodeType = expression.kind(); + + this.recordSourceMappingStart(expression); + switch (nodeType) { + case SyntaxKind.LogicalNotExpression: + this.writeToken(expression.operatorToken); + this.emit(expression.operand); + break; + case SyntaxKind.BitwiseNotExpression: + this.writeToken(expression.operatorToken); + this.emit(expression.operand); + break; + case SyntaxKind.NegateExpression: + this.writeToken(expression.operatorToken); + if (expression.operand.kind() === SyntaxKind.NegateExpression || expression.operand.kind() === SyntaxKind.PreDecrementExpression) { + this.writeToOutput(" "); + } + this.emit(expression.operand); + break; + case SyntaxKind.PlusExpression: + this.writeToken(expression.operatorToken); + if (expression.operand.kind() === SyntaxKind.PlusExpression || expression.operand.kind() === SyntaxKind.PreIncrementExpression) { + this.writeToOutput(" "); + } + this.emit(expression.operand); + break; + case SyntaxKind.PreIncrementExpression: + this.writeToOutputWithSourceMapRecord("++", expression.operatorToken); + this.emit(expression.operand); + break; + case SyntaxKind.PreDecrementExpression: + this.writeToOutputWithSourceMapRecord("--", expression.operatorToken); + this.emit(expression.operand); + break; + default: + throw Errors.abstract(); + } + + this.recordSourceMappingEnd(expression); + } + + public emitPostfixUnaryExpression(expression: PostfixUnaryExpressionSyntax): void { + var nodeType = expression.kind(); + + this.recordSourceMappingStart(expression); + switch (nodeType) { + case SyntaxKind.PostIncrementExpression: + this.emit(expression.operand); + this.writeToOutputWithSourceMapRecord("++", expression.operatorToken); + break; + case SyntaxKind.PostDecrementExpression: + this.emit(expression.operand); + this.writeToOutputWithSourceMapRecord("--", expression.operatorToken); + break; + default: + throw Errors.abstract(); + } + + this.recordSourceMappingEnd(expression); + } + + public emitTypeOfExpression(expression: TypeOfExpressionSyntax): void { + this.recordSourceMappingStart(expression); + this.writeToken(expression.typeOfKeyword); + this.writeToOutput(" "); + this.emit(expression.expression); + this.recordSourceMappingEnd(expression); + } + + public emitDeleteExpression(expression: DeleteExpressionSyntax): void { + this.recordSourceMappingStart(expression); + this.writeToken(expression.deleteKeyword); + this.writeToOutput(" "); + this.emit(expression.expression); + this.recordSourceMappingEnd(expression); + } + + public emitVoidExpression(expression: VoidExpressionSyntax): void { + this.recordSourceMappingStart(expression); + this.writeToken(expression.voidKeyword); + this.writeToOutput(" "); + this.emit(expression.expression); + this.recordSourceMappingEnd(expression); + } + + private canEmitDottedNameMemberAccessExpression(expression: MemberAccessExpressionSyntax) { + var memberExpressionNodeType = expression.expression.kind(); + + // If the memberAccess is of Name or another member access, we could potentially emit the symbol using the this memberAccessSymol + if (memberExpressionNodeType === SyntaxKind.IdentifierName || memberExpressionNodeType == SyntaxKind.MemberAccessExpression) { + var memberAccessSymbol = this.getSymbolForEmit(expression).symbol; + var memberAccessExpressionSymbol = this.getSymbolForEmit(expression.expression).symbol; + if (memberAccessSymbol && memberAccessExpressionSymbol // We have symbols resolved for this expression and access + && !this.semanticInfoChain.getAliasSymbolForAST(expression.expression) // The access is not off alias + && (PullHelpers.symbolIsModule(memberAccessExpressionSymbol) || memberAccessExpressionSymbol.kind === PullElementKind.Enum || + memberAccessExpressionSymbol.anyDeclHasFlag(PullElementFlags.InitializedModule | PullElementFlags.Enum))) { // container is module + + // If the memberAccess is in the context of the container, we could use the symbol to emit this expression + var memberAccessSymbolKind = memberAccessSymbol.kind; + if (memberAccessSymbolKind === PullElementKind.Property + || memberAccessSymbolKind === PullElementKind.EnumMember + || (memberAccessSymbol.anyDeclHasFlag(PullElementFlags.Exported) && memberAccessSymbolKind === PullElementKind.Variable && !memberAccessSymbol.anyDeclHasFlag(PullElementFlags.InitializedModule | PullElementFlags.Enum)) + || ((memberAccessSymbol.anyDeclHasFlag(PullElementFlags.Exported) && !this.symbolIsUsedInItsEnclosingContainer(memberAccessSymbol)))) { + + // If the expression is member access, we need to verify it as well + if (memberExpressionNodeType === SyntaxKind.MemberAccessExpression) { + return this.canEmitDottedNameMemberAccessExpression(expression.expression); + } + + return true; + } + } + } + + return false; + } + + // Emit the member access expression using the declPath + private emitDottedNameMemberAccessExpression(expression: MemberAccessExpressionSyntax) { + this.recordSourceMappingStart(expression); + if (expression.expression.kind() === SyntaxKind.MemberAccessExpression) { + // Emit the dotted name access expression + this.emitDottedNameMemberAccessExpressionRecurse(expression.expression); + } + else { // Name + this.emitName(expression.expression, /*addThis*/ true); + } + + this.writeToken(expression.dotToken); + this.emitName(expression.name, /*addThis*/ false); + + this.recordSourceMappingEnd(expression); + } + + // Set the right indices for the recursive member access expression before emitting it using the decl path + private emitDottedNameMemberAccessExpressionRecurse(expression: MemberAccessExpressionSyntax) { + this.emitComments(expression, true); + this.emitDottedNameMemberAccessExpression(expression); + this.emitComments(expression, false); + } + + public emitMemberAccessExpression(expression: MemberAccessExpressionSyntax): void { + if (!this.tryEmitConstant(expression)) { + // If the expression is dotted name of the modules, emit it using decl path so the name could be resolved correctly. + if (this.canEmitDottedNameMemberAccessExpression(expression)) { + this.emitDottedNameMemberAccessExpression(expression); + } + else { + this.recordSourceMappingStart(expression); + this.emit(expression.expression); + this.writeToken(expression.dotToken); + this.emitName(expression.name, false); + this.recordSourceMappingEnd(expression); + } + } + } + + public emitQualifiedName(name: QualifiedNameSyntax): void { + this.recordSourceMappingStart(name); + + this.emit(name.left); + this.writeToken(name.dotToken); + this.emitName(name.right, false); + + this.recordSourceMappingEnd(name); + } + + public emitBinaryExpression(expression: BinaryExpressionSyntax): void { + this.recordSourceMappingStart(expression); + switch (expression.kind()) { + case SyntaxKind.CommaExpression: + this.emit(expression.left); + this.writeToken(expression.operatorToken); + this.writeToOutput(" "); + this.emit(expression.right); + break; + default: + { + this.emit(expression.left); + var binOp = SyntaxFacts.getText(SyntaxFacts.getOperatorTokenFromBinaryExpression(expression.kind())); + this.writeToOutput(" "); + this.writeToOutputWithSourceMapRecord(binOp, expression.operatorToken); + this.writeToOutput(" "); + this.emit(expression.right); + } + } + this.recordSourceMappingEnd(expression); + } + + public emitSimplePropertyAssignment(property: SimplePropertyAssignmentSyntax): void { + this.recordSourceMappingStart(property); + this.emit(property.propertyName); + + this.writeToken(property.colonToken); + this.writeToOutput(" "); + this.emitCommentsArray(ASTHelpers.convertTokenTrailingComments(property.colonToken, this.text()), /*trailing:*/ true, /*noLeadingSpace:*/ true); + + this.emit(property.expression); + this.recordSourceMappingEnd(property); + } + + public emitFunctionPropertyAssignment(funcProp: FunctionPropertyAssignmentSyntax): void { + this.recordSourceMappingStart(funcProp); + + this.emit(funcProp.propertyName); + this.writeToOutput(": "); + + var pullFunctionDecl = this.semanticInfoChain.getDeclForAST(funcProp); + + var savedInArrowFunction = this.inArrowFunction; + this.inArrowFunction = false; + + var temp = this.setContainer(EmitContainer.Function); + var funcName = funcProp.propertyName; + + var pullDecl = this.semanticInfoChain.getDeclForAST(funcProp); + this.pushDecl(pullDecl); + + this.recordSourceMappingStart(funcProp); + this.writeToOutput("function "); + + //this.recordSourceMappingStart(funcProp.propertyName); + //this.writeToOutput(funcProp.propertyName.actualText); + //this.recordSourceMappingEnd(funcProp.propertyName); + + this.emitParameterList(funcProp.callSignature.parameterList); + + this.emitFunctionBodyStatements(funcProp.propertyName.text(), funcProp, + funcProp.callSignature.parameterList.parameters, funcProp.block, /*bodyExpression:*/ null); + + this.recordSourceMappingEnd(funcProp); + + // The extra call is to make sure the caller's funcDecl end is recorded, since caller wont be able to record it + this.recordSourceMappingEnd(funcProp); + + this.emitComments(funcProp, false); + + this.popDecl(pullDecl); + + this.setContainer(temp); + this.inArrowFunction = savedInArrowFunction; + } + + public emitConditionalExpression(expression: ConditionalExpressionSyntax): void { + this.emit(expression.condition); + this.writeToOutput(" "); + this.writeToken(expression.questionToken); + this.writeToOutput(" "); + this.emit(expression.whenTrue); + this.writeToOutput(" "); + this.writeToken(expression.colonToken); + this.writeToOutput(" "); + this.emit(expression.whenFalse); + } + + public emitThrowStatement(statement: ThrowStatementSyntax): void { + this.recordSourceMappingStart(statement); + this.writeToken(statement.throwKeyword); + this.writeToOutput(" "); + this.emit(statement.expression); + this.writeToOutputWithSourceMapRecord(";", statement.semicolonToken); + this.recordSourceMappingEnd(statement); + } + + public emitExpressionStatement(statement: ExpressionStatementSyntax): void { + var isArrowExpression = statement.expression.kind() === SyntaxKind.SimpleArrowFunctionExpression || statement.expression.kind() === SyntaxKind.ParenthesizedArrowFunctionExpression; + + this.recordSourceMappingStart(statement); + if (isArrowExpression) { + this.writeToOutput("("); + } + + this.emit(statement.expression); + + if (isArrowExpression) { + this.writeToOutput(")"); + } + + this.writeToOutputWithSourceMapRecord(";", statement.semicolonToken); + this.recordSourceMappingEnd(statement); + } + + public emitLabeledStatement(statement: LabeledStatementSyntax): void { + this.writeToOutputWithSourceMapRecord(statement.identifier.text(), statement.identifier); + this.writeToken(statement.colonToken); + this.writeLineToOutput(""); + this.emitJavascript(statement.statement, /*startLine:*/ true); + } + + public emitBlock(block: BlockSyntax): void { + this.recordSourceMappingStart(block); + this.writeLineToOutput(" {"); + this.indenter.increaseIndent(); + if (block.statements) { + this.emitList(block.statements); + } + this.emitCommentsArray(ASTHelpers.convertTokenLeadingComments(block.closeBraceToken, this.text()), /*trailing:*/ false); + this.indenter.decreaseIndent(); + this.emitIndent(); + this.writeToken(block.closeBraceToken); + this.recordSourceMappingEnd(block); + } + + public emitBreakStatement(jump: BreakStatementSyntax): void { + this.recordSourceMappingStart(jump); + this.writeToken(jump.breakKeyword); + + if (jump.identifier) { + this.writeToOutput(" "); + this.writeToOutputWithSourceMapRecord(jump.identifier.text(), jump.identifier); + } + + this.writeToOutputWithSourceMapRecord(";", jump.semicolonToken); + this.recordSourceMappingEnd(jump); + } + + public emitContinueStatement(jump: ContinueStatementSyntax): void { + this.recordSourceMappingStart(jump); + this.writeToken(jump.continueKeyword); + + if (jump.identifier) { + this.writeToOutput(" "); + this.writeToOutputWithSourceMapRecord(jump.identifier.text(), jump.identifier); + } + + this.writeToOutputWithSourceMapRecord(";", jump.semicolonToken); + this.recordSourceMappingEnd(jump); + } + + public emitWhileStatement(statement: WhileStatementSyntax): void { + this.recordSourceMappingStart(statement); + this.writeToken(statement.whileKeyword); + this.writeToOutput(" "); + this.writeToken(statement.openParenToken); + this.emit(statement.condition); + this.writeToken(statement.closeParenToken); + this.emitBlockOrStatement(statement.statement); + this.recordSourceMappingEnd(statement); + } + + public emitDoStatement(statement: DoStatementSyntax): void { + this.recordSourceMappingStart(statement); + this.writeToken(statement.doKeyword); + this.emitBlockOrStatement(statement.statement); + this.writeToOutput(" "); + this.writeToken(statement.whileKeyword); + this.writeToken(statement.openParenToken); + this.emit(statement.condition); + this.writeToken(statement.closeParenToken); + this.writeToOutputWithSourceMapRecord(";", statement.semicolonToken); + this.recordSourceMappingEnd(statement); + } + + public emitIfStatement(statement: IfStatementSyntax): void { + this.recordSourceMappingStart(statement); + this.writeToken(statement.ifKeyword); + this.writeToOutput(" "); + this.writeToken(statement.openParenToken); + this.emit(statement.condition); + this.writeToken(statement.closeParenToken); + + this.emitBlockOrStatement(statement.statement); + + if (statement.elseClause) { + if (statement.statement.kind() !== SyntaxKind.Block) { + this.writeLineToOutput(""); + this.emitIndent(); + } + else { + this.writeToOutput(" "); + } + + this.emit(statement.elseClause); + } + this.recordSourceMappingEnd(statement); + } + + public emitElseClause(elseClause: ElseClauseSyntax): void { + this.writeToken(elseClause.elseKeyword); + if (elseClause.statement.kind() === SyntaxKind.IfStatement) { + this.writeToOutput(" "); + this.emit(elseClause.statement); + } + else { + this.emitBlockOrStatement(elseClause.statement); + } + } + + public emitReturnStatement(statement: ReturnStatementSyntax): void { + this.recordSourceMappingStart(statement); + this.writeToken(statement.returnKeyword); + if (statement.expression) { + this.writeToOutput(" "); + this.emit(statement.expression); + } + + this.writeToOutputWithSourceMapRecord(";", statement.semicolonToken); + this.recordSourceMappingEnd(statement); + } + + public emitForInStatement(statement: ForInStatementSyntax): void { + this.recordSourceMappingStart(statement); + this.writeToken(statement.forKeyword); + this.writeToOutput(" "); + this.writeToken(statement.openParenToken); + + if (statement.left) { + this.emit(statement.left); + } + else { + this.emit(statement.variableDeclaration); + } + this.writeToOutput(" "); + this.writeToken(statement.inKeyword); + this.writeToOutput(" "); + this.emit(statement.expression); + this.writeToken(statement.closeParenToken); + this.emitBlockOrStatement(statement.statement); + this.recordSourceMappingEnd(statement); + } + + public emitForStatement(statement: ForStatementSyntax): void { + this.recordSourceMappingStart(statement); + this.writeToken(statement.forKeyword); + this.writeToOutput(" "); + this.writeToken(statement.openParenToken); + + if (statement.variableDeclaration) { + this.emit(statement.variableDeclaration); + } + else if (statement.initializer) { + this.emit(statement.initializer); + } + + this.writeToken(statement.firstSemicolonToken); + this.writeToOutput(" "); + this.emitJavascript(statement.condition, false); + this.writeToken(statement.secondSemicolonToken); + if (statement.incrementor) { + this.writeToOutput(" "); + this.emitJavascript(statement.incrementor, false); + } + this.writeToken(statement.closeParenToken); + this.emitBlockOrStatement(statement.statement); + this.recordSourceMappingEnd(statement); + } + + public emitWithStatement(statement: WithStatementSyntax): void { + this.recordSourceMappingStart(statement); + this.writeToken(statement.withKeyword); + this.writeToOutput(" "); + this.writeToken(statement.openParenToken); + if (statement.condition) { + this.emit(statement.condition); + } + + this.writeToken(statement.closeParenToken); + var prevInWithBlock = this.inWithBlock; + this.inWithBlock = true; + this.emitBlockOrStatement(statement.statement); + this.inWithBlock = prevInWithBlock; + this.recordSourceMappingEnd(statement); + } + + public emitSwitchStatement(statement: SwitchStatementSyntax): void { + this.recordSourceMappingStart(statement); + this.writeToken(statement.switchKeyword); + this.writeToOutput(" "); + this.writeToken(statement.openParenToken); + this.emit(statement.expression); + this.writeToken(statement.closeParenToken); + this.writeLineToOutput(" {"); + this.indenter.increaseIndent(); + this.emitList(statement.switchClauses, /*useNewLineSeparator:*/ false); + this.indenter.decreaseIndent(); + this.emitIndent(); + this.writeToken(statement.closeBraceToken); + this.recordSourceMappingEnd(statement); + } + + public emitCaseSwitchClause(clause: CaseSwitchClauseSyntax): void { + this.recordSourceMappingStart(clause); + this.writeToken(clause.caseKeyword); + this.writeToOutput(" "); + this.emit(clause.expression); + this.writeToken(clause.colonToken); + + this.emitSwitchClauseBody(clause.colonToken, clause.statements); + this.recordSourceMappingEnd(clause); + } + + private emitSwitchClauseBody(colonToken: ISyntaxToken, body: IStatementSyntax[]): void { + var text = this.text(); + if (body.length === 1 && childAt(body, 0).kind() === SyntaxKind.Block) { + // The case statement was written with curly braces, so emit it with the appropriate formatting + this.emit(childAt(body, 0)); + this.writeLineToOutput(""); + } + else if (body.length === 1 && this.isOnSameLine(end(colonToken, text), start(body[0], text))) { + this.writeToOutput(" "); + this.emit(childAt(body, 0)); + this.writeLineToOutput(""); + } + else { + // No curly braces. Format in the expected way + this.writeLineToOutput(""); + this.indenter.increaseIndent(); + this.emit(body); + this.indenter.decreaseIndent(); + } + } + + public emitDefaultSwitchClause(clause: DefaultSwitchClauseSyntax): void { + this.recordSourceMappingStart(clause); + this.writeToken(clause.defaultKeyword); + this.writeToken(clause.colonToken); + + this.emitSwitchClauseBody(clause.colonToken, clause.statements); + this.recordSourceMappingEnd(clause); + } + + public emitTryStatement(statement: TryStatementSyntax): void { + this.recordSourceMappingStart(statement); + this.writeToken(statement.tryKeyword); + this.writeToOutput(" "); + this.emit(statement.block); + this.emitJavascript(statement.catchClause, false); + + if (statement.finallyClause) { + this.emit(statement.finallyClause); + } + this.recordSourceMappingEnd(statement); + } + + public emitCatchClause(clause: CatchClauseSyntax): void { + this.writeToOutput(" "); + this.recordSourceMappingStart(clause); + this.writeToken(clause.catchKeyword); + this.writeToOutput(" "); + this.writeToken(clause.openParenToken); + this.emit(clause.identifier); + this.writeToken(clause.closeParenToken); + this.emit(clause.block); + this.recordSourceMappingEnd(clause); + } + + public emitFinallyClause(clause: FinallyClauseSyntax): void { + this.writeToOutput(" "); + this.writeToken(clause.finallyKeyword); + this.emit(clause.block); + } + + public emitDebuggerStatement(statement: DebuggerStatementSyntax): void { + this.writeToken(statement.debuggerKeyword); + this.writeToOutputWithSourceMapRecord(";", statement.semicolonToken); + } + + public emitNumericLiteral(literal: ISyntaxToken): void { + this.writeToOutputWithSourceMapRecord(literal.text(), literal); + } + + public emitRegularExpressionLiteral(literal: ISyntaxToken): void { + this.writeToOutputWithSourceMapRecord(literal.text(), literal); + } + + public emitStringLiteral(literal: ISyntaxToken): void { + this.writeToOutputWithSourceMapRecord(literal.text(), literal); + } + + public emitEqualsValueClause(clause: EqualsValueClauseSyntax): void { + this.writeToOutput(" "); + this.writeToken(clause.equalsToken); + this.writeToOutput(" "); + this.emitCommentsArray(ASTHelpers.convertTokenTrailingComments(clause.equalsToken, this.text()), /*trailing:*/ true, /*noLeadingSpace:*/ true); + + this.emit(clause.value); + } + + private emitParameter(parameter: ParameterSyntax): void { + this.writeToOutputWithSourceMapRecord(parameter.identifier.text(), parameter); + } + + public emitConstructorDeclaration(declaration: ConstructorDeclarationSyntax): void { + if (declaration.block) { + this.emitConstructor(declaration); + } + else { + this.emitComments(declaration, /*pre:*/ true, /*onlyPinnedOrTripleSlashComments:*/ true); + } + } + + public shouldEmitFunctionDeclaration(declaration: FunctionDeclarationSyntax): boolean { + return ASTHelpers.preComments(declaration, this.text()) !== null || (!hasModifier(declaration.modifiers, PullElementFlags.Ambient) && declaration.block !== null); + } + + public emitFunctionDeclaration(declaration: FunctionDeclarationSyntax): void { + if (!hasModifier(declaration.modifiers, PullElementFlags.Ambient) && declaration.block !== null) { + this.emitFunction(declaration); + } + else { + this.emitComments(declaration, /*pre:*/ true, /*onlyPinnedOrTripleSlashComments:*/ true); + } + } + + private emitSourceUnit(sourceUnit: SourceUnitSyntax): void { + if (!this.document.isDeclareFile()) { + var pullDecl = this.semanticInfoChain.getDeclForAST(sourceUnit); + this.pushDecl(pullDecl); + this.emitScriptElements(sourceUnit); + this.popDecl(pullDecl); + + this.emitCommentsArray(ASTHelpers.convertTokenLeadingComments(sourceUnit.endOfFileToken, this.text()), /*trailing:*/ false); + } + } + + public shouldEmitEnumDeclaration(declaration: EnumDeclarationSyntax): boolean { + return ASTHelpers.preComments(declaration, this.text()) !== null || !ASTHelpers.enumIsElided(declaration); + } + + public emitEnumDeclaration(declaration: EnumDeclarationSyntax): void { + if (!ASTHelpers.enumIsElided(declaration)) { + this.emitComments(declaration, true); + this.emitEnum(declaration); + this.emitComments(declaration, false); + } + else { + this.emitComments(declaration, true, /*onlyPinnedOrTripleSlashComments:*/ true); + } + } + + public shouldEmitModuleDeclaration(declaration: ModuleDeclarationSyntax): boolean { + return ASTHelpers.preComments(declaration, this.text()) !== null || !ASTHelpers.moduleIsElided(declaration); + } + + private emitModuleDeclaration(declaration: ModuleDeclarationSyntax): void { + if (!ASTHelpers.moduleIsElided(declaration)) { + this.emitModuleDeclarationWorker(declaration); + } + else { + this.emitComments(declaration, true, /*onlyPinnedOrTripleSlashComments:*/ true); + } + } + + public shouldEmitClassDeclaration(declaration: ClassDeclarationSyntax): boolean { + return ASTHelpers.preComments(declaration, this.text()) !== null || !hasModifier(declaration.modifiers, PullElementFlags.Ambient); + } + + public emitClassDeclaration(declaration: ClassDeclarationSyntax): void { + if (!hasModifier(declaration.modifiers, PullElementFlags.Ambient)) { + this.emitClass(declaration); + } + else { + this.emitComments(declaration, /*pre:*/ true, /*onlyPinnedOrTripleSlashComments:*/ true); + } + } + + public shouldEmitInterfaceDeclaration(declaration: InterfaceDeclarationSyntax): boolean { + return ASTHelpers.preComments(declaration, this.text()) !== null; + } + + public emitInterfaceDeclaration(declaration: InterfaceDeclarationSyntax): void { + this.emitComments(declaration, /*pre:*/ true, /*onlyPinnedOrTripleSlashComments:*/ true); + } + + private firstVariableDeclarator(statement: VariableStatementSyntax): VariableDeclaratorSyntax { + return statement.variableDeclaration.variableDeclarators[0]; + } + + private isNotAmbientOrHasInitializer(variableStatement: VariableStatementSyntax): boolean { + return !hasModifier(variableStatement.modifiers, PullElementFlags.Ambient) || this.firstVariableDeclarator(variableStatement).equalsValueClause !== null; + } + + public shouldEmitVariableStatement(statement: VariableStatementSyntax): boolean { + return ASTHelpers.preComments(statement, this.text()) !== null || this.isNotAmbientOrHasInitializer(statement); + } + + public emitVariableStatement(statement: VariableStatementSyntax): void { + if (this.isNotAmbientOrHasInitializer(statement)) { + this.emitComments(statement, true); + this.emit(statement.variableDeclaration); + this.writeToOutputWithSourceMapRecord(";", statement.semicolonToken); + this.emitComments(statement, false); + } + else { + this.emitComments(statement, /*pre:*/ true, /*onlyPinnedOrTripleSlashComments:*/ true); + } + } + + public emitGenericType(type: GenericTypeSyntax): void { + this.emit(type.name); + } + + private shouldEmit(ast: ISyntaxElement): boolean { + if (!ast) { + return false; + } + + switch (ast.kind()) { + case SyntaxKind.ImportDeclaration: + return this.shouldEmitImportDeclaration(ast); + case SyntaxKind.ClassDeclaration: + return this.shouldEmitClassDeclaration(ast); + case SyntaxKind.InterfaceDeclaration: + return this.shouldEmitInterfaceDeclaration(ast); + case SyntaxKind.FunctionDeclaration: + return this.shouldEmitFunctionDeclaration(ast); + case SyntaxKind.ModuleDeclaration: + return this.shouldEmitModuleDeclaration(ast); + case SyntaxKind.VariableStatement: + return this.shouldEmitVariableStatement(ast); + case SyntaxKind.OmittedExpression: + return false; + case SyntaxKind.EnumDeclaration: + return this.shouldEmitEnumDeclaration(ast); + } + + return true; + } + + private emit(ast: ISyntaxElement): void { + if (!ast) { + return; + } + + switch (ast.kind()) { + case SyntaxKind.SeparatedList: + return this.emitSeparatedList(ast); + case SyntaxKind.List: + return this.emitList(ast); + case SyntaxKind.SourceUnit: + return this.emitSourceUnit(ast); + case SyntaxKind.ImportDeclaration: + return this.emitImportDeclaration(ast); + case SyntaxKind.ExportAssignment: + return this.setExportAssignment(ast); + case SyntaxKind.ClassDeclaration: + return this.emitClassDeclaration(ast); + case SyntaxKind.InterfaceDeclaration: + return this.emitInterfaceDeclaration(ast); + case SyntaxKind.IdentifierName: + return this.emitName(ast, true); + case SyntaxKind.VariableDeclarator: + return this.emitVariableDeclarator(ast); + case SyntaxKind.SimpleArrowFunctionExpression: + return this.emitSimpleArrowFunctionExpression(ast); + case SyntaxKind.ParenthesizedArrowFunctionExpression: + return this.emitParenthesizedArrowFunctionExpression(ast); + case SyntaxKind.FunctionDeclaration: + return this.emitFunctionDeclaration(ast); + case SyntaxKind.ModuleDeclaration: + return this.emitModuleDeclaration(ast); + case SyntaxKind.VariableDeclaration: + return this.emitVariableDeclaration(ast); + case SyntaxKind.GenericType: + return this.emitGenericType(ast); + case SyntaxKind.ConstructorDeclaration: + return this.emitConstructorDeclaration(ast); + case SyntaxKind.EnumDeclaration: + return this.emitEnumDeclaration(ast); + case SyntaxKind.EnumElement: + return this.emitEnumElement(ast); + case SyntaxKind.FunctionExpression: + return this.emitFunctionExpression(ast); + case SyntaxKind.VariableStatement: + return this.emitVariableStatement(ast); + } + + this.emitComments(ast, true); + this.emitWorker(ast); + this.emitComments(ast, false); + } + + private emitWorker(ast: ISyntaxElement): void { + if (!ast) { + return; + } + + switch (ast.kind()) { + case SyntaxKind.NumericLiteral: + return this.emitNumericLiteral(ast); + case SyntaxKind.RegularExpressionLiteral: + return this.emitRegularExpressionLiteral(ast); + case SyntaxKind.StringLiteral: + return this.emitStringLiteral(ast); + case SyntaxKind.FalseKeyword: + case SyntaxKind.NullKeyword: + case SyntaxKind.TrueKeyword: + return this.emitLiteralExpression(ast); + case SyntaxKind.ThisKeyword: + return this.emitThisExpression(ast); + case SyntaxKind.SuperKeyword: + return this.emitSuperExpression(ast); + case SyntaxKind.ParenthesizedExpression: + return this.emitParenthesizedExpression(ast); + case SyntaxKind.ArrayLiteralExpression: + return this.emitArrayLiteralExpression(ast); + case SyntaxKind.PostDecrementExpression: + case SyntaxKind.PostIncrementExpression: + return this.emitPostfixUnaryExpression(ast); + case SyntaxKind.LogicalNotExpression: + case SyntaxKind.BitwiseNotExpression: + case SyntaxKind.NegateExpression: + case SyntaxKind.PlusExpression: + case SyntaxKind.PreIncrementExpression: + case SyntaxKind.PreDecrementExpression: + return this.emitPrefixUnaryExpression(ast); + case SyntaxKind.InvocationExpression: + return this.emitInvocationExpression(ast); + case SyntaxKind.ElementAccessExpression: + return this.emitElementAccessExpression(ast); + case SyntaxKind.MemberAccessExpression: + return this.emitMemberAccessExpression(ast); + case SyntaxKind.QualifiedName: + return this.emitQualifiedName(ast); + case SyntaxKind.CommaExpression: + case SyntaxKind.AssignmentExpression: + case SyntaxKind.AddAssignmentExpression: + case SyntaxKind.SubtractAssignmentExpression: + case SyntaxKind.MultiplyAssignmentExpression: + case SyntaxKind.DivideAssignmentExpression: + case SyntaxKind.ModuloAssignmentExpression: + case SyntaxKind.AndAssignmentExpression: + case SyntaxKind.ExclusiveOrAssignmentExpression: + case SyntaxKind.OrAssignmentExpression: + case SyntaxKind.LeftShiftAssignmentExpression: + case SyntaxKind.SignedRightShiftAssignmentExpression: + case SyntaxKind.UnsignedRightShiftAssignmentExpression: + case SyntaxKind.LogicalOrExpression: + case SyntaxKind.LogicalAndExpression: + case SyntaxKind.BitwiseOrExpression: + case SyntaxKind.BitwiseExclusiveOrExpression: + case SyntaxKind.BitwiseAndExpression: + case SyntaxKind.EqualsWithTypeConversionExpression: + case SyntaxKind.NotEqualsWithTypeConversionExpression: + case SyntaxKind.EqualsExpression: + case SyntaxKind.NotEqualsExpression: + case SyntaxKind.LessThanExpression: + case SyntaxKind.GreaterThanExpression: + case SyntaxKind.LessThanOrEqualExpression: + case SyntaxKind.GreaterThanOrEqualExpression: + case SyntaxKind.InstanceOfExpression: + case SyntaxKind.InExpression: + case SyntaxKind.LeftShiftExpression: + case SyntaxKind.SignedRightShiftExpression: + case SyntaxKind.UnsignedRightShiftExpression: + case SyntaxKind.MultiplyExpression: + case SyntaxKind.DivideExpression: + case SyntaxKind.ModuloExpression: + case SyntaxKind.AddExpression: + case SyntaxKind.SubtractExpression: + return this.emitBinaryExpression(ast); + case SyntaxKind.ConditionalExpression: + return this.emitConditionalExpression(ast); + case SyntaxKind.EqualsValueClause: + return this.emitEqualsValueClause(ast); + case SyntaxKind.Parameter: + return this.emitParameter(ast); + case SyntaxKind.Block: + return this.emitBlock(ast); + case SyntaxKind.ElseClause: + return this.emitElseClause(ast); + case SyntaxKind.IfStatement: + return this.emitIfStatement(ast); + case SyntaxKind.ExpressionStatement: + return this.emitExpressionStatement(ast); + case SyntaxKind.GetAccessor: + return this.emitGetAccessor(ast); + case SyntaxKind.SetAccessor: + return this.emitSetAccessor(ast); + case SyntaxKind.ThrowStatement: + return this.emitThrowStatement(ast); + case SyntaxKind.ReturnStatement: + return this.emitReturnStatement(ast); + case SyntaxKind.ObjectCreationExpression: + return this.emitObjectCreationExpression(ast); + case SyntaxKind.SwitchStatement: + return this.emitSwitchStatement(ast); + case SyntaxKind.CaseSwitchClause: + return this.emitCaseSwitchClause(ast); + case SyntaxKind.DefaultSwitchClause: + return this.emitDefaultSwitchClause(ast); + case SyntaxKind.BreakStatement: + return this.emitBreakStatement(ast); + case SyntaxKind.ContinueStatement: + return this.emitContinueStatement(ast); + case SyntaxKind.ForStatement: + return this.emitForStatement(ast); + case SyntaxKind.ForInStatement: + return this.emitForInStatement(ast); + case SyntaxKind.WhileStatement: + return this.emitWhileStatement(ast); + case SyntaxKind.WithStatement: + return this.emitWithStatement(ast); + case SyntaxKind.CastExpression: + return this.emitCastExpression(ast); + case SyntaxKind.ObjectLiteralExpression: + return this.emitObjectLiteralExpression(ast); + case SyntaxKind.SimplePropertyAssignment: + return this.emitSimplePropertyAssignment(ast); + case SyntaxKind.FunctionPropertyAssignment: + return this.emitFunctionPropertyAssignment(ast); + case SyntaxKind.EmptyStatement: + return this.writeToken((ast).semicolonToken); + case SyntaxKind.TryStatement: + return this.emitTryStatement(ast); + case SyntaxKind.CatchClause: + return this.emitCatchClause(ast); + case SyntaxKind.FinallyClause: + return this.emitFinallyClause(ast); + case SyntaxKind.LabeledStatement: + return this.emitLabeledStatement(ast); + case SyntaxKind.DoStatement: + return this.emitDoStatement(ast); + case SyntaxKind.TypeOfExpression: + return this.emitTypeOfExpression(ast); + case SyntaxKind.DeleteExpression: + return this.emitDeleteExpression(ast); + case SyntaxKind.VoidExpression: + return this.emitVoidExpression(ast); + case SyntaxKind.DebuggerStatement: + return this.emitDebuggerStatement(ast); + } + } + } + + export function getLastConstructor(classDecl: ClassDeclarationSyntax): ConstructorDeclarationSyntax { + for (var i = classDecl.classElements.length - 1; i >= 0; i--) { + var child = classDecl.classElements[i]; + + if (child.kind() === SyntaxKind.ConstructorDeclaration) { + return child; + } + } + + return null; + } + + export function getTrimmedTextLines(comment: Comment): string[] { + if (comment.kind() === SyntaxKind.MultiLineCommentTrivia) { + return comment.fullText().split("\n").map(s => s.trim()); + } + else { + return [comment.fullText().trim()]; + } + } +} \ No newline at end of file diff --git a/src/services/compiler/enumerator.ts b/src/services/compiler/enumerator.ts new file mode 100644 index 00000000000..eb9559b02fa --- /dev/null +++ b/src/services/compiler/enumerator.ts @@ -0,0 +1,6 @@ +declare class Enumerator { + public atEnd(): boolean; + public moveNext(): boolean; + public item(): any; + constructor (o: any); +} \ No newline at end of file diff --git a/src/services/compiler/flags.ts b/src/services/compiler/flags.ts new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/services/compiler/hashTable.ts b/src/services/compiler/hashTable.ts new file mode 100644 index 00000000000..e1bae0cd8df --- /dev/null +++ b/src/services/compiler/hashTable.ts @@ -0,0 +1,187 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript { + var proto = "__proto__" + + class BlockIntrinsics { + public prototype: T = undefined; + public toString: T = undefined; + public toLocaleString: T = undefined; + public valueOf: T = undefined; + public hasOwnProperty: T = undefined; + public propertyIsEnumerable: T = undefined; + public isPrototypeOf: T = undefined; + [s: string]: T; + + constructor() { + // initialize the 'constructor' field + this["constructor"] = undefined; + + // First we set it to null, because that's the only way to erase the value in node. Then we set it to undefined in case we are not in node, since + // in StringHashTable below, we check for undefined explicitly. + this[proto] = null; + this[proto] = undefined; + } + } + + export function createIntrinsicsObject(): IIndexable { + return new BlockIntrinsics(); + } + + export interface IHashTable { + getAllKeys(): string[]; + add(key: string, data: T): boolean; + addOrUpdate(key: string, data: T): boolean; + map(fn: (k: string, value: T, context: any) => void , context: any): void; + every(fn: (k: string, value: T, context: any) => void , context: any): boolean; + some(fn: (k: string, value: T, context: any) => void , context: any): boolean; + count(): number; + lookup(key: string): T; + } + + export class StringHashTable implements IHashTable { + private itemCount = 0; + private table: IIndexable = createIntrinsicsObject(); + + public getAllKeys(): string[] { + var result: string[] = []; + + for (var k in this.table) { + if (this.table[k] !== undefined) { + result.push(k); + } + } + + return result; + } + + public add(key: string, data: T): boolean { + if (this.table[key] !== undefined) { + return false; + } + + this.table[key] = data; + this.itemCount++; + return true; + } + + public addOrUpdate(key: string, data: T): boolean { + if (this.table[key] !== undefined) { + this.table[key] = data; + return false; + } + + this.table[key] = data; + this.itemCount++; + return true; + } + + public map(fn: (k: string, value: T, context: any) => void , context: any) { + for (var k in this.table) { + var data = this.table[k]; + + if (data !== undefined) { + fn(k, this.table[k], context); + } + } + } + + public every(fn: (k: string, value: T, context: any) => void , context: any) { + for (var k in this.table) { + var data = this.table[k]; + + if (data !== undefined) { + if (!fn(k, this.table[k], context)) { + return false; + } + } + } + + return true; + } + + public some(fn: (k: string, value: T, context: any) => void , context: any) { + for (var k in this.table) { + var data = this.table[k]; + + if (data !== undefined) { + if (fn(k, this.table[k], context)) { + return true; + } + } + } + + return false; + } + + public count(): number { + return this.itemCount; + } + + public lookup(key: string) : T { + var data = this.table[key]; + return data === undefined ? null : data; + } + + public remove(key: string): void { + if (this.table[key] !== undefined) { + this.table[key] = undefined; + this.itemCount--; + } + } + } + + + export class IdentiferNameHashTable extends StringHashTable { + public getAllKeys(): string[]{ + var result: string[] = []; + + super.map((k, v, c) => { + if (v !== undefined) { + result.push(k.substring(1)); + } + }, null); + + return result; + } + + public add(key: string, data: T): boolean { + return super.add("#" + key, data); + } + + public addOrUpdate(key: string, data: T): boolean { + return super.addOrUpdate("#" + key, data); + } + + public map(fn: (k: string, value: T, context: any) => void , context: any) { + return super.map((k, v, c) => fn(k.substring(1), v, c), context); + } + + public every(fn: (k: string, value: T, context: any) => void , context: any) { + return super.every((k, v, c) => fn(k.substring(1), v, c), context); + } + + public some(fn: (k: string, value: any, context: any) => void , context: any) { + return super.some((k, v, c) => fn(k.substring(1), v, c), context); + } + + public lookup(key: string): T { + return super.lookup("#" + key); + } + } +} \ No newline at end of file diff --git a/src/services/compiler/identifierWalker.ts b/src/services/compiler/identifierWalker.ts new file mode 100644 index 00000000000..4af0893db6c --- /dev/null +++ b/src/services/compiler/identifierWalker.ts @@ -0,0 +1,11 @@ +module TypeScript { + export class IdentifierWalker extends SyntaxWalker { + constructor(public list: IIndexable) { + super(); + } + + public visitToken(token: ISyntaxToken): void { + this.list[token.text()] = true; + } + } +} \ No newline at end of file diff --git a/src/services/compiler/io.ts b/src/services/compiler/io.ts new file mode 100644 index 00000000000..952187809b0 --- /dev/null +++ b/src/services/compiler/io.ts @@ -0,0 +1,64 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// +/// +/// + +module TypeScript { + + export interface IFindFileResult { + fileInformation: FileInformation; + path: string; + } + + export module IOUtils { + // Creates the directory including its parent if not already present + function createDirectoryStructure(ioHost: IEnvironment, dirName: string) { + if (ioHost.directoryExists(dirName)) { + return; + } + + var parentDirectory = ioHost.directoryName(dirName); + if (parentDirectory != "") { + createDirectoryStructure(ioHost, parentDirectory); + } + ioHost.createDirectory(dirName); + } + + // Creates a file including its directory structure if not already present + export function writeFileAndFolderStructure(ioHost: IEnvironment, fileName: string, contents: string, writeByteOrderMark: boolean): void { + var start = new Date().getTime(); + var path = ioHost.absolutePath(fileName); + TypeScript.ioHostResolvePathTime += new Date().getTime() - start; + + var start = new Date().getTime(); + var dirName = ioHost.directoryName(path); + TypeScript.ioHostDirectoryNameTime += new Date().getTime() - start; + + var start = new Date().getTime(); + createDirectoryStructure(ioHost, dirName); + TypeScript.ioHostCreateDirectoryStructureTime += new Date().getTime() - start; + + var start = new Date().getTime(); + ioHost.writeFile(path, contents, writeByteOrderMark); + TypeScript.ioHostWriteFileTime += new Date().getTime() - start; + } + + export function combine(prefix: string, suffix: string): string { + return prefix + "/" + suffix; + } + } +} \ No newline at end of file diff --git a/src/services/compiler/optionsParser.ts b/src/services/compiler/optionsParser.ts new file mode 100644 index 00000000000..10d9ddac84e --- /dev/null +++ b/src/services/compiler/optionsParser.ts @@ -0,0 +1,266 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript { + export interface IOptions { + name?: string; + flag?: boolean; + short?: string; + usage?: { + locCode: string; // DiagnosticCode + args: string[] + }; + set?: (s: string) => void; + type?: string; // DiagnosticCode + experimental?: boolean; + } + + export class OptionsParser { + private DEFAULT_SHORT_FLAG = "-"; + private DEFAULT_LONG_FLAG = "--"; + + private printedVersion: boolean = false; + + // Find the option record for the given string. Returns null if not found. + private findOption(arg: string) { + var upperCaseArg = arg && arg.toUpperCase(); + + for (var i = 0; i < this.options.length; i++) { + var current = this.options[i]; + + if (upperCaseArg === (current.short && current.short.toUpperCase()) || + upperCaseArg === (current.name && current.name.toUpperCase())) { + return current; + } + } + + return null; + } + + public unnamed: string[] = []; + + public options: IOptions[] = []; + + constructor(public host: IEnvironment, public version: string) { + } + + public printUsage() { + this.printVersion(); + + var optionsWord = getLocalizedText(DiagnosticCode.options, null); + var fileWord = getLocalizedText(DiagnosticCode.file1, null); + var tscSyntax = "tsc [" + optionsWord + "] [" + fileWord + " ..]"; + var syntaxHelp = getLocalizedText(DiagnosticCode.Syntax_0, [tscSyntax]); + this.host.standardOut.WriteLine(syntaxHelp); + this.host.standardOut.WriteLine(""); + this.host.standardOut.WriteLine(getLocalizedText(DiagnosticCode.Examples, null) + " tsc hello.ts"); + this.host.standardOut.WriteLine(" tsc --out foo.js foo.ts"); + this.host.standardOut.WriteLine(" tsc @args.txt"); + this.host.standardOut.WriteLine(""); + this.host.standardOut.WriteLine(getLocalizedText(DiagnosticCode.Options, null)); + + var output: string[][] = []; + var maxLength = 0; + var i = 0; + + this.options = this.options.sort(function (a, b) { + var aName = a.name.toLowerCase(); + var bName = b.name.toLowerCase(); + + if (aName > bName) { + return 1; + } else if (aName < bName) { + return -1; + } else { + return 0; + } + }); + + // Build up output array + for (i = 0; i < this.options.length; i++) { + var option = this.options[i]; + + if (option.experimental) { + continue; + } + + if (!option.usage) { + break; + } + + var usageString = " "; + var type = option.type ? (" " + TypeScript.getLocalizedText(option.type, null)) : ""; + + if (option.short) { + usageString += this.DEFAULT_SHORT_FLAG + option.short + type + ", "; + } + + usageString += this.DEFAULT_LONG_FLAG + option.name + type; + + output.push([usageString, TypeScript.getLocalizedText(option.usage.locCode, option.usage.args)]); + + if (usageString.length > maxLength) { + maxLength = usageString.length; + } + } + + var fileDescription = getLocalizedText(DiagnosticCode.Insert_command_line_options_and_files_from_a_file, null); + output.push([" @<" + fileWord + ">", fileDescription]); + + // Print padded output + for (i = 0; i < output.length; i++) { + this.host.standardOut.WriteLine(output[i][0] + (new Array(maxLength - output[i][0].length + 3)).join(" ") + output[i][1]); + } + } + + public printVersion() { + if (!this.printedVersion) { + this.host.standardOut.WriteLine(getLocalizedText(DiagnosticCode.Version_0, [this.version])); + this.printedVersion = true; + } + } + + public option(name: string, config: IOptions, short?: string) { + if (!config) { + config = short; + short = null; + } + + config.name = name; + config.short = short; + config.flag = false; + + this.options.push(config); + } + + public flag(name: string, config: IOptions, short?: string) { + if (!config) { + config = short; + short = null; + } + + config.name = name; + config.short = short; + config.flag = true + + this.options.push(config); + } + + // Parse an arguments string + public parseString(argString: string) { + var position = 0; + var tokens = argString.match(/\s+|"|[^\s"]+/g); + + function peek() { + return tokens[position]; + } + + function consume() { + return tokens[position++]; + } + + function consumeQuotedString() { + var value = ''; + consume(); // skip opening quote. + + var token = peek(); + + while (token && token !== '"') { + consume(); + + value += token; + + token = peek(); + } + + consume(); // skip ending quote; + + return value; + } + + var args: string[] = []; + var currentArg = ''; + + while (position < tokens.length) { + var token = peek(); + + if (token === '"') { + currentArg += consumeQuotedString(); + } else if (token.match(/\s/)) { + if (currentArg.length > 0) { + args.push(currentArg); + currentArg = ''; + } + + consume(); + } else { + consume(); + currentArg += token; + } + } + + if (currentArg.length > 0) { + args.push(currentArg); + } + + this.parse(args); + } + + // Parse arguments as they come from the platform: split into arguments. + public parse(args: string[]) { + var position = 0; + + function consume() { + return args[position++]; + } + + while (position < args.length) { + var current = consume(); + var match = current.match(/^(--?|@)(.*)/); + var value: any = null; + + if (match) { + if (match[1] === '@') { + this.parseString(this.host.readFile(match[2], null).contents); + } else { + var arg = match[2]; + var option = this.findOption(arg); + + if (option === null) { + this.host.standardOut.WriteLine(getDiagnosticMessage(DiagnosticCode.Unknown_compiler_option_0, [arg])); + this.host.standardOut.WriteLine(getLocalizedText(DiagnosticCode.Use_the_0_flag_to_see_options, ["--help"])); + } else { + if (!option.flag) { + value = consume(); + if (value === undefined) { + // No value provided + this.host.standardOut.WriteLine(getDiagnosticMessage(DiagnosticCode.Option_0_specified_without_1, [arg, getLocalizedText(option.type, null)])); + this.host.standardOut.WriteLine(getLocalizedText(DiagnosticCode.Use_the_0_flag_to_see_options, ["--help"])); + continue; + } + } + + option.set(value); + } + } + } else { + this.unnamed.push(current); + } + } + } + } +} \ No newline at end of file diff --git a/src/services/compiler/pathUtils.ts b/src/services/compiler/pathUtils.ts new file mode 100644 index 00000000000..3868881fc75 --- /dev/null +++ b/src/services/compiler/pathUtils.ts @@ -0,0 +1,193 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript { + export function stripStartAndEndQuotes(str: string) { + var firstCharCode = str && str.charCodeAt(0); + if (str && str.length >= 2 && firstCharCode === str.charCodeAt(str.length - 1) && (firstCharCode === CharacterCodes.singleQuote || firstCharCode === CharacterCodes.doubleQuote)) { + return str.substring(1, str.length - 1); + } + + return str; + } + + export function isSingleQuoted(str: string) { + return str && str.length >= 2 && str.charCodeAt(0) === str.charCodeAt(str.length - 1) && str.charCodeAt(0) === CharacterCodes.singleQuote; + } + + export function isDoubleQuoted(str: string) { + return str && str.length >= 2 && str.charCodeAt(0) === str.charCodeAt(str.length - 1) && str.charCodeAt(0) === CharacterCodes.doubleQuote; + } + + export function isQuoted(str: string) { + return isDoubleQuoted(str) || isSingleQuoted(str); + } + + export function quoteStr(str: string) { + return "\"" + str + "\""; + } + + var switchToForwardSlashesRegEx = /\\/g; + export function switchToForwardSlashes(path: string) { + return path.replace(switchToForwardSlashesRegEx, "/"); + } + + export function trimModName(modName: string) { + // in case's it's a declare file... + if (modName.length > 5 && modName.substring(modName.length - 5, modName.length) === ".d.ts") { + return modName.substring(0, modName.length - 5); + } + if (modName.length > 3 && modName.substring(modName.length - 3, modName.length) === ".ts") { + return modName.substring(0, modName.length - 3); + } + // in case's it's a .js file + if (modName.length > 3 && modName.substring(modName.length - 3, modName.length) === ".js") { + return modName.substring(0, modName.length - 3); + } + + return modName; + } + + export function getDeclareFilePath(fname: string) { + return isTSFile(fname) ? changePathToDTS(fname) : changePathToDTS(fname); + } + + function isFileOfExtension(fname: string, ext: string) { + var invariantFname = fname.toLocaleUpperCase(); + var invariantExt = ext.toLocaleUpperCase(); + var extLength = invariantExt.length; + return invariantFname.length > extLength && invariantFname.substring(invariantFname.length - extLength, invariantFname.length) === invariantExt; + } + + export function isTSFile(fname: string) { + return isFileOfExtension(fname, ".ts"); + } + + export function isDTSFile(fname: string) { + return isFileOfExtension(fname, ".d.ts"); + } + + export function getPrettyName(modPath: string, quote=true, treatAsFileName=false): any { + var modName = treatAsFileName ? switchToForwardSlashes(modPath) : trimModName(stripStartAndEndQuotes(modPath)); + var components = this.getPathComponents(modName); + return components.length ? (quote ? quoteStr(components[components.length - 1]) : components[components.length - 1]) : modPath; + } + + export function getPathComponents(path: string) { + return path.split("/"); + } + + export function getRelativePathToFixedPath(fixedModFilePath: string, absoluteModPath: string, isAbsoultePathURL = true) { + absoluteModPath = switchToForwardSlashes(absoluteModPath); + + var modComponents = this.getPathComponents(absoluteModPath); + var fixedModComponents = this.getPathComponents(fixedModFilePath); + + // Find the component that differs + var joinStartIndex = 0; + for (; joinStartIndex < modComponents.length && joinStartIndex < fixedModComponents.length ; joinStartIndex++) { + if (fixedModComponents[joinStartIndex] !== modComponents[joinStartIndex]) { + break; + } + } + + // Get the relative path + if (joinStartIndex !== 0) { + var relativePath = ""; + var relativePathComponents = modComponents.slice(joinStartIndex, modComponents.length); + for (; joinStartIndex < fixedModComponents.length; joinStartIndex++) { + if (fixedModComponents[joinStartIndex] !== "") { + relativePath = relativePath + "../"; + } + } + + return relativePath + relativePathComponents.join("/"); + } + + if (isAbsoultePathURL && absoluteModPath.indexOf("://") === -1) { + absoluteModPath = "file:///" + absoluteModPath; + } + + return absoluteModPath; + } + + export function changePathToDTS(modPath: string) { + return trimModName(stripStartAndEndQuotes(modPath)) + ".d.ts"; + } + + export function isRelative(path: string) { + return path.length > 0 && path.charAt(0) === "."; + } + export function isRooted(path: string) { + return path.length > 0 && (path.charAt(0) === "\\" || path.charAt(0) === "/" || (path.indexOf(":\\") !== -1) || (path.indexOf(":/") !== -1)); + } + + export function getRootFilePath(outFname: string) { + if (outFname === "") { + return outFname; + } + else { + var isPath = outFname.indexOf("/") !== -1; + return isPath ? filePath(outFname) : ""; + } + } + + export function filePathComponents(fullPath: string) { + fullPath = switchToForwardSlashes(fullPath); + var components = getPathComponents(fullPath); + return components.slice(0, components.length - 1); + } + + export function filePath(fullPath: string) { + var path = filePathComponents(fullPath); + return path.join("/") + "/"; + } + + export function convertToDirectoryPath(dirPath: string) { + if (dirPath && dirPath.charAt(dirPath.length - 1) !== "/") { + dirPath += "/"; + } + + return dirPath; + } + + var normalizePathRegEx = /^\\\\[^\\]/; + export function normalizePath(path: string): string { + // If it's a UNC style path (i.e. \\server\share), convert to a URI style (i.e. file://server/share) + if (normalizePathRegEx.test(path)) { + path = "file:" + path; + } + var parts = this.getPathComponents(switchToForwardSlashes(path)); + var normalizedParts: string[] = []; + + for (var i = 0; i < parts.length; i++) { + var part = parts[i]; + if (part === ".") { + continue; + } + + if (normalizedParts.length > 0 && ArrayUtilities.last(normalizedParts) !== ".." && part === "..") { + normalizedParts.pop(); + continue; + } + + normalizedParts.push(part); + } + + return normalizedParts.join("/"); + } +} \ No newline at end of file diff --git a/src/services/compiler/precompile.ts b/src/services/compiler/precompile.ts new file mode 100644 index 00000000000..61ba930a055 --- /dev/null +++ b/src/services/compiler/precompile.ts @@ -0,0 +1,196 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript { + /// + /// Preprocessing + /// + export interface IPreProcessedFileInfo { + referencedFiles: IFileReference[]; + importedFiles: IFileReference[]; + diagnostics: Diagnostic[]; + isLibFile: boolean; + } + + interface ITripleSlashDirectiveProperties { + noDefaultLib: boolean; + diagnostics: Diagnostic[]; + referencedFiles: IFileReference[]; + } + + function isNoDefaultLibMatch(comment: string): RegExpExecArray { + var isNoDefaultLibRegex = /^(\/\/\/\s*/gim; + return isNoDefaultLibRegex.exec(comment); + } + + export var tripleSlashReferenceRegExp = /^(\/\/\/\s*/; + + function getFileReferenceFromReferencePath(fileName: string, text: ISimpleText, position: number, comment: string, diagnostics: Diagnostic[]): IFileReference { + // First, just see if they've written: /// = 7 && fullReference[6] === "true"; + return { + line: 0, + character: 0, + position: 0, + length: 0, + path: switchToForwardSlashes(adjustedPath), + isResident: isResident + }; + } + } + } + + return null; + } + + var reportDiagnostic = () => { }; + + function processImports(text: ISimpleText, scanner: Scanner.IScanner, token: ISyntaxToken, importedFiles: IFileReference[]): void { + var lineChar = { line: -1, character: -1 }; + + var lineMap = text.lineMap(); + var start = new Date().getTime(); + // Look for: + // import foo = module("foo") + while (token.kind() !== SyntaxKind.EndOfFileToken) { + if (token.kind() === SyntaxKind.ImportKeyword) { + var importToken = token; + token = scanner.scan(/*allowRegularExpression:*/ false); + + if (SyntaxFacts.isIdentifierNameOrAnyKeyword(token)) { + token = scanner.scan(/*allowRegularExpression:*/ false); + + if (token.kind() === SyntaxKind.EqualsToken) { + token = scanner.scan(/*allowRegularExpression:*/ false); + + if (token.kind() === SyntaxKind.ModuleKeyword || token.kind() === SyntaxKind.RequireKeyword) { + token = scanner.scan(/*allowRegularExpression:*/ false); + + if (token.kind() === SyntaxKind.OpenParenToken) { + token = scanner.scan(/*allowRegularExpression:*/ false); + + lineMap.fillLineAndCharacterFromPosition(TypeScript.start(importToken, text), lineChar); + + if (token.kind() === SyntaxKind.StringLiteral) { + var ref = { + line: lineChar.line, + character: lineChar.character, + position: TypeScript.start(token, text), + length: width(token), + path: stripStartAndEndQuotes(switchToForwardSlashes(token.text())), + isResident: false + }; + importedFiles.push(ref); + } + } + } + } + } + } + + token = scanner.scan(/*allowRegularExpression:*/ false); + } + + var totalTime = new Date().getTime() - start; + TypeScript.fileResolutionScanImportsTime += totalTime; + } + + function processTripleSlashDirectives(fileName: string, text: ISimpleText, firstToken: ISyntaxToken): ITripleSlashDirectiveProperties { + var leadingTrivia = firstToken.leadingTrivia(text); + + var position = 0; + var lineChar = { line: -1, character: -1 }; + var noDefaultLib = false; + var diagnostics: Diagnostic[] = []; + var referencedFiles: IFileReference[] = []; + var lineMap = text.lineMap() + + for (var i = 0, n = leadingTrivia.count(); i < n; i++) { + var trivia = leadingTrivia.syntaxTriviaAt(i); + + if (trivia.kind() === SyntaxKind.SingleLineCommentTrivia) { + var triviaText = trivia.fullText(); + var referencedCode = getFileReferenceFromReferencePath(fileName, text, position, triviaText, diagnostics); + + if (referencedCode) { + lineMap.fillLineAndCharacterFromPosition(position, lineChar); + referencedCode.position = position; + referencedCode.length = trivia.fullWidth(); + referencedCode.line = lineChar.line; + referencedCode.character = lineChar.character; + + referencedFiles.push(referencedCode); + } + + // is it a lib file? + var isNoDefaultLib = isNoDefaultLibMatch(triviaText); + if (isNoDefaultLib) { + noDefaultLib = isNoDefaultLib[3] === "true"; + } + } + + position += trivia.fullWidth(); + } + + return { noDefaultLib: noDefaultLib, diagnostics: diagnostics, referencedFiles: referencedFiles }; + } + + export function preProcessFile(fileName: string, sourceText: IScriptSnapshot, readImportFiles = true): IPreProcessedFileInfo { + var text = SimpleText.fromScriptSnapshot(sourceText); + var scanner = Scanner.createScanner(ts.ScriptTarget.ES5, text, reportDiagnostic); + + var firstToken = scanner.scan(/*allowRegularExpression:*/ false); + + // only search out dynamic mods + // if you find a dynamic mod, ignore every other mod inside, until you balance rcurlies + // var position + + var importedFiles: IFileReference[] = []; + if (readImportFiles) { + processImports(text, scanner, firstToken, importedFiles); + } + + var properties = processTripleSlashDirectives(fileName, text, firstToken); + + return { referencedFiles: properties.referencedFiles, importedFiles: importedFiles, isLibFile: properties.noDefaultLib, diagnostics: properties.diagnostics }; + } + + export function getReferencedFiles(fileName: string, sourceText: IScriptSnapshot): IFileReference[] { + return preProcessFile(fileName, sourceText, false).referencedFiles; + } +} // Tools \ No newline at end of file diff --git a/src/services/compiler/process.ts b/src/services/compiler/process.ts new file mode 100644 index 00000000000..cd4cfde5f67 --- /dev/null +++ b/src/services/compiler/process.ts @@ -0,0 +1,17 @@ +//declare module process { +// export var argv: string[]; +// export var platform: string; +// export function on(event: string, handler: (arg: any) => void ): void; +// export module stdout { +// export function write(str: string): any; +// export function on(event: string, action: () => void ): void; +// } +// export module stderr { +// export function write(str: string): any; +// export function on(event: string, action: () => void): void; +// } +// export module mainModule { +// export var filename: string; +// } +// export function exit(exitCode?: number): any; +//} \ No newline at end of file diff --git a/src/services/compiler/referenceResolution.ts b/src/services/compiler/referenceResolution.ts new file mode 100644 index 00000000000..315c72d98f5 --- /dev/null +++ b/src/services/compiler/referenceResolution.ts @@ -0,0 +1,28 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript { + + // Note: This is being using by the host (VS) and is marshaled back and forth. When changing this make sure the changes + // are reflected in the managed side as well. + export interface IFileReference extends ILineAndCharacter { + path: string; + isResident: boolean; + position: number; + length: number; + } +} \ No newline at end of file diff --git a/src/services/compiler/referenceResolver.ts b/src/services/compiler/referenceResolver.ts new file mode 100644 index 00000000000..d1b264d0818 --- /dev/null +++ b/src/services/compiler/referenceResolver.ts @@ -0,0 +1,255 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript { + export interface IResolvedFile { + path: string; + referencedFiles: string[]; + importedFiles: string[]; + } + + export interface IReferenceResolverHost { + getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot; + resolveRelativePath(path: string, directory: string): string; + fileExists(path: string): boolean; + directoryExists(path: string): boolean; + getParentDirectory(path: string): string; + } + + export class ReferenceResolutionResult { + resolvedFiles: IResolvedFile[] = []; + diagnostics: TypeScript.Diagnostic[] = []; + seenNoDefaultLibTag: boolean = false; + } + + class ReferenceLocation { + constructor(public filePath: string, public lineMap: LineMap, public position: number, public length: number, public isImported: boolean) { + } + } + + export class ReferenceResolver { + private inputFileNames: string[]; + private host: IReferenceResolverHost; + private visited: IIndexable; + + constructor(inputFileNames: string[], host: IReferenceResolverHost, private useCaseSensitiveFileResolution: boolean) { + this.inputFileNames = inputFileNames; + this.host = host; + this.visited = {}; + } + + public static resolve(inputFileNames: string[], host: IReferenceResolverHost, useCaseSensitiveFileResolution: boolean): ReferenceResolutionResult { + var resolver = new ReferenceResolver(inputFileNames, host, useCaseSensitiveFileResolution); + return resolver.resolveInputFiles(); + } + + public resolveInputFiles(): ReferenceResolutionResult { + var result = new ReferenceResolutionResult(); + + if (!this.inputFileNames || this.inputFileNames.length <= 0) { + // Nothing to do. + return result; + } + + // Loop over the files and extract references + var referenceLocation = new ReferenceLocation(null, null, 0, 0, false); + this.inputFileNames.forEach(fileName => + this.resolveIncludedFile(fileName, referenceLocation, result)); + + return result; + } + + private resolveIncludedFile(path: string, referenceLocation: ReferenceLocation, resolutionResult: ReferenceResolutionResult): string { + var normalizedPath = this.getNormalizedFilePath(path, referenceLocation.filePath); + + if (this.isSameFile(normalizedPath, referenceLocation.filePath)) { + // Cannot reference self + if (!referenceLocation.isImported) { + resolutionResult.diagnostics.push( + new TypeScript.Diagnostic(referenceLocation.filePath, referenceLocation.lineMap, + referenceLocation.position, referenceLocation.length, DiagnosticCode.A_file_cannot_have_a_reference_to_itself, null)); + } + + return normalizedPath; + } + + if (!isTSFile(normalizedPath) && !isDTSFile(normalizedPath)) { + var dtsFile = normalizedPath + ".d.ts"; + var tsFile = normalizedPath + ".ts"; + + if (this.host.fileExists(tsFile)) { + normalizedPath = tsFile; + } + else { + normalizedPath = dtsFile; + } + } + + if (!this.host.fileExists(normalizedPath)) { + if (!referenceLocation.isImported) { + resolutionResult.diagnostics.push( + new TypeScript.Diagnostic(referenceLocation.filePath, referenceLocation.lineMap, + referenceLocation.position, referenceLocation.length, DiagnosticCode.Cannot_resolve_referenced_file_0, [path])); + } + + return normalizedPath; + } + + // Preprocess the file and resolve its imports/references + return this.resolveFile(normalizedPath, resolutionResult); + } + + private resolveImportedFile(path: string, referenceLocation: ReferenceLocation, resolutionResult: ReferenceResolutionResult): string { + var isRelativePath = TypeScript.isRelative(path); + var isRootedPath = isRelativePath ? false : isRooted(path); + + if (isRelativePath || isRootedPath) { + // Handle as a normal include file + return this.resolveIncludedFile(path, referenceLocation, resolutionResult); + } + else { + // Search for the file + var parentDirectory = this.host.getParentDirectory(referenceLocation.filePath); + var searchFilePath: string = null; + var dtsFileName = path + ".d.ts"; + var tsFilePath = path + ".ts"; + + var start = new Date().getTime(); + + // SPEC: Nov 18 + // An external import declaration that specifies a relative external module name (section 11.2.1) resolves the name + // relative to the directory of the containing source file. + // If a source file with the resulting path and file extension '.ts' exists, that file is added as a dependency. + // Otherwise, if a source file with the resulting path and file extension '.d.ts' exists, that file is added as a dependency. + do { + // Search for ".ts" file first + currentFilePath = this.host.resolveRelativePath(tsFilePath, parentDirectory); + if (this.host.fileExists(currentFilePath)) { + // Found the file + searchFilePath = currentFilePath; + break; + } + + // Search for ".d.ts" file + var currentFilePath = this.host.resolveRelativePath(dtsFileName, parentDirectory); + if (this.host.fileExists(currentFilePath)) { + // Found the file + searchFilePath = currentFilePath; + break; + } + + parentDirectory = this.host.getParentDirectory(parentDirectory); + } + while (parentDirectory); + + TypeScript.fileResolutionImportFileSearchTime += new Date().getTime() - start; + + if (!searchFilePath) { + // Cannot find file import, do not reprot an error, the typeChecker will report it later on + return path; + } + + // Preprocess the file and resolve its imports/references + return this.resolveFile(searchFilePath, resolutionResult); + } + } + + private resolveFile(normalizedPath: string, resolutionResult: ReferenceResolutionResult): string { + // If we have processed this file before, skip it + var visitedPath = this.isVisited(normalizedPath); + if (!visitedPath) { + // Record that we have seen it + this.recordVisitedFile(normalizedPath); + + // Preprocess the file + var start = new Date().getTime(); + var scriptSnapshot = this.host.getScriptSnapshot(normalizedPath); + var totalTime = new Date().getTime() - start; + TypeScript.fileResolutionIOTime += totalTime; + + var lineMap = LineMap1.fromScriptSnapshot(scriptSnapshot); + var preprocessedFileInformation = TypeScript.preProcessFile(normalizedPath, scriptSnapshot); + resolutionResult.diagnostics.push.apply(resolutionResult.diagnostics, preprocessedFileInformation.diagnostics); + + // If this file has a "no-default-lib = 'true'" tag + if (preprocessedFileInformation.isLibFile) { + resolutionResult.seenNoDefaultLibTag = true; + } + + // Resolve explicit references + var normalizedReferencePaths: string[] = []; + preprocessedFileInformation.referencedFiles.forEach(fileReference => { + var currentReferenceLocation = new ReferenceLocation(normalizedPath, lineMap, fileReference.position, fileReference.length, /* isImported */ false); + var normalizedReferencePath = this.resolveIncludedFile(fileReference.path, currentReferenceLocation, resolutionResult); + normalizedReferencePaths.push(normalizedReferencePath); + }); + + // Resolve imports + var normalizedImportPaths: string[] = []; + for (var i = 0; i < preprocessedFileInformation.importedFiles.length; i++) { + var fileImport = preprocessedFileInformation.importedFiles[i]; + var currentReferenceLocation = new ReferenceLocation(normalizedPath, lineMap, fileImport.position, fileImport.length, /* isImported */ true); + var normalizedImportPath = this.resolveImportedFile(fileImport.path, currentReferenceLocation, resolutionResult); + normalizedImportPaths.push(normalizedImportPath); + } + + // Add the file to the result list + resolutionResult.resolvedFiles.push({ + path: normalizedPath, + referencedFiles: normalizedReferencePaths, + importedFiles: normalizedImportPaths + }); + } + else { + normalizedPath = visitedPath; + } + + return normalizedPath; + } + + private getNormalizedFilePath(path: string, parentFilePath: string): string { + var parentFileDirectory = parentFilePath ? this.host.getParentDirectory(parentFilePath) : ""; + var normalizedPath = this.host.resolveRelativePath(path, parentFileDirectory); + return normalizedPath; + } + + private getUniqueFileId(filePath: string): string { + return this.useCaseSensitiveFileResolution ? filePath : filePath.toLocaleUpperCase(); + } + + private recordVisitedFile(filePath: string): void { + this.visited[this.getUniqueFileId(filePath)] = filePath; + } + + private isVisited(filePath: string): string { + return this.visited[this.getUniqueFileId(filePath)]; + } + + private isSameFile(filePath1: string, filePath2: string): boolean { + if (!filePath1 || !filePath2) { + return false; + } + + if (this.useCaseSensitiveFileResolution) { + return filePath1 === filePath2; + } + else { + return filePath1.toLocaleUpperCase() === filePath2.toLocaleUpperCase(); + } + } + } +} \ No newline at end of file diff --git a/src/services/compiler/references.ts b/src/services/compiler/references.ts new file mode 100644 index 00000000000..464af87ec50 --- /dev/null +++ b/src/services/compiler/references.ts @@ -0,0 +1,37 @@ +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// + +///// +///// diff --git a/src/services/compiler/settings.ts b/src/services/compiler/settings.ts new file mode 100644 index 00000000000..11b58fb0e41 --- /dev/null +++ b/src/services/compiler/settings.ts @@ -0,0 +1,15 @@ +/// + +module TypeScript { + export function settingsChangeAffectsSyntax(before: ts.CompilerOptions, after: ts.CompilerOptions): boolean { + // If the automatic semicolon insertion option has changed, then we have to dump all + // syntax trees in order to reparse them with the new option. + // + // If the language version changed, then that affects what types of things we parse. So + // we have to dump all syntax trees. + // + // If propagateEnumConstants changes, then that affects the constant value data we've + // stored in the ISyntaxElement. + return before.module !== after.module || before.target !== after.target; + } +} \ No newline at end of file diff --git a/src/services/compiler/sourceMapping.ts b/src/services/compiler/sourceMapping.ts new file mode 100644 index 00000000000..11fae5b4353 --- /dev/null +++ b/src/services/compiler/sourceMapping.ts @@ -0,0 +1,270 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript { + export class SourceMapPosition { + public sourceLine: number; + public sourceColumn: number; + public emittedLine: number; + public emittedColumn: number; + } + + export class SourceMapping { + public start = new SourceMapPosition(); + public end = new SourceMapPosition(); + public nameIndex: number = -1; + public childMappings: SourceMapping[] = []; + } + + export class SourceMapEntry { + constructor( + public emittedFile: string, + public emittedLine: number, + public emittedColumn: number, + public sourceFile: string, + public sourceLine: number, + public sourceColumn: number, + public sourceName: string) { + + Debug.assert(isFinite(emittedLine)); + Debug.assert(isFinite(emittedColumn)); + Debug.assert(isFinite(sourceColumn)); + Debug.assert(isFinite(sourceLine)); + } + } + + export class SourceMapper { + static MapFileExtension = ".map"; + + private jsFileName: string; + private sourceMapPath: string; + private sourceMapDirectory: string; + private sourceRoot: string; + + public names: string[] = []; + + private mappingLevel: ISpan[] = []; + + // Below two arrays represent the information about sourceFile at that index. + private tsFilePaths: string[] = []; + private allSourceMappings: SourceMapping[][] = []; + + public currentMappings: SourceMapping[][]; + public currentNameIndex: number[]; + + private sourceMapEntries: SourceMapEntry[] = []; + + constructor(private jsFile: TextWriter, + private sourceMapOut: TextWriter, + document: Document, + jsFilePath: string, + emitOptions: EmitOptions, + resolvePath: (path: string) => string) { + this.setSourceMapOptions(document, jsFilePath, emitOptions, resolvePath); + this.setNewSourceFile(document, emitOptions); + } + + public getOutputFile(): OutputFile { + var result = this.sourceMapOut.getOutputFile(); + result.sourceMapEntries = this.sourceMapEntries; + + return result; + } + + public increaseMappingLevel(ast: ISpan) { + this.mappingLevel.push(ast); + } + + public decreaseMappingLevel(ast: any) { + Debug.assert(this.mappingLevel.length > 0, "Mapping level should never be less than 0. This suggests a missing start call."); + var expectedAst = this.mappingLevel.pop(); + if (ast !== expectedAst) { + var expectedAstInfo: any = (expectedAst).kind ? SyntaxKind[(expectedAst).kind] : [expectedAst.start(), expectedAst.end()]; + var astInfo: any = (ast).kind ? SyntaxKind[(ast).kind] : [ast.start(), ast.end()] + Debug.fail( + "Provided ast is not the expected ISyntaxElement, Expected: " + expectedAstInfo + " Given: " + astInfo) + + } + } + + public setNewSourceFile(document: Document, emitOptions: EmitOptions) { + // Set new mappings + var sourceMappings: SourceMapping[] = []; + this.allSourceMappings.push(sourceMappings); + this.currentMappings = [sourceMappings]; + this.currentNameIndex = []; + + // Set new source file path + this.setNewSourceFilePath(document, emitOptions); + } + + private setSourceMapOptions(document: Document, jsFilePath: string, emitOptions: EmitOptions, resolvePath: (path: string) => string) { + // Decode mapRoot and sourceRoot + + // Js File Name = pretty name of js file + var prettyJsFileName = TypeScript.getPrettyName(jsFilePath, false, true); + var prettyMapFileName = prettyJsFileName + SourceMapper.MapFileExtension; + this.jsFileName = prettyJsFileName; + + // Figure out sourceMapPath and sourceMapDirectory + if (emitOptions.sourceMapRootDirectory()) { + // Get the sourceMap Directory + this.sourceMapDirectory = emitOptions.sourceMapRootDirectory(); + if (document.emitToOwnOutputFile()) { + // For modules or multiple emit files the mapRoot will have directory structure like the sources + // So if src\a.ts and src\lib\b.ts are compiled together user would be moving the maps into mapRoot\a.js.map and mapRoot\lib\b.js.map + this.sourceMapDirectory = this.sourceMapDirectory + switchToForwardSlashes(getRootFilePath((document.fileName)).replace(emitOptions.commonDirectoryPath(), "")); + } + + if (isRelative(this.sourceMapDirectory)) { + // The relative paths are relative to the common directory + this.sourceMapDirectory = emitOptions.commonDirectoryPath() + this.sourceMapDirectory; + this.sourceMapDirectory = convertToDirectoryPath(switchToForwardSlashes(resolvePath(this.sourceMapDirectory))); + this.sourceMapPath = getRelativePathToFixedPath(getRootFilePath(jsFilePath), this.sourceMapDirectory + prettyMapFileName); + } + else { + this.sourceMapPath = this.sourceMapDirectory + prettyMapFileName; + } + } + else { + this.sourceMapPath = prettyMapFileName; + this.sourceMapDirectory = getRootFilePath(jsFilePath); + } + this.sourceRoot = emitOptions.sourceRootDirectory(); + } + + private setNewSourceFilePath(document: Document, emitOptions: EmitOptions) { + var tsFilePath = switchToForwardSlashes(document.fileName); + if (emitOptions.sourceRootDirectory()) { + // Use the relative path corresponding to the common directory path + tsFilePath = getRelativePathToFixedPath(emitOptions.commonDirectoryPath(), tsFilePath); + } + else { + // Source locations relative to map file location + tsFilePath = getRelativePathToFixedPath(this.sourceMapDirectory, tsFilePath); + } + this.tsFilePaths.push(tsFilePath); + } + + // Generate source mapping. + // Creating files can cause exceptions, they will be caught higher up in TypeScriptCompiler.emit + public emitSourceMapping(): void { + Debug.assert( + this.mappingLevel.length === 0, + "Mapping level is not 0. This suggest a missing end call. Value: " + + this.mappingLevel.map(item => ['Node of type', SyntaxKind[(item).kind], 'at', item.start(), 'to', item.end()].join(' ')).join(', ')); + // Output map file name into the js file + this.jsFile.WriteLine("//# sourceMappingURL=" + this.sourceMapPath); + + // Now output map file + var mappingsString = ""; + + var prevEmittedColumn = 0; + var prevEmittedLine = 0; + var prevSourceColumn = 0; + var prevSourceLine = 0; + var prevSourceIndex = 0; + var prevNameIndex = 0; + var emitComma = false; + + var recordedPosition: SourceMapPosition = null; + for (var sourceIndex = 0; sourceIndex < this.tsFilePaths.length; sourceIndex++) { + var recordSourceMapping = (mappedPosition: SourceMapPosition, nameIndex: number) => { + + if (recordedPosition !== null && + recordedPosition.emittedColumn === mappedPosition.emittedColumn && + recordedPosition.emittedLine === mappedPosition.emittedLine) { + // This position is already recorded + return; + } + + // Record this position + if (prevEmittedLine !== mappedPosition.emittedLine) { + while (prevEmittedLine < mappedPosition.emittedLine) { + prevEmittedColumn = 0; + mappingsString = mappingsString + ";"; + prevEmittedLine++; + } + emitComma = false; + } + else if (emitComma) { + mappingsString = mappingsString + ","; + } + + this.sourceMapEntries.push(new SourceMapEntry( + this.jsFileName, + mappedPosition.emittedLine + 1, + mappedPosition.emittedColumn + 1, + this.tsFilePaths[sourceIndex], + mappedPosition.sourceLine, + mappedPosition.sourceColumn + 1, + nameIndex >= 0 ? this.names[nameIndex] : undefined)); + + // 1. Relative Column + mappingsString = mappingsString + Base64VLQFormat.encode(mappedPosition.emittedColumn - prevEmittedColumn); + prevEmittedColumn = mappedPosition.emittedColumn; + + // 2. Relative sourceIndex + mappingsString = mappingsString + Base64VLQFormat.encode(sourceIndex - prevSourceIndex); + prevSourceIndex = sourceIndex; + + // 3. Relative sourceLine 0 based + mappingsString = mappingsString + Base64VLQFormat.encode(mappedPosition.sourceLine - 1 - prevSourceLine); + prevSourceLine = mappedPosition.sourceLine - 1; + + // 4. Relative sourceColumn 0 based + mappingsString = mappingsString + Base64VLQFormat.encode(mappedPosition.sourceColumn - prevSourceColumn); + prevSourceColumn = mappedPosition.sourceColumn; + + // 5. Relative namePosition 0 based + if (nameIndex >= 0) { + mappingsString = mappingsString + Base64VLQFormat.encode(nameIndex - prevNameIndex); + prevNameIndex = nameIndex; + } + + emitComma = true; + recordedPosition = mappedPosition; + }; + + // Record starting spans + var recordSourceMappingSiblings = (sourceMappings: SourceMapping[]) => { + for (var i = 0; i < sourceMappings.length; i++) { + var sourceMapping = sourceMappings[i]; + recordSourceMapping(sourceMapping.start, sourceMapping.nameIndex); + recordSourceMappingSiblings(sourceMapping.childMappings); + recordSourceMapping(sourceMapping.end, sourceMapping.nameIndex); + } + }; + + recordSourceMappingSiblings(this.allSourceMappings[sourceIndex]); + } + + // Write the actual map file + this.sourceMapOut.Write(JSON.stringify({ + version: 3, + file: this.jsFileName, + sourceRoot: this.sourceRoot, + sources: this.tsFilePaths, + names: this.names, + mappings: mappingsString + })); + + // Closing files could result in exceptions, report them if they occur + this.sourceMapOut.Close(); + } + } +} \ No newline at end of file diff --git a/src/services/compiler/tsc.ts b/src/services/compiler/tsc.ts new file mode 100644 index 00000000000..e77ea9467ca --- /dev/null +++ b/src/services/compiler/tsc.ts @@ -0,0 +1,736 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// +/// +/// + +module TypeScript { + class SourceFile { + constructor(public scriptSnapshot: IScriptSnapshot, public byteOrderMark: ByteOrderMark) { + } + } + + class DiagnosticsLogger implements ILogger { + constructor(public ioHost: IEnvironment) { + } + public information(): boolean { return false; } + public debug(): boolean { return false; } + public warning(): boolean { return false; } + public error(): boolean { return false; } + public fatal(): boolean { return false; } + public log(s: string): void { + this.ioHost.standardOut.WriteLine(s); + } + } + + export class BatchCompiler implements IReferenceResolverHost { + public compilerVersion = "1.0.1.0"; + private inputFiles: string[] = []; + private compilationSettings: ImmutableCompilationSettings; + private resolvedFiles: IResolvedFile[] = []; + private fileNameToSourceFile = new StringHashTable(); + private hasErrors: boolean = false; + private logger: ILogger = null; + + constructor(private ioHost: IEnvironment) { + } + + // Begin batch compilation + public batchCompile() { + // Parse command line options + if (this.parseOptions()) { + var start = new Date().getTime(); + + if (this.compilationSettings.gatherDiagnostics()) { + this.logger = new DiagnosticsLogger(this.ioHost); + } else { + this.logger = new NullLogger(); + } + + if (this.compilationSettings.watch()) { + // Watch will cause the program to stick around as long as the files exist + this.watchFiles(); + return; + } + + // Resolve the compilation environemnt + this.resolve(); + + this.compile(); + + if (this.compilationSettings.gatherDiagnostics()) { + this.logger.log(""); + this.logger.log("File resolution time: " + TypeScript.fileResolutionTime); + this.logger.log(" file read: " + TypeScript.fileResolutionIOTime); + this.logger.log(" scan imports: " + TypeScript.fileResolutionScanImportsTime); + this.logger.log(" import search: " + TypeScript.fileResolutionImportFileSearchTime); + this.logger.log(" get lib.d.ts: " + TypeScript.fileResolutionGetDefaultLibraryTime); + + this.logger.log("SyntaxTree parse time: " + TypeScript.syntaxTreeParseTime); + this.logger.log("Syntax Diagnostics time: " + TypeScript.syntaxDiagnosticsTime); + this.logger.log("Create declarations time: " + TypeScript.createDeclarationsTime); + this.logger.log(""); + this.logger.log("Type check time: " + TypeScript.typeCheckTime); + this.logger.log(""); + this.logger.log("Emit time: " + TypeScript.emitTime); + this.logger.log("Declaration emit time: " + TypeScript.declarationEmitTime); + + this.logger.log("Total number of symbols created: " + TypeScript.pullSymbolID); + this.logger.log("Specialized types created: " + TypeScript.nSpecializationsCreated); + this.logger.log("Specialized signatures created: " + TypeScript.nSpecializedSignaturesCreated); + + this.logger.log(" IsExternallyVisibleTime: " + TypeScript.declarationEmitIsExternallyVisibleTime); + this.logger.log(" TypeSignatureTime: " + TypeScript.declarationEmitTypeSignatureTime); + this.logger.log(" GetBoundDeclTypeTime: " + TypeScript.declarationEmitGetBoundDeclTypeTime); + this.logger.log(" IsOverloadedCallSignatureTime: " + TypeScript.declarationEmitIsOverloadedCallSignatureTime); + this.logger.log(" FunctionDeclarationGetSymbolTime: " + TypeScript.declarationEmitFunctionDeclarationGetSymbolTime); + this.logger.log(" GetBaseTypeTime: " + TypeScript.declarationEmitGetBaseTypeTime); + this.logger.log(" GetAccessorFunctionTime: " + TypeScript.declarationEmitGetAccessorFunctionTime); + this.logger.log(" GetTypeParameterSymbolTime: " + TypeScript.declarationEmitGetTypeParameterSymbolTime); + this.logger.log(" GetImportDeclarationSymbolTime: " + TypeScript.declarationEmitGetImportDeclarationSymbolTime); + + this.logger.log("Emit write file time: " + TypeScript.emitWriteFileTime); + + this.logger.log("Compiler resolve path time: " + TypeScript.compilerResolvePathTime); + this.logger.log("Compiler directory name time: " + TypeScript.compilerDirectoryNameTime); + this.logger.log("Compiler directory exists time: " + TypeScript.compilerDirectoryExistsTime); + this.logger.log("Compiler file exists time: " + TypeScript.compilerFileExistsTime); + + this.logger.log("IO host resolve path time: " + TypeScript.ioHostResolvePathTime); + this.logger.log("IO host directory name time: " + TypeScript.ioHostDirectoryNameTime); + this.logger.log("IO host create directory structure time: " + TypeScript.ioHostCreateDirectoryStructureTime); + this.logger.log("IO host write file time: " + TypeScript.ioHostWriteFileTime); + + this.logger.log("Node make directory time: " + TypeScript.nodeMakeDirectoryTime); + this.logger.log("Node writeFileSync time: " + TypeScript.nodeWriteFileSyncTime); + this.logger.log("Node createBuffer time: " + TypeScript.nodeCreateBufferTime); + + this.logger.log("Total time: " + (new Date().getTime() - start)); + } + } + + // Exit with the appropriate error code + this.ioHost.quit(this.hasErrors ? 1 : 0); + } + + private resolve() { + // Resolve file dependencies, if requested + var includeDefaultLibrary = !this.compilationSettings.noLib(); + var resolvedFiles: IResolvedFile[] = []; + + var start = new Date().getTime(); + + if (!this.compilationSettings.noResolve()) { + // Resolve references + var resolutionResults = ReferenceResolver.resolve(this.inputFiles, this, this.compilationSettings.useCaseSensitiveFileResolution()); + resolvedFiles = resolutionResults.resolvedFiles; + + // Only include the library if useDefaultLib is set to true and did not see any 'no-default-lib' comments + includeDefaultLibrary = !this.compilationSettings.noLib() && !resolutionResults.seenNoDefaultLibTag; + + // Populate any diagnostic messages generated during resolution + resolutionResults.diagnostics.forEach(d => this.addDiagnostic(d)); + } + else { + for (var i = 0, n = this.inputFiles.length; i < n; i++) { + var inputFile = this.inputFiles[i]; + var referencedFiles: string[] = []; + var importedFiles: string[] = []; + + // If declaration files are going to be emitted, preprocess the file contents and add in referenced files as well + if (this.compilationSettings.generateDeclarationFiles()) { + var references = getReferencedFiles(inputFile, this.getScriptSnapshot(inputFile)); + for (var j = 0; j < references.length; j++) { + referencedFiles.push(references[j].path); + } + + inputFile = this.resolvePath(inputFile); + } + + resolvedFiles.push({ + path: inputFile, + referencedFiles: referencedFiles, + importedFiles: importedFiles + }); + } + } + + var defaultLibStart = new Date().getTime(); + if (includeDefaultLibrary) { + var libraryResolvedFile: IResolvedFile = { + path: this.getDefaultLibraryFilePath(), + referencedFiles: [], + importedFiles: [] + }; + + // Prepend the library to the resolved list + resolvedFiles = [libraryResolvedFile].concat(resolvedFiles); + } + TypeScript.fileResolutionGetDefaultLibraryTime += new Date().getTime() - defaultLibStart; + + this.resolvedFiles = resolvedFiles; + + TypeScript.fileResolutionTime = new Date().getTime() - start; + } + + // Returns true if compilation failed from some reason. + private compile(): void { + var compiler = new TypeScriptCompiler(this.logger, this.compilationSettings); + + this.resolvedFiles.forEach(resolvedFile => { + var sourceFile = this.getSourceFile(resolvedFile.path); + compiler.addFile(resolvedFile.path, sourceFile.scriptSnapshot, sourceFile.byteOrderMark, /*version:*/ 0, /*isOpen:*/ false, resolvedFile.referencedFiles); + }); + + for (var it = compiler.compile((path: string) => this.resolvePath(path)); it.moveNext();) { + var result = it.current(); + + result.diagnostics.forEach(d => this.addDiagnostic(d)); + if (!this.tryWriteOutputFiles(result.outputFiles)) { + return; + } + } + } + + // Parse command line options + private parseOptions() { + var opts = new OptionsParser(this.ioHost, this.compilerVersion); + + var mutableSettings = new CompilationSettings(); + opts.option('out', { + usage: { + locCode: DiagnosticCode.Concatenate_and_emit_output_to_single_file, + args: null + }, + type: DiagnosticCode.file2, + set: (str) => { + mutableSettings.outFileOption = str; + } + }); + + opts.option('outDir', { + usage: { + locCode: DiagnosticCode.Redirect_output_structure_to_the_directory, + args: null + }, + type: DiagnosticCode.DIRECTORY, + set: (str) => { + mutableSettings.outDirOption = str; + } + }); + + opts.flag('sourcemap', { + usage: { + locCode: DiagnosticCode.Generates_corresponding_0_file, + args: ['.map'] + }, + set: () => { + mutableSettings.mapSourceFiles = true; + } + }); + + opts.option('mapRoot', { + usage: { + locCode: DiagnosticCode.Specifies_the_location_where_debugger_should_locate_map_files_instead_of_generated_locations, + args: null + }, + type: DiagnosticCode.LOCATION, + set: (str) => { + mutableSettings.mapRoot = str; + } + }); + + opts.option('sourceRoot', { + usage: { + locCode: DiagnosticCode.Specifies_the_location_where_debugger_should_locate_TypeScript_files_instead_of_source_locations, + args: null + }, + type: DiagnosticCode.LOCATION, + set: (str) => { + mutableSettings.sourceRoot = str; + } + }); + + opts.flag('declaration', { + usage: { + locCode: DiagnosticCode.Generates_corresponding_0_file, + args: ['.d.ts'] + }, + set: () => { + mutableSettings.generateDeclarationFiles = true; + } + }, 'd'); + + if (this.ioHost.watchFile) { + opts.flag('watch', { + usage: { + locCode: DiagnosticCode.Watch_input_files, + args: null + }, + set: () => { + mutableSettings.watch = true; + } + }, 'w'); + } + + opts.flag('propagateEnumConstants', { + experimental: true, + set: () => { mutableSettings.propagateEnumConstants = true; } + }); + + opts.flag('removeComments', { + usage: { + locCode: DiagnosticCode.Do_not_emit_comments_to_output, + args: null + }, + set: () => { + mutableSettings.removeComments = true; + } + }); + + opts.flag('noResolve', { + experimental: true, + usage: { + locCode: DiagnosticCode.Skip_resolution_and_preprocessing, + args: null + }, + set: () => { + mutableSettings.noResolve = true; + } + }); + + opts.flag('noLib', { + experimental: true, + set: () => { + mutableSettings.noLib = true; + } + }); + + opts.flag('diagnostics', { + experimental: true, + set: () => { + mutableSettings.gatherDiagnostics = true; + } + }); + + opts.option('target', { + usage: { + locCode: DiagnosticCode.Specify_ECMAScript_target_version_0_default_or_1, + args: ['ES3', 'ES5'] + }, + type: DiagnosticCode.VERSION, + set: (type) => { + type = type.toLowerCase(); + + if (type === 'es3') { + mutableSettings.codeGenTarget = LanguageVersion.EcmaScript3; + } + else if (type === 'es5') { + mutableSettings.codeGenTarget = LanguageVersion.EcmaScript5; + } + else { + this.addDiagnostic( + new Diagnostic(null, null, 0, 0, DiagnosticCode.Argument_for_0_option_must_be_1_or_2, ["target", "ES3", "ES5"])); + } + } + }, 't'); + + opts.option('module', { + usage: { + locCode: DiagnosticCode.Specify_module_code_generation_0_or_1, + args: ['commonjs', 'amd'] + }, + type: DiagnosticCode.KIND, + set: (type) => { + type = type.toLowerCase(); + + if (type === 'commonjs') { + mutableSettings.moduleGenTarget = ModuleGenTarget.Synchronous; + } + else if (type === 'amd') { + mutableSettings.moduleGenTarget = ModuleGenTarget.Asynchronous; + } + else { + this.addDiagnostic( + new Diagnostic(null, null, 0, 0, DiagnosticCode.Argument_for_0_option_must_be_1_or_2, ["module", "commonjs", "amd"])); + } + } + }, 'm'); + + var needsHelp = false; + opts.flag('help', { + usage: { + locCode: DiagnosticCode.Print_this_message, + args: null + }, + set: () => { + needsHelp = true; + } + }, 'h'); + + opts.flag('useCaseSensitiveFileResolution', { + experimental: true, + set: () => { + mutableSettings.useCaseSensitiveFileResolution = true; + } + }); + var shouldPrintVersionOnly = false; + opts.flag('version', { + usage: { + locCode: DiagnosticCode.Print_the_compiler_s_version_0, + args: [this.compilerVersion] + }, + set: () => { + shouldPrintVersionOnly = true; + } + }, 'v'); + + var locale: string = null; + opts.option('locale', { + experimental: true, + usage: { + locCode: DiagnosticCode.Specify_locale_for_errors_and_messages_For_example_0_or_1, + args: ['en', 'ja-jp'] + }, + type: DiagnosticCode.STRING, + set: (value) => { + locale = value; + } + }); + + opts.flag('noImplicitAny', { + usage: { + locCode: DiagnosticCode.Warn_on_expressions_and_declarations_with_an_implied_any_type, + args: null + }, + set: () => { + mutableSettings.noImplicitAny = true; + } + }); + + if (Environment.supportsCodePage()) { + opts.option('codepage', { + usage: { + locCode: DiagnosticCode.Specify_the_codepage_to_use_when_opening_source_files, + args: null + }, + type: DiagnosticCode.NUMBER, + set: (arg) => { + mutableSettings.codepage = parseInt(arg, 10); + } + }); + } + + opts.parse(this.ioHost.arguments); + + this.compilationSettings = ImmutableCompilationSettings.fromCompilationSettings(mutableSettings); + + if (locale) { + if (!this.setLocale(locale)) { + return false; + } + } + + this.inputFiles.push.apply(this.inputFiles, opts.unnamed); + + if (shouldPrintVersionOnly) { + opts.printVersion(); + return false; + } + // If no source files provided to compiler - print usage information + else if (this.inputFiles.length === 0 || needsHelp) { + opts.printUsage(); + return false; + } + + return !this.hasErrors; + } + + private setLocale(locale: string): boolean { + var matchResult = /^([a-z]+)([_\-]([a-z]+))?$/.exec(locale.toLowerCase()); + if (!matchResult) { + this.addDiagnostic(new Diagnostic(null, null, 0, 0, DiagnosticCode.Locale_must_be_of_the_form_language_or_language_territory_For_example_0_or_1, ['en', 'ja-jp'])); + return false; + } + + var language = matchResult[1]; + var territory = matchResult[3]; + + // First try the entire locale, then fall back to just language if that's all we have. + if (!this.setLanguageAndTerritory(language, territory) && + !this.setLanguageAndTerritory(language, null)) { + + this.addDiagnostic(new Diagnostic(null, null, 0, 0, DiagnosticCode.Unsupported_locale_0, [locale])); + return false; + } + + return true; + } + + private setLanguageAndTerritory(language: string, territory: string): boolean { + + var compilerFilePath = this.ioHost.executingFilePath(); + var containingDirectoryPath = this.ioHost.directoryName(compilerFilePath); + + var filePath = IOUtils.combine(containingDirectoryPath, language); + if (territory) { + filePath = filePath + "-" + territory; + } + + filePath = this.resolvePath(IOUtils.combine(filePath, "diagnosticMessages.generated.json")); + + if (!this.fileExists(filePath)) { + return false; + } + + var fileContents = this.ioHost.readFile(filePath, this.compilationSettings.codepage()); + TypeScript.LocalizedDiagnosticMessages = JSON.parse(fileContents.contents); + return true; + } + + // Handle -watch switch + private watchFiles() { + if (!this.ioHost.watchFile) { + this.addDiagnostic( + new Diagnostic(null, null, 0, 0, DiagnosticCode.Current_host_does_not_support_0_option, ['-w[atch]'])); + return; + } + + var lastResolvedFileSet: string[] = [] + var watchers: { [x: string]: IFileWatcher; } = {}; + var firstTime = true; + + var addWatcher = (fileName: string) => { + if (!watchers[fileName]) { + var watcher = this.ioHost.watchFile(fileName, onWatchedFileChange); + watchers[fileName] = watcher; + } + }; + + var removeWatcher = (fileName: string) => { + if (watchers[fileName]) { + watchers[fileName].close(); + delete watchers[fileName]; + } + }; + + var onWatchedFileChange = () => { + // Clean errors for previous compilation + this.hasErrors = false; + + // Clear out any source file data we've cached. + this.fileNameToSourceFile = new StringHashTable(); + + // Resolve file dependencies, if requested + this.resolve(); + + // Check if any new files were added to the environment as a result of the file change + var oldFiles = lastResolvedFileSet; + var newFiles = this.resolvedFiles.map(resolvedFile => resolvedFile.path).sort(); + + var i = 0, j = 0; + while (i < oldFiles.length && j < newFiles.length) { + + var compareResult = oldFiles[i].localeCompare(newFiles[j]); + if (compareResult === 0) { + // No change here + i++; + j++; + } + else if (compareResult < 0) { + // Entry in old list does not exist in the new one, it was removed + removeWatcher(oldFiles[i]); + i++; + } + else { + // Entry in new list does exist in the new one, it was added + addWatcher(newFiles[j]); + j++; + } + } + + // All remaining unmatched items in the old list have been removed + for (var k = i; k < oldFiles.length; k++) { + removeWatcher(oldFiles[k]); + } + + // All remaing unmatched items in the new list have been added + for (k = j; k < newFiles.length; k++) { + addWatcher(newFiles[k]); + } + + // Update the state + lastResolvedFileSet = newFiles; + + // Print header + if (!firstTime) { + var fileNames = ""; + for (var k = 0; k < lastResolvedFileSet.length; k++) { + fileNames += Environment.newLine + " " + lastResolvedFileSet[k]; + } + this.ioHost.standardError.WriteLine(getLocalizedText(DiagnosticCode.NL_Recompiling_0, [fileNames])); + } + else { + firstTime = false; + } + + // Trigger a new compilation + this.compile(); + }; + + // Switch to using stdout for all error messages + this.ioHost.standardOut = this.ioHost.standardOut; + + onWatchedFileChange(); + } + + private getSourceFile(fileName: string): SourceFile { + var sourceFile: SourceFile = this.fileNameToSourceFile.lookup(fileName); + if (!sourceFile) { + // Attempt to read the file + var fileInformation: FileInformation; + + try { + fileInformation = this.ioHost.readFile(fileName, this.compilationSettings.codepage()); + } + catch (e) { + this.addDiagnostic(new Diagnostic(null, null, 0, 0, DiagnosticCode.Cannot_read_file_0_1, [fileName, e.message])); + fileInformation = new FileInformation("", ByteOrderMark.None); + } + + var snapshot = ScriptSnapshot.fromString(fileInformation.contents); + var sourceFile = new SourceFile(snapshot, fileInformation.byteOrderMark); + this.fileNameToSourceFile.add(fileName, sourceFile); + } + + return sourceFile; + } + + private getDefaultLibraryFilePath(): string { + var compilerFilePath = this.ioHost.executingFilePath(); + var containingDirectoryPath = this.ioHost.directoryName(compilerFilePath); + var libraryFilePath = this.resolvePath(IOUtils.combine(containingDirectoryPath, "lib.d.ts")); + + return libraryFilePath; + } + + /// IReferenceResolverHost methods + getScriptSnapshot(fileName: string): IScriptSnapshot { + return this.getSourceFile(fileName).scriptSnapshot; + } + + resolveRelativePath(path: string, directory: string): string { + var unQuotedPath = stripStartAndEndQuotes(path); + var normalizedPath: string; + + if (isRooted(unQuotedPath) || !directory) { + normalizedPath = unQuotedPath; + } else { + normalizedPath = IOUtils.combine(directory, unQuotedPath); + } + + // get the absolute path + normalizedPath = this.resolvePath(normalizedPath); + + // Switch to forward slashes + normalizedPath = switchToForwardSlashes(normalizedPath); + + return normalizedPath; + } + + private fileExistsCache = createIntrinsicsObject(); + + fileExists(path: string): boolean { + var exists = this.fileExistsCache[path]; + if (exists === undefined) { + var start = new Date().getTime(); + exists = this.ioHost.fileExists(path); + this.fileExistsCache[path] = exists; + TypeScript.compilerFileExistsTime += new Date().getTime() - start; + } + + return exists; + } + + getParentDirectory(path: string): string { + var start = new Date().getTime(); + var result = this.ioHost.directoryName(path); + TypeScript.compilerDirectoryNameTime += new Date().getTime() - start; + + return result; + } + + + private addDiagnostic(diagnostic: Diagnostic): void { + var diagnosticInfo = diagnostic.info(); + if (diagnosticInfo.category === DiagnosticCategory.Error) { + this.hasErrors = true; + } + + this.ioHost.standardError.Write(TypeScriptCompiler.getFullDiagnosticText(diagnostic, path => this.resolvePath(path))); + } + + private tryWriteOutputFiles(outputFiles: OutputFile[]): boolean { + for (var i = 0, n = outputFiles.length; i < n; i++) { + var outputFile = outputFiles[i]; + + try { + this.writeFile(outputFile.name, outputFile.text, outputFile.writeByteOrderMark); + } + catch (e) { + this.addDiagnostic( + new Diagnostic(outputFile.name, null, 0, 0, DiagnosticCode.Emit_Error_0, [e.message])); + return false; + } + } + + return true; + } + + writeFile(fileName: string, contents: string, writeByteOrderMark: boolean): void { + var start = new Date().getTime(); + IOUtils.writeFileAndFolderStructure(this.ioHost, fileName, contents, writeByteOrderMark); + TypeScript.emitWriteFileTime += new Date().getTime() - start; + } + + directoryExists(path: string): boolean { + var start = new Date().getTime(); + var result = this.ioHost.directoryExists(path); + TypeScript.compilerDirectoryExistsTime += new Date().getTime() - start; + return result; + } + + // For performance reasons we cache the results of resolvePath. This avoids costly lookup + // on the disk once we've already resolved a path once. + private resolvePathCache = createIntrinsicsObject(); + + resolvePath(path: string): string { + var cachedValue = this.resolvePathCache[path]; + if (!cachedValue) { + var start = new Date().getTime(); + cachedValue = this.ioHost.absolutePath(path); + this.resolvePathCache[path] = cachedValue; + TypeScript.compilerResolvePathTime += new Date().getTime() - start; + } + + return cachedValue; + } + } + + // Start the batch compilation using the current hosts IO + var batch = new TypeScript.BatchCompiler(Environment); + batch.batchCompile(); +} diff --git a/src/services/compiler/types.ts b/src/services/compiler/types.ts new file mode 100644 index 00000000000..28bef81629b --- /dev/null +++ b/src/services/compiler/types.ts @@ -0,0 +1,102 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript { + export class MemberName { + public prefix: string = ""; + public suffix: string = ""; + + public isString() { return false; } + public isArray() { return false; } + public isMarker() { return !this.isString() && !this.isArray(); } + + public toString(): string { + return MemberName.memberNameToString(this); + } + + static memberNameToString(memberName: MemberName, markerInfo?: number[], markerBaseLength: number = 0): string { + var result = memberName.prefix; + + if (memberName.isString()) { + result += (memberName).text; + } + else if (memberName.isArray()) { + var ar = memberName; + for (var index = 0; index < ar.entries.length; index++) { + if (ar.entries[index].isMarker()) { + if (markerInfo) { + markerInfo.push(markerBaseLength + result.length); + } + continue; + } + + result += MemberName.memberNameToString(ar.entries[index], markerInfo, markerBaseLength + result.length); + result += ar.delim; + } + } + + result += memberName.suffix; + return result; + } + + static create(text: string): MemberName; + static create(entry: MemberName, prefix: string, suffix: string): MemberName; + static create(arg1: any, arg2?: any, arg3?: any): MemberName { + if (typeof arg1 === "string") { + return new MemberNameString(arg1); + } + else { + var result = new MemberNameArray(); + if (arg2) + result.prefix = arg2; + if (arg3) + result.suffix = arg3; + result.entries.push(arg1); + return result; + } + } + } + + export class MemberNameString extends MemberName { + constructor(public text: string) { + super(); + } + + public isString() { return true; } + } + + export class MemberNameArray extends MemberName { + public delim: string = ""; + public entries: MemberName[] = []; + + public isArray() { return true; } + + public add(entry: MemberName) { + this.entries.push(entry); + } + + public addAll(entries: MemberName[]) { + for (var i = 0 ; i < entries.length; i++) { + this.entries.push(entries[i]); + } + } + + constructor() { + super(); + } + } +} \ No newline at end of file diff --git a/src/services/compiler/typescript.ts b/src/services/compiler/typescript.ts new file mode 100644 index 00000000000..03b59816b1d --- /dev/null +++ b/src/services/compiler/typescript.ts @@ -0,0 +1,1528 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +if (Error) (Error).stackTraceLimit = 1000; + +module TypeScript { + export var fileResolutionTime = 0; + export var fileResolutionIOTime = 0; + export var fileResolutionScanImportsTime = 0; + export var fileResolutionImportFileSearchTime = 0; + export var fileResolutionGetDefaultLibraryTime = 0; + export var sourceCharactersCompiled = 0; + export var syntaxTreeParseTime = 0; + export var typeCheckTime = 0; + export var createDeclarationsTime = 0; + + export var compilerResolvePathTime = 0; + export var compilerDirectoryNameTime = 0; + export var compilerDirectoryExistsTime = 0; + export var compilerFileExistsTime = 0; + + export var emitTime = 0; + export var emitWriteFileTime = 0; + + export var declarationEmitTime = 0; + export var declarationEmitIsExternallyVisibleTime = 0; + export var declarationEmitTypeSignatureTime = 0; + export var declarationEmitGetBoundDeclTypeTime = 0; + export var declarationEmitIsOverloadedCallSignatureTime = 0; + export var declarationEmitFunctionDeclarationGetSymbolTime = 0; + export var declarationEmitGetBaseTypeTime = 0; + export var declarationEmitGetAccessorFunctionTime = 0; + export var declarationEmitGetTypeParameterSymbolTime = 0; + export var declarationEmitGetImportDeclarationSymbolTime = 0; + + export var ioHostResolvePathTime = 0; + export var ioHostDirectoryNameTime = 0; + export var ioHostCreateDirectoryStructureTime = 0; + export var ioHostWriteFileTime = 0; + + export interface PullSymbolInfo { + symbol: PullSymbol; + aliasSymbol: PullTypeAliasSymbol; + ast: ISyntaxElement; + enclosingScopeSymbol: PullSymbol; + } + + export interface PullCallSymbolInfo { + targetSymbol: PullSymbol; + resolvedSignatures: TypeScript.PullSignatureSymbol[]; + candidateSignature: TypeScript.PullSignatureSymbol; + isConstructorCall: boolean; + ast: ISyntaxElement; + enclosingScopeSymbol: PullSymbol; + } + + export interface PullVisibleSymbolsInfo { + symbols: PullSymbol[]; + enclosingScopeSymbol: PullSymbol; + } + + export enum EmitOutputResult { + Succeeded, + FailedBecauseOfSyntaxErrors, + FailedBecauseOfCompilerOptionsErrors, + FailedToGenerateDeclarationsBecauseOfSemanticErrors + } + + export class EmitOutput { + public outputFiles: OutputFile[] = []; + public emitOutputResult: EmitOutputResult; + constructor(emitOutputResult = EmitOutputResult.Succeeded) { + this.emitOutputResult = emitOutputResult; + } + } + + export enum OutputFileType { + JavaScript, + SourceMap, + Declaration + } + + export class OutputFile { + constructor(public name: string, + public writeByteOrderMark: boolean, + public text: string, + public fileType: OutputFileType, + public sourceMapEntries: SourceMapEntry[] = []) { + } + } + + // Represents the results of the last "pull" on the compiler when using the streaming + // 'compile' method. The compile result for a single pull can have diagnostics (if + // something went wrong), and/or OutputFiles that need to get written. + export class CompileResult { + public diagnostics: Diagnostic[] = []; + public outputFiles: OutputFile[] = []; + + public static fromDiagnostics(diagnostics: Diagnostic[]): CompileResult { + var result = new CompileResult(); + result.diagnostics = diagnostics; + return result; + } + + public static fromOutputFiles(outputFiles: OutputFile[]): CompileResult { + var result = new CompileResult(); + result.outputFiles = outputFiles; + return result; + } + } + + export interface ICancellationToken { + isCancellationRequested(): boolean; + } + + export class OperationCanceledException { } + + export class CancellationToken { + + public static None: CancellationToken = new CancellationToken(null) + + constructor(private cancellationToken: ICancellationToken) { + } + + public isCancellationRequested() { + return this.cancellationToken && this.cancellationToken.isCancellationRequested(); + } + + public throwIfCancellationRequested(): void { + if (this.isCancellationRequested()) { + throw new OperationCanceledException(); + } + } + } + + class DocumentRegistryEntry { + public refCount: number = 0; + public owners: string[] = []; + constructor(public document: Document) { + } + } + + export interface IDocumentRegistry { + acquireDocument( + fileName: string, + compilationSettings: ImmutableCompilationSettings, + scriptSnapshot: IScriptSnapshot, + byteOrderMark: ByteOrderMark, + version: number, + isOpen: boolean, + referencedFiles: string[]): TypeScript.Document; + + updateDocument( + document: Document, + fileName: string, + compilationSettings: ImmutableCompilationSettings, + scriptSnapshot: IScriptSnapshot, + version: number, + isOpen: boolean, + textChangeRange: TextChangeRange + ): TypeScript.Document; + + releaseDocument(fileName: string, compilationSettings: ImmutableCompilationSettings): void + } + + export class NonCachingDocumentRegistry implements IDocumentRegistry { + + public static Instance: IDocumentRegistry = new NonCachingDocumentRegistry(); + + public acquireDocument( + fileName: string, + compilationSettings: ImmutableCompilationSettings, + scriptSnapshot: IScriptSnapshot, + byteOrderMark: ByteOrderMark, + version: number, + isOpen: boolean, + referencedFiles: string[]= []): TypeScript.Document { + return Document.create(compilationSettings, fileName, scriptSnapshot, byteOrderMark, version, isOpen, referencedFiles); + } + + public updateDocument( + document: Document, + fileName: string, + compilationSettings: ImmutableCompilationSettings, + scriptSnapshot: IScriptSnapshot, + version: number, + isOpen: boolean, + textChangeRange: TextChangeRange + ): TypeScript.Document { + return document.update(scriptSnapshot, version, isOpen, textChangeRange); + } + + public releaseDocument(fileName: string, compilationSettings: ImmutableCompilationSettings): void { + // no op since this class doesn't cache anything + } + } + + export class DocumentRegistry implements IDocumentRegistry { + private buckets: IIndexable> = {}; + + private getKeyFromCompilationSettings(settings: ImmutableCompilationSettings): string { + return "_" + settings.propagateEnumConstants().toString() + "|" + settings.allowAutomaticSemicolonInsertion().toString() + "|" + LanguageVersion[settings.codeGenTarget()]; + } + + private getBucketForCompilationSettings(settings: ImmutableCompilationSettings, createIfMissing: boolean): StringHashTable { + var key = this.getKeyFromCompilationSettings(settings); + var bucket = this.buckets[key]; + if (!bucket && createIfMissing) { + this.buckets[key] = bucket = new StringHashTable(); + } + return bucket; + } + + public reportStats() { + var bucketInfoArray = Object.keys(this.buckets).filter(name => name && name.charAt(0) === '_').map(name => { + var entries = this.buckets[name]; + var documents = entries.getAllKeys().map((name) => { + var entry = entries.lookup(name); + return { + name: name, + refCount: entry.refCount, + references: entry.owners.slice(0) + }; + }); + documents.sort((x, y) => y.refCount - x.refCount); + return { bucket: name, documents: documents } + }); + return JSON.stringify(bucketInfoArray, null, 2); + } + + public acquireDocument( + fileName: string, + compilationSettings: ImmutableCompilationSettings, + scriptSnapshot: IScriptSnapshot, + byteOrderMark: ByteOrderMark, + version: number, + isOpen: boolean, + referencedFiles: string[]= []): TypeScript.Document { + + var bucket = this.getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ true); + var entry = bucket.lookup(fileName); + if (!entry) { + var document = Document.create(compilationSettings, fileName, scriptSnapshot, byteOrderMark, version, isOpen, referencedFiles); + + entry = new DocumentRegistryEntry(document); + bucket.add(fileName, entry); + } + entry.refCount++; + + return entry.document; + } + + public updateDocument( + document: Document, + fileName: string, + compilationSettings: ImmutableCompilationSettings, + scriptSnapshot: IScriptSnapshot, + version: number, + isOpen: boolean, + textChangeRange: TextChangeRange + ): TypeScript.Document { + + var bucket = this.getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ false); + Debug.assert(bucket); + var entry = bucket.lookup(fileName); + Debug.assert(entry); + + if (entry.document.isOpen === isOpen && entry.document.version === version) { + return entry.document; + } + + entry.document = entry.document.update(scriptSnapshot, version, isOpen, textChangeRange); + return entry.document; + } + + public releaseDocument(fileName: string, compilationSettings: ImmutableCompilationSettings): void { + var bucket = this.getBucketForCompilationSettings(compilationSettings, false); + Debug.assert(bucket); + + var entry = bucket.lookup(fileName); + entry.refCount--; + + Debug.assert(entry.refCount >= 0); + if (entry.refCount === 0) { + bucket.remove(fileName); + } + } + } + + interface IExpressionWithArgumentListSyntax extends IExpressionSyntax { + expression: IExpressionSyntax; + argumentList: ArgumentListSyntax; + } + + export class TypeScriptCompiler { + private semanticInfoChain: SemanticInfoChain = null; + + constructor(public logger: ILogger = new NullLogger(), + private _settings: ImmutableCompilationSettings = ImmutableCompilationSettings.defaultSettings()) { + this.semanticInfoChain = new SemanticInfoChain(this, logger); + } + + public getSemanticInfoChain() { + return this.semanticInfoChain; + } + + public compilationSettings(): ImmutableCompilationSettings { + return this._settings; + } + + public setCompilationSettings(newSettings: ImmutableCompilationSettings) { + var oldSettings = this._settings; + this._settings = newSettings; + + if (!compareDataObjects(oldSettings, newSettings)) { + // If our options have changed at all, we have to consider any cached semantic + // data we have invalid. + this.semanticInfoChain.invalidate(oldSettings, newSettings); + } + } + + public getDocument(fileName: string): Document { + fileName = TypeScript.switchToForwardSlashes(fileName); + return this.semanticInfoChain.getDocument(fileName); + } + + public cleanupSemanticCache(): void { + this.semanticInfoChain.invalidate(); + } + + public addOrUpdateFile(document: Document): void { + // TODO: TypeScript.sourceCharactersCompiled += document. scriptSnapshot.getLength(); + // Note: the semantic info chain will recognize that this is a replacement of an + // existing script, and will handle it appropriately. + this.semanticInfoChain.addDocument(document); + } + + public addFile( + fileName: string, + scriptSnapshot: IScriptSnapshot, + byteOrderMark: ByteOrderMark, + version: number, + isOpen: boolean, + referencedFiles: string[]= []): void { + + fileName = TypeScript.switchToForwardSlashes(fileName); + var document = Document.create(this.compilationSettings(), fileName, scriptSnapshot, byteOrderMark, version, isOpen, referencedFiles); + this.addOrUpdateFile(document); + } + + public updateFile(fileName: string, scriptSnapshot: IScriptSnapshot, version: number, isOpen: boolean, textChangeRange: TextChangeRange): void { + fileName = TypeScript.switchToForwardSlashes(fileName); + + var document = this.getDocument(fileName); + var updatedDocument = document.update(scriptSnapshot, version, isOpen, textChangeRange); + + // Note: the semantic info chain will recognize that this is a replacement of an + // existing script, and will handle it appropriately. + this.addOrUpdateFile(updatedDocument); + } + + public removeFile(fileName: string): void { + fileName = TypeScript.switchToForwardSlashes(fileName); + this.semanticInfoChain.removeDocument(fileName); + } + + public mapOutputFileName(document: Document, emitOptions: EmitOptions, extensionChanger: (fname: string, wholeFileNameReplaced: boolean) => string) { + if (document.emitToOwnOutputFile()) { + var updatedFileName = document.fileName; + if (emitOptions.outputDirectory() !== "") { + // Replace the common directory path with the option specified + updatedFileName = document.fileName.replace(emitOptions.commonDirectoryPath(), ""); + updatedFileName = emitOptions.outputDirectory() + updatedFileName; + } + return extensionChanger(updatedFileName, false); + } + else { + return extensionChanger(emitOptions.sharedOutputFile(), true); + } + } + + private writeByteOrderMarkForDocument(document: Document) { + // Set this to 'true' if you want to know why the compiler emitted a document with a + // byte order mark. + var printReason = false; + + // If module its always emitted in its own file + if (document.emitToOwnOutputFile()) { + var result = document.byteOrderMark !== ByteOrderMark.None; + if (printReason) { + Environment.standardOut.WriteLine("Emitting byte order mark because of: " + document.fileName); + } + return result; + } + else { + var fileNames = this.fileNames(); + + var result = false; + for (var i = 0, n = fileNames.length; i < n; i++) { + var document = this.getDocument(fileNames[i]); + + if (document.syntaxTree().isExternalModule()) { + // Dynamic module never contributes to the single file + continue; + } + + if (document.byteOrderMark !== ByteOrderMark.None) { + if (printReason) { + Environment.standardOut.WriteLine("Emitting byte order mark because of: " + document.fileName); + result = true; + } + else { + return true; + } + } + } + + return result; + } + } + + static mapToDTSFileName(fileName: string, wholeFileNameReplaced: boolean) { + return getDeclareFilePath(fileName); + } + + public _shouldEmit(document: Document) { + // If its already a declare file or is resident or does not contain body + return !document.isDeclareFile(); + } + + public _shouldEmitDeclarations(document: Document) { + if (!this.compilationSettings().generateDeclarationFiles()) { + return false; + } + + return this._shouldEmit(document); + } + + // Does the actual work of emittin the declarations from the provided document into the + // provided emitter. If no emitter is provided a new one is created. + private emitDocumentDeclarationsWorker( + document: Document, + emitOptions: EmitOptions, + declarationEmitter?: DeclarationEmitter): DeclarationEmitter { + + var sourceUnit = document.sourceUnit(); + Debug.assert(this._shouldEmitDeclarations(document)); + + if (declarationEmitter) { + declarationEmitter.document = document; + } + else { + var declareFileName = this.mapOutputFileName(document, emitOptions, TypeScriptCompiler.mapToDTSFileName); + declarationEmitter = new DeclarationEmitter(declareFileName, document, this, emitOptions, this.semanticInfoChain); + } + + declarationEmitter.emitDeclarations(sourceUnit); + return declarationEmitter; + } + + public _emitDocumentDeclarations( + document: Document, + emitOptions: EmitOptions, + onSingleFileEmitComplete: (files: OutputFile) => void, + sharedEmitter: DeclarationEmitter): DeclarationEmitter { + + var start = new Date().getTime(); + if (this._shouldEmitDeclarations(document)) { + if (document.emitToOwnOutputFile()) { + var singleEmitter = this.emitDocumentDeclarationsWorker(document, emitOptions); + if (singleEmitter) { + onSingleFileEmitComplete(singleEmitter.getOutputFile()); + } + } + else { + // Create or reuse file + sharedEmitter = this.emitDocumentDeclarationsWorker(document, emitOptions, sharedEmitter); + } + } + + declarationEmitTime += new Date().getTime() - start; + return sharedEmitter; + } + + // Will not throw exceptions. + public emitAllDeclarations(resolvePath: (path: string) => string): EmitOutput { + var emitOutput = new EmitOutput(); + + var emitOptions = new EmitOptions(this, resolvePath); + if (emitOptions.diagnostic()) { + emitOutput.emitOutputResult = EmitOutputResult.FailedBecauseOfCompilerOptionsErrors; + return emitOutput; + } + + var sharedEmitter: DeclarationEmitter = null; + var fileNames = this.fileNames(); + + for (var i = 0, n = fileNames.length; i < n; i++) { + var fileName = fileNames[i]; + + var document = this.getDocument(fileNames[i]); + + sharedEmitter = this._emitDocumentDeclarations(document, emitOptions, + file => emitOutput.outputFiles.push(file), sharedEmitter); + } + + if (sharedEmitter) { + emitOutput.outputFiles.push(sharedEmitter.getOutputFile()); + } + + return emitOutput; + } + + // Will not throw exceptions. + public emitDeclarations(fileName: string, resolvePath: (path: string) => string): EmitOutput { + fileName = TypeScript.switchToForwardSlashes(fileName); + var emitOutput = new EmitOutput(); + + var emitOptions = new EmitOptions(this, resolvePath); + if (emitOptions.diagnostic()) { + emitOutput.emitOutputResult = EmitOutputResult.FailedBecauseOfCompilerOptionsErrors; + return emitOutput; + } + + var document = this.getDocument(fileName); + + // Emitting module or multiple files, always goes to single file + if (document.emitToOwnOutputFile()) { + this._emitDocumentDeclarations(document, emitOptions, + file => emitOutput.outputFiles.push(file), /*sharedEmitter:*/ null); + return emitOutput; + } + else { + return this.emitAllDeclarations(resolvePath); + } + } + + public canEmitDeclarations(fileName: string) { + fileName = TypeScript.switchToForwardSlashes(fileName); + var document = this.getDocument(fileName); + return this._shouldEmitDeclarations(document); + } + + static mapToFileNameExtension(extension: string, fileName: string, wholeFileNameReplaced: boolean) { + if (wholeFileNameReplaced) { + // The complete output is redirected in this file so do not change extension + return fileName; + } + else { + // Change the extension of the file + var splitFname = fileName.split("."); + splitFname.pop(); + return splitFname.join(".") + extension; + } + } + + static mapToJSFileName(fileName: string, wholeFileNameReplaced: boolean) { + return TypeScriptCompiler.mapToFileNameExtension(".js", fileName, wholeFileNameReplaced); + } + + // Caller is responsible for closing the returned emitter. + // May throw exceptions. + private emitDocumentWorker(document: Document, emitOptions: EmitOptions, emitter?: Emitter): Emitter { + var sourceUnit = document.sourceUnit(); + Debug.assert(this._shouldEmit(document)); + + var typeScriptFileName = document.fileName; + if (!emitter) { + var javaScriptFileName = this.mapOutputFileName(document, emitOptions, TypeScriptCompiler.mapToJSFileName); + var outFile = new TextWriter(javaScriptFileName, this.writeByteOrderMarkForDocument(document), OutputFileType.JavaScript); + + emitter = new Emitter(javaScriptFileName, outFile, emitOptions, this.semanticInfoChain); + + if (this.compilationSettings().mapSourceFiles()) { + // We always create map files next to the jsFiles + var sourceMapFile = new TextWriter(javaScriptFileName + SourceMapper.MapFileExtension, /*writeByteOrderMark:*/ false, OutputFileType.SourceMap); + emitter.createSourceMapper(document, javaScriptFileName, outFile, sourceMapFile, emitOptions.resolvePath); + } + } + else if (this.compilationSettings().mapSourceFiles()) { + // Already emitting into js file, update the mapper for new source info + emitter.setSourceMapperNewSourceFile(document); + } + + // Set location info + emitter.setDocument(document); + emitter.emitJavascript(sourceUnit, /*startLine:*/false); + + return emitter; + } + + // Private. only for use by compiler or CompilerIterator + public _emitDocument( + document: Document, + emitOptions: EmitOptions, + onSingleFileEmitComplete: (files: OutputFile[]) => void, + sharedEmitter: Emitter): Emitter { + + var start = new Date().getTime(); + + // Emitting module or multiple files, always goes to single file + if (this._shouldEmit(document)) { + if (document.emitToOwnOutputFile()) { + // We're outputting to mulitple files. We don't want to reuse an emitter in that case. + var singleEmitter = this.emitDocumentWorker(document, emitOptions); + if (singleEmitter) { + onSingleFileEmitComplete(singleEmitter.getOutputFiles()); + } + } + else { + // We're not outputting to multiple files. Keep using the same emitter and don't + // close until below. + sharedEmitter = this.emitDocumentWorker(document, emitOptions, sharedEmitter); + } + } + + emitTime += new Date().getTime() - start; + return sharedEmitter; + } + + // Will not throw exceptions. + public emitAll(resolvePath: (path: string) => string): EmitOutput { + var emitOutput = new EmitOutput(); + + var emitOptions = new EmitOptions(this, resolvePath); + if (emitOptions.diagnostic()) { + emitOutput.emitOutputResult = EmitOutputResult.FailedBecauseOfCompilerOptionsErrors; + return emitOutput; + } + + var fileNames = this.fileNames(); + var sharedEmitter: Emitter = null; + + // Iterate through the files, as long as we don't get an error. + for (var i = 0, n = fileNames.length; i < n; i++) { + var fileName = fileNames[i]; + + var document = this.getDocument(fileName); + + sharedEmitter = this._emitDocument(document, emitOptions, + files => emitOutput.outputFiles.push.apply(emitOutput.outputFiles, files), + sharedEmitter); + } + + if (sharedEmitter) { + emitOutput.outputFiles.push.apply(emitOutput.outputFiles, sharedEmitter.getOutputFiles()); + } + + return emitOutput; + } + + // Emit single file if outputMany is specified, else emit all + // Will not throw exceptions. + public emit(fileName: string, resolvePath: (path: string) => string): EmitOutput { + fileName = TypeScript.switchToForwardSlashes(fileName); + var emitOutput = new EmitOutput(); + + var emitOptions = new EmitOptions(this, resolvePath); + if (emitOptions.diagnostic()) { + emitOutput.emitOutputResult = EmitOutputResult.FailedBecauseOfCompilerOptionsErrors; + return emitOutput; + } + + var document = this.getDocument(fileName); + // Emitting module or multiple files, always goes to single file + if (document.emitToOwnOutputFile()) { + this._emitDocument(document, emitOptions, + files => emitOutput.outputFiles.push.apply(emitOutput.outputFiles, files), /*sharedEmitter:*/ null); + return emitOutput; + } + else { + // In output Single file mode, emit everything + return this.emitAll(resolvePath); + } + } + + // Returns an iterator that will stream compilation results from this compiler. Syntactic + // diagnostics will be returned first, then semantic diagnostics, then emit results, then + // declaration emit results. + // + // The continueOnDiagnostics flag governs whether or not iteration follows the batch compiler + // logic and doesn't perform further analysis once diagnostics are produced. For example, + // in batch compilation nothing is done if there are any syntactic diagnostics. Clients + // can override this if they still want to procede in those cases. + public compile(resolvePath: (path: string) => string, continueOnDiagnostics = false): Iterator { + return new CompilerIterator(this, resolvePath, continueOnDiagnostics); + } + + // + // Pull typecheck infrastructure + // + + public getSyntacticDiagnostics(fileName: string): Diagnostic[] { + fileName = TypeScript.switchToForwardSlashes(fileName) + return this.getDocument(fileName).diagnostics(); + } + + /** Used for diagnostics in tests */ + private getSyntaxTree(fileName: string): SyntaxTree { + return this.getDocument(fileName).syntaxTree(); + } + + private getSourceUnit(fileName: string): SourceUnitSyntax { + return this.getDocument(fileName).sourceUnit(); + } + + public getSemanticDiagnostics(fileName: string): Diagnostic[] { + fileName = TypeScript.switchToForwardSlashes(fileName); + + var document = this.getDocument(fileName); + + var startTime = (new Date()).getTime(); + PullTypeResolver.typeCheck(this.compilationSettings(), this.semanticInfoChain, document) + var endTime = (new Date()).getTime(); + + typeCheckTime += endTime - startTime; + + var errors = this.semanticInfoChain.getDiagnostics(fileName); + + errors = ArrayUtilities.distinct(errors, Diagnostic.equals); + errors.sort((d1, d2) => { + if (d1.fileName() < d2.fileName()) { + return -1; + } + else if (d1.fileName() > d2.fileName()) { + return 1; + } + + if (d1.start() < d2.start()) { + return -1; + } + else if (d1.start() > d2.start()) { + return 1; + } + + // For multiple errors reported on the same file at the same position. + var code1 = diagnosticInformationMap[d1.diagnosticKey()].code; + var code2 = diagnosticInformationMap[d2.diagnosticKey()].code; + if (code1 < code2) { + return -1; + } + else if (code1 > code2) { + return 1; + } + + return 0; + }); + + return errors; + } + + public getCompilerOptionsDiagnostics(resolvePath: (path: string) => string): Diagnostic[] { + var emitOptions = new EmitOptions(this, resolvePath); + var emitDiagnostic = emitOptions.diagnostic(); + if (emitDiagnostic) { + return [emitDiagnostic]; + } + return sentinelEmptyArray; + } + + public resolveAllFiles() { + var fileNames = this.fileNames(); + for (var i = 0, n = fileNames.length; i < n; i++) { + this.getSemanticDiagnostics(fileNames[i]); + } + } + + public getSymbolOfDeclaration(decl: PullDecl): PullSymbol { + if (!decl) { + return null; + } + + var resolver = this.semanticInfoChain.getResolver(); + var ast = this.semanticInfoChain.getASTForDecl(decl); + if (!ast) { + return null; + } + + var enclosingDecl = resolver.getEnclosingDecl(decl); + if (ast.kind() === SyntaxKind.GetAccessor || ast.kind() === SyntaxKind.SetAccessor) { + return this.getSymbolOfDeclaration(enclosingDecl); + } + + return resolver.resolveAST(ast, /*inContextuallyTypedAssignment:*/false, new PullTypeResolutionContext(resolver)); + } + + private extractResolutionContextFromAST(resolver: PullTypeResolver, ast: ISyntaxElement, document: Document, propagateContextualTypes: boolean): { ast: ISyntaxElement; enclosingDecl: PullDecl; resolutionContext: PullTypeResolutionContext; inContextuallyTypedAssignment: boolean; inWithBlock: boolean; } { + var scriptName = document.fileName; + + var enclosingDecl: PullDecl = null; + var enclosingDeclAST: ISyntaxElement = null; + var inContextuallyTypedAssignment = false; + var inWithBlock = false; + + var resolutionContext = new PullTypeResolutionContext(resolver); + + if (!ast) { + return null; + } + + var path = this.getASTPath(ast); + + // Extract infromation from path + for (var i = 0 , n = path.length; i < n; i++) { + var current = path[i]; + + switch (current.kind()) { + case SyntaxKind.FunctionExpression: + case SyntaxKind.SimpleArrowFunctionExpression: + case SyntaxKind.ParenthesizedArrowFunctionExpression: + if (propagateContextualTypes) { + resolver.resolveAST(current, /*inContextuallyTypedAssignment*/ true, resolutionContext); + } + break; + + //case SyntaxKind.Parameter: + // var parameter = current; + // inContextuallyTypedAssignment = parameter.typeExpr !== null; + + // this.extractResolutionContextForVariable(inContextuallyTypedAssignment, propagateContextualTypes, resolver, resolutionContext, enclosingDecl, parameter, parameter.init); + // break; + + case SyntaxKind.MemberVariableDeclaration: + var memberVariable = current; + inContextuallyTypedAssignment = memberVariable.variableDeclarator.typeAnnotation !== null; + + this.extractResolutionContextForVariable(inContextuallyTypedAssignment, propagateContextualTypes, resolver, resolutionContext, enclosingDecl, memberVariable, memberVariable.variableDeclarator.equalsValueClause); + break; + + case SyntaxKind.VariableDeclarator: + var variableDeclarator = current; + inContextuallyTypedAssignment = variableDeclarator.typeAnnotation !== null; + + this.extractResolutionContextForVariable(inContextuallyTypedAssignment, propagateContextualTypes, resolver, resolutionContext, enclosingDecl, variableDeclarator, variableDeclarator.equalsValueClause); + break; + + case SyntaxKind.InvocationExpression: + case SyntaxKind.ObjectCreationExpression: + if (propagateContextualTypes) { + var isNew = current.kind() === SyntaxKind.ObjectCreationExpression; + var callExpression = current; + var contextualType: PullTypeSymbol = null; + + // Check if we are in an argumnt for a call, propagate the contextual typing + if ((i + 2 < n) && callExpression.argumentList === path[i + 1] && callExpression.argumentList.arguments === path[i + 2]) { + var callResolutionResults = new PullAdditionalCallResolutionData(); + if (isNew) { + resolver.resolveObjectCreationExpression(callExpression, resolutionContext, callResolutionResults); + } + else { + resolver.resolveInvocationExpression(callExpression, resolutionContext, callResolutionResults); + } + + // Find the index in the arguments list + if (callResolutionResults.actualParametersContextTypeSymbols) { + var argExpression = path[i + 3]; + if (argExpression) { + for (var j = 0, m = callExpression.argumentList.arguments.length; j < m; j++) { + if (callExpression.argumentList.arguments[j] === argExpression) { + var callContextualType = callResolutionResults.actualParametersContextTypeSymbols[j]; + if (callContextualType) { + contextualType = callContextualType; + break; + } + } + } + } + } + } + else { + // Just resolve the call expression + if (isNew) { + resolver.resolveObjectCreationExpression(callExpression, resolutionContext); + } + else { + resolver.resolveInvocationExpression(callExpression, resolutionContext); + } + } + + resolutionContext.pushNewContextualType(contextualType); + } + + break; + + case SyntaxKind.ArrayLiteralExpression: + if (propagateContextualTypes) { + // Propagate the child element type + var contextualType: PullTypeSymbol = null; + var currentContextualType = resolutionContext.getContextualType(); + if (currentContextualType && currentContextualType.isArrayNamedTypeReference()) { + contextualType = currentContextualType.getElementType(); + } + + resolutionContext.pushNewContextualType(contextualType); + } + + break; + + case SyntaxKind.ObjectLiteralExpression: + if (propagateContextualTypes) { + var objectLiteralExpression = current; + var objectLiteralResolutionContext = new PullAdditionalObjectLiteralResolutionData(); + resolver.resolveObjectLiteralExpression(objectLiteralExpression, inContextuallyTypedAssignment, resolutionContext, objectLiteralResolutionContext); + + // find the member in the path + var memeberAST = (path[i + 1] && path[i + 1].kind() === SyntaxKind.SeparatedList) ? path[i + 2] : path[i + 1]; + if (memeberAST) { + // Propagate the member contextual type + var contextualType: PullTypeSymbol = null; + var memberDecls = objectLiteralExpression.propertyAssignments; + if (memberDecls && objectLiteralResolutionContext.membersContextTypeSymbols) { + for (var j = 0, m = memberDecls.length; j < m; j++) { + if (memberDecls[j] === memeberAST) { + var memberContextualType = objectLiteralResolutionContext.membersContextTypeSymbols[j]; + if (memberContextualType) { + contextualType = memberContextualType; + break; + } + } + } + } + + resolutionContext.pushNewContextualType(contextualType); + } + } + + break; + + case SyntaxKind.AssignmentExpression: + if (propagateContextualTypes) { + var assignmentExpression = current; + var contextualType: PullTypeSymbol = null; + + if (path[i + 1] && path[i + 1] === assignmentExpression.right) { + // propagate the left hand side type as a contextual type + var leftType = resolver.resolveAST(assignmentExpression.left, inContextuallyTypedAssignment, resolutionContext).type; + if (leftType) { + inContextuallyTypedAssignment = true; + contextualType = leftType; + } + } + + resolutionContext.pushNewContextualType(contextualType); + } + + break; + + case SyntaxKind.CastExpression: + var castExpression = current; + if (!(i + 1 < n && path[i + 1] === castExpression.type)) { + // We are outside the cast term + if (propagateContextualTypes) { + var contextualType: PullTypeSymbol = null; + var typeSymbol = resolver.resolveAST(castExpression, inContextuallyTypedAssignment, resolutionContext).type; + + // Set the context type + if (typeSymbol) { + inContextuallyTypedAssignment = true; + contextualType = typeSymbol; + } + + resolutionContext.pushNewContextualType(contextualType); + } + } + + break; + + case SyntaxKind.ReturnStatement: + if (propagateContextualTypes) { + var returnStatement = current; + var contextualType: PullTypeSymbol = null; + + if (enclosingDecl && (enclosingDecl.kind & PullElementKind.SomeFunction)) { + var typeAnnotation = ASTHelpers.getType(enclosingDeclAST); + if (typeAnnotation) { + // The containing function has a type annotation, propagate it as the contextual type + var returnTypeSymbol = resolver.resolveTypeReference(typeAnnotation, resolutionContext); + if (returnTypeSymbol) { + inContextuallyTypedAssignment = true; + contextualType = returnTypeSymbol; + } + } + else { + // No type annotation, check if there is a contextual type enforced on the function, and propagate that + var currentContextualType = resolutionContext.getContextualType(); + if (currentContextualType && currentContextualType.isFunction()) { + var contextualSignatures = currentContextualType.kind == PullElementKind.ConstructorType + ? currentContextualType.getConstructSignatures() + : currentContextualType.getCallSignatures(); + var currentContextualTypeSignatureSymbol = contextualSignatures[0]; + var currentContextualTypeReturnTypeSymbol = currentContextualTypeSignatureSymbol.returnType; + if (currentContextualTypeReturnTypeSymbol) { + inContextuallyTypedAssignment = true; + contextualType = currentContextualTypeReturnTypeSymbol; + } + } + } + } + + resolutionContext.pushNewContextualType(contextualType); + } + + break; + + case SyntaxKind.ObjectType: + // ObjectType are just like Object Literals are bound when needed, ensure we have a decl, by forcing it to be + // resolved before descending into it. + if (propagateContextualTypes && TypeScript.isTypesOnlyLocation(current)) { + resolver.resolveAST(current, /*inContextuallyTypedAssignment*/ false, resolutionContext); + } + + break; + + case SyntaxKind.WithStatement: + inWithBlock = true; + break; + + case SyntaxKind.Block: + inContextuallyTypedAssignment = false; + break; + } + + // Record enclosing Decl + var decl = this.semanticInfoChain.getDeclForAST(current); + if (decl) { + enclosingDecl = decl; + enclosingDeclAST = current; + } + } + + // if the found ISyntaxElement is a named, we want to check for previous dotted expressions, + // since those will give us the right typing + if (ast && ast.parent && ast.kind() === SyntaxKind.IdentifierName) { + if (ast.parent.kind() === SyntaxKind.MemberAccessExpression) { + if ((ast.parent).name === ast) { + ast = ast.parent; + } + } + else if (ast.parent.kind() === SyntaxKind.QualifiedName) { + if ((ast.parent).right === ast) { + ast = ast.parent; + } + } + } + + return { + ast: ast, + enclosingDecl: enclosingDecl, + resolutionContext: resolutionContext, + inContextuallyTypedAssignment: inContextuallyTypedAssignment, + inWithBlock: inWithBlock + }; + } + + private extractResolutionContextForVariable( + inContextuallyTypedAssignment: boolean, + propagateContextualTypes: boolean, + resolver: PullTypeResolver, + resolutionContext: PullTypeResolutionContext, + enclosingDecl: PullDecl, + assigningAST: ISyntaxElement, + init: ISyntaxElement): void { + if (inContextuallyTypedAssignment) { + if (propagateContextualTypes) { + resolver.resolveAST(assigningAST, /*inContextuallyTypedAssignment*/false, resolutionContext); + var varSymbol = this.semanticInfoChain.getSymbolForAST(assigningAST); + + var contextualType: PullTypeSymbol = null; + if (varSymbol && inContextuallyTypedAssignment) { + contextualType = varSymbol.type; + } + + resolutionContext.pushNewContextualType(contextualType); + + if (init) { + resolver.resolveAST(init, inContextuallyTypedAssignment, resolutionContext); + } + } + } + } + + private getASTPath(ast: ISyntaxElement): ISyntaxElement[] { + var result: ISyntaxElement[] = []; + + while (ast) { + result.unshift(ast); + ast = ast.parent; + } + + return result; + } + + public pullGetSymbolInformationFromAST(ast: ISyntaxElement, document: Document): PullSymbolInfo { + var resolver = this.semanticInfoChain.getResolver(); + var context = this.extractResolutionContextFromAST(resolver, ast, document, /*propagateContextualTypes*/ true); + if (!context || context.inWithBlock) { + return null; + } + + ast = context.ast; + var symbol = resolver.resolveAST(ast, context.inContextuallyTypedAssignment, context.resolutionContext); + + if (!symbol) { + Debug.assert( + ast.kind() === SyntaxKind.SourceUnit, + "No symbol was found for ast and ast was not source unit. Ast Kind: " + SyntaxKind[ast.kind()] ); + return null; + } + + if (symbol.isTypeReference()) { + symbol = (symbol).getReferencedTypeSymbol(); + } + + var aliasSymbol = this.semanticInfoChain.getAliasSymbolForAST(ast); + + return { + symbol: symbol, + aliasSymbol: aliasSymbol, + ast: ast, + enclosingScopeSymbol: this.getSymbolOfDeclaration(context.enclosingDecl) + }; + } + + public pullGetCallInformationFromAST(ast: ISyntaxElement, document: Document): PullCallSymbolInfo { + // ISyntaxElement has to be a call expression + if (ast.kind() !== SyntaxKind.InvocationExpression && ast.kind() !== SyntaxKind.ObjectCreationExpression) { + return null; + } + + var isNew = ast.kind() === SyntaxKind.ObjectCreationExpression; + + var resolver = this.semanticInfoChain.getResolver(); + var context = this.extractResolutionContextFromAST(resolver, ast, document, /*propagateContextualTypes*/ true); + if (!context || context.inWithBlock) { + return null; + } + + var callResolutionResults = new PullAdditionalCallResolutionData(); + + if (isNew) { + resolver.resolveObjectCreationExpression(ast, context.resolutionContext, callResolutionResults); + } + else { + resolver.resolveInvocationExpression(ast, context.resolutionContext, callResolutionResults); + } + + return { + targetSymbol: callResolutionResults.targetSymbol, + resolvedSignatures: callResolutionResults.resolvedSignatures, + candidateSignature: callResolutionResults.candidateSignature, + ast: ast, + enclosingScopeSymbol: this.getSymbolOfDeclaration(context.enclosingDecl), + isConstructorCall: isNew + }; + } + + public pullGetVisibleMemberSymbolsFromAST(ast: ISyntaxElement, document: Document): PullVisibleSymbolsInfo { + var resolver = this.semanticInfoChain.getResolver(); + var context = this.extractResolutionContextFromAST(resolver, ast, document, /*propagateContextualTypes*/ true); + if (!context || context.inWithBlock) { + return null; + } + + var symbols = resolver.getVisibleMembersFromExpression(ast, context.enclosingDecl, context.resolutionContext); + if (!symbols) { + return null; + } + + return { + symbols: symbols, + enclosingScopeSymbol: this.getSymbolOfDeclaration(context.enclosingDecl) + }; + } + + public pullGetVisibleDeclsFromAST(ast: ISyntaxElement, document: Document): PullDecl[] { + var resolver = this.semanticInfoChain.getResolver(); + var context = this.extractResolutionContextFromAST(resolver, ast, document, /*propagateContextualTypes*/ false); + if (!context || context.inWithBlock) { + return null; + } + + return resolver.getVisibleDecls(context.enclosingDecl); + } + + public pullGetContextualMembersFromAST(ast: ISyntaxElement, document: Document): PullVisibleSymbolsInfo { + // Input has to be an object literal + if (ast.kind() !== SyntaxKind.ObjectLiteralExpression) { + return null; + } + + var resolver = this.semanticInfoChain.getResolver(); + var context = this.extractResolutionContextFromAST(resolver, ast, document, /*propagateContextualTypes*/ true); + if (!context || context.inWithBlock) { + return null; + } + + var members = resolver.getVisibleContextSymbols(context.enclosingDecl, context.resolutionContext); + + return { + symbols: members, + enclosingScopeSymbol: this.getSymbolOfDeclaration(context.enclosingDecl) + }; + } + + public pullGetDeclInformation(decl: PullDecl, ast: ISyntaxElement, document: Document): PullSymbolInfo { + var resolver = this.semanticInfoChain.getResolver(); + + // Note: we not only need to resolve down to the path the ast is at, but we also need to + // resolve the path to where the decl is at. This is because, currently, some decls + // can't fin their symbols unless they are first resolved. For example, a property of + // an object literal must be resolved before its symbol can be retrieved. + var context = this.extractResolutionContextFromAST(resolver, ast, document, /*propagateContextualTypes*/ true); + if (!context || context.inWithBlock) { + return null; + } + + var astForDecl = decl.ast(); + if (!astForDecl) { + return null; + } + + var astForDeclContext = this.extractResolutionContextFromAST( + resolver, astForDecl, this.getDocument(syntaxTree(astForDecl).fileName()), /*propagateContextualTypes*/ true); + if (!astForDeclContext) { + return null; + } + + var symbol = decl.getSymbol(this.semanticInfoChain); + resolver.resolveDeclaredSymbol(symbol, context.resolutionContext); + symbol.setUnresolved(); + + return { + symbol: symbol, + aliasSymbol: null, + ast: ast, + enclosingScopeSymbol: this.getSymbolOfDeclaration(context.enclosingDecl) + }; + } + + public topLevelDeclaration(fileName: string) : PullDecl { + return this.semanticInfoChain.topLevelDecl(fileName); + } + + public getDeclForAST(ast: ISyntaxElement): PullDecl { + return this.semanticInfoChain.getDeclForAST(ast); + } + + public fileNames(): string[] { + return this.semanticInfoChain.fileNames(); + } + + public topLevelDecl(fileName: string): PullDecl { + return this.semanticInfoChain.topLevelDecl(fileName); + } + + private static getLocationText(location: Location, resolvePath: (path: string) => string): string { + return resolvePath(location.fileName()) + "(" + (location.line() + 1) + "," + (location.character() + 1) + ")"; + } + + public static getFullDiagnosticText(diagnostic: Diagnostic, resolvePath: (path: string) => string): string { + var result = ""; + if (diagnostic.fileName()) { + result += this.getLocationText(diagnostic, resolvePath) + ": "; + } + + result += diagnostic.message(); + + var additionalLocations = diagnostic.additionalLocations(); + if (additionalLocations.length > 0) { + result += " " + getLocalizedText(DiagnosticCode.Additional_locations, null) + Environment.newLine; + + for (var i = 0, n = additionalLocations.length; i < n; i++) { + result += "\t" + this.getLocationText(additionalLocations[i], resolvePath) + Environment.newLine; + } + } + else { + result += Environment.newLine; + } + + return result; + } + } + + enum CompilerPhase { + Syntax, + Semantics, + EmitOptionsValidation, + Emit, + DeclarationEmit, + } + + class CompilerIterator implements Iterator { + private compilerPhase: CompilerPhase; + private index: number = -1; + private fileNames: string[] = null; + private _current: CompileResult = null; + private _emitOptions: EmitOptions = null; + private _sharedEmitter: Emitter = null; + private _sharedDeclarationEmitter: DeclarationEmitter = null; + private hadSyntacticDiagnostics: boolean = false; + private hadSemanticDiagnostics: boolean = false; + private hadEmitDiagnostics: boolean = false; + + constructor(private compiler: TypeScriptCompiler, + private resolvePath: (path: string) => string, + private continueOnDiagnostics: boolean, + startingPhase = CompilerPhase.Syntax) { + this.fileNames = compiler.fileNames(); + this.compilerPhase = startingPhase; + } + + public current(): CompileResult { + return this._current; + } + + public moveNext(): boolean { + this._current = null; + + // Attempt to move the iterator 'one step' forward. Note: this may produce no result + // (for example, if we're emitting everything to a single file). So only return once + // we actually have a result, or we're done enumerating. + while (this.moveNextInternal()) { + if (this._current) { + return true; + } + } + + return false; + } + + private moveNextInternal(): boolean { + this.index++; + + // If we're at the end of hte set of files the compiler knows about, then move to the + // next phase of compilation. + while (this.shouldMoveToNextPhase()) { + this.index = 0; + this.compilerPhase++; + } + + if (this.compilerPhase > CompilerPhase.DeclarationEmit) { + // We're totally done. + return false; + } + + switch (this.compilerPhase) { + case CompilerPhase.Syntax: + return this.moveNextSyntaxPhase(); + case CompilerPhase.Semantics: + return this.moveNextSemanticsPhase(); + case CompilerPhase.EmitOptionsValidation: + return this.moveNextEmitOptionsValidationPhase(); + case CompilerPhase.Emit: + return this.moveNextEmitPhase(); + case CompilerPhase.DeclarationEmit: + return this.moveNextDeclarationEmitPhase(); + } + } + + private shouldMoveToNextPhase(): boolean { + switch (this.compilerPhase) { + case CompilerPhase.EmitOptionsValidation: + // Only one step in emit validation. We're done once we do that step. + return this.index === 1; + + case CompilerPhase.Syntax: + case CompilerPhase.Semantics: + // Each of these phases are done when we've processed the last file. + return this.index === this.fileNames.length; + + case CompilerPhase.Emit: + case CompilerPhase.DeclarationEmit: + // Emitting is done when we get 'one' past the end of hte file list. This is + // because we use that step to collect the results from the shared emitter. + return this.index === (this.fileNames.length + 1); + } + + return false; + } + + private moveNextSyntaxPhase(): boolean { + Debug.assert(this.index >= 0 && this.index < this.fileNames.length); + var fileName = this.fileNames[this.index]; + + var diagnostics = this.compiler.getSyntacticDiagnostics(fileName); + if (diagnostics.length) { + if (!this.continueOnDiagnostics) { + this.hadSyntacticDiagnostics = true; + } + + this._current = CompileResult.fromDiagnostics(diagnostics); + } + + return true; + } + + private moveNextSemanticsPhase(): boolean { + // Don't move forward if there were syntax diagnostics. + if (this.hadSyntacticDiagnostics) { + return false; + } + + Debug.assert(this.index >= 0 && this.index < this.fileNames.length); + var fileName = this.fileNames[this.index]; + var diagnostics = this.compiler.getSemanticDiagnostics(fileName); + if (diagnostics.length) { + if (!this.continueOnDiagnostics) { + this.hadSemanticDiagnostics = true; + } + + this._current = CompileResult.fromDiagnostics(diagnostics); + } + + return true; + } + + private moveNextEmitOptionsValidationPhase(): boolean { + Debug.assert(!this.hadSyntacticDiagnostics); + + if (!this._emitOptions) { + this._emitOptions = new EmitOptions(this.compiler, this.resolvePath); + } + + if (this._emitOptions.diagnostic()) { + if (!this.continueOnDiagnostics) { + this.hadEmitDiagnostics = true; + } + + this._current = CompileResult.fromDiagnostics([this._emitOptions.diagnostic()]); + } + + return true; + } + + private moveNextEmitPhase(): boolean { + Debug.assert(!this.hadSyntacticDiagnostics); + Debug.assert(this._emitOptions); + + if (this.hadEmitDiagnostics) { + return false; + } + + Debug.assert(this.index >= 0 && this.index <= this.fileNames.length); + if (this.index < this.fileNames.length) { + var fileName = this.fileNames[this.index]; + var document = this.compiler.getDocument(fileName); + + // Try to emit this single document. It will either get emitted to its own file + // (in which case we'll have our call back triggered), or it will get added to the + // shared emitter (and we'll take care of it after all the files are done. + this._sharedEmitter = this.compiler._emitDocument( + document, this._emitOptions, + outputFiles => { this._current = CompileResult.fromOutputFiles(outputFiles) }, + this._sharedEmitter); + return true; + } + + // If we've moved past all the files, and we have a multi-input->single-output + // emitter set up. Then add the outputs of that emitter to the results. + if (this.index === this.fileNames.length && this._sharedEmitter) { + // Collect shared emit result. + this._current = CompileResult.fromOutputFiles(this._sharedEmitter.getOutputFiles()); + } + + return true; + } + + private moveNextDeclarationEmitPhase(): boolean { + Debug.assert(!this.hadSyntacticDiagnostics); + Debug.assert(!this.hadEmitDiagnostics); + if (this.hadSemanticDiagnostics) { + return false; + } + + if (!this.compiler.compilationSettings().generateDeclarationFiles()) { + return false; + } + + Debug.assert(this.index >= 0 && this.index <= this.fileNames.length); + if (this.index < this.fileNames.length) { + var fileName = this.fileNames[this.index]; + var document = this.compiler.getDocument(fileName); + + this._sharedDeclarationEmitter = this.compiler._emitDocumentDeclarations( + document, this._emitOptions, + file => { this._current = CompileResult.fromOutputFiles([file]); }, + this._sharedDeclarationEmitter); + return true; + } + + // If we've moved past all the files, and we have a multi-input->single-output + // emitter set up. Then add the outputs of that emitter to the results. + if (this.index === this.fileNames.length && this._sharedDeclarationEmitter) { + this._current = CompileResult.fromOutputFiles([this._sharedDeclarationEmitter.getOutputFile()]); + } + + return true; + } + } + + export function compareDataObjects(dst: any, src: any): boolean { + for (var e in dst) { + if (typeof dst[e] === "object") { + if (!compareDataObjects(dst[e], src[e])) + return false; + } + else if (typeof dst[e] !== "function") { + if (dst[e] !== src[e]) + return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/src/services/compiler/walkContext.ts b/src/services/compiler/walkContext.ts new file mode 100644 index 00000000000..0d08f9af8b2 --- /dev/null +++ b/src/services/compiler/walkContext.ts @@ -0,0 +1,31 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module Tools { + export interface IWalkContext { + goChildren: boolean; + goNextSibling: boolean; + // visit siblings in reverse execution order + reverseSiblings: boolean; + } + + export class BaseWalkContext implements IWalkContext { + public goChildren = true; + public goNextSibling = true; + public reverseSiblings = false; + } +} \ No newline at end of file diff --git a/src/services/compilerState.ts b/src/services/compilerState.ts new file mode 100644 index 00000000000..a4d31494af7 --- /dev/null +++ b/src/services/compilerState.ts @@ -0,0 +1,472 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +/// + +module TypeScript.Services { + // Information about a specific host file. + class HostFileInformation { + private _sourceText: TypeScript.IScriptSnapshot; + + constructor( + public fileName: string, + private host: ILanguageServiceHost, + public version: number, + public isOpen: boolean, + public byteOrderMark: TypeScript.ByteOrderMark) { + this._sourceText = null; + } + + public getScriptSnapshot(): TypeScript.IScriptSnapshot { + if (this._sourceText === null) { + this._sourceText = this.host.getScriptSnapshot(this.fileName); + } + + return this._sourceText; + } + } + + // Cache host information about scripts. Should be refreshed + // at each language service public entry point, since we don't know when + // set of scripts handled by the host changes. + class HostCache { + private _fileNameToEntry: TypeScript.StringHashTable; + private _compilationSettings: TypeScript.ImmutableCompilationSettings; + + constructor(host: ILanguageServiceHost) { + // script id => script index + this._fileNameToEntry = new TypeScript.StringHashTable(); + + var fileNames = host.getScriptFileNames(); + for (var i = 0, n = fileNames.length; i < n; i++) { + var fileName = fileNames[i]; + this._fileNameToEntry.add(TypeScript.switchToForwardSlashes(fileName), new HostFileInformation( + fileName, host, host.getScriptVersion(fileName), host.getScriptIsOpen(fileName), host.getScriptByteOrderMark(fileName))); + } + + var settings = host.getCompilationSettings(); + if (!settings) { + // Set "ES5" target by default for language service + settings = new TypeScript.CompilationSettings(); + settings.codeGenTarget = TypeScript.LanguageVersion.EcmaScript5; + } + + this._compilationSettings = TypeScript.ImmutableCompilationSettings.fromCompilationSettings(settings); + } + + public compilationSettings() { + return this._compilationSettings; + } + + public contains(fileName: string): boolean { + return this._fileNameToEntry.lookup(TypeScript.switchToForwardSlashes(fileName)) !== null; + } + + public getHostFileName(fileName: string) { + var hostCacheEntry = this._fileNameToEntry.lookup(TypeScript.switchToForwardSlashes(fileName)); + if (hostCacheEntry) { + return hostCacheEntry.fileName; + } + return fileName; + } + + public getFileNames(): string[]{ + return this._fileNameToEntry.getAllKeys(); + } + + public getVersion(fileName: string): number { + return this._fileNameToEntry.lookup(TypeScript.switchToForwardSlashes(fileName)).version; + } + + public isOpen(fileName: string): boolean { + return this._fileNameToEntry.lookup(TypeScript.switchToForwardSlashes(fileName)).isOpen; + } + + public getByteOrderMark(fileName: string): TypeScript.ByteOrderMark { + return this._fileNameToEntry.lookup(TypeScript.switchToForwardSlashes(fileName)).byteOrderMark; + } + + public getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot { + return this._fileNameToEntry.lookup(TypeScript.switchToForwardSlashes(fileName)).getScriptSnapshot(); + } + + public getScriptTextChangeRangeSinceVersion(fileName: string, lastKnownVersion: number): TypeScript.TextChangeRange { + var currentVersion = this.getVersion(fileName); + if (lastKnownVersion === currentVersion) { + return TypeScript.TextChangeRange.unchanged; // "No changes" + } + + var scriptSnapshot = this.getScriptSnapshot(fileName); + return scriptSnapshot.getTextChangeRangeSinceVersion(lastKnownVersion); + } + } + + export class SyntaxTreeCache { + private _hostCache: HostCache; + + // For our syntactic only features, we also keep a cache of the syntax tree for the + // currently edited file. + private _currentFileName: string = ""; + private _currentFileVersion: number = -1; + private _currentFileSyntaxTree: TypeScript.SyntaxTree = null; + private _currentFileScriptSnapshot: TypeScript.IScriptSnapshot = null; + + constructor(private _host: ILanguageServiceHost) { + this._hostCache = new HostCache(_host); + } + + public getCurrentFileSyntaxTree(fileName: string): TypeScript.SyntaxTree { + this._hostCache = new HostCache(this._host); + + var version = this._hostCache.getVersion(fileName); + var syntaxTree: TypeScript.SyntaxTree = null; + + if (this._currentFileSyntaxTree === null || this._currentFileName !== fileName) { + var scriptSnapshot = this._hostCache.getScriptSnapshot(fileName); + syntaxTree = this.createSyntaxTree(fileName, scriptSnapshot); + } + else if (this._currentFileVersion !== version) { + var scriptSnapshot = this._hostCache.getScriptSnapshot(fileName); + syntaxTree = this.updateSyntaxTree(fileName, scriptSnapshot, this._currentFileSyntaxTree, this._currentFileVersion); + } + + if (syntaxTree !== null) { + // All done, ensure state is up to date + this._currentFileScriptSnapshot = scriptSnapshot; + this._currentFileVersion = version; + this._currentFileName = fileName; + this._currentFileSyntaxTree = syntaxTree; + } + + return this._currentFileSyntaxTree; + } + + private createSyntaxTree(fileName: string, scriptSnapshot: TypeScript.IScriptSnapshot): TypeScript.SyntaxTree { + var text = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot); + + // For the purposes of features that use this syntax tree, we can just use the default + // compilation settings. The features only use the syntax (and not the diagnostics), + // and the syntax isn't affected by the compilation settings. + var syntaxTree = TypeScript.Parser.parse(fileName, text, + TypeScript.ImmutableCompilationSettings.defaultSettings().codeGenTarget(), TypeScript.isDTSFile(fileName)); + + return syntaxTree; + } + + private updateSyntaxTree(fileName: string, scriptSnapshot: TypeScript.IScriptSnapshot, previousSyntaxTree: TypeScript.SyntaxTree, previousFileVersion: number): TypeScript.SyntaxTree { + var editRange = this._hostCache.getScriptTextChangeRangeSinceVersion(fileName, previousFileVersion); + + // Debug.assert(newLength >= 0); + + // The host considers the entire buffer changed. So parse a completely new tree. + if (editRange === null) { + return this.createSyntaxTree(fileName, scriptSnapshot); + } + + var nextSyntaxTree = IncrementalParser.parse( + previousSyntaxTree, editRange, SimpleText.fromScriptSnapshot(scriptSnapshot)); + + this.ensureInvariants(fileName, editRange, nextSyntaxTree, this._currentFileScriptSnapshot, scriptSnapshot); + + return nextSyntaxTree; + } + + private ensureInvariants(fileName: string, editRange: TypeScript.TextChangeRange, incrementalTree: TypeScript.SyntaxTree, oldScriptSnapshot: TypeScript.IScriptSnapshot, newScriptSnapshot: TypeScript.IScriptSnapshot) { + // First, verify that the edit range and the script snapshots make sense. + + // If this fires, then the edit range is completely bogus. Somehow the lengths of the + // old snapshot, the change range and the new snapshot aren't in sync. This is very + // bad. + var expectedNewLength = oldScriptSnapshot.getLength() - editRange.span().length() + editRange.newLength(); + var actualNewLength = newScriptSnapshot.getLength(); + + function provideMoreDebugInfo() { + + var debugInformation = ["expected length:", expectedNewLength, "and actual length:", actualNewLength, "are not equal\r\n"]; + + var oldSpan = editRange.span(); + + function prettyPrintString(s: string): string { + return '"' + s.replace(/\r/g, '\\r').replace(/\n/g, '\\n') + '"'; + } + + debugInformation.push('Edit range (old text) (start: ' + oldSpan.start() + ', end: ' + oldSpan.end() + ') \r\n'); + debugInformation.push('Old text edit range contents: ' + prettyPrintString(oldScriptSnapshot.getText(oldSpan.start(), oldSpan.end()))); + + var newSpan = editRange.newSpan(); + + debugInformation.push('Edit range (new text) (start: ' + newSpan.start() + ', end: ' + newSpan.end() + ') \r\n'); + debugInformation.push('New text edit range contents: ' + prettyPrintString(newScriptSnapshot.getText(newSpan.start(), newSpan.end()))); + + return debugInformation.join(' '); + } + + Debug.assert( + expectedNewLength === actualNewLength, + "Expected length is different from actual!", + provideMoreDebugInfo); + + if (Debug.shouldAssert(AssertionLevel.VeryAggressive)) { + // If this fires, the text change range is bogus. It says the change starts at point + // 'X', but we can see a text difference *before* that point. + var oldPrefixText = oldScriptSnapshot.getText(0, editRange.span().start()); + var newPrefixText = newScriptSnapshot.getText(0, editRange.span().start()); + Debug.assert(oldPrefixText === newPrefixText, 'Expected equal prefix texts!'); + + // If this fires, the text change range is bogus. It says the change goes only up to + // point 'X', but we can see a text difference *after* that point. + var oldSuffixText = oldScriptSnapshot.getText(editRange.span().end(), oldScriptSnapshot.getLength()); + var newSuffixText = newScriptSnapshot.getText(editRange.newSpan().end(), newScriptSnapshot.getLength()); + Debug.assert(oldSuffixText === newSuffixText, 'Expected equal suffix texts!'); + + // Ok, text change range and script snapshots look ok. Let's verify that our + // incremental parsing worked properly. + //var normalTree = this.createSyntaxTree(fileName, newScriptSnapshot); + //Debug.assert(normalTree.structuralEquals(incrementalTree), 'Expected equal incremental and normal trees'); + + // Ok, the trees looked good. So at least our incremental parser agrees with the + // normal parser. Now, verify that the incremental tree matches the contents of the + // script snapshot. + var incrementalTreeText = fullText(incrementalTree.sourceUnit()); + var actualSnapshotText = newScriptSnapshot.getText(0, newScriptSnapshot.getLength()); + Debug.assert(incrementalTreeText === actualSnapshotText, 'Expected full texts to be equal'); + } + } + } + + export class LanguageServiceCompiler { + private logger: TypeScript.ILogger; + + // The underlying typescript compiler we defer most operations to. + private compiler: TypeScript.TypeScriptCompiler = null; + + // A cache of all the information about the files on the host side. + private hostCache: HostCache = null; + + constructor(private host: ILanguageServiceHost, private documentRegistry: IDocumentRegistry, private cancellationToken: CancellationToken) { + this.logger = this.host; + } + + private synchronizeHostData(): void { + TypeScript.timeFunction(this.logger, "synchronizeHostData()", () => { + this.synchronizeHostDataWorker(); + }); + } + + private synchronizeHostDataWorker(): void { + // Reset the cache at start of every refresh + this.hostCache = new HostCache(this.host); + + var compilationSettings = this.hostCache.compilationSettings(); + + // If we don't have a compiler, then create a new one. + if (this.compiler === null) { + this.compiler = new TypeScript.TypeScriptCompiler(this.logger, compilationSettings); + } + + var oldSettings = this.compiler.compilationSettings(); + + var changesInCompilationSettingsAffectSyntax = + oldSettings && compilationSettings && !compareDataObjects(oldSettings, compilationSettings) && settingsChangeAffectsSyntax(oldSettings, compilationSettings); + + // let the compiler know about the current compilation settings. + this.compiler.setCompilationSettings(compilationSettings); + + // Now, remove any files from the compiler that are no longer in the host. + var compilerFileNames = this.compiler.fileNames(); + + for (var i = 0, n = compilerFileNames.length; i < n; i++) { + + this.cancellationToken.throwIfCancellationRequested(); + + var fileName = compilerFileNames[i]; + + if (!this.hostCache.contains(fileName) || changesInCompilationSettingsAffectSyntax) { + this.compiler.removeFile(fileName); + this.documentRegistry.releaseDocument(fileName, oldSettings); + } + } + + // Now, for every file the host knows about, either add the file (if the compiler + // doesn't know about it.). Or notify the compiler about any changes (if it does + // know about it.) + var hostFileNames = this.hostCache.getFileNames(); + + for (var i = 0, n = hostFileNames.length; i < n; i++) { + var fileName = hostFileNames[i]; + + var version = this.hostCache.getVersion(fileName); + var isOpen = this.hostCache.isOpen(fileName); + var scriptSnapshot = this.hostCache.getScriptSnapshot(fileName); + + var document: Document = this.compiler.getDocument(fileName) + if (document) { + // + // If the document is the same, assume no update + // + if (document.version === version && document.isOpen === isOpen) { + continue; + } + + // Only perform incremental parsing on open files that are being edited. If a file was + // open, but is now closed, we want to reparse entirely so we don't have any tokens that + // are holding onto expensive script snapshot instances on the host. Similarly, if a + // file was closed, then we always want to reparse. This is so our tree doesn't keep + // the old buffer alive that represented the file on disk (as the host has moved to a + // new text buffer). + var textChangeRange: TextChangeRange = null; + if (document.isOpen && isOpen) { + textChangeRange = this.hostCache.getScriptTextChangeRangeSinceVersion(fileName, document.version); + } + + document = this.documentRegistry.updateDocument(document, fileName, compilationSettings, scriptSnapshot, version, isOpen, textChangeRange); + } + else { + document = this.documentRegistry.acquireDocument(fileName, compilationSettings, scriptSnapshot, this.hostCache.getByteOrderMark(fileName), version, isOpen, []); + } + + this.compiler.addOrUpdateFile(document); + } + } + + // Methods that defer to the host cache to get the result. + + public getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot { + this.synchronizeHostData(); + return this.hostCache.getScriptSnapshot(fileName); + } + + // Methods that does not require updating the host cache information + public getCachedHostFileName(fileName: string) { + if (!this.hostCache) { + this.synchronizeHostData(); + } + + return this.hostCache.getHostFileName(fileName); + } + + public getCachedTopLevelDeclaration(fileName: string) { + if (!this.hostCache) { + this.synchronizeHostData(); + } + + return this.compiler.topLevelDeclaration(fileName); + } + + // Methods that defer to the compiler to get the result. + + public compilationSettings(): TypeScript.ImmutableCompilationSettings { + this.synchronizeHostData(); + return this.compiler.compilationSettings(); + } + + public fileNames(): string[] { + this.synchronizeHostData(); + return this.compiler.fileNames(); + } + + public cleanupSemanticCache(): void { + this.compiler.cleanupSemanticCache(); + } + + public getDocument(fileName: string): TypeScript.Document { + this.synchronizeHostData(); + return this.compiler.getDocument(fileName); + } + + public getSemanticInfoChain(): SemanticInfoChain { + this.synchronizeHostData(); + return this.compiler.getSemanticInfoChain(); + } + + public getSyntacticDiagnostics(fileName: string): TypeScript.Diagnostic[] { + this.synchronizeHostData(); + return this.compiler.getSyntacticDiagnostics(fileName); + } + + public getSemanticDiagnostics(fileName: string): TypeScript.Diagnostic[] { + this.synchronizeHostData(); + return this.compiler.getSemanticDiagnostics(fileName); + } + + public getCompilerOptionsDiagnostics(resolvePath: (path: string) => string): TypeScript.Diagnostic[] { + this.synchronizeHostData(); + return this.compiler.getCompilerOptionsDiagnostics(resolvePath); + } + + public getSymbolInformationFromAST(ast: TypeScript.ISyntaxElement, document: TypeScript.Document) { + this.synchronizeHostData(); + return this.compiler.pullGetSymbolInformationFromAST(ast, document); + } + + public getCallInformationFromAST(ast: TypeScript.ISyntaxElement, document: TypeScript.Document) { + this.synchronizeHostData(); + return this.compiler.pullGetCallInformationFromAST(ast, document); + } + + public getVisibleMemberSymbolsFromAST(ast: TypeScript.ISyntaxElement, document: TypeScript.Document) { + this.synchronizeHostData(); + return this.compiler.pullGetVisibleMemberSymbolsFromAST(ast, document); + } + + public getVisibleDeclsFromAST(ast: TypeScript.ISyntaxElement, document: TypeScript.Document) { + this.synchronizeHostData(); + return this.compiler.pullGetVisibleDeclsFromAST(ast, document); + } + + public getContextualMembersFromAST(ast: TypeScript.ISyntaxElement, document: TypeScript.Document) { + this.synchronizeHostData(); + return this.compiler.pullGetContextualMembersFromAST(ast, document); + } + + public pullGetDeclInformation(decl: TypeScript.PullDecl, ast: TypeScript.ISyntaxElement, document: TypeScript.Document) { + this.synchronizeHostData(); + return this.compiler.pullGetDeclInformation(decl, ast, document); + } + + public topLevelDeclaration(fileName: string) { + this.synchronizeHostData(); + return this.compiler.topLevelDeclaration(fileName); + } + + public getDeclForAST(ast: TypeScript.ISyntaxElement): TypeScript.PullDecl { + this.synchronizeHostData(); + return this.compiler.getDeclForAST(ast); + } + + public emit(fileName: string, resolvePath: (path: string) => string): TypeScript.EmitOutput { + this.synchronizeHostData(); + return this.compiler.emit(fileName, resolvePath); + } + + public emitDeclarations(fileName: string, resolvePath: (path: string) => string): TypeScript.EmitOutput { + this.synchronizeHostData(); + return this.compiler.emitDeclarations(fileName, resolvePath); + } + + public canEmitDeclarations(fileName: string) { + this.synchronizeHostData(); + return this.compiler.canEmitDeclarations(fileName); + } + + public dispose(): void { + if (this.compiler) { + var fileNames = this.compiler.fileNames(); + for (var i = 0; i < fileNames.length; ++i) { + this.documentRegistry.releaseDocument(fileNames[i], this.compiler.compilationSettings()); + } + } + } + } +} diff --git a/src/services/completionHelpers.ts b/src/services/completionHelpers.ts new file mode 100644 index 00000000000..c5cb961af79 --- /dev/null +++ b/src/services/completionHelpers.ts @@ -0,0 +1,193 @@ +// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0. +// See LICENSE.txt in the project root for complete license information. + +/// + +module TypeScript.Services { + export class CompletionHelpers { + private static getSpan(ast: ISyntaxElement): TextSpan { + return new TextSpan(start(ast), width(ast)); + } + + private static symbolDeclarationIntersectsPosition(symbol: PullSymbol, fileName: string, position: number) { + var decl = symbol.getDeclarations()[0]; + if (decl.fileName() === fileName && this.getSpan(decl.ast()).intersectsWithPosition(position)) { + // This is the symbol declaration from the given position in the file + return true; + } + + return false; + } + + public static filterContextualMembersList(contextualMemberSymbols: TypeScript.PullSymbol[], existingMembers: TypeScript.PullVisibleSymbolsInfo, fileName: string, position: number): TypeScript.PullSymbol[] { + if (!existingMembers || !existingMembers.symbols || existingMembers.symbols.length === 0) { + return contextualMemberSymbols; + } + + var existingMemberSymbols = existingMembers.symbols; + var existingMemberNames = TypeScript.createIntrinsicsObject(); + for (var i = 0, n = existingMemberSymbols.length; i < n; i++) { + if (this.symbolDeclarationIntersectsPosition(existingMemberSymbols[i], fileName, position)) { + // If this is the current item we are editing right now, do not filter it out + continue; + } + + existingMemberNames[TypeScript.stripStartAndEndQuotes(existingMemberSymbols[i].getDisplayName())] = true; + } + + var filteredMembers: TypeScript.PullSymbol[] = []; + for (var j = 0, m = contextualMemberSymbols.length; j < m; j++) { + var contextualMemberSymbol = contextualMemberSymbols[j]; + if (!existingMemberNames[TypeScript.stripStartAndEndQuotes(contextualMemberSymbol.getDisplayName())]) { + if (this.symbolDeclarationIntersectsPosition(contextualMemberSymbol, fileName, position)) { + // If this contextual member symbol was created as part of editing the current position, do not use it + continue; + } + filteredMembers.push(contextualMemberSymbol); + } + } + + return filteredMembers; + } + + public static isCompletionListBlocker(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean { + // We shouldn't be getting a possition that is outside the file because + // isEntirelyInsideComment can't handle when the position is out of bounds, + // callers should be fixed, however we should be resiliant to bad inputs + // so we return true (this position is a blocker for getting completions) + if (position < 0 || position > fullWidth(sourceUnit)) { + return true; + } + + // This method uses Fidelity completely. Some information can be reached using the AST, but not everything. + return TypeScript.Syntax.isEntirelyInsideComment(sourceUnit, position) || + TypeScript.Syntax.isEntirelyInStringOrRegularExpressionLiteral(sourceUnit, position) || + CompletionHelpers.isIdentifierDefinitionLocation(sourceUnit, position) || + CompletionHelpers.isRightOfIllegalDot(sourceUnit, position); + } + + public static getContainingObjectLiteralApplicableForCompletion(sourceUnit: TypeScript.SourceUnitSyntax, position: number): TypeScript.ISyntaxElement { + // The locations in an object literal expression that are applicable for completion are property name definition locations. + var previousToken = CompletionHelpers.getNonIdentifierCompleteTokenOnLeft(sourceUnit, position); + + if (previousToken) { + var parent = previousToken.parent; + + switch (previousToken.kind()) { + case TypeScript.SyntaxKind.OpenBraceToken: // var x = { | + case TypeScript.SyntaxKind.CommaToken: // var x = { a: 0, | + if (parent && parent.kind() === TypeScript.SyntaxKind.SeparatedList) { + parent = parent.parent; + } + + if (parent && parent.kind() === TypeScript.SyntaxKind.ObjectLiteralExpression) { + return parent; + } + + break; + } + } + + return null; + } + + public static isIdentifierDefinitionLocation(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean { + var positionedToken = CompletionHelpers.getNonIdentifierCompleteTokenOnLeft(sourceUnit, position); + + if (positionedToken) { + var containingNodeKind = Syntax.containingNode(positionedToken) && Syntax.containingNode(positionedToken).kind(); + switch (positionedToken.kind()) { + case TypeScript.SyntaxKind.CommaToken: + return containingNodeKind === TypeScript.SyntaxKind.ParameterList || + containingNodeKind === TypeScript.SyntaxKind.VariableDeclaration || + containingNodeKind === TypeScript.SyntaxKind.EnumDeclaration; // enum { foo, | + + case TypeScript.SyntaxKind.OpenParenToken: + return containingNodeKind === TypeScript.SyntaxKind.ParameterList || + containingNodeKind === TypeScript.SyntaxKind.CatchClause; + + case TypeScript.SyntaxKind.OpenBraceToken: + return containingNodeKind === TypeScript.SyntaxKind.EnumDeclaration; // enum { | + + case TypeScript.SyntaxKind.PublicKeyword: + case TypeScript.SyntaxKind.PrivateKeyword: + case TypeScript.SyntaxKind.StaticKeyword: + case TypeScript.SyntaxKind.DotDotDotToken: + return containingNodeKind === TypeScript.SyntaxKind.Parameter; + + case TypeScript.SyntaxKind.ClassKeyword: + case TypeScript.SyntaxKind.ModuleKeyword: + case TypeScript.SyntaxKind.EnumKeyword: + case TypeScript.SyntaxKind.InterfaceKeyword: + case TypeScript.SyntaxKind.FunctionKeyword: + case TypeScript.SyntaxKind.VarKeyword: + case TypeScript.SyntaxKind.GetKeyword: + case TypeScript.SyntaxKind.SetKeyword: + return true; + } + + // Previous token may have been a keyword that was converted to an identifier. + switch (positionedToken.text()) { + case "class": + case "interface": + case "enum": + case "module": + return true; + } + } + + return false; + } + + public static getNonIdentifierCompleteTokenOnLeft(sourceUnit: TypeScript.SourceUnitSyntax, position: number): TypeScript.ISyntaxToken { + var positionedToken = Syntax.findCompleteTokenOnLeft(sourceUnit, position, /*includeSkippedTokens*/true); + + if (positionedToken && position === end(positionedToken) && positionedToken.kind() == TypeScript.SyntaxKind.EndOfFileToken) { + // EndOfFile token is not intresting, get the one before it + positionedToken = previousToken(positionedToken, /*includeSkippedTokens*/true); + } + + if (positionedToken && position === end(positionedToken) && positionedToken.kind() === TypeScript.SyntaxKind.IdentifierName) { + // The caret is at the end of an identifier, the decession to provide completion depends on the previous token + positionedToken = previousToken(positionedToken, /*includeSkippedTokens*/true); + } + + return positionedToken; + } + + public static isRightOfIllegalDot(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean { + var positionedToken = CompletionHelpers.getNonIdentifierCompleteTokenOnLeft(sourceUnit, position); + + if (positionedToken) { + switch (positionedToken.kind()) { + case TypeScript.SyntaxKind.DotToken: + var leftOfDotPositionedToken = previousToken(positionedToken, /*includeSkippedTokens*/true); + return leftOfDotPositionedToken && leftOfDotPositionedToken.kind() === TypeScript.SyntaxKind.NumericLiteral; + + case TypeScript.SyntaxKind.NumericLiteral: + var text = positionedToken.text(); + return text.charAt(text.length - 1) === "."; + } + } + + return false; + } + + public static getValidCompletionEntryDisplayName(displayName: string): string { + if (displayName && displayName.length > 0) { + var firstChar = displayName.charCodeAt(0); + if (firstChar === TypeScript.CharacterCodes.singleQuote || firstChar === TypeScript.CharacterCodes.doubleQuote) { + // If the user entered name for the symbol was quoted, removing the quotes is not enough, as the name could be an + // invalid identifer name. We need to check if whatever was inside the quotes is actually a valid identifier name. + displayName = TypeScript.stripStartAndEndQuotes(displayName); + } + + if (TypeScript.Scanner.isValidIdentifier(TypeScript.SimpleText.fromString(displayName), TypeScript.LanguageVersion.EcmaScript5)) { + return displayName; + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/src/services/completionSession.ts b/src/services/completionSession.ts new file mode 100644 index 00000000000..6cc985fa658 --- /dev/null +++ b/src/services/completionSession.ts @@ -0,0 +1,68 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +/// + +module TypeScript.Services { + + export interface CachedCompletionEntryDetails extends CompletionEntryDetails{ + isResolved(): boolean; + } + + export class ResolvedCompletionEntry implements CachedCompletionEntryDetails { + constructor(public name: string, + public kind: string, + public kindModifiers: string, + public type: string, + public fullSymbolName: string, + public docComment: string) { + } + + public isResolved(): boolean { + return true; + } + } + + export class DeclReferenceCompletionEntry implements CachedCompletionEntryDetails { + public type: string = null; + public fullSymbolName: string = null; + public docComment: string = null; + + private hasBeenResolved = false; + + constructor(public name: string, + public kind: string, + public kindModifiers: string, + public decl: TypeScript.PullDecl) { + } + + public isResolved(): boolean { + return this.hasBeenResolved; + } + + public resolve(type: string, fullSymbolName: string, docComments: string) { + this.type = type; + this.fullSymbolName = fullSymbolName; + this.docComment = docComments; + this.hasBeenResolved = true; + } + } + + export class CompletionSession { + constructor(public fileName: string, + public position: number, + public entries: TypeScript.IdentiferNameHashTable) { + } + } +} \ No newline at end of file diff --git a/src/services/core/arrayUtilities.ts b/src/services/core/arrayUtilities.ts new file mode 100644 index 00000000000..4bfec137664 --- /dev/null +++ b/src/services/core/arrayUtilities.ts @@ -0,0 +1,205 @@ +/// + +module TypeScript { + export class ArrayUtilities { + public static sequenceEquals(array1: T[], array2: T[], equals: (v1: T, v2: T) => boolean) { + if (array1 === array2) { + return true; + } + + if (array1 === null || array2 === null) { + return false; + } + + if (array1.length !== array2.length) { + return false; + } + + for (var i = 0, n = array1.length; i < n; i++) { + if (!equals(array1[i], array2[i])) { + return false; + } + } + + return true; + } + + public static contains(array: T[], value: T): boolean { + for (var i = 0; i < array.length; i++) { + if (array[i] === value) { + return true; + } + } + + return false; + } + + // Gets unique element array + public static distinct(array: T[], equalsFn?: (a: T, b: T) => boolean): T[] { + var result: T[] = []; + + // TODO: use map when available + for (var i = 0, n = array.length; i < n; i++) { + var current = array[i]; + for (var j = 0; j < result.length; j++) { + if (equalsFn(result[j], current)) { + break; + } + } + + if (j === result.length) { + result.push(current); + } + } + + return result; + } + + public static last(array: T[]): T { + if (array.length === 0) { + throw Errors.argumentOutOfRange('array'); + } + + return array[array.length - 1]; + } + + public static lastOrDefault(array: T[], predicate: (v: T, index: number) => boolean): T { + for (var i = array.length - 1; i >= 0; i--) { + var v = array[i]; + if (predicate(v, i)) { + return v; + } + } + + return null; + } + + public static firstOrDefault(array: T[], func: (v: T, index: number) => boolean): T { + for (var i = 0, n = array.length; i < n; i++) { + var value = array[i]; + if (func(value, i)) { + return value; + } + } + + return null; + } + + public static first(array: T[], func?: (v: T, index: number) => boolean): T { + for (var i = 0, n = array.length; i < n; i++) { + var value = array[i]; + if (!func || func(value, i)) { + return value; + } + } + + throw Errors.invalidOperation(); + } + + public static sum(array: T[], func: (v: T) => number): number { + var result = 0; + + for (var i = 0, n = array.length; i < n; i++) { + result += func(array[i]); + } + + return result; + } + + public static select(values: T[], func: (v: T) => S): S[] { + var result: S[] = new Array(values.length); + + for (var i = 0; i < values.length; i++) { + result[i] = func(values[i]); + } + + return result; + } + + public static where(values: T[], func: (v: T) => boolean): T[] { + var result = new Array(); + + for (var i = 0; i < values.length; i++) { + if (func(values[i])) { + result.push(values[i]); + } + } + + return result; + } + + public static any(array: T[], func: (v: T) => boolean): boolean { + for (var i = 0, n = array.length; i < n; i++) { + if (func(array[i])) { + return true; + } + } + + return false; + } + + public static all(array: T[], func: (v: T) => boolean): boolean { + for (var i = 0, n = array.length; i < n; i++) { + if (!func(array[i])) { + return false; + } + } + + return true; + } + + public static binarySearch(array: number[], value: number): number { + var low = 0; + var high = array.length - 1; + + while (low <= high) { + var middle = low + ((high - low) >> 1); + var midValue = array[middle]; + + if (midValue === value) { + return middle; + } + else if (midValue > value) { + high = middle - 1; + } + else { + low = middle + 1; + } + } + + return ~low; + } + + public static createArray(length: number, defaultValue: any): T[] { + var result = new Array(length); + for (var i = 0; i < length; i++) { + result[i] = defaultValue; + } + + return result; + } + + public static grow(array: T[], length: number, defaultValue: T): void { + var count = length - array.length; + for (var i = 0; i < count; i++) { + array.push(defaultValue); + } + } + + public static copy(sourceArray: T[], sourceIndex: number, destinationArray: T[], destinationIndex: number, length: number): void { + for (var i = 0; i < length; i++) { + destinationArray[destinationIndex + i] = sourceArray[sourceIndex + i]; + } + } + + public static indexOf(array: T[], predicate: (v: T) => boolean): number { + for (var i = 0, n = array.length; i < n; i++) { + if (predicate(array[i])) { + return i; + } + } + + return -1; + } + } +} \ No newline at end of file diff --git a/src/services/core/bitMatrix.ts b/src/services/core/bitMatrix.ts new file mode 100644 index 00000000000..4c2fbce4112 --- /dev/null +++ b/src/services/core/bitMatrix.ts @@ -0,0 +1,82 @@ +/// + +module TypeScript { + export interface IBitMatrix { + // Returns true if the bit at the specified indices is set. False otherwise. + valueAt(x: number, y: number): boolean; + + // Sets the value at this specified indices. + setValueAt(x: number, y: number, value: boolean): void; + + // Releases the bit matrix, allowing its resources to be used by another matrix. + // This instance cannot be used after it is released. + release(): void; + } + + export module BitMatrix { + var pool: BitMatrixImpl[] = []; + + class BitMatrixImpl implements IBitMatrix { + public isReleased = false; + private vectors: IBitVector[] = []; + + constructor(public allowUndefinedValues: boolean) { + } + + public valueAt(x: number, y: number): boolean { + Debug.assert(!this.isReleased, "Should not use a released bitvector"); + var vector = this.vectors[x]; + if (!vector) { + return this.allowUndefinedValues ? undefined : false; + } + + return vector.valueAt(y); + } + + public setValueAt(x: number, y: number, value: boolean): void { + Debug.assert(!this.isReleased, "Should not use a released bitvector"); + var vector = this.vectors[x]; + if (!vector) { + if (value === undefined) { + // If they're storing an undefined value, and we don't even have a vector, + // then we can short circuit early here. + return; + } + + vector = BitVector.getBitVector(this.allowUndefinedValues); + this.vectors[x] = vector; + } + + vector.setValueAt(y, value); + } + + public release() { + Debug.assert(!this.isReleased, "Should not use a released bitvector"); + this.isReleased = true; + + // Release all the vectors back. + for (var name in this.vectors) { + if (this.vectors.hasOwnProperty(name)) { + var vector = this.vectors[name]; + vector.release(); + } + } + + this.vectors.length = 0; + pool.push(this); + } + } + + export function getBitMatrix(allowUndefinedValues: boolean): IBitMatrix { + if (pool.length === 0) { + return new BitMatrixImpl(allowUndefinedValues); + } + + var matrix = pool.pop(); + matrix.isReleased = false; + matrix.allowUndefinedValues = allowUndefinedValues; + + return matrix; + } + } +} \ No newline at end of file diff --git a/src/services/core/bitVector.ts b/src/services/core/bitVector.ts new file mode 100644 index 00000000000..6845d88182f --- /dev/null +++ b/src/services/core/bitVector.ts @@ -0,0 +1,210 @@ +/// + +module TypeScript { + export interface IBitVector { + // Returns the value at the specified index. If this is a bi-state vector, then the result + // will only be 'true' or 'false'. If this is a tri-state vector, then the result can be + // 'true', 'false', or 'undefined'. + valueAt(index: number): boolean; + + // Sets the value at this specified bit. For a bi-state vector the value must be 'true' or + // 'false'. For a tri-state vector, it can be 'true', 'false', or 'undefined'. + setValueAt(index: number, value: boolean): void; + + // Releases the bit vector, allowing its resources to be used by another BitVector. + // This instance cannot be used after it is released. + release(): void; + } + + export module BitVector { + var pool: BitVectorImpl[] = []; + enum Constants { + // We only use up to 30 bits in a number. That way the encoded value can always fit + // within an int so that the underlying engine doesn't use a 64bit float here. + MaxBitsPerEncodedNumber = 30, + BitsPerEncodedBiStateValue = 1, + + // For a tri state vector we need 2 bits per encoded value. 00 for 'undefined', + // '01' for 'false' and '10' for true. + BitsPerEncodedTriStateValue = 2, + + BiStateEncodedTrue = 1, // 1 + BiStateClearBitsMask = 1, // 1 + + TriStateEncodedFalse = 1, // 01 + TriStateEncodedTrue = 2, // 10 + TriStateClearBitsMask = 3, // 11 + } + + class BitVectorImpl implements IBitVector { + public isReleased = false; + private bits: number[] = []; + + constructor(public allowUndefinedValues: boolean) { + } + + private computeTriStateArrayIndex(index: number): number { + // The number of values that can be encoded in a single number. + var encodedValuesPerNumber = Constants.MaxBitsPerEncodedNumber / Constants.BitsPerEncodedTriStateValue; + + return (index / encodedValuesPerNumber) >>> 0; + } + + private computeBiStateArrayIndex(index: number): number { + // The number of values that can be encoded in a single number. + var encodedValuesPerNumber = Constants.MaxBitsPerEncodedNumber / Constants.BitsPerEncodedBiStateValue; + + return (index / encodedValuesPerNumber) >>> 0; + } + + private computeTriStateEncodedValueIndex(index: number): number { + // The number of values that can be encoded in a single number. + var encodedValuesPerNumber = Constants.MaxBitsPerEncodedNumber / Constants.BitsPerEncodedTriStateValue; + + return (index % encodedValuesPerNumber) * Constants.BitsPerEncodedTriStateValue; + } + + private computeBiStateEncodedValueIndex(index: number): number { + // The number of values that can be encoded in a single number. + var encodedValuesPerNumber = Constants.MaxBitsPerEncodedNumber / Constants.BitsPerEncodedBiStateValue; + + return (index % encodedValuesPerNumber) * Constants.BitsPerEncodedBiStateValue; + } + + public valueAt(index: number): boolean { + Debug.assert(!this.isReleased, "Should not use a released bitvector"); + if (this.allowUndefinedValues) { + // tri-state bit vector. 2 bits per value. + + var arrayIndex = this.computeTriStateArrayIndex(index); + var encoded = this.bits[arrayIndex]; + if (encoded === undefined) { + // We don't even have an encoded value at this array position. That's + // equivalent to 'undefined' for a tri-state vector. + return undefined; + } + + var bitIndex = this.computeTriStateEncodedValueIndex(index); + if (encoded & (Constants.TriStateEncodedTrue << bitIndex)) { + return true; + } + else if (encoded & (Constants.TriStateEncodedFalse << bitIndex)) { + return false; + } + else { + return undefined; + } + } + else { + // Normal bitvector. One bit per value stored. + + var arrayIndex = this.computeBiStateArrayIndex(index); + var encoded = this.bits[arrayIndex]; + if (encoded === undefined) { + // We don't even have an encoded value at this array position. That's + // equivalent to 'false' for a bi-state vector. + return false; + } + + // If we don't support undefined values, then we use one bit per value. Just + // index to that bit and see if it's set or not. + var bitIndex = this.computeBiStateEncodedValueIndex(index); + if (encoded & (Constants.BiStateEncodedTrue << bitIndex)) { + return true; + } + else { + return false; + } + } + } + + public setValueAt(index: number, value: boolean): void { + Debug.assert(!this.isReleased, "Should not use a released bitvector"); + if (this.allowUndefinedValues) { + Debug.assert(value === true || value === false || value === undefined, "value must only be true, false or undefined."); + + var arrayIndex = this.computeTriStateArrayIndex(index); + var encoded = this.bits[arrayIndex]; + if (encoded === undefined) { + if (value === undefined) { + // They're trying to set a bit to undefined that we don't even have an entry + // for. We can bail out quickly here. + return; + } + + encoded = 0; + } + + // First, we clear out any bits set at the appropriate index. + var bitIndex = this.computeTriStateEncodedValueIndex(index); + + // Create a mask similar to: 11111111100111111 + // i.e. all 1's except for 2 zeroes in the appropriate place. + var clearMask = ~(Constants.TriStateClearBitsMask << bitIndex) + encoded = encoded & clearMask; + + if (value === true) { + encoded = encoded | (Constants.TriStateEncodedTrue << bitIndex); + } + else if (value === false) { + encoded = encoded | (Constants.TriStateEncodedFalse << bitIndex); + } + // else { + // They're setting the value to 'undefined'. We already cleared the value + // so there's nothing we need to do here. + // } + + this.bits[arrayIndex] = encoded; + } + else { + Debug.assert(value === true || value === false, "value must only be true or false."); + + var arrayIndex = this.computeBiStateArrayIndex(index); + var encoded = this.bits[arrayIndex]; + if (encoded === undefined) { + if (value === false) { + // They're trying to set a bit to false that we don't even have an entry + // for. We can bail out quickly here. + return; + } + + encoded = 0; + } + + var bitIndex = this.computeBiStateEncodedValueIndex(index); + // First, clear out the bit at this location. + encoded = encoded & ~(Constants.BiStateClearBitsMask << bitIndex); + + if (value) { + encoded = encoded | (Constants.BiStateEncodedTrue << bitIndex); + } + // else { + // They're setting the value to 'false'. We already cleared the value + // so there's nothing we need to do here. + // } + + this.bits[arrayIndex] = encoded; + } + } + + public release() { + Debug.assert(!this.isReleased, "Should not use a released bitvector"); + this.isReleased = true; + this.bits.length = 0; + pool.push(this); + } + } + + export function getBitVector(allowUndefinedValues: boolean): IBitVector { + if (pool.length === 0) { + return new BitVectorImpl(allowUndefinedValues); + } + + var vector = pool.pop(); + vector.isReleased = false; + vector.allowUndefinedValues = allowUndefinedValues; + + return vector; + } + } +} \ No newline at end of file diff --git a/src/services/core/cancellationToken.ts b/src/services/core/cancellationToken.ts new file mode 100644 index 00000000000..f479e4d7011 --- /dev/null +++ b/src/services/core/cancellationToken.ts @@ -0,0 +1,3 @@ +interface ICancellationToken { + isCancellationRequested(): boolean; +} \ No newline at end of file diff --git a/src/services/core/cancellationTokenSource.ts b/src/services/core/cancellationTokenSource.ts new file mode 100644 index 00000000000..684bf235cb7 --- /dev/null +++ b/src/services/core/cancellationTokenSource.ts @@ -0,0 +1,7 @@ +/// + +interface ICancellationTokenSource { + token(): ICancellationToken; + + cancel(): void; +} \ No newline at end of file diff --git a/src/services/core/constants.ts b/src/services/core/constants.ts new file mode 100644 index 00000000000..9a980359313 --- /dev/null +++ b/src/services/core/constants.ts @@ -0,0 +1,9 @@ +/// + +module TypeScript { + export enum Constants { + // 2^30-1 + Max31BitInteger = 1073741823, + Min31BitInteger = -1073741824, + } +} \ No newline at end of file diff --git a/src/services/core/debug.ts b/src/services/core/debug.ts new file mode 100644 index 00000000000..e57f9745353 --- /dev/null +++ b/src/services/core/debug.ts @@ -0,0 +1,32 @@ +/// + +module TypeScript { + export enum AssertionLevel { + None = 0, + Normal = 1, + Aggressive = 2, + VeryAggressive = 3, + } + + export class Debug { + private static currentAssertionLevel = AssertionLevel.None; + public static shouldAssert(level: AssertionLevel): boolean { + return this.currentAssertionLevel >= level; + } + + public static assert(expression: any, message: string = "", verboseDebugInfo: () => string = null): void { + if (!expression) { + var verboseDebugString = ""; + if (verboseDebugInfo) { + verboseDebugString = "\r\nVerbose Debug Information:" + verboseDebugInfo(); + } + + throw new Error("Debug Failure. False expression: " + message + verboseDebugString); + } + } + + public static fail(message?: string): void { + Debug.assert(false, message); + } + } +} \ No newline at end of file diff --git a/src/services/core/diagnosticCategory.ts b/src/services/core/diagnosticCategory.ts new file mode 100644 index 00000000000..30c6513ee38 --- /dev/null +++ b/src/services/core/diagnosticCategory.ts @@ -0,0 +1,10 @@ +/// + +module TypeScript { + export enum DiagnosticCategory { + Warning, + Error, + Message, + NoPrefix, + } +} \ No newline at end of file diff --git a/src/services/core/diagnosticCore.ts b/src/services/core/diagnosticCore.ts new file mode 100644 index 00000000000..0a796a6770f --- /dev/null +++ b/src/services/core/diagnosticCore.ts @@ -0,0 +1,200 @@ +/// + +module TypeScript { + export var LocalizedDiagnosticMessages: IIndexable = null; + + export class Location { + private _fileName: string; + private _lineMap: LineMap; + private _start: number; + private _length: number; + + constructor(fileName: string, lineMap: LineMap, start: number, length: number) { + this._fileName = fileName; + this._lineMap = lineMap; + this._start = start; + this._length = length; + } + + public fileName(): string { + return this._fileName; + } + + public lineMap(): LineMap { + return this._lineMap; + } + + public line(): number { + return this._lineMap ? this._lineMap.getLineNumberFromPosition(this.start()) : 0; + } + + public character(): number { + return this._lineMap ? this._lineMap.getLineAndCharacterFromPosition(this.start()).character() : 0; + } + + public start(): number { + return this._start; + } + + public length(): number { + return this._length; + } + + public static equals(location1: Location, location2: Location): boolean { + return location1._fileName === location2._fileName && + location1._start === location2._start && + location1._length === location2._length; + } + } + + export class Diagnostic extends Location { + private _diagnosticKey: string; + private _arguments: any[]; + private _additionalLocations: Location[]; + + constructor(fileName: string, lineMap: LineMap, start: number, length: number, diagnosticKey: string, _arguments: any[]= null, additionalLocations: Location[] = null) { + super(fileName, lineMap, start, length); + this._diagnosticKey = diagnosticKey; + this._arguments = (_arguments && _arguments.length > 0) ? _arguments : null; + this._additionalLocations = (additionalLocations && additionalLocations.length > 0) ? additionalLocations : null; + } + + public toJSON(key: any): any { + var result: any = {}; + result.start = this.start(); + result.length = this.length(); + + result.diagnosticCode = this._diagnosticKey; + + var _arguments: any[] = (this).arguments(); + if (_arguments && _arguments.length > 0) { + result.arguments = _arguments; + } + + return result; + } + + public diagnosticKey(): string { + return this._diagnosticKey; + } + + public arguments(): any[] { + return this._arguments; + } + + /** + * Get the text of the message in the given language. + */ + public text(): string { + return TypeScript.getLocalizedText(this._diagnosticKey, this._arguments); + } + + /** + * Get the text of the message including the error code in the given language. + */ + public message(): string { + return TypeScript.getDiagnosticMessage(this._diagnosticKey, this._arguments); + } + + /** + * If a derived class has additional information about other referenced symbols, it can + * expose the locations of those symbols in a general way, so they can be reported along + * with the error. + */ + public additionalLocations(): Location[] { + return this._additionalLocations || []; + } + + public static equals(diagnostic1: Diagnostic, diagnostic2: Diagnostic): boolean { + return Location.equals(diagnostic1, diagnostic2) && + diagnostic1._diagnosticKey === diagnostic2._diagnosticKey && + ArrayUtilities.sequenceEquals(diagnostic1._arguments, diagnostic2._arguments, (v1, v2) => v1 === v2); + } + + public info(): DiagnosticInfo { + return getDiagnosticInfoFromKey(this.diagnosticKey()); + } + } + + export function newLine(): string { + // TODO: We need to expose an extensibility point on our hosts to have them tell us what + // they want the newline string to be. That way we can get the correct result regardless + // of which host we use + return Environment ? Environment.newLine : "\r\n"; + } + + function getLargestIndex(diagnostic: string): number { + var largest = -1; + var regex = /\{(\d+)\}/g; + + var match: RegExpExecArray; + while (match = regex.exec(diagnostic)) { + var val = parseInt(match[1]); + if (!isNaN(val) && val > largest) { + largest = val; + } + } + + return largest; + } + + function getDiagnosticInfoFromKey(diagnosticKey: string): DiagnosticInfo { + var result: DiagnosticInfo = diagnosticInformationMap[diagnosticKey]; + Debug.assert(result); + return result; + } + + export function getLocalizedText(diagnosticKey: string, args: any[]): string { + if (LocalizedDiagnosticMessages) { + //Debug.assert(LocalizedDiagnosticMessages.hasOwnProperty(diagnosticKey)); + } + + var diagnosticMessageText: string = LocalizedDiagnosticMessages ? LocalizedDiagnosticMessages[diagnosticKey] : diagnosticKey; + Debug.assert(diagnosticMessageText !== undefined && diagnosticMessageText !== null); + + var actualCount = args ? args.length : 0; + // We have a string like "foo_0_bar_1". We want to find the largest integer there. + // (i.e.'1'). We then need one more arg than that to be correct. + var expectedCount = 1 + getLargestIndex(diagnosticKey); + + if (expectedCount !== actualCount) { + throw new Error(getLocalizedText(DiagnosticCode.Expected_0_arguments_to_message_got_1_instead, [expectedCount, actualCount])); + } + + // This should also be the same number of arguments as the message text + var valueCount = 1 + getLargestIndex(diagnosticMessageText); + if (valueCount !== expectedCount) { + throw new Error(getLocalizedText(DiagnosticCode.Expected_the_message_0_to_have_1_arguments_but_it_had_2, [diagnosticMessageText, expectedCount, valueCount])); + } + + diagnosticMessageText = diagnosticMessageText.replace(/{(\d+)}/g, function (match, num?) { + return typeof args[num] !== 'undefined' + ? args[num] + : match; + }); + + diagnosticMessageText = diagnosticMessageText.replace(/{(NL)}/g, function (match) { + return TypeScript.newLine(); + }); + + return diagnosticMessageText; + } + + export function getDiagnosticMessage(diagnosticKey: string, args: any[]): string { + var diagnostic = getDiagnosticInfoFromKey(diagnosticKey); + var diagnosticMessageText = getLocalizedText(diagnosticKey, args); + + var message: string; + if (diagnostic.category === DiagnosticCategory.Error) { + message = getLocalizedText(DiagnosticCode.error_TS_0_1, [diagnostic.code, diagnosticMessageText]); + } + else if (diagnostic.category === DiagnosticCategory.Warning) { + message = getLocalizedText(DiagnosticCode.warning_TS_0_1, [diagnostic.code, diagnosticMessageText]); + } + else { + message = diagnosticMessageText; + } + + return message; + } +} \ No newline at end of file diff --git a/src/services/core/diagnosticInfo.ts b/src/services/core/diagnosticInfo.ts new file mode 100644 index 00000000000..515f3cff309 --- /dev/null +++ b/src/services/core/diagnosticInfo.ts @@ -0,0 +1,9 @@ +/// + +module TypeScript { + export interface DiagnosticInfo { + category: DiagnosticCategory; + message: string; + code: number; + } +} \ No newline at end of file diff --git a/src/services/core/environment.ts b/src/services/core/environment.ts new file mode 100644 index 00000000000..ab1b351aed1 --- /dev/null +++ b/src/services/core/environment.ts @@ -0,0 +1,505 @@ +/// +/// +/// + +declare var Buffer: { + new (str: string, encoding?: string): any; +} + +module TypeScript { + export var nodeMakeDirectoryTime = 0; + export var nodeCreateBufferTime = 0; + export var nodeWriteFileSyncTime = 0; + + export enum ByteOrderMark { + None = 0, + Utf8 = 1, + Utf16BigEndian = 2, + Utf16LittleEndian = 3, + } + + export class FileInformation { + constructor(public contents: string, public byteOrderMark: ByteOrderMark) { + } + } + + export interface IFileWatcher { + close(): void; + } + + export interface IEnvironment { + supportsCodePage(): boolean; + readFile(path: string, codepage: number): FileInformation; + writeFile(path: string, contents: string, writeByteOrderMark: boolean): void; + deleteFile(path: string): void; + fileExists(path: string): boolean; + directoryExists(path: string): boolean; + directoryName(path: string): string; + createDirectory(path: string): void; + absolutePath(path: string): string; + listFiles(path: string, re?: RegExp, options?: { recursive?: boolean; }): string[]; + + arguments: string[]; + standardOut: ITextWriter; + standardError: ITextWriter; + + executingFilePath(): string; + currentDirectory(): string; + newLine: string; + + watchFile(fileName: string, callback: (x: string) => void): IFileWatcher; + quit(exitCode?: number): void; + } + + function throwIOError(message: string, error: Error) { + var errorMessage = message; + if (error && error.message) { + errorMessage += (" " + error.message); + } + throw new Error(errorMessage); + } + + export var Environment: IEnvironment = (function () { + // Create an IO object for use inside WindowsScriptHost hosts + // Depends on WSCript and FileSystemObject + function getWindowsScriptHostEnvironment(): IEnvironment { + try { + var fso = new ActiveXObject("Scripting.FileSystemObject"); + } catch (e) { + return null; + } + + var streamObjectPool: any[] = []; + + function getStreamObject(): any { + if (streamObjectPool.length > 0) { + return streamObjectPool.pop(); + } + else { + return new ActiveXObject("ADODB.Stream"); + } + } + + function releaseStreamObject(obj: any) { + streamObjectPool.push(obj); + } + + var args: string[] = []; + for (var i = 0; i < WScript.Arguments.length; i++) { + args[i] = WScript.Arguments.Item(i); + } + + return { + // On windows, the newline sequence is always "\r\n"; + newLine: "\r\n", + + currentDirectory: () => (WScript).CreateObject("WScript.Shell").CurrentDirectory, + + supportsCodePage: () => (WScript).ReadFile, + + absolutePath: path => fso.GetAbsolutePathName(path), + + readFile: function (path, codepage) { + try { + // If a codepage is requested, defer to our host to do the reading. If it + // fails, fall back to our normal BOM/utf8 logic. + if (codepage !== null && this.supportsCodePage()) { + try { + var contents = (WScript).ReadFile(path, codepage); + return new FileInformation(contents, ByteOrderMark.None); + } + catch (e) { + // We couldn't read it with that code page. Fall back to the normal + // BOM/utf8 logic below. + } + } + + // Initially just read the first two bytes of the file to see if there's a bom. + var streamObj = getStreamObject(); + streamObj.Open(); + streamObj.Type = 2; // Text data + + // Start reading individual chars without any interpretation. That way we can check for a bom. + streamObj.Charset = 'x-ansi'; + + streamObj.LoadFromFile(path); + var bomChar = streamObj.ReadText(2); // Read the BOM char + + // Position has to be at 0 before changing the encoding + streamObj.Position = 0; + + var byteOrderMark = ByteOrderMark.None; + + if (bomChar.charCodeAt(0) === 0xFE && bomChar.charCodeAt(1) === 0xFF) { + streamObj.Charset = 'unicode'; + byteOrderMark = ByteOrderMark.Utf16BigEndian; + } + else if (bomChar.charCodeAt(0) === 0xFF && bomChar.charCodeAt(1) === 0xFE) { + streamObj.Charset = 'unicode'; + byteOrderMark = ByteOrderMark.Utf16LittleEndian; + } + else if (bomChar.charCodeAt(0) === 0xEF && bomChar.charCodeAt(1) === 0xBB) { + streamObj.Charset = 'utf-8'; + byteOrderMark = ByteOrderMark.Utf8; + } + else { + // Always read a file as utf8 if it has no bom. + streamObj.Charset = 'utf-8'; + } + + // Read the whole file + var contents = streamObj.ReadText(-1 /* read from the current position to EOS */); + streamObj.Close(); + releaseStreamObject(streamObj); + return new FileInformation(contents, byteOrderMark); + } + catch (err) { + // -2147024809 is the javascript value for 0x80070057 which is the HRESULT for + // "the parameter is incorrect". + var message: string; + if (err.number === -2147024809) { + message = TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.Unsupported_file_encoding, null); + } + else { + message = TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.Cannot_read_file_0_1, [path, err.message]); + } + + throw new Error(message); + } + }, + + writeFile: (path, contents, writeByteOrderMark) => { + // First, convert the text contents passed in to binary in UTF8 format. + var textStream = getStreamObject(); + textStream.Charset = 'utf-8'; + textStream.Open(); + textStream.WriteText(contents, 0 /*do not add newline*/); + + // If they don't want the BOM, then skip it (it will be added automatically + // when we write the utf8 bytes out above). + if (!writeByteOrderMark) { + textStream.Position = 3; + } + else { + textStream.Position = 0; + } + + // Now, write all those bytes out to a file. + var fileStream = getStreamObject(); + fileStream.Type = 1; //binary data. + fileStream.Open(); + + textStream.CopyTo(fileStream); + + // Flush and save the file. + fileStream.Flush(); + fileStream.SaveToFile(path, 2 /*overwrite*/); + fileStream.Close(); + + textStream.Flush(); + textStream.Close(); + }, + + fileExists: path => fso.FileExists(path), + + deleteFile: path => { + if (fso.FileExists(path)) { + fso.DeleteFile(path, true); // true: delete read-only files + } + }, + + directoryExists: path => fso.FolderExists(path), + + directoryName: path => fso.GetParentFolderName(path), + + createDirectory: function (path) { + try { + if (!this.directoryExists(path)) { + fso.CreateFolder(path); + } + } catch (e) { + throwIOError(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.Could_not_create_directory_0, [path]), e); + } + }, + + listFiles: (path, spec?, options?) => { + options = options || <{ recursive?: boolean; }>{}; + function filesInFolder(folder: any, root: string): string[] { + var paths: string[] = []; + var fc: Enumerator; + + if (options.recursive) { + fc = new Enumerator(folder.subfolders); + + for (; !fc.atEnd(); fc.moveNext()) { + paths = paths.concat(filesInFolder(fc.item(), root + "\\" + fc.item().Name)); + } + } + + fc = new Enumerator(folder.files); + + for (; !fc.atEnd(); fc.moveNext()) { + if (!spec || fc.item().Name.match(spec)) { + paths.push(root + "\\" + fc.item().Name); + } + } + + return paths; + } + + var folder: any = fso.GetFolder(path); + var paths: string[] = []; + + return filesInFolder(folder, path); + }, + + arguments: args, + + standardOut: WScript.StdOut, + standardError: WScript.StdErr, + + executingFilePath: () => WScript.ScriptFullName, + + quit: (exitCode = 0) => { + try { + WScript.Quit(exitCode); + } catch (e) { + } + }, + + watchFile: null, + }; + }; + + function getNodeEnvironment(): IEnvironment { + var _fs = require('fs'); + var _path = require('path'); + var _module = require('module'); + var _os = require('os'); + + return { + // On node pick up the newline character from the OS + newLine: _os.EOL, + + currentDirectory: () => (process).cwd(), + + supportsCodePage: () => false, + + absolutePath: path => _path.resolve(path), + + readFile: (file, codepage) => { + if (codepage !== null) { + throw new Error(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.codepage_option_not_supported_on_current_platform, null)); + } + + var buffer = _fs.readFileSync(file); + switch (buffer[0]) { + case 0xFE: + if (buffer[1] === 0xFF) { + // utf16-be. Reading the buffer as big endian is not supported, so convert it to + // Little Endian first + var i = 0; + while ((i + 1) < buffer.length) { + var temp = buffer[i]; + buffer[i] = buffer[i + 1]; + buffer[i + 1] = temp; + i += 2; + } + return new FileInformation(buffer.toString("ucs2", 2), ByteOrderMark.Utf16BigEndian); + } + break; + case 0xFF: + if (buffer[1] === 0xFE) { + // utf16-le + return new FileInformation(buffer.toString("ucs2", 2), ByteOrderMark.Utf16LittleEndian); + } + break; + case 0xEF: + if (buffer[1] === 0xBB) { + // utf-8 + return new FileInformation(buffer.toString("utf8", 3), ByteOrderMark.Utf8); + } + } + + // Default behaviour + return new FileInformation(buffer.toString("utf8", 0), ByteOrderMark.None); + }, + + writeFile: (path, contents, writeByteOrderMark) => { + function mkdirRecursiveSync(path: string) { + var stats = _fs.statSync(path); + if (stats.isFile()) { + throw "\"" + path + "\" exists but isn't a directory."; + } + else if (stats.isDirectory()) { + return; + } + else { + mkdirRecursiveSync(_path.dirname(path)); + _fs.mkdirSync(path, 509 /*775 in octal*/); + } + } + var start = new Date().getTime(); + mkdirRecursiveSync(_path.dirname(path)); + TypeScript.nodeMakeDirectoryTime += new Date().getTime() - start; + + if (writeByteOrderMark) { + contents = '\uFEFF' + contents; + } + + var start = new Date().getTime(); + + var chunkLength = 4 * 1024; + var fileDescriptor = _fs.openSync(path, "w"); + try { + for (var index = 0; index < contents.length; index += chunkLength) { + var bufferStart = new Date().getTime(); + var buffer = new Buffer(contents.substr(index, chunkLength), "utf8"); + TypeScript.nodeCreateBufferTime += new Date().getTime() - bufferStart; + + _fs.writeSync(fileDescriptor, buffer, 0, buffer.length, null); + } + } + finally { + _fs.closeSync(fileDescriptor); + } + + TypeScript.nodeWriteFileSyncTime += new Date().getTime() - start; + }, + + fileExists: path => _fs.existsSync(path), + + deleteFile: path => { + try { + _fs.unlinkSync(path); + } catch (e) { + } + }, + + directoryExists: path => + _fs.existsSync(path) && _fs.statSync(path).isDirectory(), + + directoryName: path => { + var dirPath = _path.dirname(path); + + // Node will just continue to repeat the root path, rather than return null + if (dirPath === path) { + dirPath = null; + } + + return dirPath; + }, + + createDirectory: function (path) { + try { + if (!this.directoryExists(path)) { + _fs.mkdirSync(path); + } + } catch (e) { + throwIOError(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.Could_not_create_directory_0, [path]), e); + } + }, + + listFiles: (path, spec?, options?) => { + options = options || <{ recursive?: boolean; }>{}; + + function filesInFolder(folder: string): string[] { + var paths: string[] = []; + + var files = _fs.readdirSync(folder); + for (var i = 0; i < files.length; i++) { + var pathToFile = _path.join(folder, files[i]); + var stat = _fs.statSync(pathToFile); + if (options.recursive && stat.isDirectory()) { + paths = paths.concat(filesInFolder(pathToFile)); + } + else if (stat.isFile() && (!spec || files[i].match(spec))) { + paths.push(pathToFile); + } + } + + return paths; + } + + return filesInFolder(path); + }, + + arguments: process.argv.slice(2), + + standardOut: { + Write: str => process.stdout.write(str), + WriteLine: str => process.stdout.write(str + '\n'), + Close() { } + }, + + standardError: { + Write: str => process.stderr.write(str), + WriteLine: str => process.stderr.write(str + '\n'), + Close() { } + }, + + executingFilePath: () => process.mainModule.filename, + + quit: code => { + var stderrFlushed = process.stderr.write(''); + var stdoutFlushed = process.stdout.write(''); + process.stderr.on('drain', function () { + stderrFlushed = true; + if (stdoutFlushed) { + process.exit(code); + } + }); + process.stdout.on('drain', function () { + stdoutFlushed = true; + if (stderrFlushed) { + process.exit(code); + } + }); + setTimeout(function () { + process.exit(code); + }, 5); + }, + + watchFile: (fileName, callback) => { + var firstRun = true; + var processingChange = false; + + var fileChanged: any = function (curr: any, prev: any) { + if (!firstRun) { + if (curr.mtime < prev.mtime) { + return; + } + + _fs.unwatchFile(fileName, fileChanged); + if (!processingChange) { + processingChange = true; + callback(fileName); + setTimeout(function () { processingChange = false; }, 100); + } + } + firstRun = false; + _fs.watchFile(fileName, { persistent: true, interval: 500 }, fileChanged); + }; + + fileChanged(); + return { + fileName: fileName, + close: function () { + _fs.unwatchFile(fileName, fileChanged); + } + }; + }, + }; + }; + + if (typeof WScript !== "undefined" && typeof ActiveXObject === "function") { + return getWindowsScriptHostEnvironment(); + } + else if (typeof module !== 'undefined' && module.exports) { + return getNodeEnvironment(); + } + else { + return null; // Unsupported host + } + })(); +} diff --git a/src/services/core/errors.ts b/src/services/core/errors.ts new file mode 100644 index 00000000000..77f0643f333 --- /dev/null +++ b/src/services/core/errors.ts @@ -0,0 +1,29 @@ +/// + +module TypeScript { + export class Errors { + public static argument(argument: string, message?: string): Error { + return new Error("Invalid argument: " + argument + ". " + message); + } + + public static argumentOutOfRange(argument: string): Error { + return new Error("Argument out of range: " + argument); + } + + public static argumentNull(argument: string): Error { + return new Error("Argument null: " + argument); + } + + public static abstract(): Error { + return new Error("Operation not implemented properly by subclass."); + } + + public static notYetImplemented(): Error { + return new Error("Not yet implemented."); + } + + public static invalidOperation(message?: string): Error { + return new Error("Invalid operation: " + message); + } + } +} \ No newline at end of file diff --git a/src/services/core/hash.ts b/src/services/core/hash.ts new file mode 100644 index 00000000000..ef117df8025 --- /dev/null +++ b/src/services/core/hash.ts @@ -0,0 +1,112 @@ +/// + +module TypeScript { + export class Hash { + // This table uses FNV1a as a string hash + private static FNV_BASE = 2166136261; + private static FNV_PRIME = 16777619; + + private static computeFnv1aCharArrayHashCode(text: number[], start: number, len: number): number { + var hashCode = Hash.FNV_BASE; + var end = start + len; + + for (var i = start; i < end; i++) { + hashCode = IntegerUtilities.integerMultiplyLow32Bits(hashCode ^ text[i], Hash.FNV_PRIME); + } + + return hashCode; + } + + public static computeSimple31BitCharArrayHashCode(key: number[], start: number, len: number): number { + // Start with an int. + var hash = 0; + + for (var i = 0; i < len; i++) { + var ch = key[start + i]; + + // Left shift keeps things as a 32bit int. And we're only doing two adds. Chakra and + // V8 recognize this as not needing to go past the 53 bits needed for the float + // mantissa. Or'ing with 0 keeps this 32 bits. + hash = ((((hash << 5) - hash) | 0) + ch) | 0; + } + + // Ensure we fit in 31 bits. That way if/when this gets stored, it won't require any heap + // allocation. + return hash & 0x7FFFFFFF; + } + + public static computeSimple31BitStringHashCode(key: string): number { + // Start with an int. + var hash = 0; + + var start = 0; + var len = key.length; + + for (var i = 0; i < len; i++) { + var ch = key.charCodeAt(start + i); + + // Left shift keeps things as a 32bit int. And we're only doing two adds. Chakra and + // V8 recognize this as not needing to go past the 53 bits needed for the float + // mantissa. Or'ing with 0 keeps this 32 bits. + hash = ((((hash << 5) - hash) | 0) + ch) | 0; + } + + // Ensure we fit in 31 bits. That way if/when this gets stored, it won't require any heap + // allocation. + return hash & 0x7FFFFFFF; + } + + public static computeMurmur2StringHashCode(key: string, seed: number): number { + // 'm' and 'r' are mixing constants generated offline. + // They're not really 'magic', they just happen to work well. + + var m: number = 0x5bd1e995; + var r: number = 24; + + // Initialize the hash to a 'random' value + + var numberOfCharsLeft = key.length; + var h = Math.abs(seed ^ numberOfCharsLeft); + + // Mix 4 bytes at a time into the hash. NOTE: 4 bytes is two chars, so we iterate + // through the string two chars at a time. + var index = 0; + while (numberOfCharsLeft >= 2) { + var c1 = key.charCodeAt(index); + var c2 = key.charCodeAt(index + 1); + + var k = Math.abs(c1 | (c2 << 16)); + + k = IntegerUtilities.integerMultiplyLow32Bits(k, m); + k ^= k >> r; + k = IntegerUtilities.integerMultiplyLow32Bits(k, m); + + h = IntegerUtilities.integerMultiplyLow32Bits(h, m); + h ^= k; + + index += 2; + numberOfCharsLeft -= 2; + } + + // Handle the last char (or 2 bytes) if they exist. This happens if the original string had + // odd length. + if (numberOfCharsLeft === 1) { + h ^= key.charCodeAt(index); + h = IntegerUtilities.integerMultiplyLow32Bits(h, m); + } + + // Do a few final mixes of the hash to ensure the last few bytes are well-incorporated. + + h ^= h >> 13; + h = IntegerUtilities.integerMultiplyLow32Bits(h, m); + h ^= h >> 15; + + return h; + } + + public static combine(value: number, currentHash: number): number { + // Ensure we stay within 31 bits. + return (((currentHash << 5) + currentHash) + value) & 0x7FFFFFFF; + } + } +} \ No newline at end of file diff --git a/src/services/core/indexable.ts b/src/services/core/indexable.ts new file mode 100644 index 00000000000..c879b38cc75 --- /dev/null +++ b/src/services/core/indexable.ts @@ -0,0 +1,7 @@ +/// + +module TypeScript { + export interface IIndexable { + [s: string]: T; + } +} \ No newline at end of file diff --git a/src/services/core/integerUtilities.ts b/src/services/core/integerUtilities.ts new file mode 100644 index 00000000000..0af38471dfd --- /dev/null +++ b/src/services/core/integerUtilities.ts @@ -0,0 +1,28 @@ +/// + +module TypeScript { + export module IntegerUtilities { + export function integerDivide(numerator: number, denominator: number): number { + return (numerator / denominator) >> 0; + } + + export function integerMultiplyLow32Bits(n1: number, n2: number): number { + var n1Low16 = n1 & 0x0000ffff; + var n1High16 = n1 >>> 16; + + var n2Low16 = n2 & 0x0000ffff; + var n2High16 = n2 >>> 16; + + var resultLow32 = (((n1 & 0xffff0000) * n2) >>> 0) + (((n1 & 0x0000ffff) * n2) >>> 0) >>> 0; + return resultLow32; + } + + export function isInteger(text: string): boolean { + return /^[0-9]+$/.test(text); + } + + export function isHexInteger(text: string): boolean { + return /^0(x|X)[0-9a-fA-F]+$/.test(text); + } + } +} \ No newline at end of file diff --git a/src/services/core/iterator.ts b/src/services/core/iterator.ts new file mode 100644 index 00000000000..a2c31746bb5 --- /dev/null +++ b/src/services/core/iterator.ts @@ -0,0 +1,8 @@ +/// + +module TypeScript { + export interface Iterator { + moveNext(): boolean; + current(): T; + } +} \ No newline at end of file diff --git a/src/services/core/lineAndCharacter.ts b/src/services/core/lineAndCharacter.ts new file mode 100644 index 00000000000..8af46296d34 --- /dev/null +++ b/src/services/core/lineAndCharacter.ts @@ -0,0 +1,8 @@ +/// + +module TypeScript { + export interface ILineAndCharacter { + line: number; + character: number; + } +} \ No newline at end of file diff --git a/src/services/core/lineMap.ts b/src/services/core/lineMap.ts new file mode 100644 index 00000000000..8820f55b920 --- /dev/null +++ b/src/services/core/lineMap.ts @@ -0,0 +1,82 @@ +/// + +module TypeScript { + export class LineMap { + public static empty = new LineMap(() => [0], 0); + private _lineStarts: number[] = null; + + constructor(private _computeLineStarts: () => number[], private length: number) { + } + + public toJSON(key: any) { + return { lineStarts: this.lineStarts(), length: this.length }; + } + + public equals(other: LineMap): boolean { + return this.length === other.length && + ArrayUtilities.sequenceEquals(this.lineStarts(), other.lineStarts(), (v1, v2) => v1 === v2); + } + + public lineStarts(): number[] { + if (this._lineStarts === null) { + this._lineStarts = this._computeLineStarts(); + } + + return this._lineStarts; + } + + public lineCount(): number { + return this.lineStarts().length; + } + + public getPosition(line: number, character: number): number { + return this.lineStarts()[line] + character; + } + + public getLineNumberFromPosition(position: number): number { + if (position < 0 || position > this.length) { + throw Errors.argumentOutOfRange("position"); + } + + if (position === this.length) { + // this can happen when the user tried to get the line of items + // that are at the absolute end of this text (i.e. the EndOfLine + // token, or missing tokens that are at the end of the text). + // In this case, we want the last line in the text. + return this.lineCount() - 1; + } + + // Binary search to find the right line + var lineNumber = ArrayUtilities.binarySearch(this.lineStarts(), position); + if (lineNumber < 0) { + lineNumber = (~lineNumber) - 1; + } + + return lineNumber; + } + + public getLineStartPosition(lineNumber: number): number { + return this.lineStarts()[lineNumber]; + } + + public fillLineAndCharacterFromPosition(position: number, lineAndCharacter: ILineAndCharacter): void { + if (position < 0 || position > this.length) { + throw Errors.argumentOutOfRange("position"); + } + + var lineNumber = this.getLineNumberFromPosition(position); + lineAndCharacter.line = lineNumber; + lineAndCharacter.character = position - this.lineStarts()[lineNumber]; + } + + public getLineAndCharacterFromPosition(position: number): LineAndCharacter { + if (position < 0 || position > this.length) { + throw Errors.argumentOutOfRange("position"); + } + + var lineNumber = this.getLineNumberFromPosition(position); + + return new LineAndCharacter(lineNumber, position - this.lineStarts()[lineNumber]); + } + } +} \ No newline at end of file diff --git a/src/services/core/linePosition.ts b/src/services/core/linePosition.ts new file mode 100644 index 00000000000..119c367ee3e --- /dev/null +++ b/src/services/core/linePosition.ts @@ -0,0 +1,35 @@ +/// + +module TypeScript { + export class LineAndCharacter { + private _line: number = 0; + private _character: number = 0; + + /** + * Initializes a new instance of a LinePosition with the given line and character. ArgumentOutOfRangeException if "line" or "character" is less than zero. + * @param line The line of the line position. The first line in a file is defined as line 0 (zero based line numbering). + * @param character The character position in the line. + */ + + constructor(line: number, character: number) { + if (line < 0) { + throw Errors.argumentOutOfRange("line"); + } + + if (character < 0) { + throw Errors.argumentOutOfRange("character"); + } + + this._line = line; + this._character = character; + } + + public line(): number { + return this._line; + } + + public character(): number { + return this._character; + } + } +} \ No newline at end of file diff --git a/src/services/core/mathPrototype.ts b/src/services/core/mathPrototype.ts new file mode 100644 index 00000000000..fe4c23f9d91 --- /dev/null +++ b/src/services/core/mathPrototype.ts @@ -0,0 +1,13 @@ +/// + +module TypeScript { + export class MathPrototype { + public static max(a: number, b: number): number { + return a >= b ? a : b; + } + + public static min(a: number, b: number): number { + return a <= b ? a : b; + } + } +} \ No newline at end of file diff --git a/src/services/core/references.ts b/src/services/core/references.ts new file mode 100644 index 00000000000..a03523834ca --- /dev/null +++ b/src/services/core/references.ts @@ -0,0 +1,24 @@ +/// + +/// + +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +// /// +/// +/// \ No newline at end of file diff --git a/src/services/core/require.ts b/src/services/core/require.ts new file mode 100644 index 00000000000..fcd5a5cbda9 --- /dev/null +++ b/src/services/core/require.ts @@ -0,0 +1,5 @@ +/// + +// Forward declarations of the variables we use from 'node'. +declare var require: any; +declare var module: any; \ No newline at end of file diff --git a/src/services/core/stringTable.ts b/src/services/core/stringTable.ts new file mode 100644 index 00000000000..18af8be8b5c --- /dev/null +++ b/src/services/core/stringTable.ts @@ -0,0 +1,159 @@ +/// + +module TypeScript.Collections { + export var DefaultStringTableCapacity = 256; + + class StringTableEntry { + constructor(public Text: string, + public HashCode: number, + public Next: StringTableEntry) { + } + } + + // A table of interned strings. Faster and better than an arbitrary hashtable for the needs of the + // scanner. Specifically, the scanner operates over a sliding window of characters, with a start + // and end pointer for the current lexeme. The scanner then wants to get the *interned* string + // represented by that subsection. + // + // Importantly, if the string is already interned, then it wants ask "is the string represented by + // this section of a char array contained within the table" in a non-allocating fashion. i.e. if + // you have "[' ', 'p', 'u', 'b', 'l', 'i', 'c', ' ']" and you ask to get the string represented by + // range [1, 7), then this table will return "public" without any allocations if that value was + // already in the table. + // + // Of course, if the value is not in the table then there will be an initial cost to allocate the + // string and the bucket for the table. However, that is only incurred the first time each unique + // string is added. + export class StringTable { + // TODO: uncomment this once typecheck bug is fixed. + private entries: StringTableEntry[]; + private count: number = 0; + + constructor(capacity: number) { + var size = Hash.getPrime(capacity); + this.entries = ArrayUtilities.createArray(size, null); + } + + public addCharArray(key: number[], start: number, len: number): string { + // Compute the hash for this key. Also ensure that it fits within 31 bits (so that it + // stays a non-heap integer, and so we can index into the array safely). + var hashCode = Hash.computeSimple31BitCharArrayHashCode(key, start, len) & 0x7FFFFFFF; + // Debug.assert(hashCode > 0); + + // First see if we already have the string represented by "key[start, start + len)" already + // present in this table. If we do, just return that string. Do this without any + // allocations + var entry = this.findCharArrayEntry(key, start, len, hashCode); + if (entry !== null) { + return entry.Text; + } + + // We don't have an entry for that string in our table. Convert that + var slice: number[] = key.slice(start, start + len); + return this.addEntry(StringUtilities.fromCharCodeArray(slice), hashCode); + } + + private findCharArrayEntry(key: number[], start: number, len: number, hashCode: number) { + for (var e = this.entries[hashCode % this.entries.length]; e !== null; e = e.Next) { + if (e.HashCode === hashCode && StringTable.textCharArrayEquals(e.Text, key, start, len)) { + return e; + } + } + + return null; + } + + private addEntry(text: string, hashCode: number): string { + var index = hashCode % this.entries.length; + + var e = new StringTableEntry(text, hashCode, this.entries[index]); + + this.entries[index] = e; + + // We grow when our load factor equals 1. I tried different load factors (like .75 and + // .5), however they seemed to have no effect on running time. With a load factor of 1 + // we seem to get about 80% slot fill rate with an average of around 1.25 table entries + // per slot. + if (this.count === this.entries.length) { + this.grow(); + } + + this.count++; + return e.Text; + } + + //private dumpStats() { + // var standardOut = Environment.standardOut; + + // standardOut.WriteLine("----------------------") + // standardOut.WriteLine("String table stats"); + // standardOut.WriteLine("Count : " + this.count); + // standardOut.WriteLine("Entries Length : " + this.entries.length); + + // var longestSlot = 0; + // var occupiedSlots = 0; + // for (var i = 0; i < this.entries.length; i++) { + // if (this.entries[i] !== null) { + // occupiedSlots++; + + // var current = this.entries[i]; + // var slotCount = 0; + // while (current !== null) { + // slotCount++; + // current = current.Next; + // } + + // longestSlot = MathPrototype.max(longestSlot, slotCount); + // } + // } + + // standardOut.WriteLine("Occupied slots : " + occupiedSlots); + // standardOut.WriteLine("Longest slot : " + longestSlot); + // standardOut.WriteLine("Avg Length/Slot : " + (this.count / occupiedSlots)); + // standardOut.WriteLine("----------------------"); + //} + + private grow(): void { + // this.dumpStats(); + + var newSize = Hash.expandPrime(this.entries.length); + + var oldEntries = this.entries; + var newEntries: StringTableEntry[] = ArrayUtilities.createArray(newSize, null); + + this.entries = newEntries; + + for (var i = 0; i < oldEntries.length; i++) { + var e = oldEntries[i]; + while (e !== null) { + var newIndex = e.HashCode % newSize; + var tmp = e.Next; + e.Next = newEntries[newIndex]; + newEntries[newIndex] = e; + e = tmp; + } + } + + // this.dumpStats(); + } + + private static textCharArrayEquals(text: string, array: number[], start: number, length: number): boolean { + if (text.length !== length) { + return false; + } + + var s = start; + for (var i = 0; i < length; i++) { + if (text.charCodeAt(i) !== array[s]) { + return false; + } + + s++; + } + + return true; + } + } + + export var DefaultStringTable = new StringTable(DefaultStringTableCapacity); +} \ No newline at end of file diff --git a/src/services/core/stringUtilities.ts b/src/services/core/stringUtilities.ts new file mode 100644 index 00000000000..0ed2b4a7e8f --- /dev/null +++ b/src/services/core/stringUtilities.ts @@ -0,0 +1,21 @@ +/// + +module TypeScript { + export class StringUtilities { + public static isString(value: any): boolean { + return Object.prototype.toString.apply(value, []) === '[object String]'; + } + + public static endsWith(string: string, value: string): boolean { + return string.substring(string.length - value.length, string.length) === value; + } + + public static startsWith(string: string, value: string): boolean { + return string.substr(0, value.length) === value; + } + + public static repeat(value: string, count: number) { + return Array(count + 1).join(value); + } + } +} \ No newline at end of file diff --git a/src/services/core/timer.ts b/src/services/core/timer.ts new file mode 100644 index 00000000000..7d6e3b0784e --- /dev/null +++ b/src/services/core/timer.ts @@ -0,0 +1,52 @@ +/// + +var global: any = Function("return this").call(null); + +module TypeScript { + module Clock { + export var now: () => number; + export var resolution: number; + + declare module WScript { + export function InitializeProjection(): void; + } + + declare module TestUtilities { + export function QueryPerformanceCounter(): number; + export function QueryPerformanceFrequency(): number; + } + + if (typeof WScript !== "undefined" && typeof global['WScript'].InitializeProjection !== "undefined") { + // Running in JSHost. + global['WScript'].InitializeProjection(); + + now = function () { + return TestUtilities.QueryPerformanceCounter(); + }; + + resolution = TestUtilities.QueryPerformanceFrequency(); + } + else { + now = function () { + return Date.now(); + }; + + resolution = 1000; + } + } + + export class Timer { + public startTime: number; + public time = 0; + + public start() { + this.time = 0; + this.startTime = Clock.now(); + } + + public end() { + // Set time to MS. + this.time = (Clock.now() - this.startTime); + } + } +} \ No newline at end of file diff --git a/src/services/coreServices.ts b/src/services/coreServices.ts new file mode 100644 index 00000000000..3db06ba3a8f --- /dev/null +++ b/src/services/coreServices.ts @@ -0,0 +1,74 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// +/// +/// + +// Access to "Debug" object +var debugObjectHost = (this); + +module TypeScript.Services { + + export interface ICoreServicesHost { + logger: TypeScript.ILogger; + } + + export class CoreServices { + constructor (public host: ICoreServicesHost) { + } + + public getPreProcessedFileInfo(fileName: string, sourceText: TypeScript.IScriptSnapshot): TypeScript.IPreProcessedFileInfo { + return TypeScript.preProcessFile(fileName, sourceText); + } + + public getDefaultCompilationSettings(): ts.CompilerOptions { + // Set "ES5" target by default for language service + return { + target: ts.ScriptTarget.ES5 + } + } + + public dumpMemory(): string { + if (!debugObjectHost || !debugObjectHost.Debug || !debugObjectHost.Debug.dumpHeap) { + throw new Error(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.This_version_of_the_Javascript_runtime_does_not_support_the_0_function, ['Debug.dumpHeap()'])); + } + + var objects = debugObjectHost.Debug.dumpHeap(2); + var totalSize = 0; + for (var i = 0; i < objects.length; i++) { + totalSize += objects[i].size; + } + + return "There are " + objects.length + " object(s) accessible from 'global', for a total of " + totalSize + " byte(s)."; + } + + public getMemoryInfo(): any[] { + if (!debugObjectHost || !debugObjectHost.Debug || !debugObjectHost.Debug.getMemoryInfo) { + throw new Error(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.This_version_of_the_Javascript_runtime_does_not_support_the_0_function, ['Debug.getMemoryInfo()'])); + } + + return debugObjectHost.Debug.getMemoryInfo(); + } + + public collectGarbage(): void { + if (!debugObjectHost || !debugObjectHost.CollectGarbage) { + throw new Error(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.This_version_of_the_Javascript_runtime_does_not_support_the_0_function, ['collectGarbage()'])); + } + + debugObjectHost.CollectGarbage(); + } + } +} diff --git a/src/services/diagnosticServices.ts b/src/services/diagnosticServices.ts new file mode 100644 index 00000000000..885170a8131 --- /dev/null +++ b/src/services/diagnosticServices.ts @@ -0,0 +1,7 @@ +/// + +module TypeScript.Services { + export interface ILanguageServicesDiagnostics { + log(content: string): void; + } +} diff --git a/src/services/diagnosticsParser.ts b/src/services/diagnosticsParser.ts new file mode 100644 index 00000000000..9ea7096bb65 --- /dev/null +++ b/src/services/diagnosticsParser.ts @@ -0,0 +1,363 @@ +/// +/// +/// + +module DiagnosticsParser { + + class FourSlashGenerator { + + private fsFiles: { [s: string]: IFourSlashFile; }; + + constructor(private diagnosticsFile: string) { + this.fsFiles = {}; + } + + public generate(args: string[]): void { + + if (IO.fileExists(this.diagnosticsFile)) { + + this.parseDiagnostics(args); + + if (args !== undefined) { + for (var i = 0; i < args.length; i++) { + for (var fsFile in this.fsFiles) { + var strippedScriptId = fsFile.replace(/.+\\/, ''); + if (strippedScriptId === args[i]) { + this.writeFile(fsFile); + } + } + } + } else { + for (var fsFile in this.fsFiles) { + this.writeFile(fsFile); + } + } + + } + } + + private parseDiagnostics(args: string[]) { + + var file: string = IO.readFile(this.diagnosticsFile); + var lines: string[] = file.split('\r\n'); + + var updateMode: boolean; + var scriptId: string; + + var editBlock: string; + var editRange: TypeScript.ScriptEditRange; + + var startPosition: number; + var caretPosition: number; + var collapsingBlock: string; + + var openEditTag = /^.*/; + var closeEditTag = /.*/; + + // Loops through the lines of the diagnostics file + for (var i = 0; i < lines.length; i++) { + + // Indicates the user opening a file + if (lines[i].match(/\/\/=New=\\\\/)) { + + updateMode = false; + + // Indicates the user making updates to an opened file + } else if (lines[i].match(/\/\/=Update=\\\\/)) { + + updateMode = true; + + // Record the filePath of the opened/modified file + } else if (lines[i].match(/^scriptId: /)) { + + var newScriptId = lines[i].replace(/^scriptId: /, ''); + if (scriptId !== undefined && newScriptId !== scriptId && collapsingBlock !== undefined) { + this.fsFiles[scriptId].insertAt(startPosition, caretPosition, collapsingBlock); + + startPosition = undefined; + caretPosition = undefined; + collapsingBlock = undefined + } + scriptId = newScriptId; + + // Records the editRange (minChar, limChar, deltaOfCaret) + } else if (lines[i].match(/^editRange\(/)) { + + //Capture numbers in editRange(minChar=###, limChar=###, delta=###) + var match = /editRange\(minChar=([0-9]+), limChar=([0-9]+), delta=(-?[0-9]+)\)/.exec(lines[i]); + if (match !== null) { + editRange = new TypeScript.ScriptEditRange(parseInt(match[1], 10), parseInt(match[2], 10), parseInt(match[3], 10)); + } + + // Indicates the beginning of added text and records + } else if (lines[i].match(openEditTag)) { + + var editLines: string[] = []; + + lines[i] = lines[i].replace(openEditTag, ''); + while (lines[i].match(closeEditTag) === null) { + editLines.push(lines[i]); + i++; + } + + editLines.push(lines[i].replace(closeEditTag, '')); + editBlock = editLines.join('\r\n'); + + // Indicates the end of the edit block, and then adds the text to the relevant file + } else if (lines[i].match(/\\\\=====\/\//) && editRange !== null) { + + if (updateMode) { + + var range: number = editRange.limChar - editRange.minChar; + var deleting: boolean = (range !== 0); + + if (deleting) { + + if (collapsingBlock !== undefined) { + this.fsFiles[scriptId].insertAt(startPosition, caretPosition, collapsingBlock); + } + + caretPosition = editRange.minChar + (editBlock !== undefined ? editBlock.length : 0); + + this.fsFiles[scriptId].deleteAt(editRange.limChar, caretPosition, range, editBlock); + + startPosition = undefined; + caretPosition = undefined; + collapsingBlock = undefined; + + } else { + if (editRange.minChar === caretPosition) { + collapsingBlock += editBlock; + } else { + if (collapsingBlock !== undefined) { + this.fsFiles[scriptId].insertAt(startPosition, caretPosition, collapsingBlock); + } + startPosition = editRange.minChar; + collapsingBlock = editBlock; + } + caretPosition = editRange.minChar + editRange.delta; + } + } else { + this.fsFiles[scriptId] = new FourSlashFile(scriptId, editBlock); + } + editBlock = undefined; + } + } + + // Add any text that hasn't been stored to its relevant file + if (collapsingBlock !== undefined) { + this.fsFiles[scriptId].insertAt(startPosition, caretPosition, collapsingBlock); + } + } + + private writeFile(scriptId: string): void { + if (this.fsFiles[scriptId] !== undefined) { + var fsFileName = this.fsFiles[scriptId].getFsFileName(); + IO.writeFile(fsFileName, this.fsFiles[scriptId].getFile()); + } + } + + } + + interface IFourSlashFile { + getFile(): string; + getFsFileName(): string; + getOriginalScriptId(): string; + updateInternalFile(minChar: number, limChar: number, content: string): void; + insertAt(position: number, caretPosition: number, content: string): void; + deleteAt(position: number, caretPosition: number, amount: number, content?: string): void; + addInternalState(caretPosition: number): void; + } + + interface IFourSlashNode { + getNode(): string; + } + + class FourSlashFile implements IFourSlashFile { + + private static header = "/// " + '\r\n' + '\r\n'; + + private fsScriptId: string; + + private commands: IFourSlashNode[]; + + private internalState: string; + + constructor(private originalScriptId: string, private startingContent: string) { + + this.fsScriptId = 'tests\\cases\\fourslash\\' + originalScriptId.replace(/.+\\(.+).ts/, '$1_generated.ts'); + this.commands = []; + this.internalState = startingContent; + + } + + public getFile(): string { + var file: string; + + //Split on \r\n and add //// + var rnlines = this.startingContent.split('\r\n'); + rnlines.forEach((line, index, array) => { array[index] = '////' + line }); + var rnfile = rnlines.join('\r\n'); + + //Repeat for \n + var nlines = rnfile.split(/([^\r]\n|\r[^\n])/); + nlines.forEach((line, index, array) => { if (line.indexOf('////') !== 0) { array[index] = '////' + line } }); + var nfile = nlines.join('\n'); + + file = FourSlashFile.header + nfile + '\r\n' + '\r\n'; + this.commands.forEach((command, index, array) => { file += command.getNode() }); + + return file; + } + + private getWithWhitespace(text: string) { + return text.replace(/ /g, '\u00B7').replace(/\r/g, '\u00B6').replace(/\n/g, '\u2193\n').replace(/\t/g, '\u2192\ '); + } + + public getFsFileName(): string { + return this.fsScriptId; + } + + public getOriginalScriptId(): string { + return this.originalScriptId; + } + + public updateInternalFile(minChar: number, limChar: number, content: string): void { + this.internalState = this.internalState.substring(0, minChar) + content + this.internalState.substr(limChar); + } + + public insertAt(position: number, caretPosition: number, content: string): void { + var posOffset = this.getInsertOffset(position); + var insertNode = new FourSlashInsert(position - posOffset, content.replace(/(\r\n|\r|\n)/g, '\n')); + this.commands.push(insertNode); + this.updateInternalFile(position, position, content); + this.addInternalState(caretPosition); + } + + public deleteAt(position: number, caretPosition: number, amount: number, content?: string): void { + var posOffset = this.getInsertOffset(position); + var amountOffset = this.getDeleteOffset(position, amount); + var deleteNode = new FourSlashDelete(position - posOffset, amount - amountOffset, (content !== undefined ? content.replace(/(\r\n|\r|\n)/g, '\n') : undefined)); + this.commands.push(deleteNode); + this.updateInternalFile(position - amount, position, content); + this.addInternalState(caretPosition); + } + + public addInternalState(caretPosition: number): void { + var caretedState = this.internalState.substr(0, caretPosition) + '|' + this.internalState.substr(caretPosition); + var internalState = new FourSlashStateComment(caretedState); + this.commands.push(internalState); + } + + private getInsertOffset(position: number) { + var offset: number = 0; + var match = this.internalState.substring(0, position).match(/\r\n/g); + if (match !== null) { + offset = match.length; + } + offset = (match !== null ? match.length : 0); + return offset; + } + + private getDeleteOffset(position: number, amount: number) { + var offset: number = 0; + var match = this.internalState.substring(position - amount, position).match(/\r\n/g); + if (match !== null) { + offset = match.length; + } + return offset; + } + + } + + class FourSlashInsert implements IFourSlashNode { + + constructor(private position: number, private content: string) { + this.content = this.content.replace(/([\/\\"'])/g, '\\$1'); + this.content = this.content.replace(/\r\n/g, '\\r\\n'); + this.content = this.content.replace(/(\r|\n)/g, '\\n'); + } + + public getNode(): string { + var insertNode: string = "goTo.position(" + this.position.toString() + ");" + "\n" + + "edit.insert(\'" + this.content + "\');" + "\n"; + return insertNode; + } + + } + + class FourSlashDelete implements IFourSlashNode { + + constructor(private position: number, private deletionAmount: number, private content: string) { + if (this.content !== undefined) { + this.content = this.content.replace(/([\/\\"'])/g, '\\$1'); + this.content = this.content.replace(/\r\n/g, '\\r\\n'); + this.content = this.content.replace(/(\r|\n)/g, '\\n'); + } + } + + public getNode(): string { + var deleteNode: string = "goTo.position(" + this.position.toString() + ");" + "\n" + + "edit.backspace(" + this.deletionAmount + ");" + "\n"; + if (this.content !== undefined && this.content !== "") { + deleteNode += "edit.insert(\'" + this.content + "\');" + "\n"; + } + return deleteNode; + } + + } + + class FourSlashStateComment implements IFourSlashNode { + + constructor(private state: string) { } + + public getNode(): string { + + var lines = this.state.replace(/\r\n|\r|\n/g, '\r\n').split('\n'); + lines.forEach((line, index, array) => { array[index] = '//-' + line; }); + var stateNode = lines.join('\n'); + + return stateNode + '\n' + '\n'; + + } + + } + + class DiagnosticsLocator { + + private diagnosticsFile: string = 'diagnostics.txt'; + + public find(): string { + return this.findDiagnosticsInFolder("C:/Users"); + } + + private findDiagnosticsInFolder(path: string): string { + if (IO.directoryExists(path)) { + var diagnosticsPath = undefined; + var dir: string[] = IO.dir(path, undefined, { recursive: true }); + for (var i = 0; i < dir.length; i++) { + if (dir[i].indexOf(this.diagnosticsFile) !== -1) { + diagnosticsPath = dir[i]; + } + } + return diagnosticsPath; + } + } + + } + + var diagnosticsFile: string = undefined; + var diagnosticArgs: string[] = undefined + if (process.argv.length > 2) { + if (IO.fileExists(process.argv[2])) { + diagnosticsFile = process.argv[2]; + } + //Grab remaining arguments + diagnosticArgs = process.argv.slice(3, process.argv.length - 1); + } + + if (diagnosticsFile !== undefined) { + new FourSlashGenerator(diagnosticsFile).generate(diagnosticArgs); + } + +} \ No newline at end of file diff --git a/src/services/document.ts b/src/services/document.ts new file mode 100644 index 00000000000..44c97e6aa20 --- /dev/null +++ b/src/services/document.ts @@ -0,0 +1,6 @@ +/// + +module TypeScript.Services { + // Inject support for incremental parsing to the core compiler Document class. + Document.incrementalParse = IncrementalParser.parse; +} \ No newline at end of file diff --git a/src/services/es5compat.ts b/src/services/es5compat.ts new file mode 100644 index 00000000000..1cd6a50905a --- /dev/null +++ b/src/services/es5compat.ts @@ -0,0 +1,354 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/*----------------- ThirdPartyNotices ------------------------------------------------------- + +This file is based on or incorporates material from the projects listed below +(collectively "Third Party Code"). Microsoft is not the original author of the +Third Party Code. The original copyright notice and the license, under which +Microsoft received such Third Party Code, are set forth below. Such license and +notices are provided for informational purposes only. Microsoft licenses the Third +Party Code to you under the terms of the Apache 2.0 License. + +-- +Array filter Compatibility Method, +Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter + +Array forEach Compatibility Method, +Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach + +Array indexOf Compatibility Method, +Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf + +Array map Compatibility Method, +Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map + +Array Reduce Compatibility Method, +Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/Reduce + +Array some Compatibility Method, +Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/some + +String Trim Compatibility Method, +Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/Trim + +Date now Compatibility Method, +Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/now + +Copyright (c) 2007 - 2012 Mozilla Developer Network and individual contributors + +Licensed by Microsoft under the Apache License, Version 2.0 (the "License"); you +may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR +CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions and +limitations under the License. + +-- +Original License provided for Informational Purposes Only +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------- End of ThirdPartyNotices --------------------------------------------------- */ + + +// Compatibility with non ES5 compliant engines +if (!String.prototype.trim) { + String.prototype.trim = function() { + return this.replace(/^\s+|\s+$/g, ''); + }; +} + +// Compatibility with non ES5 compliant engines +if (!Array.prototype.indexOf) { + Array.prototype.indexOf = function (searchElement: any, fromIndex?: any) { + "use strict"; + if (this == null) { + throw new TypeError(); + } + var t = Object(this); + var len: any = t.length >>> 0; + if (len === 0) { + return -1; + } + var n: any = 0; + if (arguments.length > 0) { + n = Number(arguments[1]); + if (n != n) { // shortcut for verifying if it's NaN + n = 0; + } + else if (n != 0 && n != Infinity && n != -Infinity) { + n = (n > 0 || -1) * Math.floor(Math.abs(n)); + } + } + if (n >= len) { + return -1; + } + var k: any = n >= 0 ? n : Math.max(len - Math.abs(n), 0); + for (; k < len; k++) { + if (k in t && t[k] === searchElement) { + return k; + } + } + return -1; + } +} + +if (!Array.prototype.filter) +{ + Array.prototype.filter = function(fun: any, thisp?: any) + { + "use strict"; + + if (this == null) + throw new TypeError(); + + var t = Object(this); + var len = t.length >>> 0; + if (typeof fun != "function") + throw new TypeError(); + + var res: any[] = []; + for (var i = 0; i < len; i++) + { + if (i in t) + { + var val = t[i]; // in case fun mutates this + if (fun.call(thisp, val, i, t)) + res.push(val); + } + } + + return res; + }; +} + +// Production steps of ECMA-262, Edition 5, 15.4.4.19 +// Reference: http://es5.github.com/#x15.4.4.19 +if (!Array.prototype.map) { + Array.prototype.map = function(callback: any, thisArg?: any) { + + var T: any = undefined, A: any, k: any; + + if (this == null) { + throw new TypeError(" this is null or not defined"); + } + + // 1. Let O be the result of calling ToObject passing the |this| value as the argument. + var O = Object(this); + + // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". + // 3. Let len be ToUint32(lenValue). + var len = O.length >>> 0; + + // 4. If IsCallable(callback) is false, throw a TypeError exception. + // See: http://es5.github.com/#x9.11 + if ({}.toString.call(callback) != "[object Function]") { + throw new TypeError(callback + " is not a function"); + } + + // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. + if (thisArg) { + T = thisArg; + } + + // 6. Let A be a new array created as if by the expression new Array(len) where Array is + // the standard built-in constructor with that name and len is the value of len. + A = new Array(len); + + // 7. Let k be 0 + k = 0; + + // 8. Repeat, while k < len + while(k < len) { + + var kValue: any, mappedValue: any; + + // a. Let Pk be ToString(k). + // This is implicit for LHS operands of the in operator + // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. + // This step can be combined with c + // c. If kPresent is true, then + if (k in O) { + + // i. Let kValue be the result of calling the Get internal method of O with argument Pk. + kValue = O[ k ]; + + // ii. Let mappedValue be the result of calling the Call internal method of callback + // with T as the this value and argument list containing kValue, k, and O. + mappedValue = callback.call(T, kValue, k, O); + + // iii. Call the DefineOwnProperty internal method of A with arguments + // Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true}, + // and false. + + // In browsers that support Object.defineProperty, use the following: + // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true }); + + // For best browser support, use the following: + A[ k ] = mappedValue; + } + // d. Increase k by 1. + k++; + } + + // 9. return A + return A; + }; +} + +if (!Array.prototype.reduce) { + Array.prototype.reduce = function reduce(accumulator: any){ + if (this===null || this===undefined) throw new TypeError("Object is null or undefined"); + var i = 0, l = this.length >> 0, curr: any; + + if(typeof accumulator !== "function") // ES5 : "If IsCallable(callbackfn) is false, throw a TypeError exception." + throw new TypeError("First argument is not callable"); + + if(arguments.length < 2) { + if (l === 0) throw new TypeError("Array length is 0 and no second argument"); + curr = this[0]; + i = 1; // start accumulating at the second element + } + else + curr = arguments[1]; + + while (i < l) { + if(i in this) curr = accumulator.call(undefined, curr, this[i], i, this); + ++i; + } + + return curr; + }; +} + +// Compatibility with non ES5 compliant engines +// Production steps of ECMA-262, Edition 5, 15.4.4.18 +// Reference: http://es5.github.com/#x15.4.4.18 +if (!Array.prototype.forEach) { + Array.prototype.forEach = function(callback: any, thisArg?: any) { + + var T: any, k: any; + + if (this == null) { + throw new TypeError(" this is null or not defined"); + } + + // 1. Let O be the result of calling ToObject passing the |this| value as the argument. + var O = Object(this); + + // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". + // 3. Let len be ToUint32(lenValue). + var len = O.length >>> 0; // Hack to convert O.length to a UInt32 + + // 4. If IsCallable(callback) is false, throw a TypeError exception. + // See: http://es5.github.com/#x9.11 + if ({ }.toString.call(callback) != "[object Function]") { + throw new TypeError(callback + " is not a function"); + } + + // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. + if (thisArg) { + T = thisArg; + } + else { + T = undefined; // added to stop definite assignment error + } + + // 6. Let k be 0 + k = 0; + + // 7. Repeat, while k < len + while (k < len) { + + var kValue: any; + + // a. Let Pk be ToString(k). + // This is implicit for LHS operands of the in operator + // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. + // This step can be combined with c + // c. If kPresent is true, then + if (k in O) { + + // i. Let kValue be the result of calling the Get internal method of O with argument Pk. + kValue = O[k]; + + // ii. Call the Call internal method of callback with T as the this value and + // argument list containing kValue, k, and O. + callback.call(T, kValue, k, O); + } + // d. Increase k by 1. + k++; + } + // 8. return undefined + }; +} + +// Compatibility with non ES5 compliant engines +if (!Date.now) { + Date.now = function() { + return (new Date()).getTime(); + }; +} + +// Compatibility with non ES5 compliant engines +// Production steps of ECMA-262, Edition 5.1, 15.4.4.17 +if (!Array.prototype.some) +{ + Array.prototype.some = function(fun: any /*, thisp */) + { + "use strict"; + + if (this == null) + throw new TypeError(); + + var t = Object(this); + var len = t.length >>> 0; + if (typeof fun != "function") + throw new TypeError(); + + var thisp = arguments[1]; + for (var i = 0; i < len; i++) + { + var idx = i.toString(); // REVIEW: this line is not from the Mozilla page, necessary to avoid our compile time checks against non-string/any types in an in expression + if (idx in t && fun.call(thisp, t[i], i, t)) + return true; + } + + return false; + }; +} \ No newline at end of file diff --git a/src/services/findReferenceHelpers.ts b/src/services/findReferenceHelpers.ts new file mode 100644 index 00000000000..2e47a90ba12 --- /dev/null +++ b/src/services/findReferenceHelpers.ts @@ -0,0 +1,152 @@ +// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0. +// See LICENSE.txt in the project root for complete license information. + +/// + +module TypeScript.Services { + export class FindReferenceHelpers { + public static compareSymbolsForLexicalIdentity(firstSymbol: TypeScript.PullSymbol, secondSymbol: TypeScript.PullSymbol): boolean { + // Unwrap modules so that we're always referring to the variable. + if (!firstSymbol.isAlias() && firstSymbol.isContainer()) { + var containerForFirstSymbol = (firstSymbol); + if (containerForFirstSymbol.getInstanceSymbol()) { + firstSymbol = containerForFirstSymbol.getInstanceSymbol(); + } + } + + if (!secondSymbol.isAlias() && secondSymbol.isContainer()) { + var containerForSecondSymbol = (secondSymbol); + if (containerForSecondSymbol.getInstanceSymbol()) { + secondSymbol = containerForSecondSymbol.getInstanceSymbol(); + } + } + + if (firstSymbol.kind === secondSymbol.kind) { + if (firstSymbol === secondSymbol) { + return true; + } + + // If we have two variables and they have the same name and the same parent, then + // they are the same symbol. + if (firstSymbol.kind === TypeScript.PullElementKind.Variable && + firstSymbol.name === secondSymbol.name && + firstSymbol.getDeclarations() && firstSymbol.getDeclarations().length >= 1 && + secondSymbol.getDeclarations() && secondSymbol.getDeclarations().length >= 1) { + + var firstSymbolDecl = firstSymbol.getDeclarations()[0]; + var secondSymbolDecl = secondSymbol.getDeclarations()[0]; + + return firstSymbolDecl.getParentDecl() === secondSymbolDecl.getParentDecl(); + } + + // If we have two properties that belong to an object literal, then we need ot see + // if they came from teh same object literal ast. + if (firstSymbol.kind === TypeScript.PullElementKind.Property && + firstSymbol.name === secondSymbol.name && + firstSymbol.getDeclarations() && firstSymbol.getDeclarations().length >= 1 && + secondSymbol.getDeclarations() && secondSymbol.getDeclarations().length >= 1) { + + var firstSymbolDecl = firstSymbol.getDeclarations()[0]; + var secondSymbolDecl = secondSymbol.getDeclarations()[0]; + + var firstParentDecl = firstSymbolDecl.getParentDecl(); + var secondParentDecl = secondSymbolDecl.getParentDecl() + + if (firstParentDecl.kind === TypeScript.PullElementKind.ObjectLiteral && + secondParentDecl.kind === TypeScript.PullElementKind.ObjectLiteral) { + + return firstParentDecl.ast() === secondParentDecl.ast(); + } + } + + // check if we are dealing with the implementation of interface method or a method override + if (firstSymbol.name === secondSymbol.name) { + // at this point firstSymbol.kind === secondSymbol.kind so we can pick any of those + switch (firstSymbol.kind) { + case PullElementKind.Property: + case PullElementKind.Method: + case PullElementKind.GetAccessor: + case PullElementKind.SetAccessor: + // these kinds can only be defined in types + var t1 = firstSymbol.getContainer(); + var t2 = secondSymbol.getContainer(); + t1._resolveDeclaredSymbol(); + t2._resolveDeclaredSymbol(); + + return t1.hasBase(t2) || t2.hasBase(t1); + break; + } + } + + return false; + } + else { + switch (firstSymbol.kind) { + case TypeScript.PullElementKind.Class: { + return this.checkSymbolsForDeclarationEquality(firstSymbol, secondSymbol); + } + case TypeScript.PullElementKind.Property: { + if (firstSymbol.isAccessor()) { + var getterSymbol = (firstSymbol).getGetter(); + var setterSymbol = (firstSymbol).getSetter(); + + if (getterSymbol && getterSymbol === secondSymbol) { + return true; + } + + if (setterSymbol && setterSymbol === secondSymbol) { + return true; + } + } + return false; + } + case TypeScript.PullElementKind.Function: { + if (secondSymbol.isAccessor()) { + var getterSymbol = (secondSymbol).getGetter(); + var setterSymbol = (secondSymbol).getSetter(); + + if (getterSymbol && getterSymbol === firstSymbol) { + return true; + } + + if (setterSymbol && setterSymbol === firstSymbol) { + return true; + } + } + return false; + } + case TypeScript.PullElementKind.ConstructorMethod: { + return this.checkSymbolsForDeclarationEquality(firstSymbol, secondSymbol); + } + } + } + + return firstSymbol === secondSymbol; + } + + private static checkSymbolsForDeclarationEquality(firstSymbol: TypeScript.PullSymbol, secondSymbol: TypeScript.PullSymbol): boolean { + var firstSymbolDeclarations: TypeScript.PullDecl[] = firstSymbol.getDeclarations(); + var secondSymbolDeclarations: TypeScript.PullDecl[] = secondSymbol.getDeclarations(); + for (var i = 0, iLen = firstSymbolDeclarations.length; i < iLen; i++) { + for (var j = 0, jLen = secondSymbolDeclarations.length; j < jLen; j++) { + if (this.declarationsAreSameOrParents(firstSymbolDeclarations[i], secondSymbolDeclarations[j])) { + return true; + } + } + } + return false; + } + + private static declarationsAreSameOrParents(firstDecl: TypeScript.PullDecl, secondDecl: TypeScript.PullDecl): boolean { + var firstParent: TypeScript.PullDecl = firstDecl.getParentDecl(); + var secondParent: TypeScript.PullDecl = secondDecl.getParentDecl(); + if (firstDecl === secondDecl || + firstDecl === secondParent || + firstParent === secondDecl || + firstParent === secondParent) { + return true; + } + return false; + } + } +} \ No newline at end of file diff --git a/src/services/formatting/formatter.ts b/src/services/formatting/formatter.ts new file mode 100644 index 00000000000..e4a1229abef --- /dev/null +++ b/src/services/formatting/formatter.ts @@ -0,0 +1,320 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export class Formatter extends MultipleTokenIndenter { + private previousTokenSpan: TokenSpan = null; + private previousTokenParent: IndentationNodeContext = null; + + // TODO: implement it with skipped tokens in Fidelity + private scriptHasErrors: boolean = false; + + private rulesProvider: RulesProvider; + private formattingRequestKind: FormattingRequestKind; + private formattingContext: FormattingContext; + + constructor(textSpan: TextSpan, + sourceUnit: SourceUnitSyntax, + indentFirstToken: boolean, + options: FormattingOptions, + snapshot: ITextSnapshot, + rulesProvider: RulesProvider, + formattingRequestKind: FormattingRequestKind) { + + super(textSpan, sourceUnit, snapshot, indentFirstToken, options); + + this.previousTokenParent = this.parent().clone(this.indentationNodeContextPool()); + + this.rulesProvider = rulesProvider; + this.formattingRequestKind = formattingRequestKind; + this.formattingContext = new FormattingContext(this.snapshot(), this.formattingRequestKind); + } + + public static getEdits(textSpan: TextSpan, + sourceUnit: SourceUnitSyntax, + options: FormattingOptions, + indentFirstToken: boolean, + snapshot: ITextSnapshot, + rulesProvider: RulesProvider, + formattingRequestKind: FormattingRequestKind): TextEditInfo[] { + var walker = new Formatter(textSpan, sourceUnit, indentFirstToken, options, snapshot, rulesProvider, formattingRequestKind); + visitNodeOrToken(walker, sourceUnit); + return walker.edits(); + } + + public visitTokenInSpan(token: ISyntaxToken): void { + if (token.fullWidth() !== 0) { + var tokenSpan = new TextSpan(this.position() + token.leadingTriviaWidth(), width(token)); + if (this.textSpan().containsTextSpan(tokenSpan)) { + this.processToken(token); + } + } + + // Call the base class to process the token and indent it if needed + super.visitTokenInSpan(token); + } + + private processToken(token: ISyntaxToken): void { + var position = this.position(); + + // Extract any leading comments + if (token.leadingTriviaWidth() !== 0) { + this.processTrivia(token.leadingTrivia(), position); + position += token.leadingTriviaWidth(); + } + + // Push the token + var currentTokenSpan = new TokenSpan(token.kind(), position, width(token)); + if (!this.parent().hasSkippedOrMissingTokenChild()) { + if (this.previousTokenSpan) { + // Note that formatPair calls TrimWhitespaceInLineRange in between the 2 tokens + this.formatPair(this.previousTokenSpan, this.previousTokenParent, currentTokenSpan, this.parent()); + } + else { + // We still want to trim whitespace even if it is the first trivia of the first token. Trim from the beginning of the span to the trivia + this.trimWhitespaceInLineRange(this.getLineNumber(this.textSpan()), this.getLineNumber(currentTokenSpan)); + } + } + this.previousTokenSpan = currentTokenSpan; + if (this.previousTokenParent) { + // Make sure to clear the previous parent before assigning a new value to it + this.indentationNodeContextPool().releaseNode(this.previousTokenParent, /* recursive */true); + } + this.previousTokenParent = this.parent().clone(this.indentationNodeContextPool()); + position += width(token); + + // Extract any trailing comments + if (token.trailingTriviaWidth() !== 0) { + this.processTrivia(token.trailingTrivia(), position); + } + } + + private processTrivia(triviaList: ISyntaxTriviaList, fullStart: number) { + var position = fullStart; + + for (var i = 0, n = triviaList.count(); i < n ; i++) { + var trivia = triviaList.syntaxTriviaAt(i); + // For a comment, format it like it is a token. For skipped text, eat it up as a token, but skip the formatting + if (trivia.isComment() || trivia.isSkippedToken()) { + var currentTokenSpan = new TokenSpan(trivia.kind(), position, trivia.fullWidth()); + if (this.textSpan().containsTextSpan(currentTokenSpan)) { + if (trivia.isComment() && this.previousTokenSpan) { + // Note that formatPair calls TrimWhitespaceInLineRange in between the 2 tokens + this.formatPair(this.previousTokenSpan, this.previousTokenParent, currentTokenSpan, this.parent()); + } + else { + // We still want to trim whitespace even if it is the first trivia of the first token. Trim from the beginning of the span to the trivia + var startLine = this.getLineNumber(this.previousTokenSpan || this.textSpan()); + this.trimWhitespaceInLineRange(startLine, this.getLineNumber(currentTokenSpan)); + } + this.previousTokenSpan = currentTokenSpan; + if (this.previousTokenParent) { + // Make sure to clear the previous parent before assigning a new value to it + this.indentationNodeContextPool().releaseNode(this.previousTokenParent, /* recursive */true); + } + this.previousTokenParent = this.parent().clone(this.indentationNodeContextPool()); + } + } + + position += trivia.fullWidth(); + } + } + + private findCommonParents(parent1: IndentationNodeContext, parent2: IndentationNodeContext): IndentationNodeContext { + // TODO: disable debug assert message + + var shallowParent: IndentationNodeContext; + var shallowParentDepth: number; + var deepParent: IndentationNodeContext; + var deepParentDepth: number; + + if (parent1.depth() < parent2.depth()) { + shallowParent = parent1; + shallowParentDepth = parent1.depth(); + deepParent = parent2; + deepParentDepth = parent2.depth(); + } + else { + shallowParent = parent2; + shallowParentDepth = parent2.depth(); + deepParent = parent1; + deepParentDepth = parent1.depth(); + } + + Debug.assert(shallowParentDepth >= 0, "Expected shallowParentDepth >= 0"); + Debug.assert(deepParentDepth >= 0, "Expected deepParentDepth >= 0"); + Debug.assert(deepParentDepth >= shallowParentDepth, "Expected deepParentDepth >= shallowParentDepth"); + + while (deepParentDepth > shallowParentDepth) { + deepParent = deepParent.parent(); + deepParentDepth--; + } + + Debug.assert(deepParentDepth === shallowParentDepth, "Expected deepParentDepth === shallowParentDepth"); + + while (deepParent.node() && shallowParent.node()) { + if (deepParent.node() === shallowParent.node()) { + return deepParent; + } + deepParent = deepParent.parent(); + shallowParent = shallowParent.parent(); + } + + // The root should be the first element in the parent chain, we can not be here unless something wrong + // happened along the way + throw Errors.invalidOperation(); + } + + private formatPair(t1: TokenSpan, t1Parent: IndentationNodeContext, t2: TokenSpan, t2Parent: IndentationNodeContext): void { + var token1Line = this.getLineNumber(t1); + var token2Line = this.getLineNumber(t2); + + // Find common parent + var commonParent= this.findCommonParents(t1Parent, t2Parent); + + // Update the context + this.formattingContext.updateContext(t1, t1Parent, t2, t2Parent, commonParent); + + // Find rules matching the current context + var rule = this.rulesProvider.getRulesMap().GetRule(this.formattingContext); + + if (rule != null) { + // Record edits from the rule + this.RecordRuleEdits(rule, t1, t2); + + // Handle the case where the next line is moved to be the end of this line. + // In this case we don't indent the next line in the next pass. + if ((rule.Operation.Action == RuleAction.Space || rule.Operation.Action == RuleAction.Delete) && + token1Line != token2Line) { + this.forceSkipIndentingNextToken(t2.start()); + } + + // Handle the case where token2 is moved to the new line. + // In this case we indent token2 in the next pass but we set + // sameLineIndent flag to notify the indenter that the indentation is within the line. + if (rule.Operation.Action == RuleAction.NewLine && token1Line == token2Line) { + this.forceIndentNextToken(t2.start()); + } + } + + // We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line + if (token1Line != token2Line && (!rule || (rule.Operation.Action != RuleAction.Delete && rule.Flag != RuleFlags.CanDeleteNewLines))) { + this.trimWhitespaceInLineRange(token1Line, token2Line, t1); + } + } + + private getLineNumber(span: TextSpan): number { + return this.snapshot().getLineNumberFromPosition(span.start()); + } + + private trimWhitespaceInLineRange(startLine: number, endLine: number, token?: TokenSpan): void { + for (var lineNumber = startLine; lineNumber < endLine; ++lineNumber) { + var line = this.snapshot().getLineFromLineNumber(lineNumber); + + this.trimWhitespace(line, token); + } + } + + private trimWhitespace(line: ITextSnapshotLine, token?: TokenSpan): void { + // Don't remove the trailing spaces inside comments (this includes line comments and block comments) + if (token && (token.kind == SyntaxKind.MultiLineCommentTrivia || token.kind == SyntaxKind.SingleLineCommentTrivia) && token.start() <= line.endPosition() && token.end() >= line.endPosition()) + return; + + var text = line.getText(); + var index = 0; + + for (index = text.length - 1; index >= 0; --index) { + if (!CharacterInfo.isWhitespace(text.charCodeAt(index))) { + break; + } + } + + ++index; + + if (index < text.length) { + this.recordEdit(line.startPosition() + index, line.length() - index, ""); + } + } + + private RecordRuleEdits(rule: Rule, t1: TokenSpan, t2: TokenSpan): void { + if (rule.Operation.Action == RuleAction.Ignore) { + return; + } + + var betweenSpan: TextSpan; + + switch (rule.Operation.Action) { + case RuleAction.Delete: + { + betweenSpan = new TextSpan(t1.end(), t2.start() - t1.end()); + + if (betweenSpan.length() > 0) { + this.recordEdit(betweenSpan.start(), betweenSpan.length(), ""); + return; + } + } + break; + + case RuleAction.NewLine: + { + if (!(rule.Flag == RuleFlags.CanDeleteNewLines || this.getLineNumber(t1) == this.getLineNumber(t2))) { + return; + } + + betweenSpan = new TextSpan(t1.end(), t2.start() - t1.end()); + + var doEdit = false; + var betweenText = this.snapshot().getText(betweenSpan); + + var lineFeedLoc = betweenText.indexOf(this.options.newLineCharacter); + if (lineFeedLoc < 0) { + // no linefeeds, do the edit + doEdit = true; + } + else { + // We only require one line feed. If there is another one, do the edit + lineFeedLoc = betweenText.indexOf(this.options.newLineCharacter, lineFeedLoc + 1); + if (lineFeedLoc >= 0) { + doEdit = true; + } + } + + if (doEdit) { + this.recordEdit(betweenSpan.start(), betweenSpan.length(), this.options.newLineCharacter); + return; + } + } + break; + + case RuleAction.Space: + { + if (!(rule.Flag == RuleFlags.CanDeleteNewLines || this.getLineNumber(t1) == this.getLineNumber(t2))) { + return; + } + + betweenSpan = new TextSpan(t1.end(), t2.start() - t1.end()); + + if (betweenSpan.length() > 1 || this.snapshot().getText(betweenSpan) != " ") { + this.recordEdit(betweenSpan.start(), betweenSpan.length(), " "); + return; + } + } + break; + } + } + } +} \ No newline at end of file diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts new file mode 100644 index 00000000000..d8e510b13a6 --- /dev/null +++ b/src/services/formatting/formatting.ts @@ -0,0 +1,40 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// \ No newline at end of file diff --git a/src/services/formatting/formattingContext.ts b/src/services/formatting/formattingContext.ts new file mode 100644 index 00000000000..9ced31ecef2 --- /dev/null +++ b/src/services/formatting/formattingContext.ts @@ -0,0 +1,116 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export class FormattingContext { + public currentTokenSpan: TokenSpan = null; + public nextTokenSpan: TokenSpan = null; + public contextNode: IndentationNodeContext = null; + public currentTokenParent: IndentationNodeContext = null; + public nextTokenParent: IndentationNodeContext = null; + + private contextNodeAllOnSameLine: boolean = null; + private nextNodeAllOnSameLine: boolean = null; + private tokensAreOnSameLine: boolean = null; + private contextNodeBlockIsOnOneLine: boolean = null; + private nextNodeBlockIsOnOneLine: boolean = null; + + constructor(private snapshot: ITextSnapshot, public formattingRequestKind: FormattingRequestKind) { + Debug.assert(this.snapshot != null, "snapshot is null"); + } + + public updateContext(currentTokenSpan: TokenSpan, currentTokenParent: IndentationNodeContext, nextTokenSpan: TokenSpan, nextTokenParent: IndentationNodeContext, commonParent: IndentationNodeContext) { + Debug.assert(currentTokenSpan != null, "currentTokenSpan is null"); + Debug.assert(currentTokenParent != null, "currentTokenParent is null"); + Debug.assert(nextTokenSpan != null, "nextTokenSpan is null"); + Debug.assert(nextTokenParent != null, "nextTokenParent is null"); + Debug.assert(commonParent != null, "commonParent is null"); + + this.currentTokenSpan = currentTokenSpan; + this.currentTokenParent = currentTokenParent; + this.nextTokenSpan = nextTokenSpan; + this.nextTokenParent = nextTokenParent; + this.contextNode = commonParent; + + this.contextNodeAllOnSameLine = null; + this.nextNodeAllOnSameLine = null; + this.tokensAreOnSameLine = null; + this.contextNodeBlockIsOnOneLine = null; + this.nextNodeBlockIsOnOneLine = null; + } + + public ContextNodeAllOnSameLine(): boolean { + if (this.contextNodeAllOnSameLine === null) { + this.contextNodeAllOnSameLine = this.NodeIsOnOneLine(this.contextNode); + } + + return this.contextNodeAllOnSameLine; + } + + public NextNodeAllOnSameLine(): boolean { + if (this.nextNodeAllOnSameLine === null) { + this.nextNodeAllOnSameLine = this.NodeIsOnOneLine(this.nextTokenParent); + } + + return this.nextNodeAllOnSameLine; + } + + public TokensAreOnSameLine(): boolean { + if (this.tokensAreOnSameLine === null) { + var startLine = this.snapshot.getLineNumberFromPosition(this.currentTokenSpan.start()); + var endLine = this.snapshot.getLineNumberFromPosition(this.nextTokenSpan.start()); + + this.tokensAreOnSameLine = (startLine == endLine); + } + + return this.tokensAreOnSameLine; + } + + public ContextNodeBlockIsOnOneLine() { + if (this.contextNodeBlockIsOnOneLine === null) { + this.contextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.contextNode); + } + + return this.contextNodeBlockIsOnOneLine; + } + + public NextNodeBlockIsOnOneLine() { + if (this.nextNodeBlockIsOnOneLine === null) { + this.nextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.nextTokenParent); + } + + return this.nextNodeBlockIsOnOneLine; + } + + public NodeIsOnOneLine(node: IndentationNodeContext): boolean { + var startLine = this.snapshot.getLineNumberFromPosition(node.start()); + var endLine = this.snapshot.getLineNumberFromPosition(node.end()); + + return startLine == endLine; + } + + // Now we know we have a block (or a fake block represented by some other kind of node with an open and close brace as children). + // IMPORTANT!!! This relies on the invariant that IsBlockContext must return true ONLY for nodes with open and close braces as immediate children + public BlockIsOnOneLine(node: IndentationNodeContext): boolean { + var block = node.node(); + + // Now check if they are on the same line + return this.snapshot.getLineNumberFromPosition(end(block.openBraceToken)) === + this.snapshot.getLineNumberFromPosition(start(block.closeBraceToken)); + } + } +} \ No newline at end of file diff --git a/src/services/formatting/formattingManager.ts b/src/services/formatting/formattingManager.ts new file mode 100644 index 00000000000..b3cdf5fd4f6 --- /dev/null +++ b/src/services/formatting/formattingManager.ts @@ -0,0 +1,125 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export class FormattingManager { + private options: FormattingOptions; + + constructor(private syntaxTree: SyntaxTree, private snapshot: ITextSnapshot, private rulesProvider: RulesProvider, editorOptions: TypeScript.Services.EditorOptions) { + // + // TODO: convert to use FormattingOptions instead of EditorOptions + this.options = new FormattingOptions(!editorOptions.ConvertTabsToSpaces, editorOptions.TabSize, editorOptions.IndentSize, editorOptions.NewLineCharacter) + } + + public formatSelection(minChar: number, limChar: number): TypeScript.Services.TextEdit[] { + var span = TextSpan.fromBounds(minChar, limChar); + return this.formatSpan(span, FormattingRequestKind.FormatSelection); + } + + public formatDocument(minChar: number, limChar: number): TypeScript.Services.TextEdit[] { + var span = TextSpan.fromBounds(minChar, limChar); + return this.formatSpan(span, FormattingRequestKind.FormatDocument); + } + + public formatOnPaste(minChar: number, limChar: number): TypeScript.Services.TextEdit[] { + var span = TextSpan.fromBounds(minChar, limChar); + return this.formatSpan(span, FormattingRequestKind.FormatOnPaste); + } + + public formatOnSemicolon(caretPosition: number): TypeScript.Services.TextEdit[] { + var sourceUnit = this.syntaxTree.sourceUnit(); + var semicolonPositionedToken = findToken(sourceUnit, caretPosition - 1); + + if (semicolonPositionedToken.kind() === SyntaxKind.SemicolonToken) { + // Find the outer most parent that this semicolon terminates + var current: ISyntaxElement = semicolonPositionedToken; + while (current.parent !== null && + end(current.parent) === end(semicolonPositionedToken) && + current.parent.kind() !== SyntaxKind.List) { + current = current.parent; + } + + // Compute the span + var span = new TextSpan(fullStart(current), fullWidth(current)); + + // Format the span + return this.formatSpan(span, FormattingRequestKind.FormatOnSemicolon); + } + + return []; + } + + public formatOnClosingCurlyBrace(caretPosition: number): TypeScript.Services.TextEdit[] { + var sourceUnit = this.syntaxTree.sourceUnit(); + var closeBracePositionedToken = findToken(sourceUnit, caretPosition - 1); + + if (closeBracePositionedToken.kind() === SyntaxKind.CloseBraceToken) { + // Find the outer most parent that this closing brace terminates + var current: ISyntaxElement = closeBracePositionedToken; + while (current.parent !== null && + end(current.parent) === end(closeBracePositionedToken) && + current.parent.kind() !== SyntaxKind.List) { + current = current.parent; + } + + // Compute the span + var span = new TextSpan(fullStart(current), fullWidth(current)); + + // Format the span + return this.formatSpan(span, FormattingRequestKind.FormatOnClosingCurlyBrace); + } + + return []; + } + + public formatOnEnter(caretPosition: number): TypeScript.Services.TextEdit[] { + var lineNumber = this.snapshot.getLineNumberFromPosition(caretPosition); + + if (lineNumber > 0) { + // Format both lines + var prevLine = this.snapshot.getLineFromLineNumber(lineNumber - 1); + var currentLine = this.snapshot.getLineFromLineNumber(lineNumber); + var span = TextSpan.fromBounds(prevLine.startPosition(), currentLine.endPosition()); + + // Format the span + return this.formatSpan(span, FormattingRequestKind.FormatOnEnter); + + } + + return []; + } + + private formatSpan(span: TextSpan, formattingRequestKind: FormattingRequestKind): TypeScript.Services.TextEdit[] { + // Always format from the beginning of the line + var startLine = this.snapshot.getLineFromPosition(span.start()); + span = TextSpan.fromBounds(startLine.startPosition(), span.end()); + + var result: TypeScript.Services.TextEdit[] = []; + + var formattingEdits = Formatter.getEdits(span, this.syntaxTree.sourceUnit(), this.options, true, this.snapshot, this.rulesProvider, formattingRequestKind); + + // + // TODO: Change the ILanguageService interface to return TextEditInfo (with start, and length) instead of TextEdit (with minChar and limChar) + formattingEdits.forEach((item) => { + var edit = new TypeScript.Services.TextEdit(item.position, item.position + item.length, item.replaceWith); + result.push(edit); + }); + + return result; + } + } +} \ No newline at end of file diff --git a/src/services/formatting/formattingRequestKind.ts b/src/services/formatting/formattingRequestKind.ts new file mode 100644 index 00000000000..b766058e1ca --- /dev/null +++ b/src/services/formatting/formattingRequestKind.ts @@ -0,0 +1,27 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export enum FormattingRequestKind { + FormatDocument, + FormatSelection, + FormatOnEnter, + FormatOnSemicolon, + FormatOnClosingCurlyBrace, + FormatOnPaste + } +} \ No newline at end of file diff --git a/src/services/formatting/indentationNodeContext.ts b/src/services/formatting/indentationNodeContext.ts new file mode 100644 index 00000000000..398d4998eed --- /dev/null +++ b/src/services/formatting/indentationNodeContext.ts @@ -0,0 +1,103 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export class IndentationNodeContext { + private _node: ISyntaxNode; + private _parent: IndentationNodeContext; + private _fullStart: number; + private _indentationAmount: number; + private _childIndentationAmountDelta: number; + private _depth: number; + private _hasSkippedOrMissingTokenChild: boolean; + + constructor(parent: IndentationNodeContext, node: ISyntaxNode, fullStart: number, indentationAmount: number, childIndentationAmountDelta: number) { + this.update(parent, node, fullStart, indentationAmount, childIndentationAmountDelta); + } + + public parent(): IndentationNodeContext { + return this._parent; + } + + public node(): ISyntaxNode { + return this._node; + } + + public fullStart(): number { + return this._fullStart; + } + + public fullWidth(): number { + return fullWidth(this._node); + } + + public start(): number { + return this._fullStart + leadingTriviaWidth(this._node); + } + + public end(): number { + return this._fullStart + leadingTriviaWidth(this._node) + width(this._node); + } + + public indentationAmount(): number { + return this._indentationAmount; + } + + public childIndentationAmountDelta(): number { + return this._childIndentationAmountDelta; + } + + public depth(): number { + return this._depth; + } + + public kind(): SyntaxKind { + return this._node.kind(); + } + + public hasSkippedOrMissingTokenChild(): boolean { + if (this._hasSkippedOrMissingTokenChild === null) { + this._hasSkippedOrMissingTokenChild = Syntax.nodeHasSkippedOrMissingTokens(this._node); + } + return this._hasSkippedOrMissingTokenChild; + } + + public clone(pool: IndentationNodeContextPool): IndentationNodeContext { + var parent: IndentationNodeContext = null; + if (this._parent) { + parent = this._parent.clone(pool); + } + return pool.getNode(parent, this._node, this._fullStart, this._indentationAmount, this._childIndentationAmountDelta); + } + + public update(parent: IndentationNodeContext, node: ISyntaxNode, fullStart: number, indentationAmount: number, childIndentationAmountDelta: number) { + this._parent = parent; + this._node = node; + this._fullStart = fullStart; + this._indentationAmount = indentationAmount; + this._childIndentationAmountDelta = childIndentationAmountDelta; + this._hasSkippedOrMissingTokenChild = null; + + if (parent) { + this._depth = parent.depth() + 1; + } + else { + this._depth = 0; + } + } + } +} \ No newline at end of file diff --git a/src/services/formatting/indentationNodeContextPool.ts b/src/services/formatting/indentationNodeContextPool.ts new file mode 100644 index 00000000000..ea5b26277b5 --- /dev/null +++ b/src/services/formatting/indentationNodeContextPool.ts @@ -0,0 +1,43 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export class IndentationNodeContextPool { + private nodes: IndentationNodeContext[] = []; + + public getNode(parent: IndentationNodeContext, node: ISyntaxNode, fullStart: number, indentationLevel: number, childIndentationLevelDelta: number): IndentationNodeContext { + if (this.nodes.length > 0) { + var cachedNode = this.nodes.pop(); + cachedNode.update(parent, node, fullStart, indentationLevel, childIndentationLevelDelta); + return cachedNode; + } + + return new IndentationNodeContext(parent, node, fullStart, indentationLevel, childIndentationLevelDelta); + } + + public releaseNode(node: IndentationNodeContext, recursive: boolean = false): void { + this.nodes.push(node); + + if (recursive) { + var parent = node.parent(); + if (parent) { + this.releaseNode(parent, recursive); + } + } + } + } +} \ No newline at end of file diff --git a/src/services/formatting/indentationTrackingWalker.ts b/src/services/formatting/indentationTrackingWalker.ts new file mode 100644 index 00000000000..b07b477623e --- /dev/null +++ b/src/services/formatting/indentationTrackingWalker.ts @@ -0,0 +1,349 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export class IndentationTrackingWalker extends SyntaxWalker { + private _position: number = 0; + private _parent: IndentationNodeContext = null; + private _textSpan: TextSpan; + private _snapshot: ITextSnapshot; + private _lastTriviaWasNewLine: boolean; + private _indentationNodeContextPool: IndentationNodeContextPool; + private _text: ISimpleText; + + constructor(textSpan: TextSpan, sourceUnit: SourceUnitSyntax, snapshot: ITextSnapshot, indentFirstToken: boolean, public options: FormattingOptions) { + super(); + + // Create a pool object to manage context nodes while walking the tree + this._indentationNodeContextPool = new IndentationNodeContextPool(); + + this._textSpan = textSpan; + this._text = sourceUnit.syntaxTree.text; + this._snapshot = snapshot; + this._parent = this._indentationNodeContextPool.getNode(null, sourceUnit, 0, 0, 0); + + // Is the first token in the span at the start of a new line. + this._lastTriviaWasNewLine = indentFirstToken; + } + + public position(): number { + return this._position; + } + + public parent(): IndentationNodeContext { + return this._parent; + } + + public textSpan(): TextSpan { + return this._textSpan; + } + + public snapshot(): ITextSnapshot { + return this._snapshot; + } + + public indentationNodeContextPool(): IndentationNodeContextPool { + return this._indentationNodeContextPool; + } + + public forceIndentNextToken(tokenStart: number): void { + this._lastTriviaWasNewLine = true; + this.forceRecomputeIndentationOfParent(tokenStart, true); + } + + public forceSkipIndentingNextToken(tokenStart: number): void { + this._lastTriviaWasNewLine = false; + this.forceRecomputeIndentationOfParent(tokenStart, false); + } + + public indentToken(token: ISyntaxToken, indentationAmount: number, commentIndentationAmount: number): void { + throw Errors.abstract(); + } + + public visitTokenInSpan(token: ISyntaxToken): void { + if (this._lastTriviaWasNewLine) { + // Compute the indentation level at the current token + var indentationAmount = this.getTokenIndentationAmount(token); + var commentIndentationAmount = this.getCommentIndentationAmount(token); + + // Process the token + this.indentToken(token, indentationAmount, commentIndentationAmount); + } + } + + public visitToken(token: ISyntaxToken): void { + var tokenSpan = new TextSpan(this._position, token.fullWidth()); + + if (tokenSpan.intersectsWithTextSpan(this._textSpan)) { + this.visitTokenInSpan(token); + + // Only track new lines on tokens within the range. Make sure to check that the last trivia is a newline, and not just one of the trivia + var trivia = token.trailingTrivia(); + this._lastTriviaWasNewLine = trivia.hasNewLine() && trivia.syntaxTriviaAt(trivia.count() - 1).kind() == SyntaxKind.NewLineTrivia; + } + + // Update the position + this._position += token.fullWidth(); + } + + public visitNode(node: ISyntaxNode): void { + var nodeSpan = new TextSpan(this._position, fullWidth(node)); + + if (nodeSpan.intersectsWithTextSpan(this._textSpan)) { + // Update indentation level + var indentation = this.getNodeIndentation(node); + + // Update the parent + var currentParent = this._parent; + this._parent = this._indentationNodeContextPool.getNode(currentParent, node, this._position, indentation.indentationAmount, indentation.indentationAmountDelta); + + // Visit node + visitNodeOrToken(this, node); + + // Reset state + this._indentationNodeContextPool.releaseNode(this._parent); + this._parent = currentParent; + } + else { + // We're skipping the node, so update our position accordingly. + this._position += fullWidth(node); + } + } + + private getTokenIndentationAmount(token: ISyntaxToken): number { + // If this is the first token of a node, it should follow the node indentation and not the child indentation; + // (e.g.class in a class declaration or module in module declariotion). + // Open and close braces should follow the indentation of thier parent as well(e.g. + // class { + // } + // Also in a do-while statement, the while should be indented like the parent. + if (firstToken(this._parent.node()) === token || + token.kind() === SyntaxKind.OpenBraceToken || token.kind() === SyntaxKind.CloseBraceToken || + token.kind() === SyntaxKind.OpenBracketToken || token.kind() === SyntaxKind.CloseBracketToken || + (token.kind() === SyntaxKind.WhileKeyword && this._parent.node().kind() == SyntaxKind.DoStatement)) { + return this._parent.indentationAmount(); + } + + return (this._parent.indentationAmount() + this._parent.childIndentationAmountDelta()); + } + + private getCommentIndentationAmount(token: ISyntaxToken): number { + // If this is token terminating an indentation scope, leading comments should be indented to follow the children + // indentation level and not the node + + if (token.kind() === SyntaxKind.CloseBraceToken || token.kind() === SyntaxKind.CloseBracketToken) { + return (this._parent.indentationAmount() + this._parent.childIndentationAmountDelta()); + } + return this._parent.indentationAmount(); + } + + private getNodeIndentation(node: ISyntaxNode, newLineInsertedByFormatting?: boolean): { indentationAmount: number; indentationAmountDelta: number; } { + var parent = this._parent; + + // We need to get the parent's indentation, which could be one of 2 things. If first token of the parent is in the span, use the parent's computed indentation. + // If the parent was outside the span, use the actual indentation of the parent. + var parentIndentationAmount: number; + if (this._textSpan.containsPosition(parent.start())) { + parentIndentationAmount = parent.indentationAmount(); + } + else { + if (parent.kind() === SyntaxKind.Block && !this.shouldIndentBlockInParent(this._parent.parent())) { + // Blocks preserve the indentation of their containing node (unless they're a + // standalone block in a list). i.e. if you have: + // + // function foo( + // a: number) { + // + // Then we expect the indentation of the block to be tied to the function, not to + // the line that the block is defined on. If we were to do the latter, then the + // indentation would be here: + // + // function foo( + // a: number) { + // | + // + // Instead of: + // + // function foo( + // a: number) { + // | + parent = this._parent.parent(); + } + + var line = this._snapshot.getLineFromPosition(parent.start()).getText(); + var firstNonWhiteSpacePosition = Indentation.firstNonWhitespacePosition(line); + parentIndentationAmount = Indentation.columnForPositionInString(line, firstNonWhiteSpacePosition, this.options); + } + var parentIndentationAmountDelta = parent.childIndentationAmountDelta(); + + // The indentation level of the node + var indentationAmount: number; + + // The delta it adds to its children. + var indentationAmountDelta: number; + var parentNode = parent.node(); + + switch (node.kind()) { + default: + // General case + // This node should follow the child indentation set by its parent + // This node does not introduce any new indentation scope, indent any decendants of this node (tokens or child nodes) + // using the same indentation level + indentationAmount = (parentIndentationAmount + parentIndentationAmountDelta); + indentationAmountDelta = 0; + break; + + // Statements introducing {} + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.ObjectType: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.SwitchStatement: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.ConstructorDeclaration: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.MemberFunctionDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.IndexMemberDeclaration: + case SyntaxKind.CatchClause: + // Statements introducing [] + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.ArrayType: + case SyntaxKind.ElementAccessExpression: + case SyntaxKind.IndexSignature: + // Other statements + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.CaseSwitchClause: + case SyntaxKind.DefaultSwitchClause: + case SyntaxKind.ReturnStatement: + case SyntaxKind.ThrowStatement: + case SyntaxKind.SimpleArrowFunctionExpression: + case SyntaxKind.ParenthesizedArrowFunctionExpression: + case SyntaxKind.VariableDeclaration: + case SyntaxKind.ExportAssignment: + + // Expressions which have argument lists or parameter lists + case SyntaxKind.InvocationExpression: + case SyntaxKind.ObjectCreationExpression: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + + // These nodes should follow the child indentation set by its parent; + // they introduce a new indenation scope; children should be indented at one level deeper + indentationAmount = (parentIndentationAmount + parentIndentationAmountDelta); + indentationAmountDelta = this.options.indentSpaces; + break; + + case SyntaxKind.IfStatement: + if (parent.kind() === SyntaxKind.ElseClause && + !SyntaxUtilities.isLastTokenOnLine((parentNode).elseKeyword, this._text)) { + // This is an else if statement with the if on the same line as the else, do not indent the if statmement. + // Note: Children indentation has already been set by the parent if statement, so no need to increment + indentationAmount = parentIndentationAmount; + } + else { + // Otherwise introduce a new indenation scope; children should be indented at one level deeper + indentationAmount = (parentIndentationAmount + parentIndentationAmountDelta); + } + indentationAmountDelta = this.options.indentSpaces; + break; + + case SyntaxKind.ElseClause: + // Else should always follow its parent if statement indentation. + // Note: Children indentation has already been set by the parent if statement, so no need to increment + indentationAmount = parentIndentationAmount; + indentationAmountDelta = this.options.indentSpaces; + break; + + + case SyntaxKind.Block: + // Check if the block is a member in a list of statements (if the parent is a source unit, module, or block, or switch clause) + if (this.shouldIndentBlockInParent(parent)) { + indentationAmount = parentIndentationAmount + parentIndentationAmountDelta; + } + else { + indentationAmount = parentIndentationAmount; + } + + indentationAmountDelta = this.options.indentSpaces; + break; + } + + // If the parent happens to start on the same line as this node, then override the current node indenation with that + // of the parent. This avoid having to add an extra level of indentation for the children. e.g.: + // return { + // a:1 + // }; + // instead of: + // return { + // a:1 + // }; + // We also need to pass the delta (if it is nonzero) to the children, so that subsequent lines get indented. Essentially, if any node starting on the given line + // has a nonzero delta , the resulting delta should be inherited from this node. This is to indent cases like the following: + // return a + // || b; + // Lastly, it is possible the node indentation needs to be recomputed because the formatter inserted a newline before its first token. + // If this is the case, we know the node no longer starts on the same line as its parent (or at least we shouldn't treat it as such). + if (parentNode) { + if (!newLineInsertedByFormatting /*This could be false or undefined here*/) { + var parentStartLine = this._snapshot.getLineNumberFromPosition(parent.start()); + var currentNodeStartLine = this._snapshot.getLineNumberFromPosition(this._position + leadingTriviaWidth(node)); + if (parentStartLine === currentNodeStartLine || newLineInsertedByFormatting === false /*meaning a new line was removed and we are force recomputing*/) { + indentationAmount = parentIndentationAmount; + indentationAmountDelta = Math.min(this.options.indentSpaces, parentIndentationAmountDelta + indentationAmountDelta); + } + } + } + + return { + indentationAmount: indentationAmount, + indentationAmountDelta: indentationAmountDelta + }; + } + + private shouldIndentBlockInParent(parent: IndentationNodeContext): boolean { + switch (parent.kind()) { + case SyntaxKind.SourceUnit: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.Block: + case SyntaxKind.CaseSwitchClause: + case SyntaxKind.DefaultSwitchClause: + return true; + + default: + return false; + } + } + + private forceRecomputeIndentationOfParent(tokenStart: number, newLineAdded: boolean /*as opposed to removed*/): void { + var parent = this._parent; + if (parent.fullStart() === tokenStart) { + // Temporarily pop the parent before recomputing + this._parent = parent.parent(); + var indentation = this.getNodeIndentation(parent.node(), /* newLineInsertedByFormatting */ newLineAdded); + parent.update(parent.parent(), parent.node(), parent.fullStart(), indentation.indentationAmount, indentation.indentationAmountDelta); + this._parent = parent; + } + } + } +} \ No newline at end of file diff --git a/src/services/formatting/multipleTokenIndenter.ts b/src/services/formatting/multipleTokenIndenter.ts new file mode 100644 index 00000000000..23181571427 --- /dev/null +++ b/src/services/formatting/multipleTokenIndenter.ts @@ -0,0 +1,206 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export class MultipleTokenIndenter extends IndentationTrackingWalker { + private _edits: TextEditInfo[] = []; + + constructor(textSpan: TextSpan, sourceUnit: SourceUnitSyntax, snapshot: ITextSnapshot, indentFirstToken: boolean, options: FormattingOptions) { + super(textSpan, sourceUnit, snapshot, indentFirstToken, options); + } + + public indentToken(token: ISyntaxToken, indentationAmount: number, commentIndentationAmount: number): void { + // Ignore generated tokens + if (token.fullWidth() === 0) { + return; + } + + // If we have any skipped tokens as children, do not process this node for indentation or formatting + if (this.parent().hasSkippedOrMissingTokenChild()) { + return; + } + + // Be strict, and only consider nodes that fall inside the span. This avoids indenting a multiline string + // on enter at the end of, as the whole token was not included in the span + var tokenSpan = new TextSpan(this.position() + token.leadingTriviaWidth(), width(token)); + if (!this.textSpan().containsTextSpan(tokenSpan)) { + return; + } + + // Compute an indentation string for this token + var indentationString = Indentation.indentationString(indentationAmount, this.options); + + var commentIndentationString = Indentation.indentationString(commentIndentationAmount, this.options); + + // Record any needed indentation edits + this.recordIndentationEditsForToken(token, indentationString, commentIndentationString); + } + + public edits(): TextEditInfo[]{ + return this._edits; + } + + public recordEdit(position: number, length: number, replaceWith: string): void { + this._edits.push(new TextEditInfo(position, length, replaceWith)); + } + + private recordIndentationEditsForToken(token: ISyntaxToken, indentationString: string, commentIndentationString: string) { + var position = this.position(); + var indentNextTokenOrTrivia = true; + var leadingWhiteSpace = ""; // We need to track the whitespace before a multiline comment + + // Process any leading trivia if any + var triviaList = token.leadingTrivia(); + if (triviaList) { + for (var i = 0, length = triviaList.count(); i < length; i++, position += trivia.fullWidth()) { + var trivia = triviaList.syntaxTriviaAt(i); + // Skip this trivia if it is not in the span + if (!this.textSpan().containsTextSpan(new TextSpan(position, trivia.fullWidth()))) { + continue; + } + + switch (trivia.kind()) { + case SyntaxKind.MultiLineCommentTrivia: + // We will only indent the first line of the multiline comment if we were planning to indent the next trivia. However, + // subsequent lines will always be indented + this.recordIndentationEditsForMultiLineComment(trivia, position, commentIndentationString, leadingWhiteSpace, !indentNextTokenOrTrivia /* already indented first line */); + indentNextTokenOrTrivia = false; + leadingWhiteSpace = ""; + break; + + case SyntaxKind.SingleLineCommentTrivia: + case SyntaxKind.SkippedTokenTrivia: + if (indentNextTokenOrTrivia) { + this.recordIndentationEditsForSingleLineOrSkippedText(trivia, position, commentIndentationString); + indentNextTokenOrTrivia = false; + } + break; + + case SyntaxKind.WhitespaceTrivia: + // If the next trivia is a comment, use the comment indentation level instead of the regular indentation level + // If the next trivia is a newline, this whole line is just whitespace, so don't do anything (trimming will take care of it) + var nextTrivia = length > i + 1 && triviaList.syntaxTriviaAt(i + 1); + var whiteSpaceIndentationString = nextTrivia && nextTrivia.isComment() ? commentIndentationString : indentationString; + if (indentNextTokenOrTrivia) { + if (!(nextTrivia && nextTrivia.isNewLine())) { + this.recordIndentationEditsForWhitespace(trivia, position, whiteSpaceIndentationString); + } + indentNextTokenOrTrivia = false; + } + leadingWhiteSpace += trivia.fullText(); + break; + + case SyntaxKind.NewLineTrivia: + // We hit a newline processing the trivia. We need to add the indentation to the + // next line as well. Note: don't bother indenting the newline itself. This will + // just insert ugly whitespace that most users probably will not want. + indentNextTokenOrTrivia = true; + leadingWhiteSpace = ""; + break; + + default: + throw Errors.invalidOperation(); + } + } + + } + + if (token.kind() !== SyntaxKind.EndOfFileToken && indentNextTokenOrTrivia) { + // If the last trivia item was a new line, or no trivia items were encounterd record the + // indentation edit at the token position + if (indentationString.length > 0) { + this.recordEdit(position, 0, indentationString); + } + } + } + + private recordIndentationEditsForSingleLineOrSkippedText(trivia: ISyntaxTrivia, fullStart: number, indentationString: string): void { + // Record the edit + if (indentationString.length > 0) { + this.recordEdit(fullStart, 0, indentationString); + } + } + + private recordIndentationEditsForWhitespace(trivia: ISyntaxTrivia, fullStart: number, indentationString: string): void { + var text = trivia.fullText(); + + // Check if the current indentation matches the desired indentation or not + if (indentationString === text) { + return; + } + + // Record the edit + this.recordEdit(fullStart, text.length, indentationString); + } + + private recordIndentationEditsForMultiLineComment(trivia: ISyntaxTrivia, fullStart: number, indentationString: string, leadingWhiteSpace: string, firstLineAlreadyIndented: boolean): void { + // If the multiline comment spans multiple lines, we need to add the right indent amount to + // each successive line segment as well. + var position = fullStart; + var segments = Syntax.splitMultiLineCommentTriviaIntoMultipleLines(trivia); + + if (segments.length <= 1) { + if (!firstLineAlreadyIndented) { + // Process the one-line multiline comment just like a single line comment + this.recordIndentationEditsForSingleLineOrSkippedText(trivia, fullStart, indentationString); + } + return; + } + + // Find number of columns in first segment + var whiteSpaceColumnsInFirstSegment = Indentation.columnForPositionInString(leadingWhiteSpace, leadingWhiteSpace.length, this.options); + + var indentationColumns = Indentation.columnForPositionInString(indentationString, indentationString.length, this.options); + var startIndex = 0; + if (firstLineAlreadyIndented) { + startIndex = 1; + position += segments[0].length; + } + for (var i = startIndex; i < segments.length; i++) { + var segment = segments[i]; + this.recordIndentationEditsForSegment(segment, position, indentationColumns, whiteSpaceColumnsInFirstSegment); + position += segment.length; + } + } + + private recordIndentationEditsForSegment(segment: string, fullStart: number, indentationColumns: number, whiteSpaceColumnsInFirstSegment: number): void { + // Indent subsequent lines using a column delta of the actual indentation relative to the first line + var firstNonWhitespacePosition = Indentation.firstNonWhitespacePosition(segment); + var leadingWhiteSpaceColumns = Indentation.columnForPositionInString(segment, firstNonWhitespacePosition, this.options); + var deltaFromFirstSegment = leadingWhiteSpaceColumns - whiteSpaceColumnsInFirstSegment; + var finalColumns = indentationColumns + deltaFromFirstSegment; + if (finalColumns < 0) { + finalColumns = 0; + } + var indentationString = Indentation.indentationString(finalColumns, this.options); + + if (firstNonWhitespacePosition < segment.length && + CharacterInfo.isLineTerminator(segment.charCodeAt(firstNonWhitespacePosition))) { + // If this segment was just a newline, then don't bother indenting it. That will just + // leave the user with an ugly indent in their output that they probably do not want. + return; + } + + if (indentationString === segment.substring(0, firstNonWhitespacePosition)) { + return; + } + + // Record the edit + this.recordEdit(fullStart, firstNonWhitespacePosition, indentationString); + } + } +} \ No newline at end of file diff --git a/src/services/formatting/rule.ts b/src/services/formatting/rule.ts new file mode 100644 index 00000000000..273f0590ce7 --- /dev/null +++ b/src/services/formatting/rule.ts @@ -0,0 +1,32 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export class Rule { + constructor( + public Descriptor: RuleDescriptor, + public Operation: RuleOperation, + public Flag: RuleFlags = RuleFlags.None) { + } + + public toString() { + return "[desc=" + this.Descriptor + "," + + "operation=" + this.Operation + "," + + "flag=" + this.Flag + "]"; + } + } +} \ No newline at end of file diff --git a/src/services/formatting/ruleAction.ts b/src/services/formatting/ruleAction.ts new file mode 100644 index 00000000000..32c67c950ca --- /dev/null +++ b/src/services/formatting/ruleAction.ts @@ -0,0 +1,25 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export enum RuleAction { + Ignore, + Space, + NewLine, + Delete + } +} \ No newline at end of file diff --git a/src/services/formatting/ruleDescriptor.ts b/src/services/formatting/ruleDescriptor.ts new file mode 100644 index 00000000000..52ee970130e --- /dev/null +++ b/src/services/formatting/ruleDescriptor.ts @@ -0,0 +1,46 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export class RuleDescriptor { + constructor(public LeftTokenRange: Shared.TokenRange, public RightTokenRange: Shared.TokenRange) { + } + + public toString(): string { + return "[leftRange=" + this.LeftTokenRange + "," + + "rightRange=" + this.RightTokenRange + "]"; + } + + static create1(left: SyntaxKind, right: SyntaxKind): RuleDescriptor { + return RuleDescriptor.create4(Shared.TokenRange.FromToken(left), Shared.TokenRange.FromToken(right)) + } + + static create2(left: Shared.TokenRange, right: SyntaxKind): RuleDescriptor { + return RuleDescriptor.create4(left, Shared.TokenRange.FromToken(right)); + } + + static create3(left: SyntaxKind, right: Shared.TokenRange): RuleDescriptor + //: this(TokenRange.FromToken(left), right) + { + return RuleDescriptor.create4(Shared.TokenRange.FromToken(left), right); + } + + static create4(left: Shared.TokenRange, right: Shared.TokenRange): RuleDescriptor { + return new RuleDescriptor(left, right); + } + } +} \ No newline at end of file diff --git a/src/services/formatting/ruleFlag.ts b/src/services/formatting/ruleFlag.ts new file mode 100644 index 00000000000..d815537dfd9 --- /dev/null +++ b/src/services/formatting/ruleFlag.ts @@ -0,0 +1,23 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export enum RuleFlags { + None, + CanDeleteNewLines + } +} \ No newline at end of file diff --git a/src/services/formatting/ruleOperation.ts b/src/services/formatting/ruleOperation.ts new file mode 100644 index 00000000000..1f74aea0784 --- /dev/null +++ b/src/services/formatting/ruleOperation.ts @@ -0,0 +1,44 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export class RuleOperation { + public Context: RuleOperationContext; + public Action: RuleAction; + + constructor() { + this.Context = null; + this.Action = null; + } + + public toString(): string { + return "[context=" + this.Context + "," + + "action=" + this.Action + "]"; + } + + static create1(action: RuleAction) { + return RuleOperation.create2(RuleOperationContext.Any, action) + } + + static create2(context: RuleOperationContext, action: RuleAction) { + var result = new RuleOperation(); + result.Context = context; + result.Action = action; + return result; + } + } +} \ No newline at end of file diff --git a/src/services/formatting/ruleOperationContext.ts b/src/services/formatting/ruleOperationContext.ts new file mode 100644 index 00000000000..a1e349210e4 --- /dev/null +++ b/src/services/formatting/ruleOperationContext.ts @@ -0,0 +1,47 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + + export class RuleOperationContext { + private customContextChecks: { (context: FormattingContext): boolean; }[]; + + constructor(...funcs: { (context: FormattingContext): boolean; }[]) { + this.customContextChecks = funcs; + } + + static Any: RuleOperationContext = new RuleOperationContext(); + + + public IsAny(): boolean { + return this == RuleOperationContext.Any; + } + + public InContext(context: FormattingContext): boolean { + if (this.IsAny()) { + return true; + } + + for (var i = 0, len = this.customContextChecks.length; i < len; i++) { + if (!this.customContextChecks[i](context)) { + return false; + } + } + return true; + } + } +} \ No newline at end of file diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts new file mode 100644 index 00000000000..2a297efc371 --- /dev/null +++ b/src/services/formatting/rules.ts @@ -0,0 +1,678 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export class Rules { + public getRuleName(rule: Rule) { + var o: IIndexable = this; + for (var name in o) { + if (o[name] === rule) { + return name; + } + } + throw new Error(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.Unknown_rule, null)); + } + + [name: string]: any; + + public IgnoreBeforeComment: Rule; + public IgnoreAfterLineComment: Rule; + + // Space after keyword but not before ; or : or ? + public NoSpaceBeforeSemicolon: Rule; + public NoSpaceBeforeColon: Rule; + public NoSpaceBeforeQMark: Rule; + public SpaceAfterColon: Rule; + public SpaceAfterQMark: Rule; + public SpaceAfterSemicolon: Rule; + + // Space/new line after }. + public SpaceAfterCloseBrace: Rule; + + // Special case for (}, else) and (}, while) since else & while tokens are not part of the tree which makes SpaceAfterCloseBrace rule not applied + // Also should not apply to }) + public SpaceBetweenCloseBraceAndElse: Rule; + public SpaceBetweenCloseBraceAndWhile: Rule; + public NoSpaceAfterCloseBrace: Rule; + + // No space for indexer and dot + public NoSpaceBeforeDot: Rule; + public NoSpaceAfterDot: Rule; + public NoSpaceBeforeOpenBracket: Rule; + public NoSpaceAfterOpenBracket: Rule; + public NoSpaceBeforeCloseBracket: Rule; + public NoSpaceAfterCloseBracket: Rule; + + // Insert a space after { and before } in single-line contexts, but remove space from empty object literals {}. + public SpaceAfterOpenBrace: Rule; + public SpaceBeforeCloseBrace: Rule; + public NoSpaceBetweenEmptyBraceBrackets: Rule; + + // Insert new line after { and before } in multi-line contexts. + public NewLineAfterOpenBraceInBlockContext: Rule; + + // For functions and control block place } on a new line [multi-line rule] + public NewLineBeforeCloseBraceInBlockContext: Rule; + + // Special handling of unary operators. + // Prefix operators generally shouldn't have a space between + // them and their target unary expression. + public NoSpaceAfterUnaryPrefixOperator: Rule; + public NoSpaceAfterUnaryPreincrementOperator: Rule; + public NoSpaceAfterUnaryPredecrementOperator: Rule; + public NoSpaceBeforeUnaryPostincrementOperator: Rule; + public NoSpaceBeforeUnaryPostdecrementOperator: Rule; + + // More unary operator special-casing. + // DevDiv 181814: Be careful when removing leading whitespace + // around unary operators. Examples: + // 1 - -2 --X--> 1--2 + // a + ++b --X--> a+++b + public SpaceAfterPostincrementWhenFollowedByAdd: Rule; + public SpaceAfterAddWhenFollowedByUnaryPlus: Rule; + public SpaceAfterAddWhenFollowedByPreincrement: Rule; + public SpaceAfterPostdecrementWhenFollowedBySubtract: Rule; + public SpaceAfterSubtractWhenFollowedByUnaryMinus: Rule; + public SpaceAfterSubtractWhenFollowedByPredecrement: Rule; + + public NoSpaceBeforeComma: Rule; + + public SpaceAfterCertainKeywords: Rule; + public NoSpaceBeforeOpenParenInFuncCall: Rule; + public SpaceAfterFunctionInFuncDecl: Rule; + public NoSpaceBeforeOpenParenInFuncDecl: Rule; + public SpaceAfterVoidOperator: Rule; + + public NoSpaceBetweenReturnAndSemicolon: Rule; + + // Add a space between statements. All keywords except (do,else,case) has open/close parens after them. + // So, we have a rule to add a space for [),Any], [do,Any], [else,Any], and [case,Any] + public SpaceBetweenStatements: Rule; + + // This low-pri rule takes care of "try {" and "finally {" in case the rule SpaceBeforeOpenBraceInControl didn't execute on FormatOnEnter. + public SpaceAfterTryFinally: Rule; + + // For get/set members, we check for (identifier,identifier) since get/set don't have tokens and they are represented as just an identifier token. + // Though, we do extra check on the context to make sure we are dealing with get/set node. Example: + // get x() {} + // set x(val) {} + public SpaceAfterGetSetInMember: Rule; + + // Special case for binary operators (that are keywords). For these we have to add a space and shouldn't follow any user options. + public SpaceBeforeBinaryKeywordOperator: Rule; + public SpaceAfterBinaryKeywordOperator: Rule; + + // TypeScript-specific rules + + // Treat constructor as an identifier in a function declaration, and remove spaces between constructor and following left parentheses + public NoSpaceAfterConstructor: Rule; + + // Use of module as a function call. e.g.: import m2 = module("m2"); + public NoSpaceAfterModuleImport: Rule; + + // Add a space around certain TypeScript keywords + public SpaceAfterCertainTypeScriptKeywords: Rule; + public SpaceBeforeCertainTypeScriptKeywords: Rule; + + // Treat string literals in module names as identifiers, and add a space between the literal and the opening Brace braces, e.g.: module "m2" { + public SpaceAfterModuleName: Rule; + + // Lambda expressions + public SpaceAfterArrow: Rule; + + // Optional parameters and var args + public NoSpaceAfterEllipsis: Rule; + public NoSpaceAfterOptionalParameters: Rule; + + // generics + public NoSpaceBeforeOpenAngularBracket: Rule; + public NoSpaceBetweenCloseParenAndAngularBracket: Rule; + public NoSpaceAfterOpenAngularBracket: Rule; + public NoSpaceBeforeCloseAngularBracket: Rule; + public NoSpaceAfterCloseAngularBracket: Rule; + + // Remove spaces in empty interface literals. e.g.: x: {} + public NoSpaceBetweenEmptyInterfaceBraceBrackets: Rule; + + // These rules are higher in priority than user-configurable rules. + public HighPriorityCommonRules: Rule[]; + + // These rules are lower in priority than user-configurable rules. + public LowPriorityCommonRules: Rule[]; + + /// + /// Rules controlled by user options + /// + + // Insert space after comma delimiter + public SpaceAfterComma: Rule; + public NoSpaceAfterComma: Rule; + + // Insert space before and after binary operators + public SpaceBeforeBinaryOperator: Rule; + public SpaceAfterBinaryOperator: Rule; + public NoSpaceBeforeBinaryOperator: Rule; + public NoSpaceAfterBinaryOperator: Rule; + + // Insert space after keywords in control flow statements + public SpaceAfterKeywordInControl: Rule; + public NoSpaceAfterKeywordInControl: Rule; + + // Open Brace braces after function + //TypeScript: Function can have return types, which can be made of tons of different token kinds + public FunctionOpenBraceLeftTokenRange: Shared.TokenRange; + public SpaceBeforeOpenBraceInFunction: Rule; + public NewLineBeforeOpenBraceInFunction: Rule; + + // Open Brace braces after TypeScript module/class/interface + public TypeScriptOpenBraceLeftTokenRange: Shared.TokenRange; + public SpaceBeforeOpenBraceInTypeScriptDeclWithBlock: Rule; + public NewLineBeforeOpenBraceInTypeScriptDeclWithBlock: Rule; + + // Open Brace braces after control block + public ControlOpenBraceLeftTokenRange: Shared.TokenRange; + public SpaceBeforeOpenBraceInControl: Rule; + public NewLineBeforeOpenBraceInControl: Rule; + + // Insert space after semicolon in for statement + public SpaceAfterSemicolonInFor: Rule; + public NoSpaceAfterSemicolonInFor: Rule; + + // Insert space after opening and before closing nonempty parenthesis + public SpaceAfterOpenParen: Rule; + public SpaceBeforeCloseParen: Rule; + public NoSpaceBetweenParens: Rule; + public NoSpaceAfterOpenParen: Rule; + public NoSpaceBeforeCloseParen: Rule; + + // Insert space after function keyword for anonymous functions + public SpaceAfterAnonymousFunctionKeyword: Rule; + public NoSpaceAfterAnonymousFunctionKeyword: Rule; + + constructor() { + /// + /// Common Rules + /// + + // Leave comments alone + this.IgnoreBeforeComment = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.Comments), RuleOperation.create1(RuleAction.Ignore)); + this.IgnoreAfterLineComment = new Rule(RuleDescriptor.create3(SyntaxKind.SingleLineCommentTrivia, Shared.TokenRange.Any), RuleOperation.create1(RuleAction.Ignore)); + + // Space after keyword but not before ; or : or ? + this.NoSpaceBeforeSemicolon = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.SemicolonToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceBeforeColon = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.ColonToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete)); + this.NoSpaceBeforeQMark = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.QuestionToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete)); + this.SpaceAfterColon = new Rule(RuleDescriptor.create3(SyntaxKind.ColonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Space)); + this.SpaceAfterQMark = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Space)); + this.SpaceAfterSemicolon = new Rule(RuleDescriptor.create3(SyntaxKind.SemicolonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + + // Space after }. + this.SpaceAfterCloseBrace = new Rule(RuleDescriptor.create3(SyntaxKind.CloseBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsAfterCodeBlockContext), RuleAction.Space)); + + // Special case for (}, else) and (}, while) since else & while tokens are not part of the tree which makes SpaceAfterCloseBrace rule not applied + this.SpaceBetweenCloseBraceAndElse = new Rule(RuleDescriptor.create1(SyntaxKind.CloseBraceToken, SyntaxKind.ElseKeyword), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + this.SpaceBetweenCloseBraceAndWhile = new Rule(RuleDescriptor.create1(SyntaxKind.CloseBraceToken, SyntaxKind.WhileKeyword), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + this.NoSpaceAfterCloseBrace = new Rule(RuleDescriptor.create3(SyntaxKind.CloseBraceToken, Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.CommaToken, SyntaxKind.SemicolonToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + + // No space for indexer and dot + this.NoSpaceBeforeDot = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.DotToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceAfterDot = new Rule(RuleDescriptor.create3(SyntaxKind.DotToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceBeforeOpenBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenBracketToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceAfterOpenBracket = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBracketToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceBeforeCloseBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBracketToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceAfterCloseBracket = new Rule(RuleDescriptor.create3(SyntaxKind.CloseBracketToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + + // Place a space before open brace in a function declaration + this.FunctionOpenBraceLeftTokenRange = Shared.TokenRange.AnyIncludingMultilineComments; + this.SpaceBeforeOpenBraceInFunction = new Rule(RuleDescriptor.create2(this.FunctionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines); + + // Place a space before open brace in a TypeScript declaration that has braces as children (class, module, enum, etc) + this.TypeScriptOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.MultiLineCommentTrivia]); + this.SpaceBeforeOpenBraceInTypeScriptDeclWithBlock = new Rule(RuleDescriptor.create2(this.TypeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsTypeScriptDeclWithBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines); + + // Place a space before open brace in a control flow construct + this.ControlOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.MultiLineCommentTrivia, SyntaxKind.DoKeyword, SyntaxKind.TryKeyword, SyntaxKind.FinallyKeyword, SyntaxKind.ElseKeyword]); + this.SpaceBeforeOpenBraceInControl = new Rule(RuleDescriptor.create2(this.ControlOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsControlDeclContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines); + + // Insert a space after { and before } in single-line contexts, but remove space from empty object literals {}. + this.SpaceAfterOpenBrace = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSingleLineBlockContext), RuleAction.Space)); + this.SpaceBeforeCloseBrace = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSingleLineBlockContext), RuleAction.Space)); + this.NoSpaceBetweenEmptyBraceBrackets = new Rule(RuleDescriptor.create1(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsObjectContext), RuleAction.Delete)); + + // Insert new line after { and before } in multi-line contexts. + this.NewLineAfterOpenBraceInBlockContext = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsMultilineBlockContext), RuleAction.NewLine)); + + // For functions and control block place } on a new line [multi-line rule] + this.NewLineBeforeCloseBraceInBlockContext = new Rule(RuleDescriptor.create2(Shared.TokenRange.AnyIncludingMultilineComments, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsMultilineBlockContext), RuleAction.NewLine)); + + // Special handling of unary operators. + // Prefix operators generally shouldn't have a space between + // them and their target unary expression. + this.NoSpaceAfterUnaryPrefixOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.UnaryPrefixOperators, Shared.TokenRange.UnaryPrefixExpressions), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete)); + this.NoSpaceAfterUnaryPreincrementOperator = new Rule(RuleDescriptor.create3(SyntaxKind.PlusPlusToken, Shared.TokenRange.UnaryPreincrementExpressions), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceAfterUnaryPredecrementOperator = new Rule(RuleDescriptor.create3(SyntaxKind.MinusMinusToken, Shared.TokenRange.UnaryPredecrementExpressions), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceBeforeUnaryPostincrementOperator = new Rule(RuleDescriptor.create2(Shared.TokenRange.UnaryPostincrementExpressions, SyntaxKind.PlusPlusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceBeforeUnaryPostdecrementOperator = new Rule(RuleDescriptor.create2(Shared.TokenRange.UnaryPostdecrementExpressions, SyntaxKind.MinusMinusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + + // More unary operator special-casing. + // DevDiv 181814: Be careful when removing leading whitespace + // around unary operators. Examples: + // 1 - -2 --X--> 1--2 + // a + ++b --X--> a+++b + this.SpaceAfterPostincrementWhenFollowedByAdd = new Rule(RuleDescriptor.create1(SyntaxKind.PlusPlusToken, SyntaxKind.PlusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + this.SpaceAfterAddWhenFollowedByUnaryPlus = new Rule(RuleDescriptor.create1(SyntaxKind.PlusToken, SyntaxKind.PlusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + this.SpaceAfterAddWhenFollowedByPreincrement = new Rule(RuleDescriptor.create1(SyntaxKind.PlusToken, SyntaxKind.PlusPlusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + this.SpaceAfterPostdecrementWhenFollowedBySubtract = new Rule(RuleDescriptor.create1(SyntaxKind.MinusMinusToken, SyntaxKind.MinusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + this.SpaceAfterSubtractWhenFollowedByUnaryMinus = new Rule(RuleDescriptor.create1(SyntaxKind.MinusToken, SyntaxKind.MinusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + this.SpaceAfterSubtractWhenFollowedByPredecrement = new Rule(RuleDescriptor.create1(SyntaxKind.MinusToken, SyntaxKind.MinusMinusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + + this.NoSpaceBeforeComma = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CommaToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + + this.SpaceAfterCertainKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.VarKeyword, SyntaxKind.ThrowKeyword, SyntaxKind.NewKeyword, SyntaxKind.DeleteKeyword, SyntaxKind.ReturnKeyword, SyntaxKind.TypeOfKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + this.NoSpaceBeforeOpenParenInFuncCall = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsFunctionCallOrNewContext), RuleAction.Delete)); + this.SpaceAfterFunctionInFuncDecl = new Rule(RuleDescriptor.create3(SyntaxKind.FunctionKeyword, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space)); + this.NoSpaceBeforeOpenParenInFuncDecl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsFunctionDeclContext), RuleAction.Delete)); + this.SpaceAfterVoidOperator = new Rule(RuleDescriptor.create3(SyntaxKind.VoidKeyword, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsVoidOpContext), RuleAction.Space)); + + this.NoSpaceBetweenReturnAndSemicolon = new Rule(RuleDescriptor.create1(SyntaxKind.ReturnKeyword, SyntaxKind.SemicolonToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + + // Add a space between statements. All keywords except (do,else,case) has open/close parens after them. + // So, we have a rule to add a space for [),Any], [do,Any], [else,Any], and [case,Any] + this.SpaceBetweenStatements = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.DoKeyword, SyntaxKind.ElseKeyword, SyntaxKind.CaseKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotForContext), RuleAction.Space)); + + // This low-pri rule takes care of "try {" and "finally {" in case the rule SpaceBeforeOpenBraceInControl didn't execute on FormatOnEnter. + this.SpaceAfterTryFinally = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.TryKeyword, SyntaxKind.FinallyKeyword]), SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + + // get x() {} + // set x(val) {} + this.SpaceAfterGetSetInMember = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.GetKeyword, SyntaxKind.SetKeyword]), SyntaxKind.IdentifierName), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space)); + + // Special case for binary operators (that are keywords). For these we have to add a space and shouldn't follow any user options. + this.SpaceBeforeBinaryKeywordOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryKeywordOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + this.SpaceAfterBinaryKeywordOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.BinaryKeywordOperators, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + + // TypeScript-specific higher priority rules + + // Treat constructor as an identifier in a function declaration, and remove spaces between constructor and following left parentheses + this.NoSpaceAfterConstructor = new Rule(RuleDescriptor.create1(SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + + // Use of module as a function call. e.g.: import m2 = module("m2"); + this.NoSpaceAfterModuleImport = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.ModuleKeyword, SyntaxKind.RequireKeyword]), SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + + // Add a space around certain TypeScript keywords + this.SpaceAfterCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.ClassKeyword, SyntaxKind.DeclareKeyword, SyntaxKind.EnumKeyword, SyntaxKind.ExportKeyword, SyntaxKind.ExtendsKeyword, SyntaxKind.GetKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.ImportKeyword, SyntaxKind.InterfaceKeyword, SyntaxKind.ModuleKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.PublicKeyword, SyntaxKind.SetKeyword, SyntaxKind.StaticKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + this.SpaceBeforeCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.ExtendsKeyword, SyntaxKind.ImplementsKeyword])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + + // Treat string literals in module names as identifiers, and add a space between the literal and the opening Brace braces, e.g.: module "m2" { + this.SpaceAfterModuleName = new Rule(RuleDescriptor.create1(SyntaxKind.StringLiteral, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsModuleDeclContext), RuleAction.Space)); + + // Lambda expressions + this.SpaceAfterArrow = new Rule(RuleDescriptor.create3(SyntaxKind.EqualsGreaterThanToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + + // Optional parameters and var args + this.NoSpaceAfterEllipsis = new Rule(RuleDescriptor.create1(SyntaxKind.DotDotDotToken, SyntaxKind.IdentifierName), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceAfterOptionalParameters = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.CommaToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete)); + + // generics + this.NoSpaceBeforeOpenAngularBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.TypeNames, SyntaxKind.LessThanToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsTypeArgumentOrParameterContext), RuleAction.Delete)); + this.NoSpaceBetweenCloseParenAndAngularBracket = new Rule(RuleDescriptor.create1(SyntaxKind.CloseParenToken, SyntaxKind.LessThanToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsTypeArgumentOrParameterContext), RuleAction.Delete)); + this.NoSpaceAfterOpenAngularBracket = new Rule(RuleDescriptor.create3(SyntaxKind.LessThanToken, Shared.TokenRange.TypeNames), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsTypeArgumentOrParameterContext), RuleAction.Delete)); + this.NoSpaceBeforeCloseAngularBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.GreaterThanToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsTypeArgumentOrParameterContext), RuleAction.Delete)); + this.NoSpaceAfterCloseAngularBracket = new Rule(RuleDescriptor.create3(SyntaxKind.GreaterThanToken, Shared.TokenRange.FromTokens([SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.GreaterThanToken, SyntaxKind.CommaToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsTypeArgumentOrParameterContext), RuleAction.Delete)); + + // Remove spaces in empty interface literals. e.g.: x: {} + this.NoSpaceBetweenEmptyInterfaceBraceBrackets = new Rule(RuleDescriptor.create1(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsObjectTypeContext), RuleAction.Delete)); + + // These rules are higher in priority than user-configurable rules. + this.HighPriorityCommonRules = + [ + this.IgnoreBeforeComment, this.IgnoreAfterLineComment, + this.NoSpaceBeforeColon, this.SpaceAfterColon, this.NoSpaceBeforeQMark, this.SpaceAfterQMark, + this.NoSpaceBeforeDot, this.NoSpaceAfterDot, + this.NoSpaceAfterUnaryPrefixOperator, + this.NoSpaceAfterUnaryPreincrementOperator, this.NoSpaceAfterUnaryPredecrementOperator, + this.NoSpaceBeforeUnaryPostincrementOperator, this.NoSpaceBeforeUnaryPostdecrementOperator, + this.SpaceAfterPostincrementWhenFollowedByAdd, + this.SpaceAfterAddWhenFollowedByUnaryPlus, this.SpaceAfterAddWhenFollowedByPreincrement, + this.SpaceAfterPostdecrementWhenFollowedBySubtract, + this.SpaceAfterSubtractWhenFollowedByUnaryMinus, this.SpaceAfterSubtractWhenFollowedByPredecrement, + this.NoSpaceAfterCloseBrace, + this.SpaceAfterOpenBrace, this.SpaceBeforeCloseBrace, this.NewLineBeforeCloseBraceInBlockContext, + this.SpaceAfterCloseBrace, this.SpaceBetweenCloseBraceAndElse, this.SpaceBetweenCloseBraceAndWhile, this.NoSpaceBetweenEmptyBraceBrackets, + this.SpaceAfterFunctionInFuncDecl, this.NewLineAfterOpenBraceInBlockContext, this.SpaceAfterGetSetInMember, + this.NoSpaceBetweenReturnAndSemicolon, + this.SpaceAfterCertainKeywords, + this.NoSpaceBeforeOpenParenInFuncCall, + this.SpaceBeforeBinaryKeywordOperator, this.SpaceAfterBinaryKeywordOperator, + this.SpaceAfterVoidOperator, + + // TypeScript-specific rules + this.NoSpaceAfterConstructor, this.NoSpaceAfterModuleImport, + this.SpaceAfterCertainTypeScriptKeywords, this.SpaceBeforeCertainTypeScriptKeywords, + this.SpaceAfterModuleName, + this.SpaceAfterArrow, + this.NoSpaceAfterEllipsis, + this.NoSpaceAfterOptionalParameters, + this.NoSpaceBetweenEmptyInterfaceBraceBrackets, + this.NoSpaceBeforeOpenAngularBracket, + this.NoSpaceBetweenCloseParenAndAngularBracket, + this.NoSpaceAfterOpenAngularBracket, + this.NoSpaceBeforeCloseAngularBracket, + this.NoSpaceAfterCloseAngularBracket + ]; + + // These rules are lower in priority than user-configurable rules. + this.LowPriorityCommonRules = + [ + this.NoSpaceBeforeSemicolon, + this.SpaceBeforeOpenBraceInControl, this.SpaceBeforeOpenBraceInFunction, this.SpaceBeforeOpenBraceInTypeScriptDeclWithBlock, + this.NoSpaceBeforeComma, + this.NoSpaceBeforeOpenBracket, this.NoSpaceAfterOpenBracket, + this.NoSpaceBeforeCloseBracket, this.NoSpaceAfterCloseBracket, + this.SpaceAfterSemicolon, + this.NoSpaceBeforeOpenParenInFuncDecl, + this.SpaceBetweenStatements, this.SpaceAfterTryFinally + ]; + + /// + /// Rules controlled by user options + /// + + // Insert space after comma delimiter + this.SpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + this.NoSpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + + // Insert space before and after binary operators + this.SpaceBeforeBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + this.SpaceAfterBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.BinaryOperators, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space)); + this.NoSpaceBeforeBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Delete)); + this.NoSpaceAfterBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.BinaryOperators, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Delete)); + + // Insert space after keywords in control flow statements + this.SpaceAfterKeywordInControl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Keywords, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsControlDeclContext), RuleAction.Space)); + this.NoSpaceAfterKeywordInControl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Keywords, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsControlDeclContext), RuleAction.Delete)); + + // Open Brace braces after function + //TypeScript: Function can have return types, which can be made of tons of different token kinds + this.NewLineBeforeOpenBraceInFunction = new Rule(RuleDescriptor.create2(this.FunctionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext, Rules.IsBeforeMultilineBlockContext), RuleAction.NewLine), RuleFlags.CanDeleteNewLines); + + // Open Brace braces after TypeScript module/class/interface + this.NewLineBeforeOpenBraceInTypeScriptDeclWithBlock = new Rule(RuleDescriptor.create2(this.TypeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsTypeScriptDeclWithBlockContext, Rules.IsBeforeMultilineBlockContext), RuleAction.NewLine), RuleFlags.CanDeleteNewLines); + + // Open Brace braces after control block + this.NewLineBeforeOpenBraceInControl = new Rule(RuleDescriptor.create2(this.ControlOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsControlDeclContext, Rules.IsBeforeMultilineBlockContext), RuleAction.NewLine), RuleFlags.CanDeleteNewLines); + + // Insert space after semicolon in for statement + this.SpaceAfterSemicolonInFor = new Rule(RuleDescriptor.create3(SyntaxKind.SemicolonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsForContext), RuleAction.Space)); + this.NoSpaceAfterSemicolonInFor = new Rule(RuleDescriptor.create3(SyntaxKind.SemicolonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsForContext), RuleAction.Delete)); + + // Insert space after opening and before closing nonempty parenthesis + this.SpaceAfterOpenParen = new Rule(RuleDescriptor.create3(SyntaxKind.OpenParenToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + this.SpaceBeforeCloseParen = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); + this.NoSpaceBetweenParens = new Rule(RuleDescriptor.create1(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceAfterOpenParen = new Rule(RuleDescriptor.create3(SyntaxKind.OpenParenToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceBeforeCloseParen = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + + // Insert space after function keyword for anonymous functions + this.SpaceAfterAnonymousFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space)); + this.NoSpaceAfterAnonymousFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Delete)); + } + + /// + /// Contexts + /// + + static IsForContext(context: FormattingContext): boolean { + return context.contextNode.kind() === SyntaxKind.ForStatement; + } + + static IsNotForContext(context: FormattingContext): boolean { + return !Rules.IsForContext(context); + } + + static IsBinaryOpContext(context: FormattingContext): boolean { + + switch (context.contextNode.kind()) { + // binary expressions + case SyntaxKind.AssignmentExpression: + case SyntaxKind.AddAssignmentExpression: + case SyntaxKind.SubtractAssignmentExpression: + case SyntaxKind.MultiplyAssignmentExpression: + case SyntaxKind.DivideAssignmentExpression: + case SyntaxKind.ModuloAssignmentExpression: + case SyntaxKind.AndAssignmentExpression: + case SyntaxKind.ExclusiveOrAssignmentExpression: + case SyntaxKind.OrAssignmentExpression: + case SyntaxKind.LeftShiftAssignmentExpression: + case SyntaxKind.SignedRightShiftAssignmentExpression: + case SyntaxKind.UnsignedRightShiftAssignmentExpression: + case SyntaxKind.ConditionalExpression: + case SyntaxKind.LogicalOrExpression: + case SyntaxKind.LogicalAndExpression: + case SyntaxKind.BitwiseOrExpression: + case SyntaxKind.BitwiseExclusiveOrExpression: + case SyntaxKind.BitwiseAndExpression: + case SyntaxKind.EqualsWithTypeConversionExpression: + case SyntaxKind.NotEqualsWithTypeConversionExpression: + case SyntaxKind.EqualsExpression: + case SyntaxKind.NotEqualsExpression: + case SyntaxKind.LessThanExpression: + case SyntaxKind.GreaterThanExpression: + case SyntaxKind.LessThanOrEqualExpression: + case SyntaxKind.GreaterThanOrEqualExpression: + case SyntaxKind.InstanceOfExpression: + case SyntaxKind.InExpression: + case SyntaxKind.LeftShiftExpression: + case SyntaxKind.SignedRightShiftExpression: + case SyntaxKind.UnsignedRightShiftExpression: + case SyntaxKind.MultiplyExpression: + case SyntaxKind.DivideExpression: + case SyntaxKind.ModuloExpression: + case SyntaxKind.AddExpression: + case SyntaxKind.SubtractExpression: + return true; + + // equal in import a = module('a'); + case SyntaxKind.ImportDeclaration: + // equal in var a = 0; + case SyntaxKind.VariableDeclarator: + case SyntaxKind.EqualsValueClause: + return context.currentTokenSpan.kind === SyntaxKind.EqualsToken || context.nextTokenSpan.kind === SyntaxKind.EqualsToken; + // "in" keyword in for (var x in []) { } + case SyntaxKind.ForInStatement: + return context.currentTokenSpan.kind === SyntaxKind.InKeyword || context.nextTokenSpan.kind === SyntaxKind.InKeyword; + } + return false; + } + + static IsNotBinaryOpContext(context: FormattingContext): boolean { + return !Rules.IsBinaryOpContext(context); + } + + static IsSameLineTokenOrBeforeMultilineBlockContext(context: FormattingContext): boolean { + //// This check is mainly used inside SpaceBeforeOpenBraceInControl and SpaceBeforeOpenBraceInFunction. + //// + //// Ex: + //// if (1) { .... + //// * ) and { are on the same line so apply the rule. Here we don't care whether it's same or multi block context + //// + //// Ex: + //// if (1) + //// { ... } + //// * ) and { are on differnet lines. We only need to format if the block is multiline context. So in this case we don't format. + //// + //// Ex: + //// if (1) + //// { ... + //// } + //// * ) and { are on differnet lines. We only need to format if the block is multiline context. So in this case we format. + + return context.TokensAreOnSameLine() || Rules.IsBeforeMultilineBlockContext(context); + } + + // This check is done before an open brace in a control construct, a function, or a typescript block declaration + static IsBeforeMultilineBlockContext(context: FormattingContext): boolean { + return Rules.IsBeforeBlockContext(context) && !(context.NextNodeAllOnSameLine() || context.NextNodeBlockIsOnOneLine()); + } + + static IsMultilineBlockContext(context: FormattingContext): boolean { + return Rules.IsBlockContext(context) && !(context.ContextNodeAllOnSameLine() || context.ContextNodeBlockIsOnOneLine()); + } + + static IsSingleLineBlockContext(context: FormattingContext): boolean { + return Rules.IsBlockContext(context) && (context.ContextNodeAllOnSameLine() || context.ContextNodeBlockIsOnOneLine()); + } + + static IsBlockContext(context: FormattingContext): boolean { + return Rules.NodeIsBlockContext(context.contextNode); + } + + static IsBeforeBlockContext(context: FormattingContext): boolean { + return Rules.NodeIsBlockContext(context.nextTokenParent); + } + + // IMPORTANT!!! This method must return true ONLY for nodes with open and close braces as immediate children + static NodeIsBlockContext(node: IndentationNodeContext): boolean { + if (Rules.NodeIsTypeScriptDeclWithBlockContext(node)) { + // This means we are in a context that looks like a block to the user, but in the grammar is actually not a node (it's a class, module, enum, object type literal, etc). + return true; + } + + switch (node.kind()) { + case SyntaxKind.Block: + case SyntaxKind.SwitchStatement: + case SyntaxKind.ObjectLiteralExpression: + return true; + } + + return false; + } + + static IsFunctionDeclContext(context: FormattingContext): boolean { + switch (context.contextNode.kind()) { + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.MemberFunctionDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.MethodSignature: + case SyntaxKind.CallSignature: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ConstructorDeclaration: + case SyntaxKind.SimpleArrowFunctionExpression: + case SyntaxKind.ParenthesizedArrowFunctionExpression: + case SyntaxKind.InterfaceDeclaration: // This one is not truly a function, but for formatting purposes, it acts just like one + return true; + } + + return false; + } + + static IsTypeScriptDeclWithBlockContext(context: FormattingContext): boolean { + return Rules.NodeIsTypeScriptDeclWithBlockContext(context.contextNode); + } + + static NodeIsTypeScriptDeclWithBlockContext(node: IndentationNodeContext): boolean { + switch (node.kind()) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.ObjectType: + case SyntaxKind.ModuleDeclaration: + return true; + } + + return false; + } + + static IsAfterCodeBlockContext(context: FormattingContext): boolean { + switch (context.currentTokenParent.kind()) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.Block: + case SyntaxKind.SwitchStatement: + return true; + } + return false; + } + + static IsControlDeclContext(context: FormattingContext): boolean { + switch (context.contextNode.kind()) { + case SyntaxKind.IfStatement: + case SyntaxKind.SwitchStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.TryStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.ElseClause: + case SyntaxKind.CatchClause: + case SyntaxKind.FinallyClause: + return true; + + default: + return false; + } + } + + static IsObjectContext(context: FormattingContext): boolean { + return context.contextNode.kind() === SyntaxKind.ObjectLiteralExpression; + } + + static IsFunctionCallContext(context: FormattingContext): boolean { + return context.contextNode.kind() === SyntaxKind.InvocationExpression; + } + + static IsNewContext(context: FormattingContext): boolean { + return context.contextNode.kind() === SyntaxKind.ObjectCreationExpression; + } + + static IsFunctionCallOrNewContext(context: FormattingContext): boolean { + return Rules.IsFunctionCallContext(context) || Rules.IsNewContext(context); + } + + static IsSameLineTokenContext(context: FormattingContext): boolean { + return context.TokensAreOnSameLine(); + } + + static IsNotFormatOnEnter(context: FormattingContext): boolean { + return context.formattingRequestKind != FormattingRequestKind.FormatOnEnter; + } + + static IsModuleDeclContext(context: FormattingContext): boolean { + return context.contextNode.kind() === SyntaxKind.ModuleDeclaration; + } + + static IsObjectTypeContext(context: FormattingContext): boolean { + return context.contextNode.kind() === SyntaxKind.ObjectType && context.contextNode.parent().kind() !== SyntaxKind.InterfaceDeclaration; + } + + static IsTypeArgumentOrParameter(tokenKind: SyntaxKind, parentKind: SyntaxKind): boolean { + return ((tokenKind === SyntaxKind.LessThanToken || tokenKind === SyntaxKind.GreaterThanToken) && + (parentKind === SyntaxKind.TypeParameterList || parentKind === SyntaxKind.TypeArgumentList)); + } + + static IsTypeArgumentOrParameterContext(context: FormattingContext): boolean { + return Rules.IsTypeArgumentOrParameter(context.currentTokenSpan.kind, context.currentTokenParent.kind()) || + Rules.IsTypeArgumentOrParameter(context.nextTokenSpan.kind, context.nextTokenParent.kind()); + } + + static IsVoidOpContext(context: FormattingContext): boolean { + return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword && context.currentTokenParent.kind() === SyntaxKind.VoidExpression; + } + } +} \ No newline at end of file diff --git a/src/services/formatting/rulesMap.ts b/src/services/formatting/rulesMap.ts new file mode 100644 index 00000000000..0fbe81d16c9 --- /dev/null +++ b/src/services/formatting/rulesMap.ts @@ -0,0 +1,189 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export class RulesMap { + public map: RulesBucket[]; + public mapRowLength: number; + + constructor() { + this.map = []; + this.mapRowLength = 0; + } + + static create(rules: Rule[]): RulesMap { + var result = new RulesMap(); + result.Initialize(rules); + return result; + } + + public Initialize(rules: Rule[]) { + this.mapRowLength = SyntaxKind.LastToken + 1; + this.map = new Array(this.mapRowLength * this.mapRowLength);//new Array(this.mapRowLength * this.mapRowLength); + + // This array is used only during construction of the rulesbucket in the map + var rulesBucketConstructionStateList: RulesBucketConstructionState[] = new Array(this.map.length);//new Array(this.map.length); + + this.FillRules(rules, rulesBucketConstructionStateList); + return this.map; + } + + public FillRules(rules: Rule[], rulesBucketConstructionStateList: RulesBucketConstructionState[]): void { + rules.forEach((rule) => { + this.FillRule(rule, rulesBucketConstructionStateList); + }); + } + + private GetRuleBucketIndex(row: number, column: number): number { + var rulesBucketIndex = (row * this.mapRowLength) + column; + //Debug.Assert(rulesBucketIndex < this.map.Length, "Trying to access an index outside the array."); + return rulesBucketIndex; + } + + private FillRule(rule: Rule, rulesBucketConstructionStateList: RulesBucketConstructionState[]): void { + var specificRule = rule.Descriptor.LeftTokenRange != Shared.TokenRange.Any && + rule.Descriptor.RightTokenRange != Shared.TokenRange.Any; + + rule.Descriptor.LeftTokenRange.GetTokens().forEach((left) => { + rule.Descriptor.RightTokenRange.GetTokens().forEach((right) => { + var rulesBucketIndex = this.GetRuleBucketIndex(left, right); + + var rulesBucket = this.map[rulesBucketIndex]; + if (rulesBucket == undefined) { + rulesBucket = this.map[rulesBucketIndex] = new RulesBucket(); + } + + rulesBucket.AddRule(rule, specificRule, rulesBucketConstructionStateList, rulesBucketIndex); + }) + }) + } + + public GetRule(context: FormattingContext): Rule { + var bucketIndex = this.GetRuleBucketIndex(context.currentTokenSpan.kind, context.nextTokenSpan.kind); + var bucket = this.map[bucketIndex]; + if (bucket != null) { + for (var i = 0, len = bucket.Rules().length; i < len; i++) { + var rule = bucket.Rules()[i]; + if (rule.Operation.Context.InContext(context)) + return rule; + } + } + return null; + } + } + + var MaskBitSize = 5; + var Mask = 0x1f; + + export enum RulesPosition { + IgnoreRulesSpecific = 0, + IgnoreRulesAny = MaskBitSize * 1, + ContextRulesSpecific = MaskBitSize * 2, + ContextRulesAny = MaskBitSize * 3, + NoContextRulesSpecific = MaskBitSize * 4, + NoContextRulesAny = MaskBitSize * 5 + } + + export class RulesBucketConstructionState { + private rulesInsertionIndexBitmap: number; + + constructor() { + //// The Rules list contains all the inserted rules into a rulebucket in the following order: + //// 1- Ignore rules with specific token combination + //// 2- Ignore rules with any token combination + //// 3- Context rules with specific token combination + //// 4- Context rules with any token combination + //// 5- Non-context rules with specific token combination + //// 6- Non-context rules with any token combination + //// + //// The member rulesInsertionIndexBitmap is used to describe the number of rules + //// in each sub-bucket (above) hence can be used to know the index of where to insert + //// the next rule. It's a bitmap which contains 6 different sections each is given 5 bits. + //// + //// Example: + //// In order to insert a rule to the end of sub-bucket (3), we get the index by adding + //// the values in the bitmap segments 3rd, 2nd, and 1st. + this.rulesInsertionIndexBitmap = 0; + } + + public GetInsertionIndex(maskPosition: RulesPosition): number { + var index = 0; + + var pos = 0; + var indexBitmap = this.rulesInsertionIndexBitmap; + + while (pos <= maskPosition) { + index += (indexBitmap & Mask); + indexBitmap >>= MaskBitSize; + pos += MaskBitSize; + } + + return index; + } + + public IncreaseInsertionIndex(maskPosition: RulesPosition): void { + var value = (this.rulesInsertionIndexBitmap >> maskPosition) & Mask; + value++; + Debug.assert((value & Mask) == value, "Adding more rules into the sub-bucket than allowed. Maximum allowed is 32 rules."); + + var temp = this.rulesInsertionIndexBitmap & ~(Mask << maskPosition); + temp |= value << maskPosition; + + this.rulesInsertionIndexBitmap = temp; + } + } + + export class RulesBucket { + private rules: Rule[]; + + constructor() { + this.rules = []; + } + + public Rules(): Rule[] { + return this.rules; + } + + public AddRule(rule: Rule, specificTokens: boolean, constructionState: RulesBucketConstructionState[], rulesBucketIndex: number): void { + var position: RulesPosition; + + if (rule.Operation.Action == RuleAction.Ignore) { + position = specificTokens ? + RulesPosition.IgnoreRulesSpecific : + RulesPosition.IgnoreRulesAny; + } + else if (!rule.Operation.Context.IsAny()) { + position = specificTokens ? + RulesPosition.ContextRulesSpecific : + RulesPosition.ContextRulesAny; + } + else { + position = specificTokens ? + RulesPosition.NoContextRulesSpecific : + RulesPosition.NoContextRulesAny; + } + + var state = constructionState[rulesBucketIndex]; + if (state === undefined) { + state = constructionState[rulesBucketIndex] = new RulesBucketConstructionState(); + } + var index = state.GetInsertionIndex(position); + this.rules.splice(index, 0, rule); + state.IncreaseInsertionIndex(position); + } + } +} \ No newline at end of file diff --git a/src/services/formatting/rulesProvider.ts b/src/services/formatting/rulesProvider.ts new file mode 100644 index 00000000000..0b100500f2d --- /dev/null +++ b/src/services/formatting/rulesProvider.ts @@ -0,0 +1,117 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export class RulesProvider { + private globalRules: Rules; + private options: TypeScript.Services.FormatCodeOptions; + private activeRules: Rule[]; + private rulesMap: RulesMap; + + constructor(private logger: TypeScript.ILogger) { + this.globalRules = new Rules(); + } + + public getRuleName(rule: Rule): string { + return this.globalRules.getRuleName(rule); + } + + public getRuleByName(name: string): Rule { + return this.globalRules[name]; + } + + public getRulesMap() { + return this.rulesMap; + } + + public ensureUpToDate(options: TypeScript.Services.FormatCodeOptions) { + if (this.options == null || !TypeScript.compareDataObjects(this.options, options)) { + var activeRules: Rule[] = TypeScript.timeFunction(this.logger, "RulesProvider: createActiveRules()", () => { return this.createActiveRules(options); }); + var rulesMap: RulesMap = TypeScript.timeFunction(this.logger, "RulesProvider: RulesMap.create()", () => { return RulesMap.create(activeRules); }); + + this.activeRules = activeRules; + this.rulesMap = rulesMap; + this.options = TypeScript.Services.FormatCodeOptions.clone(options); + } + } + + private createActiveRules(options: TypeScript.Services.FormatCodeOptions): Rule[] { + var rules = this.globalRules.HighPriorityCommonRules.slice(0); + + if (options.InsertSpaceAfterCommaDelimiter) { + rules.push(this.globalRules.SpaceAfterComma); + } + else { + rules.push(this.globalRules.NoSpaceAfterComma); + } + + if (options.InsertSpaceAfterFunctionKeywordForAnonymousFunctions) { + rules.push(this.globalRules.SpaceAfterAnonymousFunctionKeyword); + } + else { + rules.push(this.globalRules.NoSpaceAfterAnonymousFunctionKeyword); + } + + if (options.InsertSpaceAfterKeywordsInControlFlowStatements) { + rules.push(this.globalRules.SpaceAfterKeywordInControl); + } + else { + rules.push(this.globalRules.NoSpaceAfterKeywordInControl); + } + + if (options.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis) { + rules.push(this.globalRules.SpaceAfterOpenParen); + rules.push(this.globalRules.SpaceBeforeCloseParen); + rules.push(this.globalRules.NoSpaceBetweenParens); + } + else { + rules.push(this.globalRules.NoSpaceAfterOpenParen); + rules.push(this.globalRules.NoSpaceBeforeCloseParen); + rules.push(this.globalRules.NoSpaceBetweenParens); + } + + if (options.InsertSpaceAfterSemicolonInForStatements) { + rules.push(this.globalRules.SpaceAfterSemicolonInFor); + } + else { + rules.push(this.globalRules.NoSpaceAfterSemicolonInFor); + } + + if (options.InsertSpaceBeforeAndAfterBinaryOperators) { + rules.push(this.globalRules.SpaceBeforeBinaryOperator); + rules.push(this.globalRules.SpaceAfterBinaryOperator); + } + else { + rules.push(this.globalRules.NoSpaceBeforeBinaryOperator); + rules.push(this.globalRules.NoSpaceAfterBinaryOperator); + } + + if (options.PlaceOpenBraceOnNewLineForControlBlocks) { + rules.push(this.globalRules.NewLineBeforeOpenBraceInControl); + } + + if (options.PlaceOpenBraceOnNewLineForFunctions) { + rules.push(this.globalRules.NewLineBeforeOpenBraceInFunction); + rules.push(this.globalRules.NewLineBeforeOpenBraceInTypeScriptDeclWithBlock); + } + + rules = rules.concat(this.globalRules.LowPriorityCommonRules); + + return rules; + } + } +} \ No newline at end of file diff --git a/src/services/formatting/singleTokenIndenter.ts b/src/services/formatting/singleTokenIndenter.ts new file mode 100644 index 00000000000..896c2e8ac01 --- /dev/null +++ b/src/services/formatting/singleTokenIndenter.ts @@ -0,0 +1,46 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export class SingleTokenIndenter extends IndentationTrackingWalker { + private indentationAmount: number = null; + private indentationPosition: number; + + constructor(indentationPosition: number, sourceUnit: SourceUnitSyntax, snapshot: ITextSnapshot, indentFirstToken: boolean, options: FormattingOptions) { + super(new TextSpan(indentationPosition, 1), sourceUnit, snapshot, indentFirstToken, options); + + this.indentationPosition = indentationPosition; + } + + public static getIndentationAmount(position: number, sourceUnit: SourceUnitSyntax, snapshot: ITextSnapshot, options: FormattingOptions): number { + var walker = new SingleTokenIndenter(position, sourceUnit, snapshot, true, options); + visitNodeOrToken(walker, sourceUnit); + return walker.indentationAmount; + } + + public indentToken(token: ISyntaxToken, indentationAmount: number, commentIndentationAmount: number): void { + // Compute an indentation string for this token + if (token.fullWidth() === 0 || (this.indentationPosition - this.position() < token.leadingTriviaWidth())) { + // The position is in the leading trivia, use comment indentation + this.indentationAmount = commentIndentationAmount; + } + else { + this.indentationAmount = indentationAmount; + } + } + } +} \ No newline at end of file diff --git a/src/services/formatting/snapshotPoint.ts b/src/services/formatting/snapshotPoint.ts new file mode 100644 index 00000000000..762748dbc70 --- /dev/null +++ b/src/services/formatting/snapshotPoint.ts @@ -0,0 +1,30 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + + export class SnapshotPoint { + constructor(public snapshot: ITextSnapshot, public position: number) { + } + public getContainingLine(): ITextSnapshotLine { + return this.snapshot.getLineFromPosition(this.position); + } + public add(offset: number): SnapshotPoint { + return new SnapshotPoint(this.snapshot, this.position + offset); + } + } +} \ No newline at end of file diff --git a/src/services/formatting/textEditInfo.ts b/src/services/formatting/textEditInfo.ts new file mode 100644 index 00000000000..bdcbdd0ddc8 --- /dev/null +++ b/src/services/formatting/textEditInfo.ts @@ -0,0 +1,28 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export class TextEditInfo { + + constructor(public position: number, public length: number, public replaceWith: string) { + } + + public toString() { + return "[ position: " + this.position + ", length: " + this.length + ", replaceWith: '" + this.replaceWith + "' ]"; + } + } +} \ No newline at end of file diff --git a/src/services/formatting/textSnapshot.ts b/src/services/formatting/textSnapshot.ts new file mode 100644 index 00000000000..c91ea7ae492 --- /dev/null +++ b/src/services/formatting/textSnapshot.ts @@ -0,0 +1,84 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export interface ITextSnapshot { + getText(span: TextSpan): string; + getLineNumberFromPosition(position: number): number; + getLineFromPosition(position: number): ITextSnapshotLine; + getLineFromLineNumber(lineNumber: number): ITextSnapshotLine; + } + + export class TextSnapshot implements ITextSnapshot { + private lines: TextSnapshotLine[]; + + constructor(private snapshot: ISimpleText) { + this.lines = []; + } + + public getText(span: TextSpan): string { + return this.snapshot.substr(span.start(), span.length()); + } + + public getLineNumberFromPosition(position: number): number { + return this.snapshot.lineMap().getLineNumberFromPosition(position); + } + + public getLineFromPosition(position: number): ITextSnapshotLine { + var lineNumber = this.getLineNumberFromPosition(position); + return this.getLineFromLineNumber(lineNumber); + } + + public getLineFromLineNumber(lineNumber: number): ITextSnapshotLine { + var line = this.lines[lineNumber]; + if (line === undefined) { + line = this.getLineFromLineNumberWorker(lineNumber); + this.lines[lineNumber] = line; + } + return line; + } + + private getLineFromLineNumberWorker(lineNumber: number): ITextSnapshotLine { + var lineMap = this.snapshot.lineMap().lineStarts(); + var lineMapIndex = lineNumber; //Note: lineMap is 0-based + if (lineMapIndex < 0 || lineMapIndex >= lineMap.length) + throw new Error(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.Invalid_line_number_0, [lineMapIndex])); + var start = lineMap[lineMapIndex]; + + var end: number; + var endIncludingLineBreak: number; + var lineBreak = ""; + if (lineMapIndex == lineMap.length) { + end = endIncludingLineBreak = this.snapshot.length(); + } + else { + endIncludingLineBreak = (lineMapIndex >= lineMap.length - 1 ? this.snapshot.length() : lineMap[lineMapIndex + 1]); + for (var p = endIncludingLineBreak - 1; p >= start; p--) { + var c = this.snapshot.substr(p, 1); + //TODO: Other ones? + if (c != "\r" && c != "\n") { + break; + } + } + end = p + 1; + lineBreak = this.snapshot.substr(end, endIncludingLineBreak - end); + } + var result = new TextSnapshotLine(this, lineNumber, start, end, lineBreak); + return result; + } + } +} \ No newline at end of file diff --git a/src/services/formatting/textSnapshotLine.ts b/src/services/formatting/textSnapshotLine.ts new file mode 100644 index 00000000000..df2d9eff237 --- /dev/null +++ b/src/services/formatting/textSnapshotLine.ts @@ -0,0 +1,80 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export interface ITextSnapshotLine { + snapshot(): ITextSnapshot; + + start(): SnapshotPoint; + startPosition(): number; + + end(): SnapshotPoint; + endPosition(): number; + + endIncludingLineBreak(): SnapshotPoint; + endIncludingLineBreakPosition(): number; + + length(): number; + lineNumber(): number; + getText(): string; + } + + export class TextSnapshotLine implements ITextSnapshotLine { + constructor(private _snapshot: ITextSnapshot, private _lineNumber: number, private _start: number, private _end: number, private _lineBreak: string) { + } + + public snapshot() { + return this._snapshot; + } + + public start() { + return new SnapshotPoint(this._snapshot, this._start); + } + + public startPosition() { + return this._start; + } + + public end() { + return new SnapshotPoint(this._snapshot, this._end); + } + + public endPosition() { + return this._end; + } + + public endIncludingLineBreak() { + return new SnapshotPoint(this._snapshot, this._end + this._lineBreak.length); + } + + public endIncludingLineBreakPosition() { + return this._end + this._lineBreak.length; + } + + public length() { + return this._end - this._start; + } + + public lineNumber() { + return this._lineNumber; + } + + public getText(): string { + return this._snapshot.getText(TextSpan.fromBounds(this._start, this._end)); + } + } +} \ No newline at end of file diff --git a/src/services/formatting/tokenRange.ts b/src/services/formatting/tokenRange.ts new file mode 100644 index 00000000000..0c06f797025 --- /dev/null +++ b/src/services/formatting/tokenRange.ts @@ -0,0 +1,152 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services.Formatting { + export module Shared { + export interface ITokenAccess { + GetTokens(): SyntaxKind[]; + Contains(token: SyntaxKind): boolean; + } + + export class TokenRangeAccess implements ITokenAccess { + private tokens: SyntaxKind[]; + + constructor(from: SyntaxKind, to: SyntaxKind, except: SyntaxKind[]) { + this.tokens = []; + for (var token = from; token <= to; token++) { + if (except.indexOf(token) < 0) { + this.tokens.push(token); + } + } + } + + public GetTokens(): SyntaxKind[] { + return this.tokens; + } + + public Contains(token: SyntaxKind): boolean { + return this.tokens.indexOf(token) >= 0; + } + + + public toString(): string { + return "[tokenRangeStart=" + SyntaxKind[this.tokens[0]] + "," + + "tokenRangeEnd=" + SyntaxKind[this.tokens[this.tokens.length - 1]] + "]"; + } + } + + export class TokenValuesAccess implements ITokenAccess { + private tokens: SyntaxKind[]; + + constructor(tks: SyntaxKind[]) { + this.tokens = tks && tks.length ? tks : []; + } + + public GetTokens(): SyntaxKind[] { + return this.tokens; + } + + public Contains(token: SyntaxKind): boolean { + return this.tokens.indexOf(token) >= 0; + } + } + + export class TokenSingleValueAccess implements ITokenAccess { + constructor(public token: SyntaxKind) { + } + + public GetTokens(): SyntaxKind[] { + return [this.token]; + } + + public Contains(tokenValue: SyntaxKind): boolean { + return tokenValue == this.token; + } + + public toString(): string { + return "[singleTokenKind=" + SyntaxKind[this.token] + "]"; + } + } + + export class TokenAllAccess implements ITokenAccess { + public GetTokens(): SyntaxKind[] { + var result: SyntaxKind[] = []; + for (var token = SyntaxKind.FirstToken; token <= SyntaxKind.LastToken; token++) { + result.push(token); + } + return result; + } + + public Contains(tokenValue: SyntaxKind): boolean { + return true; + } + + public toString(): string { + return "[allTokens]"; + } + } + + export class TokenRange { + constructor(public tokenAccess: ITokenAccess) { + } + + static FromToken(token: SyntaxKind): TokenRange { + return new TokenRange(new TokenSingleValueAccess(token)); + } + + static FromTokens(tokens: SyntaxKind[]): TokenRange { + return new TokenRange(new TokenValuesAccess(tokens)); + } + + static FromRange(f: SyntaxKind, to: SyntaxKind, except: SyntaxKind[] = []): TokenRange { + return new TokenRange(new TokenRangeAccess(f, to, except)); + } + + static AllTokens(): TokenRange { + return new TokenRange(new TokenAllAccess()); + } + + public GetTokens(): SyntaxKind[] { + return this.tokenAccess.GetTokens(); + } + + public Contains(token: SyntaxKind): boolean { + return this.tokenAccess.Contains(token); + } + + public toString(): string { + return this.tokenAccess.toString(); + } + + static Any: TokenRange = TokenRange.AllTokens(); + static AnyIncludingMultilineComments = TokenRange.FromTokens(TokenRange.Any.GetTokens().concat([SyntaxKind.MultiLineCommentTrivia])); + static Keywords = TokenRange.FromRange(SyntaxKind.FirstKeyword, SyntaxKind.LastKeyword); + static Operators = TokenRange.FromRange(SyntaxKind.SemicolonToken, SyntaxKind.SlashEqualsToken); + static BinaryOperators = TokenRange.FromRange(SyntaxKind.LessThanToken, SyntaxKind.SlashEqualsToken); + static BinaryKeywordOperators = TokenRange.FromTokens([SyntaxKind.InKeyword, SyntaxKind.InstanceOfKeyword]); + static ReservedKeywords = TokenRange.FromRange(SyntaxKind.FirstFutureReservedStrictKeyword, SyntaxKind.LastFutureReservedStrictKeyword); + static UnaryPrefixOperators = TokenRange.FromTokens([SyntaxKind.PlusPlusToken, SyntaxKind.MinusMinusToken, SyntaxKind.TildeToken, SyntaxKind.ExclamationToken]); + static UnaryPrefixExpressions = TokenRange.FromTokens([SyntaxKind.NumericLiteral, SyntaxKind.IdentifierName, SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.OpenBraceToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]); + static UnaryPreincrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]); + static UnaryPostincrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]); + static UnaryPredecrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]); + static UnaryPostdecrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]); + static Comments = TokenRange.FromTokens([SyntaxKind.SingleLineCommentTrivia, SyntaxKind.MultiLineCommentTrivia]); + static TypeNames = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.NumberKeyword, SyntaxKind.StringKeyword, SyntaxKind.BooleanKeyword, SyntaxKind.VoidKeyword, SyntaxKind.AnyKeyword]); + } + } +} \ No newline at end of file diff --git a/src/services/formatting/tokenSpan.ts b/src/services/formatting/tokenSpan.ts new file mode 100644 index 00000000000..aba9c372f35 --- /dev/null +++ b/src/services/formatting/tokenSpan.ts @@ -0,0 +1,25 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + + +module TypeScript.Services.Formatting { + export class TokenSpan extends TextSpan { + constructor(public kind: SyntaxKind, start: number, length: number) { + super(start, length); + } + } +} \ No newline at end of file diff --git a/src/services/getScriptLexicalStructureWalker.ts b/src/services/getScriptLexicalStructureWalker.ts new file mode 100644 index 00000000000..c62ef11136d --- /dev/null +++ b/src/services/getScriptLexicalStructureWalker.ts @@ -0,0 +1,352 @@ + +/// +module TypeScript.Services { + interface LexicalScope { + items: TypeScript.IIndexable; + itemNames: string[]; + childScopes: TypeScript.IIndexable; + childScopeNames: string[]; + } + + export class GetScriptLexicalStructureWalker extends TypeScript.SyntaxWalker { + private nameStack: string[] = []; + private kindStack: string[] = []; + + private parentScopes: LexicalScope[] = []; + private currentScope: LexicalScope; + + private createScope(): LexicalScope { + return { + items: TypeScript.createIntrinsicsObject(), + childScopes: TypeScript.createIntrinsicsObject(), + childScopeNames: [], + itemNames: [] + }; + } + + private pushNewContainerScope(containerName: string, kind: string): LexicalScope { + Debug.assert(containerName, "No scope name provided"); + + var key = kind + "+" + containerName; + this.nameStack.push(containerName); + this.kindStack.push(kind); + + var parentScope = this.currentScope; + this.parentScopes.push(parentScope); + + var scope = parentScope.childScopes[key]; + if (!scope) { + scope = this.createScope() + parentScope.childScopes[key] = scope; + parentScope.childScopeNames.push(key); + } + + this.currentScope = scope; + return parentScope; + } + + private popScope() { + Debug.assert(this.parentScopes.length > 0, "No parent scopes to return to") + this.currentScope = this.parentScopes.pop(); + this.kindStack.pop(); + this.nameStack.pop(); + } + + constructor(private fileName: string) { + super(); + this.currentScope = this.createScope(); + } + + private collectItems(items: NavigateToItem[], scope = this.currentScope) { + scope.itemNames.forEach(item => { + items.push(scope.items[item]); + }); + + scope.childScopeNames.forEach(childScope => { + this.collectItems(items, scope.childScopes[childScope]); + }); + } + + static getListsOfAllScriptLexicalStructure(items: NavigateToItem[], fileName: string, unit: TypeScript.SourceUnitSyntax) { + var visitor = new GetScriptLexicalStructureWalker(fileName); + visitNodeOrToken(visitor, unit); + visitor.collectItems(items); + } + + private createItem(node: TypeScript.ISyntaxNode, modifiers: ISyntaxToken[], kind: string, name: string): void { + var key = kind + "+" + name; + + if (this.currentScope.items[key] !== undefined) { + this.addAdditionalSpan(node, key); + return; + } + + var item = new NavigateToItem(); + item.name = name; + item.kind = kind; + item.matchKind = MatchKind.exact; + item.fileName = this.fileName; + item.kindModifiers = this.getKindModifiers(modifiers); + item.minChar = start(node); + item.limChar = end(node); + item.containerName = this.nameStack.join("."); + item.containerKind = this.kindStack.length === 0 ? "" : TypeScript.ArrayUtilities.last(this.kindStack); + + this.currentScope.items[key] = item; + this.currentScope.itemNames.push(key); + } + + private addAdditionalSpan( + node: TypeScript.ISyntaxNode, + key: string) { + + var item = this.currentScope.items[key] + Debug.assert(item !== undefined); + + var start = TypeScript.start(node); + var span = new SpanInfo(start, start + width(node)); + + + if (item.additionalSpans) { + item.additionalSpans.push(span); + } + else { + item.additionalSpans = [span]; + } + } + + private getKindModifiers(modifiers: TypeScript.ISyntaxToken[]): string { + var result: string[] = []; + + for (var i = 0, n = modifiers.length; i < n; i++) { + result.push(modifiers[i].text()); + } + + return result.length > 0 ? result.join(',') : ScriptElementKindModifier.none; + } + + public visitModuleDeclaration(node: TypeScript.ModuleDeclarationSyntax): void { + var names = this.getModuleNames(node); + this.visitModuleDeclarationWorker(node, names, 0); + } + + private visitModuleDeclarationWorker(node: TypeScript.ModuleDeclarationSyntax, names: string[], nameIndex: number): void { + if (nameIndex === names.length) { + // We're after all the module names, descend and process all children. + super.visitModuleDeclaration(node); + } + else { + var name = names[nameIndex]; + var kind = ScriptElementKind.moduleElement; + + this.createItem(node, node.modifiers, kind, name); + + this.pushNewContainerScope(name, kind); + + this.visitModuleDeclarationWorker(node, names, nameIndex + 1); + + this.popScope(); + } + } + + private getModuleNames(node: TypeScript.ModuleDeclarationSyntax): string[] { + var result: string[] = []; + + if (node.stringLiteral) { + result.push(node.stringLiteral.text()); + } + else { + this.getModuleNamesHelper(node.name, result); + } + + return result; + } + + private getModuleNamesHelper(name: TypeScript.INameSyntax, result: string[]): void { + if (name.kind() === TypeScript.SyntaxKind.QualifiedName) { + var qualifiedName = name; + this.getModuleNamesHelper(qualifiedName.left, result); + result.push(qualifiedName.right.text()); + } + else { + result.push((name).text()); + } + } + + public visitClassDeclaration(node: TypeScript.ClassDeclarationSyntax): void { + var name = node.identifier.text(); + var kind = ScriptElementKind.classElement; + + this.createItem(node, node.modifiers, kind, name); + + this.pushNewContainerScope(name, kind); + + super.visitClassDeclaration(node); + + this.popScope(); + } + + public visitInterfaceDeclaration(node: TypeScript.InterfaceDeclarationSyntax): void { + var name = node.identifier.text(); + var kind = ScriptElementKind.interfaceElement; + + this.createItem(node, node.modifiers, kind, name); + + this.pushNewContainerScope(name, kind); + + super.visitInterfaceDeclaration(node); + + this.popScope(); + } + + public visitObjectType(node: TypeScript.ObjectTypeSyntax): void { + // Ignore an object type if we aren't inside an interface declaration. We don't want + // to add some random object type's members to the nav bar. + if (node.parent.kind() === SyntaxKind.InterfaceDeclaration) { + super.visitObjectType(node); + } + } + + public visitEnumDeclaration(node: TypeScript.EnumDeclarationSyntax): void { + var name = node.identifier.text(); + var kind = ScriptElementKind.enumElement; + + this.createItem(node, node.modifiers, kind, name); + + this.pushNewContainerScope(name, kind); + + super.visitEnumDeclaration(node); + + this.popScope(); + } + + public visitConstructorDeclaration(node: TypeScript.ConstructorDeclarationSyntax): void { + this.createItem(node, TypeScript.Syntax.emptyList(), ScriptElementKind.constructorImplementationElement, "constructor"); + + // Search the parameter list of class properties + var parameters = node.callSignature.parameterList.parameters; + if (parameters) { + for (var i = 0, n = parameters.length; i < n; i++) { + var parameter = parameters[i]; + + Debug.assert(parameter.kind() === SyntaxKind.Parameter); + + if (SyntaxUtilities.containsToken(parameter.modifiers, SyntaxKind.PublicKeyword) || + SyntaxUtilities.containsToken(parameter.modifiers, SyntaxKind.PrivateKeyword)) { + this.createItem(node, parameter.modifiers, ScriptElementKind.memberVariableElement, parameter.identifier.text()); + } + } + } + + // No need to descend into a constructor; + } + + public visitMemberFunctionDeclaration(node: TypeScript.MemberFunctionDeclarationSyntax): void { + this.createItem(node, node.modifiers, ScriptElementKind.memberFunctionElement, node.propertyName.text()); + + // No need to descend into a member function; + } + + public visitGetAccessor(node: TypeScript.GetAccessorSyntax): void { + this.createItem(node, node.modifiers, ScriptElementKind.memberGetAccessorElement, node.propertyName.text()); + + // No need to descend into a member accessor; + } + + public visitSetAccessor(node: TypeScript.SetAccessorSyntax): void { + this.createItem(node, node.modifiers, ScriptElementKind.memberSetAccessorElement, node.propertyName.text()); + + // No need to descend into a member accessor; + } + + public visitVariableDeclarator(node: TypeScript.VariableDeclaratorSyntax): void { + var modifiers = node.parent.kind() === SyntaxKind.MemberVariableDeclaration + ? (node.parent).modifiers + : TypeScript.Syntax.emptyList(); + var kind = node.parent.kind() === SyntaxKind.MemberVariableDeclaration + ? ScriptElementKind.memberVariableElement + : ScriptElementKind.variableElement; + this.createItem(node, modifiers, kind, node.propertyName.text()); + + // No need to descend into a variable declarator; + } + + public visitIndexSignature(node: TypeScript.IndexSignatureSyntax): void { + this.createItem(node, TypeScript.Syntax.emptyList(), ScriptElementKind.indexSignatureElement, "[]"); + + // No need to descend into an index signature; + } + + public visitEnumElement(node: TypeScript.EnumElementSyntax): void { + this.createItem(node, TypeScript.Syntax.emptyList(), ScriptElementKind.memberVariableElement, node.propertyName.text()); + + // No need to descend into an enum element; + } + + public visitCallSignature(node: TypeScript.CallSignatureSyntax): void { + this.createItem(node, TypeScript.Syntax.emptyList(), ScriptElementKind.callSignatureElement, "()"); + + // No need to descend into a call signature; + } + + public visitConstructSignature(node: TypeScript.ConstructSignatureSyntax): void { + this.createItem(node, TypeScript.Syntax.emptyList(), ScriptElementKind.constructSignatureElement, "new()"); + + // No need to descend into a construct signature; + } + + public visitMethodSignature(node: TypeScript.MethodSignatureSyntax): void { + this.createItem(node, TypeScript.Syntax.emptyList(), ScriptElementKind.memberFunctionElement, node.propertyName.text()); + + // No need to descend into a method signature; + } + + public visitPropertySignature(node: TypeScript.PropertySignatureSyntax): void { + this.createItem(node, TypeScript.Syntax.emptyList(), ScriptElementKind.memberVariableElement, node.propertyName.text()); + + // No need to descend into a property signature; + } + + public visitFunctionDeclaration(node: TypeScript.FunctionDeclarationSyntax): void { + // in the case of: + // declare function + // the parser will synthesize an identifier. + // we shouldn't add an unnamed function declaration + if (width(node.identifier) > 0) { + this.createItem(node, node.modifiers, ScriptElementKind.functionElement, node.identifier.text()); + } + + // No need to descend into a function declaration; + } + + // Common statement types. Don't even bother walking into them as we'll never find anything + // inside that we'd put in the navbar. + + public visitBlock(node: TypeScript.BlockSyntax): void { + } + + public visitIfStatement(node: TypeScript.IfStatementSyntax): void { + } + + public visitExpressionStatement(node: TypeScript.ExpressionStatementSyntax): void { + } + + public visitThrowStatement(node: TypeScript.ThrowStatementSyntax): void { + } + + public visitReturnStatement(node: TypeScript.ReturnStatementSyntax): void { + } + + public visitSwitchStatement(node: TypeScript.SwitchStatementSyntax): void { + } + + public visitWithStatement(node: TypeScript.WithStatementSyntax): void { + } + + public visitTryStatement(node: TypeScript.TryStatementSyntax): void { + } + + public visitLabeledStatement(node: TypeScript.LabeledStatementSyntax): void { + } + } +} \ No newline at end of file diff --git a/src/services/indentation.ts b/src/services/indentation.ts new file mode 100644 index 00000000000..b067e817d99 --- /dev/null +++ b/src/services/indentation.ts @@ -0,0 +1,155 @@ +/// + +module TypeScript.Indentation { + export function columnForEndOfTokenAtPosition(syntaxTree: SyntaxTree, position: number, options: FormattingOptions): number { + var token = findToken(syntaxTree.sourceUnit(), position); + return columnForStartOfTokenAtPosition(syntaxTree, position, options) + width(token); + } + + export function columnForStartOfTokenAtPosition(syntaxTree: SyntaxTree, position: number, options: FormattingOptions): number { + var token = findToken(syntaxTree.sourceUnit(), position); + + // Walk backward from this token until we find the first token in the line. For each token + // we see (that is not the first tokem in line), push the entirety of the text into the text + // array. Then, for the first token, add its text (without its leading trivia) to the text + // array. i.e. if we have: + // + // var foo = a => bar(); + // + // And we want the column for the start of 'bar', then we'll add the underlinded portions to + // the text array: + // + // var foo = a => bar(); + // _ + // __ + // __ + // ____ + // ____ + var firstTokenInLine = Syntax.firstTokenInLineContainingPosition(syntaxTree, token.fullStart()); + var leadingTextInReverse: string[] = []; + + var current = token; + while (current !== firstTokenInLine) { + current = previousToken(current); + + if (current === firstTokenInLine) { + // We're at the first token in teh line. + // We don't want the leading trivia for this token. That will be taken care of in + // columnForFirstNonWhitespaceCharacterInLine. So just push the trailing trivia + // and then the token text. + leadingTextInReverse.push(current.trailingTrivia().fullText()); + leadingTextInReverse.push(current.text()); + } + else { + // We're at an intermediate token on the line. Just push all its text into the array. + leadingTextInReverse.push(current.fullText()); + } + } + + // Now, add all trivia to the start of the line on the first token in the list. + collectLeadingTriviaTextToStartOfLine(firstTokenInLine, leadingTextInReverse); + + return columnForLeadingTextInReverse(leadingTextInReverse, options); + } + + export function columnForStartOfFirstTokenInLineContainingPosition(syntaxTree: SyntaxTree, position: number, options: FormattingOptions): number { + // Walk backward through the tokens until we find the first one on the line. + var firstTokenInLine = Syntax.firstTokenInLineContainingPosition(syntaxTree, position); + var leadingTextInReverse: string[] = []; + + // Now, add all trivia to the start of the line on the first token in the list. + collectLeadingTriviaTextToStartOfLine(firstTokenInLine, leadingTextInReverse); + + return columnForLeadingTextInReverse(leadingTextInReverse, options); + } + + // Collect all the trivia that precedes this token. Stopping when we hit a newline trivia + // or a multiline comment that spans multiple lines. This is meant to be called on the first + // token in a line. + function collectLeadingTriviaTextToStartOfLine(firstTokenInLine: ISyntaxToken, + leadingTextInReverse: string[]) { + var leadingTrivia = firstTokenInLine.leadingTrivia(); + + for (var i = leadingTrivia.count() - 1; i >= 0; i--) { + var trivia = leadingTrivia.syntaxTriviaAt(i); + if (trivia.kind() === SyntaxKind.NewLineTrivia) { + break; + } + + if (trivia.kind() === SyntaxKind.MultiLineCommentTrivia) { + var lineSegments = Syntax.splitMultiLineCommentTriviaIntoMultipleLines(trivia); + leadingTextInReverse.push(ArrayUtilities.last(lineSegments)); + + if (lineSegments.length > 0) { + // This multiline comment actually spanned multiple lines. So we're done. + break; + } + + // It was only on a single line, so keep on going. + } + + leadingTextInReverse.push(trivia.fullText()); + } + } + + function columnForLeadingTextInReverse(leadingTextInReverse: string[], + options: FormattingOptions): number { + var column = 0; + + // walk backwards. This means we're actually walking forward from column 0 to the start of + // the token. + for (var i = leadingTextInReverse.length - 1; i >= 0; i--) { + var text = leadingTextInReverse[i]; + column = columnForPositionInStringWorker(text, text.length, column, options); + } + + return column; + } + + // Returns the column that this input string ends at (assuming it starts at column 0). + export function columnForPositionInString(input: string, position: number, options: FormattingOptions): number { + return columnForPositionInStringWorker(input, position, 0, options); + } + + function columnForPositionInStringWorker(input: string, position: number, startColumn: number, options: FormattingOptions): number { + var column = startColumn; + var spacesPerTab = options.spacesPerTab; + + for (var j = 0; j < position; j++) { + var ch = input.charCodeAt(j); + + if (ch === CharacterCodes.tab) { + column += spacesPerTab - column % spacesPerTab; + } + else { + column++; + } + } + + return column; + } + + export function indentationString(column: number, options: FormattingOptions): string { + var numberOfTabs = 0; + var numberOfSpaces = Math.max(0, column); + + if (options.useTabs) { + numberOfTabs = Math.floor(column / options.spacesPerTab); + numberOfSpaces -= numberOfTabs * options.spacesPerTab; + } + + return StringUtilities.repeat('\t', numberOfTabs) + + StringUtilities.repeat(' ', numberOfSpaces); + } + + export function firstNonWhitespacePosition(value: string): number { + for (var i = 0; i < value.length; i++) { + var ch = value.charCodeAt(i); + if (!CharacterInfo.isWhitespace(ch)) { + return i; + } + } + + return value.length; + } +} \ No newline at end of file diff --git a/src/services/indenter.ts b/src/services/indenter.ts new file mode 100644 index 00000000000..f082a3fe024 --- /dev/null +++ b/src/services/indenter.ts @@ -0,0 +1,207 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services { + export class Indenter { + public static getIndentation(node: TypeScript.SourceUnitSyntax, soruceText: TypeScript.IScriptSnapshot, position: number, editorOptions: TypeScript.Services.EditorOptions): number { + var indentation = 0; + var currentToken = TypeScript.findToken(node, position); + var currentNode: TypeScript.ISyntaxElement = currentToken; + + if (currentToken.kind() === TypeScript.SyntaxKind.EndOfFileToken) { + // Ignore EOF tokens, pick the one before it + currentNode = previousToken(currentToken); + } + else if (Indenter.belongsToBracket(soruceText, currentToken, position)) { + // Let braces and brackets take the indentation of thier parents + currentNode = currentToken.parent; + } + + if (currentNode === null) { + return indentation; + } + + // Check if this is a valid node to provide indentation + if (currentNode.kind() === TypeScript.SyntaxKind.StringLiteral || + currentNode.kind() === TypeScript.SyntaxKind.RegularExpressionLiteral) { + return indentation; + } + + var currentElement = currentNode; + var parent = currentNode.parent; + + while (parent !== null) { + // Skip nodes that start at the position, these will have the indentation level of thier parent + if (fullStart(parent) !== fullStart(currentNode)) { + if (Indenter.isInContainerNode(parent, currentElement)) { + indentation += editorOptions.IndentSize; + } + else { + var listIndentation = Indenter.getCustomListIndentation(parent, currentElement); + if (listIndentation !== -1) { + // Found a list node with special indentation, If the list items span multiple lines, we want + // to use the user-specified indentation; return. + return indentation + listIndentation; + } + } + } + currentNode = parent; + currentElement = parent; + parent = parent.parent; + } + + return indentation; + } + + private static belongsToBracket(sourceText: TypeScript.IScriptSnapshot, token: TypeScript.ISyntaxToken, position: number): boolean { + switch (token.kind()) { + case TypeScript.SyntaxKind.OpenBraceToken: + case TypeScript.SyntaxKind.CloseBraceToken: + case TypeScript.SyntaxKind.OpenParenToken: + case TypeScript.SyntaxKind.CloseParenToken: + case TypeScript.SyntaxKind.OpenBracketToken: + case TypeScript.SyntaxKind.CloseBracketToken: + // the current token is a bracket, check if the current position is separated from it by a new line + if (position < start(token)) { + var text = sourceText.getText(position, start(token)); + for(var i = 0; i< text.length; i++){ + if (TypeScript.CharacterInfo.isLineTerminator(text.charCodeAt(i))) { + return false; + } + } + } + return true; + } + return false; + } + + private static isInContainerNode(parent: TypeScript.ISyntaxElement, element: TypeScript.ISyntaxElement): boolean { + switch (parent.kind()) { + case TypeScript.SyntaxKind.ClassDeclaration: + case TypeScript.SyntaxKind.ModuleDeclaration: + case TypeScript.SyntaxKind.EnumDeclaration: + case TypeScript.SyntaxKind.ImportDeclaration: + case TypeScript.SyntaxKind.Block: + case TypeScript.SyntaxKind.SwitchStatement: + case TypeScript.SyntaxKind.CaseSwitchClause: + case TypeScript.SyntaxKind.DefaultSwitchClause: + return true; + + case TypeScript.SyntaxKind.ObjectType: + return true; + + case TypeScript.SyntaxKind.InterfaceDeclaration: + return element.kind() !== TypeScript.SyntaxKind.ObjectType; + + case TypeScript.SyntaxKind.FunctionDeclaration: + case TypeScript.SyntaxKind.MemberFunctionDeclaration: + case TypeScript.SyntaxKind.GetAccessor: + case TypeScript.SyntaxKind.SetAccessor: + case TypeScript.SyntaxKind.FunctionExpression: + case TypeScript.SyntaxKind.CatchClause: + case TypeScript.SyntaxKind.FinallyClause: + case TypeScript.SyntaxKind.FunctionDeclaration: + case TypeScript.SyntaxKind.ConstructorDeclaration: + case TypeScript.SyntaxKind.ForStatement: + case TypeScript.SyntaxKind.ForInStatement: + case TypeScript.SyntaxKind.WhileStatement: + case TypeScript.SyntaxKind.DoStatement: + case TypeScript.SyntaxKind.WithStatement: + case TypeScript.SyntaxKind.IfStatement: + case TypeScript.SyntaxKind.ElseClause: + // The block has already been conted before, ignore the container node + return element.kind() !== TypeScript.SyntaxKind.Block; + + case TypeScript.SyntaxKind.TryStatement: + // If inside the try body, the block element will take care of the indentation + // If not, we do not want to indent, as the next token would probally be catch or finally + // and we want these on the same indentation level. + return false; + default: + return isNode(parent) && SyntaxUtilities.isStatement(parent); + } + } + + private static getCustomListIndentation(list: TypeScript.ISyntaxElement, element: TypeScript.ISyntaxElement): number { + switch (list.kind()) { + case TypeScript.SyntaxKind.SeparatedList: + // If it is the first in the list, let it have its parents indentation; no custom indentation here. + for (var i = 0, n = childCount(list); i < n ; i++) { + var child = childAt(list, i); + if (child !== null && child === element) + return Indenter.getListItemIndentation(list, i - 1); + } + break; + + case TypeScript.SyntaxKind.ArgumentList: + // The separated list has been handled in the previous case, this is just if we are after + // the last element of the list, we want to get the indentation of the last element of the list + var argumentList = list; + var _arguments = argumentList.arguments; + if (_arguments !== null && argumentList.closeParenToken === element) { + return Indenter.getListItemIndentation(_arguments, childCount(_arguments) - 1); + } + break; + + case TypeScript.SyntaxKind.ParameterList: + // The separated list has been handled in the previous case, this is just if we are after + // the last element of the list, we want to get the indentation of the last element of the list + var parameterList = list; + var parameters = parameterList.parameters; + if (parameters !== null && parameterList.closeParenToken === element) { + return Indenter.getListItemIndentation(parameters, childCount(parameters) - 1); + } + break; + + case TypeScript.SyntaxKind.TypeArgumentList: + // The separated list has been handled in the previous case, this is just if we are after + // the last element of the list, we want to get the indentation of the last element of the list + var typeArgumentList = list; + var typeArguments = typeArgumentList.typeArguments; + if (typeArguments !== null && typeArgumentList.greaterThanToken === element) { + return Indenter.getListItemIndentation(typeArguments, childCount(typeArguments) - 1); + } + break; + + case TypeScript.SyntaxKind.TypeParameterList: + // The separated list has been handled in the previous case, this is just if we are after + // the last element of the list, we want to get the indentation of the last element of the list + var typeParameterList = list; + var typeParameters = typeParameterList.typeParameters; + if (typeParameters !== null && typeParameterList.greaterThanToken === element) { + return Indenter.getListItemIndentation(typeParameters, childCount(typeParameters) - 1); + } + break; + } + return -1; + } + + private static getListItemIndentation(list: TypeScript.ISyntaxElement, elementIndex: number): number { + for (var i = elementIndex; i > 0 ; i--) { + var child = childAt(list, i); + var previousChild = childAt(list, i - 1); + if ((child !== null && firstToken(child).leadingTrivia().hasNewLine()) || + (previousChild !== null && lastToken(previousChild).trailingTrivia().hasNewLine())) { + + // TODO: get the trivia after new line + return leadingTriviaWidth(child); + } + } + return -1; + } + } +} diff --git a/src/services/keywordCompletions.ts b/src/services/keywordCompletions.ts new file mode 100644 index 00000000000..90ebc5bdd53 --- /dev/null +++ b/src/services/keywordCompletions.ts @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0. +// See LICENSE.txt in the project root for complete license information. + +/// + +module TypeScript.Services { + export class KeywordCompletions { + private static keywords = [ + "break", + "case", + "catch", + "class", + "constructor", + "continue", + "debugger", + "declare", + "default", + "delete", + "do", + "else", + "enum", + "export", + "extends", + "false", + "finally", + "for", + "function", + "get", + "if", + "implements", + "import", + "in", + "instanceof", + "interface", + "module", + "new", + "null", + "private", + "public", + "require", + "return", + "set", + "static", + "super", + "switch", + "this", + "throw", + "true", + "try", + "typeof", + "var", + "while", + "with", + ]; + + private static keywordCompletions: ResolvedCompletionEntry[] = null; + + public static getKeywordCompltions(): ResolvedCompletionEntry[]{ + if (KeywordCompletions.keywordCompletions === null) { + var completions: ResolvedCompletionEntry[] = []; + for (var i = 0, n = KeywordCompletions.keywords.length; i < n; i++) { + var keyword = KeywordCompletions.keywords[i]; + var entry = new ResolvedCompletionEntry(/*name*/ keyword, ScriptElementKind.keyword, ScriptElementKindModifier.none, /*type*/null, /*fullName*/ keyword, /*docComment*/ null); + completions.push(entry); + } + + KeywordCompletions.keywordCompletions = completions; + } + + return KeywordCompletions.keywordCompletions; + } + } +} \ No newline at end of file diff --git a/src/services/languageService.ts b/src/services/languageService.ts new file mode 100644 index 00000000000..efaf0283373 --- /dev/null +++ b/src/services/languageService.ts @@ -0,0 +1,345 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// +/// + +module TypeScript.Services { + + // + // Public interface of the host of a language service instance. + // + export interface ILanguageServiceHost extends TypeScript.ILogger, TypeScript.IReferenceResolverHost { + getCompilationSettings(): ts.CompilerOptions; + + getScriptFileNames(): string[]; + getScriptVersion(fileName: string): number; + getScriptIsOpen(fileName: string): boolean; + getScriptByteOrderMark(fileName: string): TypeScript.ByteOrderMark; + getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot; + getDiagnosticsObject(): TypeScript.Services.ILanguageServicesDiagnostics; + getLocalizedDiagnosticMessages(): any; + getCancellationToken(): ICancellationToken; + } + + // + // Public services of a language service instance associated + // with a language service host instance + // + export interface ILanguageService { + // Note: refresh is a no-op now. It is only around for back compat purposes. + refresh(): void; + + cleanupSemanticCache(): void; + + getSyntacticDiagnostics(fileName: string): ts.Diagnostic[]; + getSemanticDiagnostics(fileName: string): ts.Diagnostic[]; + getCompilerOptionsDiagnostics(): ts.Diagnostic[]; + + getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean): CompletionInfo; + getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails; + + getTypeAtPosition(fileName: string, position: number): TypeInfo; + + getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): SpanInfo; + + getBreakpointStatementAtPosition(fileName: string, position: number): SpanInfo; + + getSignatureAtPosition(fileName: string, position: number): SignatureInfo; + + getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; + getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[]; + getOccurrencesAtPosition(fileName: string, position: number): ReferenceEntry[]; + getImplementorsAtPosition(fileName: string, position: number): ReferenceEntry[]; + + getNavigateToItems(searchValue: string): NavigateToItem[]; + getScriptLexicalStructure(fileName: string): NavigateToItem[]; + + getOutliningRegions(fileName: string): TypeScript.TextSpan[]; + getBraceMatchingAtPosition(fileName: string, position: number): TypeScript.TextSpan[]; + getIndentationAtPosition(fileName: string, position: number, options: TypeScript.Services.EditorOptions): number; + + getFormattingEditsForRange(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[]; + getFormattingEditsForDocument(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[]; + getFormattingEditsOnPaste(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[]; + getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions): TextEdit[]; + + getEmitOutput(fileName: string): TypeScript.EmitOutput; + + getSyntaxTree(fileName: string): TypeScript.SyntaxTree; + + dispose(): void; + } + + export function logInternalError(logger: TypeScript.ILogger, err: Error) { + logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message); + } + + export class ReferenceEntry { + public fileName: string = "" + public minChar: number = -1; + public limChar: number = -1; + public isWriteAccess: boolean = false; + + constructor(fileName: string, minChar: number, limChar: number, isWriteAccess: boolean) { + this.fileName = fileName; + this.minChar = minChar; + this.limChar = limChar; + this.isWriteAccess = isWriteAccess; + } + } + + export class NavigateToItem { + public name: string = ""; + public kind: string = ""; // see ScriptElementKind + public kindModifiers: string = ""; // see ScriptElementKindModifier, comma separated + public matchKind: string = ""; + public fileName: string = ""; + public minChar: number = -1; + public limChar: number = -1; + public additionalSpans: SpanInfo[] = null; + public containerName: string = ""; + public containerKind: string = ""; // see ScriptElementKind + } + + export class TextEdit { + constructor(public minChar: number, public limChar: number, public text: string) { + } + + static createInsert(pos: number, text: string): TextEdit { + return new TextEdit(pos, pos, text); + } + static createDelete(minChar: number, limChar: number): TextEdit { + return new TextEdit(minChar, limChar, ""); + } + static createReplace(minChar: number, limChar: number, text: string): TextEdit { + return new TextEdit(minChar, limChar, text); + } + } + + export class EditorOptions { + public IndentSize: number = 4; + public TabSize: number = 4; + public NewLineCharacter: string = "\r\n"; + public ConvertTabsToSpaces: boolean = true; + + public static clone(objectToClone: EditorOptions): EditorOptions { + var editorOptions = new EditorOptions(); + editorOptions.IndentSize = objectToClone.IndentSize; + editorOptions.TabSize = objectToClone.TabSize; + editorOptions.NewLineCharacter = objectToClone.NewLineCharacter; + editorOptions.ConvertTabsToSpaces = objectToClone.ConvertTabsToSpaces; + return editorOptions; + } + } + + export class FormatCodeOptions extends EditorOptions { + public InsertSpaceAfterCommaDelimiter: boolean = true; + public InsertSpaceAfterSemicolonInForStatements: boolean = true; + public InsertSpaceBeforeAndAfterBinaryOperators: boolean = true; + public InsertSpaceAfterKeywordsInControlFlowStatements: boolean = true; + public InsertSpaceAfterFunctionKeywordForAnonymousFunctions: boolean = false; + public InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: boolean = false; + public PlaceOpenBraceOnNewLineForFunctions: boolean = false; + public PlaceOpenBraceOnNewLineForControlBlocks: boolean = false; + + public static clone(objectToClone: FormatCodeOptions ): FormatCodeOptions { + var formatCodeOptions = EditorOptions.clone(objectToClone); + formatCodeOptions.InsertSpaceAfterCommaDelimiter = objectToClone.InsertSpaceAfterCommaDelimiter; + formatCodeOptions.InsertSpaceAfterSemicolonInForStatements = objectToClone.InsertSpaceAfterSemicolonInForStatements; + formatCodeOptions.InsertSpaceBeforeAndAfterBinaryOperators = objectToClone.InsertSpaceBeforeAndAfterBinaryOperators; + formatCodeOptions.InsertSpaceAfterKeywordsInControlFlowStatements = objectToClone.InsertSpaceAfterKeywordsInControlFlowStatements; + formatCodeOptions.InsertSpaceAfterFunctionKeywordForAnonymousFunctions = objectToClone.InsertSpaceAfterFunctionKeywordForAnonymousFunctions; + formatCodeOptions.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis = objectToClone.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis; + formatCodeOptions.PlaceOpenBraceOnNewLineForFunctions = objectToClone.PlaceOpenBraceOnNewLineForFunctions; + formatCodeOptions.PlaceOpenBraceOnNewLineForControlBlocks = objectToClone.PlaceOpenBraceOnNewLineForControlBlocks; + return formatCodeOptions; + } + } + + export class DefinitionInfo { + constructor( + public fileName: string, + public minChar: number, + public limChar: number, + public kind: string, + public name: string, + public containerKind: string, + public containerName: string) { + } + } + + export class TypeInfo { + constructor( + public memberName: TypeScript.MemberName, + public docComment: string, + public fullSymbolName: string, + public kind: string, + public minChar: number, + public limChar: number) { + } + } + + export class SpanInfo { + constructor(public minChar: number, public limChar: number, public text: string = null) { + } + } + + export class SignatureInfo { + public actual: ActualSignatureInfo; + public formal: FormalSignatureItemInfo[] = []; // Formal signatures + public activeFormal: number; // Index of the "best match" formal signature + } + + export class FormalSignatureItemInfo { + public signatureInfo: string; + public typeParameters: FormalTypeParameterInfo[] = []; + public parameters: FormalParameterInfo[] = []; // Array of parameters + public docComment: string; // Help for the signature + } + + export class FormalTypeParameterInfo { + public name: string; // Type parameter name + public docComment: string; // Comments that contain help for the parameter + public minChar: number; // minChar for parameter info in the formal signature info string + public limChar: number; // lim char for parameter info in the formal signature info string + } + + export class FormalParameterInfo { + public name: string; // Parameter name + public isVariable: boolean; // true if parameter is var args + public docComment: string; // Comments that contain help for the parameter + public minChar: number; // minChar for parameter info in the formal signature info string + public limChar: number; // lim char for parameter info in the formal signature info string + } + + export class ActualSignatureInfo { + public parameterMinChar: number; + public parameterLimChar: number; + public currentParameterIsTypeParameter: boolean; // current parameter is a type argument or a normal argument + public currentParameter: number; // Index of active parameter in "parameters" or "typeParamters" array + } + + export class CompletionInfo { + public maybeInaccurate = false; + public isMemberCompletion = false; + public entries: CompletionEntry[] = []; + } + + export interface CompletionEntry { + name: string; + kind: string; // see ScriptElementKind + kindModifiers: string; // see ScriptElementKindModifier, comma separated + } + + export interface CompletionEntryDetails { + name: string; + kind: string; // see ScriptElementKind + kindModifiers: string; // see ScriptElementKindModifier, comma separated + type: string; + fullSymbolName: string; + docComment: string; + } + + + export class ScriptElementKind { + static unknown = ""; + + // predefined type (void) or keyword (class) + static keyword = "keyword"; + + // top level script node + static scriptElement = "script"; + + // module foo {} + static moduleElement = "module"; + + // class X {} + static classElement = "class"; + + // interface Y {} + static interfaceElement = "interface"; + + // enum E + static enumElement = "enum"; + + // Inside module and script only + // var v = .. + static variableElement = "var"; + + // Inside function + static localVariableElement = "local var"; + + // Inside module and script only + // function f() { } + static functionElement = "function"; + + // Inside function + static localFunctionElement = "local function"; + + // class X { [public|private]* foo() {} } + static memberFunctionElement = "method"; + + // class X { [public|private]* [get|set] foo:number; } + static memberGetAccessorElement = "getter"; + static memberSetAccessorElement = "setter"; + + // class X { [public|private]* foo:number; } + // interface Y { foo:number; } + static memberVariableElement = "property"; + + // class X { constructor() { } } + static constructorImplementationElement = "constructor"; + + // interface Y { ():number; } + static callSignatureElement = "call"; + + // interface Y { []:number; } + static indexSignatureElement = "index"; + + // interface Y { new():Y; } + static constructSignatureElement = "construct"; + + // function foo(*Y*: string) + static parameterElement = "parameter"; + + static typeParameterElement = "type parameter"; + + static primitiveType = "primitive type"; + } + + export class ScriptElementKindModifier { + static none = ""; + static publicMemberModifier = "public"; + static privateMemberModifier = "private"; + static exportedModifier = "export"; + static ambientModifier = "declare"; + static staticModifier = "static"; + } + + export class MatchKind { + static none: string = null; + static exact = "exact"; + static subString = "substring"; + static prefix = "prefix"; + } + + export class DiagnosticCategory { + static none = ""; + static error = "error"; + static warning = "warning"; + static message = "message"; + } +} diff --git a/src/services/languageServiceCopy.ts b/src/services/languageServiceCopy.ts new file mode 100644 index 00000000000..912006eea0c --- /dev/null +++ b/src/services/languageServiceCopy.ts @@ -0,0 +1,342 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// +/// + +module TypeScript.Services { + + // + // Public interface of the host of a language service instance. + // + export interface ILanguageServiceHost extends TypeScript.ILogger, TypeScript.IReferenceResolverHost { + getCompilationSettings(): TypeScript.CompilationSettings; + + getScriptFileNames(): string[]; + getScriptVersion(fileName: string): number; + getScriptIsOpen(fileName: string): boolean; + getScriptByteOrderMark(fileName: string): TypeScript.ByteOrderMark; + getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot; + getDiagnosticsObject(): TypeScript.Services.ILanguageServicesDiagnostics; + getLocalizedDiagnosticMessages(): any; + } + + // + // Public services of a language service instance associated + // with a language service host instance + // + export interface ILanguageService { + // Note: refresh is a no-op now. It is only around for back compat purposes. + refresh(): void; + + cleanupSemanticCache(): void; + + getSyntacticDiagnostics(fileName: string): TypeScript.Diagnostic[]; + getSemanticDiagnostics(fileName: string): TypeScript.Diagnostic[]; + getCompilerOptionsDiagnostics(): TypeScript.Diagnostic[]; + + getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean): CompletionInfo; + getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails; + + getTypeAtPosition(fileName: string, position: number): TypeInfo; + + getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): SpanInfo; + + getBreakpointStatementAtPosition(fileName: string, position: number): SpanInfo; + + getSignatureAtPosition(fileName: string, position: number): SignatureInfo; + + getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; + getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[]; + getOccurrencesAtPosition(fileName: string, position: number): ReferenceEntry[]; + getImplementorsAtPosition(fileName: string, position: number): ReferenceEntry[]; + + getNavigateToItems(searchValue: string): NavigateToItem[]; + getScriptLexicalStructure(fileName: string): NavigateToItem[]; + + getOutliningRegions(fileName: string): TypeScript.TextSpan[]; + getBraceMatchingAtPosition(fileName: string, position: number): TypeScript.TextSpan[]; + getIndentationAtPosition(fileName: string, position: number, options: TypeScript.Services.EditorOptions): number; + + getFormattingEditsForRange(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[]; + getFormattingEditsForDocument(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[]; + getFormattingEditsOnPaste(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[]; + getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions): TextEdit[]; + + getEmitOutput(fileName: string): TypeScript.EmitOutput; + + getSyntaxTree(fileName: string): TypeScript.SyntaxTree; + } + + export function logInternalError(logger: TypeScript.ILogger, err: Error) { + logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message); + } + + export class ReferenceEntry { + public fileName: string = "" + public minChar: number = -1; + public limChar: number = -1; + public isWriteAccess: boolean = false; + + constructor(fileName: string, minChar: number, limChar: number, isWriteAccess: boolean) { + this.fileName = fileName; + this.minChar = minChar; + this.limChar = limChar; + this.isWriteAccess = isWriteAccess; + } + } + + export class NavigateToItem { + public name: string = ""; + public kind: string = ""; // see ScriptElementKind + public kindModifiers: string = ""; // see ScriptElementKindModifier, comma separated + public matchKind: string = ""; + public fileName: string = ""; + public minChar: number = -1; + public limChar: number = -1; + public additionalSpans: SpanInfo[] = null; + public containerName: string = ""; + public containerKind: string = ""; // see ScriptElementKind + } + + export class TextEdit { + constructor(public minChar: number, public limChar: number, public text: string) { + } + + static createInsert(pos: number, text: string): TextEdit { + return new TextEdit(pos, pos, text); + } + static createDelete(minChar: number, limChar: number): TextEdit { + return new TextEdit(minChar, limChar, ""); + } + static createReplace(minChar: number, limChar: number, text: string): TextEdit { + return new TextEdit(minChar, limChar, text); + } + } + + export class EditorOptions { + public IndentSize: number = 4; + public TabSize: number = 4; + public NewLineCharacter: string = "\r\n"; + public ConvertTabsToSpaces: boolean = true; + + public static clone(objectToClone: EditorOptions): EditorOptions { + var editorOptions = new EditorOptions(); + editorOptions.IndentSize = objectToClone.IndentSize; + editorOptions.TabSize = objectToClone.TabSize; + editorOptions.NewLineCharacter = objectToClone.NewLineCharacter; + editorOptions.ConvertTabsToSpaces = objectToClone.ConvertTabsToSpaces; + return editorOptions; + } + } + + export class FormatCodeOptions extends EditorOptions { + public InsertSpaceAfterCommaDelimiter: boolean = true; + public InsertSpaceAfterSemicolonInForStatements: boolean = true; + public InsertSpaceBeforeAndAfterBinaryOperators: boolean = true; + public InsertSpaceAfterKeywordsInControlFlowStatements: boolean = true; + public InsertSpaceAfterFunctionKeywordForAnonymousFunctions: boolean = false; + public InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: boolean = false; + public PlaceOpenBraceOnNewLineForFunctions: boolean = false; + public PlaceOpenBraceOnNewLineForControlBlocks: boolean = false; + + public static clone(objectToClone: FormatCodeOptions ): FormatCodeOptions { + var formatCodeOptions = EditorOptions.clone(objectToClone); + formatCodeOptions.InsertSpaceAfterCommaDelimiter = objectToClone.InsertSpaceAfterCommaDelimiter; + formatCodeOptions.InsertSpaceAfterSemicolonInForStatements = objectToClone.InsertSpaceAfterSemicolonInForStatements; + formatCodeOptions.InsertSpaceBeforeAndAfterBinaryOperators = objectToClone.InsertSpaceBeforeAndAfterBinaryOperators; + formatCodeOptions.InsertSpaceAfterKeywordsInControlFlowStatements = objectToClone.InsertSpaceAfterKeywordsInControlFlowStatements; + formatCodeOptions.InsertSpaceAfterFunctionKeywordForAnonymousFunctions = objectToClone.InsertSpaceAfterFunctionKeywordForAnonymousFunctions; + formatCodeOptions.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis = objectToClone.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis; + formatCodeOptions.PlaceOpenBraceOnNewLineForFunctions = objectToClone.PlaceOpenBraceOnNewLineForFunctions; + formatCodeOptions.PlaceOpenBraceOnNewLineForControlBlocks = objectToClone.PlaceOpenBraceOnNewLineForControlBlocks; + return formatCodeOptions; + } + } + + export class DefinitionInfo { + constructor( + public fileName: string, + public minChar: number, + public limChar: number, + public kind: string, + public name: string, + public containerKind: string, + public containerName: string) { + } + } + + export class TypeInfo { + constructor( + public memberName: TypeScript.MemberName, + public docComment: string, + public fullSymbolName: string, + public kind: string, + public minChar: number, + public limChar: number) { + } + } + + export class SpanInfo { + constructor(public minChar: number, public limChar: number, public text: string = null) { + } + } + + export class SignatureInfo { + public actual: ActualSignatureInfo; + public formal: FormalSignatureItemInfo[] = []; // Formal signatures + public activeFormal: number; // Index of the "best match" formal signature + } + + export class FormalSignatureItemInfo { + public signatureInfo: string; + public typeParameters: FormalTypeParameterInfo[] = []; + public parameters: FormalParameterInfo[] = []; // Array of parameters + public docComment: string; // Help for the signature + } + + export class FormalTypeParameterInfo { + public name: string; // Type parameter name + public docComment: string; // Comments that contain help for the parameter + public minChar: number; // minChar for parameter info in the formal signature info string + public limChar: number; // lim char for parameter info in the formal signature info string + } + + export class FormalParameterInfo { + public name: string; // Parameter name + public isVariable: boolean; // true if parameter is var args + public docComment: string; // Comments that contain help for the parameter + public minChar: number; // minChar for parameter info in the formal signature info string + public limChar: number; // lim char for parameter info in the formal signature info string + } + + export class ActualSignatureInfo { + public parameterMinChar: number; + public parameterLimChar: number; + public currentParameterIsTypeParameter: boolean; // current parameter is a type argument or a normal argument + public currentParameter: number; // Index of active parameter in "parameters" or "typeParamters" array + } + + export class CompletionInfo { + public maybeInaccurate = false; + public isMemberCompletion = false; + public entries: CompletionEntry[] = []; + } + + export interface CompletionEntry { + name: string; + kind: string; // see ScriptElementKind + kindModifiers: string; // see ScriptElementKindModifier, comma separated + } + + export interface CompletionEntryDetails { + name: string; + kind: string; // see ScriptElementKind + kindModifiers: string; // see ScriptElementKindModifier, comma separated + type: string; + fullSymbolName: string; + docComment: string; + } + + + export class ScriptElementKind { + static unknown = ""; + + // predefined type (void) or keyword (class) + static keyword = "keyword"; + + // top level script node + static scriptElement = "script"; + + // module foo {} + static moduleElement = "module"; + + // class X {} + static classElement = "class"; + + // interface Y {} + static interfaceElement = "interface"; + + // enum E + static enumElement = "enum"; + + // Inside module and script only + // var v = .. + static variableElement = "var"; + + // Inside function + static localVariableElement = "local var"; + + // Inside module and script only + // function f() { } + static functionElement = "function"; + + // Inside function + static localFunctionElement = "local function"; + + // class X { [public|private]* foo() {} } + static memberFunctionElement = "method"; + + // class X { [public|private]* [get|set] foo:number; } + static memberGetAccessorElement = "getter"; + static memberSetAccessorElement = "setter"; + + // class X { [public|private]* foo:number; } + // interface Y { foo:number; } + static memberVariableElement = "property"; + + // class X { constructor() { } } + static constructorImplementationElement = "constructor"; + + // interface Y { ():number; } + static callSignatureElement = "call"; + + // interface Y { []:number; } + static indexSignatureElement = "index"; + + // interface Y { new():Y; } + static constructSignatureElement = "construct"; + + // function foo(*Y*: string) + static parameterElement = "parameter"; + + static typeParameterElement = "type parameter"; + + static primitiveType = "primitive type"; + } + + export class ScriptElementKindModifier { + static none = ""; + static publicMemberModifier = "public"; + static privateMemberModifier = "private"; + static exportedModifier = "export"; + static ambientModifier = "declare"; + static staticModifier = "static"; + } + + export class MatchKind { + static none: string = null; + static exact = "exact"; + static subString = "substring"; + static prefix = "prefix"; + } + + export class DiagnosticCategory { + static none = ""; + static error = "error"; + static warning = "warning"; + static message = "message"; + } +} diff --git a/src/services/outliningElementsCollector.ts b/src/services/outliningElementsCollector.ts new file mode 100644 index 00000000000..8a873a8774d --- /dev/null +++ b/src/services/outliningElementsCollector.ts @@ -0,0 +1,109 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// + +module TypeScript.Services { + export class OutliningElementsCollector extends TypeScript.DepthLimitedWalker { + // The maximum depth for collecting spans; this will cause us to miss deeply nested function/modules spans, + // but will guarantee performance will not be closely tied to tree depth. + private static MaximumDepth: number = 10; + private inObjectLiteralExpression: boolean = false; + + private elements: TypeScript.TextSpan[] = []; + + constructor() { + super(OutliningElementsCollector.MaximumDepth); + } + + public visitClassDeclaration(node: TypeScript.ClassDeclarationSyntax): void { + this.addOutlineRange(node, node.openBraceToken, node.closeBraceToken); + super.visitClassDeclaration(node); + } + + public visitInterfaceDeclaration(node: TypeScript.InterfaceDeclarationSyntax): void { + this.addOutlineRange(node, node.body.openBraceToken, node.body.closeBraceToken); + super.visitInterfaceDeclaration(node); + } + + public visitModuleDeclaration(node: TypeScript.ModuleDeclarationSyntax): void { + this.addOutlineRange(node, node.openBraceToken, node.closeBraceToken); + super.visitModuleDeclaration(node); + } + + public visitEnumDeclaration(node: TypeScript.EnumDeclarationSyntax): void { + this.addOutlineRange(node, node.openBraceToken, node.closeBraceToken); + super.visitEnumDeclaration(node); + } + + public visitFunctionDeclaration(node: TypeScript.FunctionDeclarationSyntax): void { + this.addOutlineRange(node, node.block, node.block); + super.visitFunctionDeclaration(node); + } + + public visitFunctionExpression(node: TypeScript.FunctionExpressionSyntax): void { + this.addOutlineRange(node, node.block, node.block); + super.visitFunctionExpression(node); + } + + public visitConstructorDeclaration(node: TypeScript.ConstructorDeclarationSyntax): void { + this.addOutlineRange(node, node.block, node.block); + super.visitConstructorDeclaration(node); + } + + public visitMemberFunctionDeclaration(node: TypeScript.MemberFunctionDeclarationSyntax): void { + this.addOutlineRange(node, node.block, node.block); + super.visitMemberFunctionDeclaration(node); + } + + public visitGetAccessor(node: TypeScript.GetAccessorSyntax): void { + if (!this.inObjectLiteralExpression) { + this.addOutlineRange(node, node.block, node.block); + } + super.visitGetAccessor(node); + } + + public visitSetAccessor(node: TypeScript.SetAccessorSyntax): void { + if (!this.inObjectLiteralExpression) { + this.addOutlineRange(node, node.block, node.block); + } + super.visitSetAccessor(node); + } + + public visitObjectLiteralExpression(node: TypeScript.ObjectLiteralExpressionSyntax): void { + var savedInObjectLiteralExpression = this.inObjectLiteralExpression; + this.inObjectLiteralExpression = true; + super.visitObjectLiteralExpression(node); + this.inObjectLiteralExpression = savedInObjectLiteralExpression; + } + + private addOutlineRange(node: TypeScript.ISyntaxNode, startElement: TypeScript.ISyntaxNodeOrToken, endElement: TypeScript.ISyntaxNodeOrToken) { + if (startElement && endElement && !isShared(startElement) && !isShared(endElement)) { + // Compute the position + var start = TypeScript.start(startElement); + var end = TypeScript.end(endElement); + + // Push the new range + this.elements.push(TypeScript.TextSpan.fromBounds(start, end)); + } + } + + public static collectElements(node: TypeScript.SourceUnitSyntax): TypeScript.TextSpan[] { + var collector = new OutliningElementsCollector(); + visitNodeOrToken(collector, node); + return collector.elements; + } + } +} diff --git a/src/services/pullLanguageService.ts b/src/services/pullLanguageService.ts new file mode 100644 index 00000000000..93d2251d0d7 --- /dev/null +++ b/src/services/pullLanguageService.ts @@ -0,0 +1,733 @@ +/// + +/// +/// +/// +/// +/// + +module TypeScript.Services { + // Information about a specific host file. + class HostFileInformation { + private _sourceText: TypeScript.IScriptSnapshot; + + constructor( + public filename: string, + private host: ILanguageServiceHost, + public version: number, + public isOpen: boolean, + public byteOrderMark: TypeScript.ByteOrderMark) { + this._sourceText = null; + } + + public getScriptSnapshot(): TypeScript.IScriptSnapshot { + if (this._sourceText === null) { + this._sourceText = this.host.getScriptSnapshot(this.filename); + } + + return this._sourceText; + } + } + + export function getDefaultCompilerOptions(): ts.CompilerOptions { + // Set "ES5" target by default for language service + return { target: ts.ScriptTarget.ES5 }; + } + + // Cache host information about scripts. Should be refreshed + // at each language service public entry point, since we don't know when + // set of scripts handled by the host changes. + class HostCache { + private _filenameToEntry: TypeScript.StringHashTable; + private _compilationSettings: ts.CompilerOptions; + + constructor(host: ILanguageServiceHost) { + // script id => script index + this._filenameToEntry = new TypeScript.StringHashTable(); + + var filenames = host.getScriptFileNames(); + for (var i = 0, n = filenames.length; i < n; i++) { + var filename = filenames[i]; + this._filenameToEntry.add(TypeScript.switchToForwardSlashes(filename), new HostFileInformation( + filename, host, host.getScriptVersion(filename), host.getScriptIsOpen(filename), host.getScriptByteOrderMark(filename))); + } + + this._compilationSettings = host.getCompilationSettings() || getDefaultCompilerOptions(); + } + + public compilationSettings() { + return this._compilationSettings; + } + + public contains(filename: string): boolean { + return this._filenameToEntry.lookup(TypeScript.switchToForwardSlashes(filename)) !== null; + } + + public getHostfilename(filename: string) { + var hostCacheEntry = this._filenameToEntry.lookup(TypeScript.switchToForwardSlashes(filename)); + if (hostCacheEntry) { + return hostCacheEntry.filename; + } + return filename; + } + + public getfilenames(): string[] { + return this._filenameToEntry.getAllKeys(); + } + + public getVersion(filename: string): number { + return this._filenameToEntry.lookup(TypeScript.switchToForwardSlashes(filename)).version; + } + + public isOpen(filename: string): boolean { + return this._filenameToEntry.lookup(TypeScript.switchToForwardSlashes(filename)).isOpen; + } + + public getByteOrderMark(filename: string): TypeScript.ByteOrderMark { + return this._filenameToEntry.lookup(TypeScript.switchToForwardSlashes(filename)).byteOrderMark; + } + + public getScriptSnapshot(filename: string): TypeScript.IScriptSnapshot { + return this._filenameToEntry.lookup(TypeScript.switchToForwardSlashes(filename)).getScriptSnapshot(); + } + + public getScriptTextChangeRangeSinceVersion(filename: string, lastKnownVersion: number): TypeScript.TextChangeRange { + var currentVersion = this.getVersion(filename); + if (lastKnownVersion === currentVersion) { + return TypeScript.TextChangeRange.unchanged; // "No changes" + } + + var scriptSnapshot = this.getScriptSnapshot(filename); + return scriptSnapshot.getTextChangeRangeSinceVersion(lastKnownVersion); + } + } + + export class SyntaxTreeCache { + private _hostCache: HostCache; + + // For our syntactic only features, we also keep a cache of the syntax tree for the + // currently edited file. + private _currentfilename: string = ""; + private _currentFileVersion: number = -1; + private _currentFileSyntaxTree: TypeScript.SyntaxTree = null; + private _currentFileScriptSnapshot: TypeScript.IScriptSnapshot = null; + + constructor(private _host: ILanguageServiceHost) { + this._hostCache = new HostCache(_host); + } + + public getCurrentFileSyntaxTree(filename: string): TypeScript.SyntaxTree { + this._hostCache = new HostCache(this._host); + + var version = this._hostCache.getVersion(filename); + var syntaxTree: TypeScript.SyntaxTree = null; + + if (this._currentFileSyntaxTree === null || this._currentfilename !== filename) { + var scriptSnapshot = this._hostCache.getScriptSnapshot(filename); + syntaxTree = this.createSyntaxTree(filename, scriptSnapshot); + } + else if (this._currentFileVersion !== version) { + var scriptSnapshot = this._hostCache.getScriptSnapshot(filename); + syntaxTree = this.updateSyntaxTree(filename, scriptSnapshot, this._currentFileSyntaxTree, this._currentFileVersion); + } + + if (syntaxTree !== null) { + // All done, ensure state is up to date + this._currentFileScriptSnapshot = scriptSnapshot; + this._currentFileVersion = version; + this._currentfilename = filename; + this._currentFileSyntaxTree = syntaxTree; + } + + return this._currentFileSyntaxTree; + } + + public getCurrentScriptSnapshot(filename: string): IScriptSnapshot { + // update _currentFileScriptSnapshot as a part of 'getCurrentFileSyntaxTree' call + this.getCurrentFileSyntaxTree(filename); + return this._currentFileScriptSnapshot; + } + + private createSyntaxTree(filename: string, scriptSnapshot: TypeScript.IScriptSnapshot): TypeScript.SyntaxTree { + var text = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot); + + // For the purposes of features that use this syntax tree, we can just use the default + // compilation settings. The features only use the syntax (and not the diagnostics), + // and the syntax isn't affected by the compilation settings. + var syntaxTree = TypeScript.Parser.parse(filename, text, getDefaultCompilerOptions().target, TypeScript.isDTSFile(filename)); + + return syntaxTree; + } + + private updateSyntaxTree(filename: string, scriptSnapshot: TypeScript.IScriptSnapshot, previousSyntaxTree: TypeScript.SyntaxTree, previousFileVersion: number): TypeScript.SyntaxTree { + var editRange = this._hostCache.getScriptTextChangeRangeSinceVersion(filename, previousFileVersion); + + // Debug.assert(newLength >= 0); + + // The host considers the entire buffer changed. So parse a completely new tree. + if (editRange === null) { + return this.createSyntaxTree(filename, scriptSnapshot); + } + + var nextSyntaxTree = IncrementalParser.parse( + previousSyntaxTree, editRange, SimpleText.fromScriptSnapshot(scriptSnapshot)); + + this.ensureInvariants(filename, editRange, nextSyntaxTree, this._currentFileScriptSnapshot, scriptSnapshot); + + return nextSyntaxTree; + } + + private ensureInvariants(filename: string, editRange: TypeScript.TextChangeRange, incrementalTree: TypeScript.SyntaxTree, oldScriptSnapshot: TypeScript.IScriptSnapshot, newScriptSnapshot: TypeScript.IScriptSnapshot) { + // First, verify that the edit range and the script snapshots make sense. + + // If this fires, then the edit range is completely bogus. Somehow the lengths of the + // old snapshot, the change range and the new snapshot aren't in sync. This is very + // bad. + var expectedNewLength = oldScriptSnapshot.getLength() - editRange.span().length() + editRange.newLength(); + var actualNewLength = newScriptSnapshot.getLength(); + + function provideMoreDebugInfo() { + + var debugInformation = ["expected length:", expectedNewLength, "and actual length:", actualNewLength, "are not equal\r\n"]; + + var oldSpan = editRange.span(); + + function prettyPrintString(s: string): string { + return '"' + s.replace(/\r/g, '\\r').replace(/\n/g, '\\n') + '"'; + } + + debugInformation.push('Edit range (old text) (start: ' + oldSpan.start() + ', end: ' + oldSpan.end() + ') \r\n'); + debugInformation.push('Old text edit range contents: ' + prettyPrintString(oldScriptSnapshot.getText(oldSpan.start(), oldSpan.end()))); + + var newSpan = editRange.newSpan(); + + debugInformation.push('Edit range (new text) (start: ' + newSpan.start() + ', end: ' + newSpan.end() + ') \r\n'); + debugInformation.push('New text edit range contents: ' + prettyPrintString(newScriptSnapshot.getText(newSpan.start(), newSpan.end()))); + + return debugInformation.join(' '); + } + + Debug.assert( + expectedNewLength === actualNewLength, + "Expected length is different from actual!", + provideMoreDebugInfo); + + if (Debug.shouldAssert(AssertionLevel.VeryAggressive)) { + // If this fires, the text change range is bogus. It says the change starts at point + // 'X', but we can see a text difference *before* that point. + var oldPrefixText = oldScriptSnapshot.getText(0, editRange.span().start()); + var newPrefixText = newScriptSnapshot.getText(0, editRange.span().start()); + Debug.assert(oldPrefixText === newPrefixText, 'Expected equal prefix texts!'); + + // If this fires, the text change range is bogus. It says the change goes only up to + // point 'X', but we can see a text difference *after* that point. + var oldSuffixText = oldScriptSnapshot.getText(editRange.span().end(), oldScriptSnapshot.getLength()); + var newSuffixText = newScriptSnapshot.getText(editRange.newSpan().end(), newScriptSnapshot.getLength()); + Debug.assert(oldSuffixText === newSuffixText, 'Expected equal suffix texts!'); + + // Ok, text change range and script snapshots look ok. Let's verify that our + // incremental parsing worked properly. + //var normalTree = this.createSyntaxTree(filename, newScriptSnapshot); + //Debug.assert(normalTree.structuralEquals(incrementalTree), 'Expected equal incremental and normal trees'); + + // Ok, the trees looked good. So at least our incremental parser agrees with the + // normal parser. Now, verify that the incremental tree matches the contents of the + // script snapshot. + var incrementalTreeText = fullText(incrementalTree.sourceUnit()); + var actualSnapshotText = newScriptSnapshot.getText(0, newScriptSnapshot.getLength()); + Debug.assert(incrementalTreeText === actualSnapshotText, 'Expected full texts to be equal'); + } + } + } + + class FormattingOptions { + constructor(public useTabs: boolean, + public spacesPerTab: number, + public indentSpaces: number, + public newLineCharacter: string) { + } + + public static defaultOptions = new FormattingOptions(/*useTabs:*/ false, /*spacesPerTab:*/ 4, /*indentSpaces:*/ 4, /*newLineCharacter*/ "\r\n"); + } + + class DocumentRegistryEntry { + public refCount: number = 0; + public owners: string[] = []; + constructor(public document: Document) { + } + } + + export interface IDocumentRegistry { + acquireDocument( + filename: string, + compilationSettings: ts.CompilerOptions, + scriptSnapshot: IScriptSnapshot, + byteOrderMark: ByteOrderMark, + version: number, + isOpen: boolean, + referencedFiles: string[]): TypeScript.Document; + + updateDocument( + document: Document, + filename: string, + compilationSettings: ts.CompilerOptions, + scriptSnapshot: IScriptSnapshot, + version: number, + isOpen: boolean, + textChangeRange: TextChangeRange + ): TypeScript.Document; + + releaseDocument(filename: string, compilationSettings: ts.CompilerOptions): void + } + + export class NonCachingDocumentRegistry implements IDocumentRegistry { + + public static Instance: IDocumentRegistry = new NonCachingDocumentRegistry(); + + public acquireDocument( + filename: string, + compilationSettings: ts.CompilerOptions, + scriptSnapshot: IScriptSnapshot, + byteOrderMark: ByteOrderMark, + version: number, + isOpen: boolean, + referencedFiles: string[]= []): TypeScript.Document { + return Document.create(compilationSettings, filename, scriptSnapshot, byteOrderMark, version, isOpen, referencedFiles); + } + + public updateDocument( + document: Document, + filename: string, + compilationSettings: ts.CompilerOptions, + scriptSnapshot: IScriptSnapshot, + version: number, + isOpen: boolean, + textChangeRange: TextChangeRange + ): TypeScript.Document { + return document.update(scriptSnapshot, version, isOpen, textChangeRange); + } + + public releaseDocument(filename: string, compilationSettings: ts.CompilerOptions): void { + // no op since this class doesn't cache anything + } + } + + export class DocumentRegistry implements IDocumentRegistry { + private buckets: IIndexable> = {}; + + private getKeyFromCompilationSettings(settings: ts.CompilerOptions): string { + return "_" + ts.ScriptTarget[settings.target]; // + "|" + settings.propagateEnumConstants.toString() + } + + private getBucketForCompilationSettings(settings: ts.CompilerOptions, createIfMissing: boolean): StringHashTable { + var key = this.getKeyFromCompilationSettings(settings); + var bucket = this.buckets[key]; + if (!bucket && createIfMissing) { + this.buckets[key] = bucket = new StringHashTable(); + } + return bucket; + } + + public reportStats() { + var bucketInfoArray = Object.keys(this.buckets).filter(name => name && name.charAt(0) === '_').map(name => { + var entries = this.buckets[name]; + var documents = entries.getAllKeys().map((name) => { + var entry = entries.lookup(name); + return { + name: name, + refCount: entry.refCount, + references: entry.owners.slice(0) + }; + }); + documents.sort((x, y) => y.refCount - x.refCount); + return { bucket: name, documents: documents } + }); + return JSON.stringify(bucketInfoArray, null, 2); + } + + public acquireDocument( + filename: string, + compilationSettings: ts.CompilerOptions, + scriptSnapshot: IScriptSnapshot, + byteOrderMark: ByteOrderMark, + version: number, + isOpen: boolean, + referencedFiles: string[]= []): TypeScript.Document { + + var bucket = this.getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ true); + var entry = bucket.lookup(filename); + if (!entry) { + var document = Document.create(compilationSettings, filename, scriptSnapshot, byteOrderMark, version, isOpen, referencedFiles); + + entry = new DocumentRegistryEntry(document); + bucket.add(filename, entry); + } + entry.refCount++; + + return entry.document; + } + + public updateDocument( + document: Document, + filename: string, + compilationSettings: ts.CompilerOptions, + scriptSnapshot: IScriptSnapshot, + version: number, + isOpen: boolean, + textChangeRange: TextChangeRange + ): TypeScript.Document { + + var bucket = this.getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ false); + Debug.assert(bucket); + var entry = bucket.lookup(filename); + Debug.assert(entry); + + if (entry.document.isOpen === isOpen && entry.document.version === version) { + return entry.document; + } + + entry.document = entry.document.update(scriptSnapshot, version, isOpen, textChangeRange); + return entry.document; + } + + public releaseDocument(filename: string, compilationSettings: ts.CompilerOptions): void { + var bucket = this.getBucketForCompilationSettings(compilationSettings, false); + Debug.assert(bucket); + + var entry = bucket.lookup(filename); + entry.refCount--; + + Debug.assert(entry.refCount >= 0); + if (entry.refCount === 0) { + bucket.remove(filename); + } + } + } + + export class LanguageService implements ILanguageService { + private logger: TypeScript.ILogger; + private _syntaxTreeCache: SyntaxTreeCache; + private formattingRulesProvider: Formatting.RulesProvider; + + // A cache of all the information about the files on the host side. + private hostCache: HostCache = null; + private program: ts.Program; + private typeChecker: ts.TypeChecker; + private useCaseSensitivefilenames = false; + private documentsByName: ts.Map = {}; + private documentRegistry: IDocumentRegistry + private cancellationToken: CancellationToken; + + constructor(public host: ILanguageServiceHost, documentRegistry: IDocumentRegistry) { + this.logger = this.host; + this.cancellationToken = new CancellationToken(this.host.getCancellationToken()); + this.documentRegistry = documentRegistry; + this._syntaxTreeCache = new SyntaxTreeCache(this.host); + + // Check if the localized messages json is set, otherwise query the host for it + if (!TypeScript.LocalizedDiagnosticMessages) { + TypeScript.LocalizedDiagnosticMessages = this.host.getLocalizedDiagnosticMessages(); + } + } + + private createCompilerHost(): ts.CompilerHost { + return { + getSourceFile: (filename, languageVersion) => { + var document = this.documentsByName[filename]; + + Debug.assert(!!document, "document can not be undefined"); + + return document.sourceFile(); + }, + getCancellationToken: () => this.cancellationToken, + getCanonicalFileName: (filename) => this.useCaseSensitivefilenames ? filename : filename.toLowerCase(), + useCaseSensitiveFileNames: () => this.useCaseSensitivefilenames, + // Need something that doesn't depend on sys.ts here + getDefaultLibFilename: (): string => { + throw Error("TOD:: getDefaultLibfilename"); + }, + writeFile: (filename, data) => { + throw Error("TODO: write file"); + }, + getCurrentDirectory: (): string => { + throw Error("TODO: getCurrentDirectory"); + } + }; + } + + private synchronizeHostData(): void { + // Reset the cache at start of every refresh + this.hostCache = new HostCache(this.host); + + var compilationSettings = this.hostCache.compilationSettings(); + + // TODO: check if we need to create a new compiler to start with + // 1. files are identical + // 2. compilation settings are identical + + // Now, remove any files from the compiler that are no longer in the host. + var oldDocumentsByName = this.documentsByName; + this.documentsByName = {}; + + var oldProgram = this.program; + if (oldProgram) { + var oldSettings = this.program.getCompilerOptions(); + var changesInCompilationSettingsAffectSyntax = + oldSettings && compilationSettings && !compareDataObjects(oldSettings, compilationSettings) && settingsChangeAffectsSyntax(oldSettings, compilationSettings); + var oldSourceFiles = this.program.getSourceFiles(); + + for (var i = 0, n = oldSourceFiles.length; i < n; i++) { + this.cancellationToken.throwIfCancellationRequested(); + var filename = oldSourceFiles[i].filename; + if (!this.hostCache.contains(filename) || changesInCompilationSettingsAffectSyntax) { + this.documentRegistry.releaseDocument(filename, oldSettings); + } + } + } + + // Now, for every file the host knows about, either add the file (if the compiler + // doesn't know about it.). Or notify the compiler about any changes (if it does + // know about it.) + var hostfilenames = this.hostCache.getfilenames(); + + for (var i = 0, n = hostfilenames.length; i < n; i++) { + var filename = hostfilenames[i]; + + var version = this.hostCache.getVersion(filename); + var isOpen = this.hostCache.isOpen(filename); + var scriptSnapshot = this.hostCache.getScriptSnapshot(filename); + + var document: Document = oldDocumentsByName[filename]; + if (document) { + // + // If the document is the same, assume no update + // + if (document.version === version && document.isOpen === isOpen) { + continue; + } + + // Only perform incremental parsing on open files that are being edited. If a file was + // open, but is now closed, we want to reparse entirely so we don't have any tokens that + // are holding onto expensive script snapshot instances on the host. Similarly, if a + // file was closed, then we always want to reparse. This is so our tree doesn't keep + // the old buffer alive that represented the file on disk (as the host has moved to a + // new text buffer). + var textChangeRange: TextChangeRange = null; + if (document.isOpen && isOpen) { + textChangeRange = this.hostCache.getScriptTextChangeRangeSinceVersion(filename, document.version); + } + + document = this.documentRegistry.updateDocument(document, filename, compilationSettings, scriptSnapshot, version, isOpen, textChangeRange); + } + else { + document = this.documentRegistry.acquireDocument(filename, compilationSettings, scriptSnapshot, this.hostCache.getByteOrderMark(filename), version, isOpen, []); + } + + // Remeber the new document + this.documentsByName[filename] = document; + } + + // Now create a new compiler + this.program = ts.createProgram(hostfilenames, compilationSettings, this.createCompilerHost()); + this.typeChecker = this.program.getTypeChecker(); + } + + dispose(): void { + if (this.program) { + ts.forEach(this.program.getSourceFiles(), + (f) => this.documentRegistry.releaseDocument(f.filename, this.program.getCompilerOptions())); + } + } + + refresh() { + // No-op. Only kept around for compatability with the interface we shipped. + } + cleanupSemanticCache() { } + + getSyntacticDiagnostics(filename: string) { + this.synchronizeHostData(); + return this.program.getDiagnostics(this.program.getSourceFile(filename)); + } + getSemanticDiagnostics(filename: string) { + this.synchronizeHostData(); + return this.typeChecker.getDiagnostics(this.program.getSourceFile(filename)); + } + getCompilerOptionsDiagnostics() { + this.synchronizeHostData(); + return this.program.getGlobalDiagnostics(); + } + getCompletionsAtPosition(filename: string, position: number, isMemberCompletion: boolean) { + return undefined; + } + getCompletionEntryDetails(filename: string, position: number, entryName: string) { + return undefined; + } + getTypeAtPosition(filename: string, position: number) { + return undefined; + } + getSignatureAtPosition(filename: string, position: number) { + return undefined; + } + getDefinitionAtPosition(filename: string, position: number) { + return []; + } + getReferencesAtPosition(filename: string, position: number) { + return []; + } + getOccurrencesAtPosition(filename: string, position: number) { + return []; + } + getImplementorsAtPosition(filename: string, position: number) { + return []; + } + getNavigateToItems(searchValue: string) { + return []; + } + getEmitOutput(filename: string) { + return undefined; + } + + + private getTypeInfoEligiblePath(filename: string, position: number, isConstructorValidPosition: boolean) { + var sourceUnit = this._syntaxTreeCache.getCurrentFileSyntaxTree(filename).sourceUnit(); + + var ast = TypeScript.ASTHelpers.getAstAtPosition(sourceUnit, position, /*useTrailingTriviaAsLimChar*/ false, /*forceInclusive*/ true); + if (ast === null) { + return null; + } + + if (ast.kind() === SyntaxKind.ParameterList && ast.parent.kind() === SyntaxKind.CallSignature && ast.parent.parent.kind() === SyntaxKind.ConstructorDeclaration) { + ast = ast.parent.parent; + } + + switch (ast.kind()) { + default: + return null; + case TypeScript.SyntaxKind.ConstructorDeclaration: + var constructorAST = ast; + if (!isConstructorValidPosition || !(position >= start(constructorAST) && position <= start(constructorAST) + "constructor".length)) { + return null; + } + else { + return ast; + } + case TypeScript.SyntaxKind.FunctionDeclaration: + return null; + case TypeScript.SyntaxKind.MemberAccessExpression: + case TypeScript.SyntaxKind.QualifiedName: + case TypeScript.SyntaxKind.SuperKeyword: + case TypeScript.SyntaxKind.StringLiteral: + case TypeScript.SyntaxKind.ThisKeyword: + case TypeScript.SyntaxKind.IdentifierName: + return ast; + } + } + getNameOrDottedNameSpan(filename: string, startPos: number, endPos: number) { + filename = TypeScript.switchToForwardSlashes(filename); + + var node = this.getTypeInfoEligiblePath(filename, startPos, false); + if (!node) return null; + + while (node) { + if (TypeScript.ASTHelpers.isNameOfMemberAccessExpression(node) || + TypeScript.ASTHelpers.isRightSideOfQualifiedName(node)) { + node = node.parent; + } + else { + break; + } + } + + var spanInfo = new SpanInfo(start(node), end(node)); + return spanInfo; + } + getBreakpointStatementAtPosition(filename: string, position: number) { + // doesn't use compiler - no need to synchronize with host + filename = TypeScript.switchToForwardSlashes(filename); + + var syntaxtree = this.getSyntaxTree(filename); + return TypeScript.Services.Breakpoints.getBreakpointLocation(syntaxtree, position); + } + getScriptLexicalStructure(filename: string) { + filename = TypeScript.switchToForwardSlashes(filename); + var syntaxTree = this.getSyntaxTree(filename); + var items: NavigateToItem[] = []; + GetScriptLexicalStructureWalker.getListsOfAllScriptLexicalStructure(items, filename, syntaxTree.sourceUnit()); + return items; + } + getOutliningRegions(filename: string) { + // doesn't use compiler - no need to synchronize with host + filename = TypeScript.switchToForwardSlashes(filename); + var syntaxTree = this.getSyntaxTree(filename); + return OutliningElementsCollector.collectElements(syntaxTree.sourceUnit()); + } + getBraceMatchingAtPosition(filename: string, position: number) { + filename = TypeScript.switchToForwardSlashes(filename); + var syntaxTree = this.getSyntaxTree(filename); + return BraceMatcher.getMatchSpans(syntaxTree, position); + } + getIndentationAtPosition(filename: string, position: number, editorOptions: EditorOptions) { + filename = TypeScript.switchToForwardSlashes(filename); + + var syntaxTree = this.getSyntaxTree(filename); + + var scriptSnapshot = this._syntaxTreeCache.getCurrentScriptSnapshot(filename); + var scriptText = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot); + var textSnapshot = new TypeScript.Services.Formatting.TextSnapshot(scriptText); + var options = new FormattingOptions(!editorOptions.ConvertTabsToSpaces, editorOptions.TabSize, editorOptions.IndentSize, editorOptions.NewLineCharacter) + + return TypeScript.Services.Formatting.SingleTokenIndenter.getIndentationAmount(position, syntaxTree.sourceUnit(), textSnapshot, options); + } + getFormattingEditsForRange(filename: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[] { + filename = TypeScript.switchToForwardSlashes(filename); + + var manager = this.getFormattingManager(filename, options); + return manager.formatSelection(minChar, limChar); + } + getFormattingEditsForDocument(filename: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[] { + filename = TypeScript.switchToForwardSlashes(filename); + + var manager = this.getFormattingManager(filename, options); + return manager.formatDocument(minChar, limChar); + } + getFormattingEditsOnPaste(filename: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[] { + filename = TypeScript.switchToForwardSlashes(filename); + + var manager = this.getFormattingManager(filename, options); + return manager.formatOnPaste(minChar, limChar); + } + getFormattingEditsAfterKeystroke(filename: string, position: number, key: string, options: FormatCodeOptions): TextEdit[] { + filename = TypeScript.switchToForwardSlashes(filename); + + var manager = this.getFormattingManager(filename, options); + if (key === "}") return manager.formatOnClosingCurlyBrace(position); + else if (key === ";") return manager.formatOnSemicolon(position); + else if (key === "\n") return manager.formatOnEnter(position); + else return []; + } + private getFormattingManager(filename: string, options: FormatCodeOptions) { + // Ensure rules are initialized and up to date wrt to formatting options + if (this.formattingRulesProvider == null) { + this.formattingRulesProvider = new TypeScript.Services.Formatting.RulesProvider(this.logger); + } + + this.formattingRulesProvider.ensureUpToDate(options); + + // Get the Syntax Tree + var syntaxTree = this.getSyntaxTree(filename); + + // Convert IScriptSnapshot to ITextSnapshot + var scriptSnapshot = this._syntaxTreeCache.getCurrentScriptSnapshot(filename); + var scriptText = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot); + var textSnapshot = new TypeScript.Services.Formatting.TextSnapshot(scriptText); + + var manager = new TypeScript.Services.Formatting.FormattingManager(syntaxTree, textSnapshot, this.formattingRulesProvider, options); + + return manager; + } + getSyntaxTree(filename: string): TypeScript.SyntaxTree { + filename = TypeScript.switchToForwardSlashes(filename); + return this._syntaxTreeCache.getCurrentFileSyntaxTree(filename); + } + } +} \ No newline at end of file diff --git a/src/services/references.ts b/src/services/references.ts new file mode 100644 index 00000000000..f1f4245c122 --- /dev/null +++ b/src/services/references.ts @@ -0,0 +1,26 @@ +///// +///// + +//// document.ts depends on incrementalParser.ts being run first. +///// +///// + +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// +///// \ No newline at end of file diff --git a/src/services/resources/diagnosticCode.generated.ts b/src/services/resources/diagnosticCode.generated.ts new file mode 100644 index 00000000000..26df20b428d --- /dev/null +++ b/src/services/resources/diagnosticCode.generated.ts @@ -0,0 +1,445 @@ +// +module TypeScript { + export var DiagnosticCode = { + error_TS_0_1: "error TS{0}: {1}", + warning_TS_0_1: "warning TS{0}: {1}", + Unrecognized_escape_sequence: "Unrecognized escape sequence.", + Unexpected_character_0: "Unexpected character {0}.", + Missing_close_quote_character: "Missing close quote character.", + Identifier_expected: "Identifier expected.", + _0_keyword_expected: "'{0}' keyword expected.", + _0_expected: "'{0}' expected.", + Identifier_expected_0_is_a_keyword: "Identifier expected; '{0}' is a keyword.", + Automatic_semicolon_insertion_not_allowed: "Automatic semicolon insertion not allowed.", + Unexpected_token_0_expected: "Unexpected token; '{0}' expected.", + Trailing_comma_not_allowed: "Trailing comma not allowed.", + AsteriskSlash_expected: "'*/' expected.", + public_or_private_modifier_must_precede_static: "'public' or 'private' modifier must precede 'static'.", + Unexpected_token: "Unexpected token.", + Catch_clause_parameter_cannot_have_a_type_annotation: "Catch clause parameter cannot have a type annotation.", + A_rest_parameter_must_be_last_in_a_parameter_list: "A rest parameter must be last in a parameter list.", + Parameter_cannot_have_question_mark_and_initializer: "Parameter cannot have question mark and initializer.", + A_required_parameter_cannot_follow_an_optional_parameter: "A required parameter cannot follow an optional parameter.", + Index_signatures_cannot_have_rest_parameters: "Index signatures cannot have rest parameters.", + Index_signature_parameter_cannot_have_accessibility_modifiers: "Index signature parameter cannot have accessibility modifiers.", + Index_signature_parameter_cannot_have_a_question_mark: "Index signature parameter cannot have a question mark.", + Index_signature_parameter_cannot_have_an_initializer: "Index signature parameter cannot have an initializer.", + Index_signature_must_have_a_type_annotation: "Index signature must have a type annotation.", + Index_signature_parameter_must_have_a_type_annotation: "Index signature parameter must have a type annotation.", + Index_signature_parameter_type_must_be_string_or_number: "Index signature parameter type must be 'string' or 'number'.", + extends_clause_already_seen: "'extends' clause already seen.", + extends_clause_must_precede_implements_clause: "'extends' clause must precede 'implements' clause.", + Classes_can_only_extend_a_single_class: "Classes can only extend a single class.", + implements_clause_already_seen: "'implements' clause already seen.", + Accessibility_modifier_already_seen: "Accessibility modifier already seen.", + _0_modifier_must_precede_1_modifier: "'{0}' modifier must precede '{1}' modifier.", + _0_modifier_already_seen: "'{0}' modifier already seen.", + _0_modifier_cannot_appear_on_a_class_element: "'{0}' modifier cannot appear on a class element.", + Interface_declaration_cannot_have_implements_clause: "Interface declaration cannot have 'implements' clause.", + super_invocation_cannot_have_type_arguments: "'super' invocation cannot have type arguments.", + Only_ambient_modules_can_use_quoted_names: "Only ambient modules can use quoted names.", + Statements_are_not_allowed_in_ambient_contexts: "Statements are not allowed in ambient contexts.", + A_function_implementation_cannot_be_declared_in_an_ambient_context: "A function implementation cannot be declared in an ambient context.", + A_declare_modifier_cannot_be_used_in_an_already_ambient_context: "A 'declare' modifier cannot be used in an already ambient context.", + Initializers_are_not_allowed_in_ambient_contexts: "Initializers are not allowed in ambient contexts.", + _0_modifier_cannot_appear_on_a_module_element: "'{0}' modifier cannot appear on a module element.", + A_declare_modifier_cannot_be_used_with_an_interface_declaration: "A 'declare' modifier cannot be used with an interface declaration.", + A_declare_modifier_is_required_for_a_top_level_declaration_in_a_d_ts_file: "A 'declare' modifier is required for a top level declaration in a .d.ts file.", + A_rest_parameter_cannot_be_optional: "A rest parameter cannot be optional.", + A_rest_parameter_cannot_have_an_initializer: "A rest parameter cannot have an initializer.", + set_accessor_must_have_exactly_one_parameter: "'set' accessor must have exactly one parameter.", + set_accessor_parameter_cannot_be_optional: "'set' accessor parameter cannot be optional.", + set_accessor_parameter_cannot_have_an_initializer: "'set' accessor parameter cannot have an initializer.", + set_accessor_cannot_have_rest_parameter: "'set' accessor cannot have rest parameter.", + get_accessor_cannot_have_parameters: "'get' accessor cannot have parameters.", + Modifiers_cannot_appear_here: "Modifiers cannot appear here.", + Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher: "Accessors are only available when targeting ECMAScript 5 and higher.", + Enum_member_must_have_initializer: "Enum member must have initializer.", + Export_assignment_cannot_be_used_in_internal_modules: "Export assignment cannot be used in internal modules.", + Ambient_enum_elements_can_only_have_integer_literal_initializers: "Ambient enum elements can only have integer literal initializers.", + module_class_interface_enum_import_or_statement: "module, class, interface, enum, import or statement", + constructor_function_accessor_or_variable: "constructor, function, accessor or variable", + statement: "statement", + case_or_default_clause: "case or default clause", + identifier: "identifier", + call_construct_index_property_or_function_signature: "call, construct, index, property or function signature", + expression: "expression", + type_name: "type name", + property_or_accessor: "property or accessor", + parameter: "parameter", + type: "type", + type_parameter: "type parameter", + A_declare_modifier_cannot_be_used_with_an_import_declaration: "A 'declare' modifier cannot be used with an import declaration.", + Invalid_reference_directive_syntax: "Invalid 'reference' directive syntax.", + Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher: "Octal literals are not available when targeting ECMAScript 5 and higher.", + Accessors_are_not_allowed_in_ambient_contexts: "Accessors are not allowed in ambient contexts.", + _0_modifier_cannot_appear_on_a_constructor_declaration: "'{0}' modifier cannot appear on a constructor declaration.", + _0_modifier_cannot_appear_on_a_parameter: "'{0}' modifier cannot appear on a parameter.", + Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement: "Only a single variable declaration is allowed in a 'for...in' statement.", + Type_parameters_cannot_appear_on_a_constructor_declaration: "Type parameters cannot appear on a constructor declaration.", + Type_annotation_cannot_appear_on_a_constructor_declaration: "Type annotation cannot appear on a constructor declaration.", + Type_parameters_cannot_appear_on_an_accessor: "Type parameters cannot appear on an accessor.", + Type_annotation_cannot_appear_on_a_set_accessor: "Type annotation cannot appear on a 'set' accessor.", + Index_signature_must_have_exactly_one_parameter: "Index signature must have exactly one parameter.", + _0_list_cannot_be_empty: "'{0}' list cannot be empty.", + variable_declaration: "variable declaration", + type_argument: "type argument", + Invalid_use_of_0_in_strict_mode: "Invalid use of '{0}' in strict mode.", + with_statements_are_not_allowed_in_strict_mode: "'with' statements are not allowed in strict mode.", + delete_cannot_be_called_on_an_identifier_in_strict_mode: "'delete' cannot be called on an identifier in strict mode.", + Invalid_left_hand_side_in_for_in_statement: "Invalid left-hand side in 'for...in' statement.", + continue_statement_can_only_be_used_within_an_enclosing_iteration_statement: "'continue' statement can only be used within an enclosing iteration statement.", + break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement: "'break' statement can only be used within an enclosing iteration or switch statement.", + Jump_target_not_found: "Jump target not found.", + Jump_target_cannot_cross_function_boundary: "Jump target cannot cross function boundary.", + return_statement_must_be_contained_within_a_function_body: "'return' statement must be contained within a function body.", + Expression_expected: "Expression expected.", + Type_expected: "Type expected.", + Duplicate_identifier_0: "Duplicate identifier '{0}'.", + The_name_0_does_not_exist_in_the_current_scope: "The name '{0}' does not exist in the current scope.", + The_name_0_does_not_refer_to_a_value: "The name '{0}' does not refer to a value.", + super_can_only_be_used_inside_a_class_instance_method: "'super' can only be used inside a class instance method.", + The_left_hand_side_of_an_assignment_expression_must_be_a_variable_property_or_indexer: "The left-hand side of an assignment expression must be a variable, property or indexer.", + Value_of_type_0_is_not_callable_Did_you_mean_to_include_new: "Value of type '{0}' is not callable. Did you mean to include 'new'?", + Value_of_type_0_is_not_callable: "Value of type '{0}' is not callable.", + Value_of_type_0_is_not_newable: "Value of type '{0}' is not newable.", + An_index_expression_argument_must_be_string_number_or_any: "An index expression argument must be 'string', 'number', or 'any'.", + Operator_0_cannot_be_applied_to_types_1_and_2: "Operator '{0}' cannot be applied to types '{1}' and '{2}'.", + Type_0_is_not_assignable_to_type_1: "Type '{0}' is not assignable to type '{1}'.", + Type_0_is_not_assignable_to_type_1_NL_2: "Type '{0}' is not assignable to type '{1}':{NL}{2}", + Expected_var_class_interface_or_module: "Expected var, class, interface, or module.", + Getter_0_already_declared: "Getter '{0}' already declared.", + Setter_0_already_declared: "Setter '{0}' already declared.", + Exported_class_0_extends_private_class_1: "Exported class '{0}' extends private class '{1}'.", + Exported_class_0_implements_private_interface_1: "Exported class '{0}' implements private interface '{1}'.", + Exported_interface_0_extends_private_interface_1: "Exported interface '{0}' extends private interface '{1}'.", + Exported_class_0_extends_class_from_inaccessible_module_1: "Exported class '{0}' extends class from inaccessible module {1}.", + Exported_class_0_implements_interface_from_inaccessible_module_1: "Exported class '{0}' implements interface from inaccessible module {1}.", + Exported_interface_0_extends_interface_from_inaccessible_module_1: "Exported interface '{0}' extends interface from inaccessible module {1}.", + Public_static_property_0_of_exported_class_has_or_is_using_private_type_1: "Public static property '{0}' of exported class has or is using private type '{1}'.", + Public_property_0_of_exported_class_has_or_is_using_private_type_1: "Public property '{0}' of exported class has or is using private type '{1}'.", + Property_0_of_exported_interface_has_or_is_using_private_type_1: "Property '{0}' of exported interface has or is using private type '{1}'.", + Exported_variable_0_has_or_is_using_private_type_1: "Exported variable '{0}' has or is using private type '{1}'.", + Public_static_property_0_of_exported_class_is_using_inaccessible_module_1: "Public static property '{0}' of exported class is using inaccessible module {1}.", + Public_property_0_of_exported_class_is_using_inaccessible_module_1: "Public property '{0}' of exported class is using inaccessible module {1}.", + Property_0_of_exported_interface_is_using_inaccessible_module_1: "Property '{0}' of exported interface is using inaccessible module {1}.", + Exported_variable_0_is_using_inaccessible_module_1: "Exported variable '{0}' is using inaccessible module {1}.", + Parameter_0_of_constructor_from_exported_class_has_or_is_using_private_type_1: "Parameter '{0}' of constructor from exported class has or is using private type '{1}'.", + Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_private_type_1: "Parameter '{0}' of public static property setter from exported class has or is using private type '{1}'.", + Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_private_type_1: "Parameter '{0}' of public property setter from exported class has or is using private type '{1}'.", + Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_type_1: "Parameter '{0}' of constructor signature from exported interface has or is using private type '{1}'.", + Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_type_1: "Parameter '{0}' of call signature from exported interface has or is using private type '{1}'.", + Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_type_1: "Parameter '{0}' of public static method from exported class has or is using private type '{1}'.", + Parameter_0_of_public_method_from_exported_class_has_or_is_using_private_type_1: "Parameter '{0}' of public method from exported class has or is using private type '{1}'.", + Parameter_0_of_method_from_exported_interface_has_or_is_using_private_type_1: "Parameter '{0}' of method from exported interface has or is using private type '{1}'.", + Parameter_0_of_exported_function_has_or_is_using_private_type_1: "Parameter '{0}' of exported function has or is using private type '{1}'.", + Parameter_0_of_constructor_from_exported_class_is_using_inaccessible_module_1: "Parameter '{0}' of constructor from exported class is using inaccessible module {1}.", + Parameter_0_of_public_static_property_setter_from_exported_class_is_using_inaccessible_module_1: "Parameter '{0}' of public static property setter from exported class is using inaccessible module {1}.", + Parameter_0_of_public_property_setter_from_exported_class_is_using_inaccessible_module_1: "Parameter '{0}' of public property setter from exported class is using inaccessible module {1}.", + Parameter_0_of_constructor_signature_from_exported_interface_is_using_inaccessible_module_1: "Parameter '{0}' of constructor signature from exported interface is using inaccessible module {1}.", + Parameter_0_of_call_signature_from_exported_interface_is_using_inaccessible_module_1: "Parameter '{0}' of call signature from exported interface is using inaccessible module {1}", + Parameter_0_of_public_static_method_from_exported_class_is_using_inaccessible_module_1: "Parameter '{0}' of public static method from exported class is using inaccessible module {1}.", + Parameter_0_of_public_method_from_exported_class_is_using_inaccessible_module_1: "Parameter '{0}' of public method from exported class is using inaccessible module {1}.", + Parameter_0_of_method_from_exported_interface_is_using_inaccessible_module_1: "Parameter '{0}' of method from exported interface is using inaccessible module {1}.", + Parameter_0_of_exported_function_is_using_inaccessible_module_1: "Parameter '{0}' of exported function is using inaccessible module {1}.", + Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_private_type_0: "Return type of public static property getter from exported class has or is using private type '{0}'.", + Return_type_of_public_property_getter_from_exported_class_has_or_is_using_private_type_0: "Return type of public property getter from exported class has or is using private type '{0}'.", + Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_private_type_0: "Return type of constructor signature from exported interface has or is using private type '{0}'.", + Return_type_of_call_signature_from_exported_interface_has_or_is_using_private_type_0: "Return type of call signature from exported interface has or is using private type '{0}'.", + Return_type_of_index_signature_from_exported_interface_has_or_is_using_private_type_0: "Return type of index signature from exported interface has or is using private type '{0}'.", + Return_type_of_public_static_method_from_exported_class_has_or_is_using_private_type_0: "Return type of public static method from exported class has or is using private type '{0}'.", + Return_type_of_public_method_from_exported_class_has_or_is_using_private_type_0: "Return type of public method from exported class has or is using private type '{0}'.", + Return_type_of_method_from_exported_interface_has_or_is_using_private_type_0: "Return type of method from exported interface has or is using private type '{0}'.", + Return_type_of_exported_function_has_or_is_using_private_type_0: "Return type of exported function has or is using private type '{0}'.", + Return_type_of_public_static_property_getter_from_exported_class_is_using_inaccessible_module_0: "Return type of public static property getter from exported class is using inaccessible module {0}.", + Return_type_of_public_property_getter_from_exported_class_is_using_inaccessible_module_0: "Return type of public property getter from exported class is using inaccessible module {0}.", + Return_type_of_constructor_signature_from_exported_interface_is_using_inaccessible_module_0: "Return type of constructor signature from exported interface is using inaccessible module {0}.", + Return_type_of_call_signature_from_exported_interface_is_using_inaccessible_module_0: "Return type of call signature from exported interface is using inaccessible module {0}.", + Return_type_of_index_signature_from_exported_interface_is_using_inaccessible_module_0: "Return type of index signature from exported interface is using inaccessible module {0}.", + Return_type_of_public_static_method_from_exported_class_is_using_inaccessible_module_0: "Return type of public static method from exported class is using inaccessible module {0}.", + Return_type_of_public_method_from_exported_class_is_using_inaccessible_module_0: "Return type of public method from exported class is using inaccessible module {0}.", + Return_type_of_method_from_exported_interface_is_using_inaccessible_module_0: "Return type of method from exported interface is using inaccessible module {0}.", + Return_type_of_exported_function_is_using_inaccessible_module_0: "Return type of exported function is using inaccessible module {0}.", + new_T_cannot_be_used_to_create_an_array_Use_new_Array_T_instead: "'new T[]' cannot be used to create an array. Use 'new Array()' instead.", + A_parameter_list_must_follow_a_generic_type_argument_list_expected: "A parameter list must follow a generic type argument list. '(' expected.", + Multiple_constructor_implementations_are_not_allowed: "Multiple constructor implementations are not allowed.", + Cannot_find_external_module_0: "Cannot find external module '{0}'.", + Module_cannot_be_aliased_to_a_non_module_type: "Module cannot be aliased to a non-module type.", + A_class_may_only_extend_another_class: "A class may only extend another class.", + A_class_may_only_implement_another_class_or_interface: "A class may only implement another class or interface.", + An_interface_may_only_extend_a_class_or_another_interface: "An interface may only extend a class or another interface.", + Unable_to_resolve_type: "Unable to resolve type.", + Unable_to_resolve_type_of_0: "Unable to resolve type of '{0}'.", + Unable_to_resolve_type_parameter_constraint: "Unable to resolve type parameter constraint.", + Type_parameter_constraint_cannot_be_a_primitive_type: "Type parameter constraint cannot be a primitive type.", + Supplied_parameters_do_not_match_any_signature_of_call_target: "Supplied parameters do not match any signature of call target.", + Supplied_parameters_do_not_match_any_signature_of_call_target_NL_0: "Supplied parameters do not match any signature of call target:{NL}{0}", + Cannot_use_new_with_an_expression_whose_type_lacks_a_signature: "Cannot use 'new' with an expression whose type lacks a signature.", + Only_a_void_function_can_be_called_with_the_new_keyword: "Only a void function can be called with the 'new' keyword.", + Could_not_select_overload_for_new_expression: "Could not select overload for 'new' expression.", + Type_0_does_not_satisfy_the_constraint_1: "Type '{0}' does not satisfy the constraint '{1}'.", + Could_not_select_overload_for_call_expression: "Could not select overload for 'call' expression.", + Cannot_invoke_an_expression_whose_type_lacks_a_call_signature: "Cannot invoke an expression whose type lacks a call signature.", + Calls_to_super_are_only_valid_inside_a_class: "Calls to 'super' are only valid inside a class.", + Generic_type_0_requires_1_type_argument_s: "Generic type '{0}' requires {1} type argument(s).", + Type_of_array_literal_cannot_be_determined_Best_common_type_could_not_be_found_for_array_elements: "Type of array literal cannot be determined. Best common type could not be found for array elements.", + Could_not_find_enclosing_symbol_for_dotted_name_0: "Could not find enclosing symbol for dotted name '{0}'.", + Property_0_does_not_exist_on_value_of_type_1: "Property '{0}' does not exist on value of type '{1}'.", + Cannot_find_name_0: "Cannot find name '{0}'.", + get_and_set_accessor_must_have_the_same_type: "'get' and 'set' accessor must have the same type.", + this_cannot_be_referenced_in_current_location: "'this' cannot be referenced in current location.", + Static_members_cannot_reference_class_type_parameters: "Static members cannot reference class type parameters.", + Type_0_recursively_references_itself_as_a_base_type: "Type '{0}' recursively references itself as a base type.", + super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class: "'super' property access is permitted only in a constructor, member function, or member accessor of a derived class.", + super_can_only_be_referenced_in_a_derived_class: "'super' can only be referenced in a derived class.", + A_super_call_must_be_the_first_statement_in_the_constructor_when_a_class_contains_initialized_properties_or_has_parameter_properties: "A 'super' call must be the first statement in the constructor when a class contains initialized properties or has parameter properties.", + Constructors_for_derived_classes_must_contain_a_super_call: "Constructors for derived classes must contain a 'super' call.", + Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors: "Super calls are not permitted outside constructors or in nested functions inside constructors.", + _0_1_is_inaccessible: "'{0}.{1}' is inaccessible.", + this_cannot_be_referenced_in_a_module_body: "'this' cannot be referenced in a module body.", + Invalid_expression_types_not_known_to_support_the_addition_operator: "Invalid '+' expression - types not known to support the addition operator.", + The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type: "The right-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.", + The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type: "The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.", + An_arithmetic_operand_must_be_of_type_any_number_or_an_enum_type: "An arithmetic operand must be of type 'any', 'number' or an enum type.", + Variable_declarations_of_a_for_statement_cannot_use_a_type_annotation: "Variable declarations of a 'for' statement cannot use a type annotation.", + Variable_declarations_of_a_for_statement_must_be_of_types_string_or_any: "Variable declarations of a 'for' statement must be of types 'string' or 'any'.", + The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter: "The right-hand side of a 'for...in' statement must be of type 'any', an object type or a type parameter.", + The_left_hand_side_of_an_in_expression_must_be_of_types_any_string_or_number: "The left-hand side of an 'in' expression must be of types 'any', 'string' or 'number'.", + The_right_hand_side_of_an_in_expression_must_be_of_type_any_an_object_type_or_a_type_parameter: "The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter.", + The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter: "The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter.", + The_right_hand_side_of_an_instanceof_expression_must_be_of_type_any_or_of_a_type_assignable_to_the_Function_interface_type: "The right-hand side of an 'instanceof' expression must be of type 'any' or of a type assignable to the 'Function' interface type.", + Setters_cannot_return_a_value: "Setters cannot return a value.", + Tried_to_query_type_of_uninitialized_module_0: "Tried to query type of uninitialized module '{0}'.", + Tried_to_set_variable_type_to_uninitialized_module_type_0: "Tried to set variable type to uninitialized module type '{0}'.", + Type_0_is_not_generic: "Type '{0}' is not generic.", + Getters_must_return_a_value: "Getters must return a value.", + Getter_and_setter_accessors_do_not_agree_in_visibility: "Getter and setter accessors do not agree in visibility.", + Invalid_left_hand_side_of_assignment_expression: "Invalid left-hand side of assignment expression.", + Function_declared_a_non_void_return_type_but_has_no_return_expression: "Function declared a non-void return type, but has no return expression.", + Cannot_resolve_return_type_reference: "Cannot resolve return type reference.", + Constructors_cannot_have_a_return_type_of_void: "Constructors cannot have a return type of 'void'.", + Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2: "Subsequent variable declarations must have the same type. Variable '{0}' must be of type '{1}', but here has type '{2}'.", + All_symbols_within_a_with_block_will_be_resolved_to_any: "All symbols within a with block will be resolved to 'any'.", + Import_declarations_in_an_internal_module_cannot_reference_an_external_module: "Import declarations in an internal module cannot reference an external module.", + Class_0_declares_interface_1_but_does_not_implement_it_NL_2: "Class {0} declares interface {1} but does not implement it:{NL}{2}", + Class_0_declares_class_1_as_an_interface_but_does_not_implement_it_NL_2: "Class {0} declares class {1} as an interface but does not implement it:{NL}{2}", + The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_property_or_indexer: "The operand of an increment or decrement operator must be a variable, property or indexer.", + this_cannot_be_referenced_in_a_static_property_initializer: "'this' cannot be referenced in a static property initializer.", + Class_0_cannot_extend_class_1_NL_2: "Class '{0}' cannot extend class '{1}':{NL}{2}", + Interface_0_cannot_extend_class_1_NL_2: "Interface '{0}' cannot extend class '{1}':{NL}{2}", + Interface_0_cannot_extend_interface_1_NL_2: "Interface '{0}' cannot extend interface '{1}':{NL}{2}", + Overload_signature_is_not_compatible_with_function_definition: "Overload signature is not compatible with function definition.", + Overload_signature_is_not_compatible_with_function_definition_NL_0: "Overload signature is not compatible with function definition:{NL}{0}", + Overload_signatures_must_all_be_public_or_private: "Overload signatures must all be public or private.", + Overload_signatures_must_all_be_exported_or_not_exported: "Overload signatures must all be exported or not exported.", + Overload_signatures_must_all_be_ambient_or_non_ambient: "Overload signatures must all be ambient or non-ambient.", + Overload_signatures_must_all_be_optional_or_required: "Overload signatures must all be optional or required.", + Specialized_overload_signature_is_not_assignable_to_any_non_specialized_signature: "Specialized overload signature is not assignable to any non-specialized signature.", + this_cannot_be_referenced_in_constructor_arguments: "'this' cannot be referenced in constructor arguments.", + Instance_member_cannot_be_accessed_off_a_class: "Instance member cannot be accessed off a class.", + Untyped_function_calls_may_not_accept_type_arguments: "Untyped function calls may not accept type arguments.", + Non_generic_functions_may_not_accept_type_arguments: "Non-generic functions may not accept type arguments.", + A_generic_type_may_not_reference_itself_with_a_wrapped_form_of_its_own_type_parameters: "A generic type may not reference itself with a wrapped form of its own type parameters.", + A_rest_parameter_must_be_of_an_array_type: "A rest parameter must be of an array type.", + Overload_signature_implementation_cannot_use_specialized_type: "Overload signature implementation cannot use specialized type.", + Export_assignments_may_only_be_used_at_the_top_level_of_external_modules: "Export assignments may only be used at the top-level of external modules.", + Export_assignments_may_only_be_made_with_variables_functions_classes_interfaces_enums_and_internal_modules: "Export assignments may only be made with variables, functions, classes, interfaces, enums and internal modules.", + Only_public_methods_of_the_base_class_are_accessible_via_the_super_keyword: "Only public methods of the base class are accessible via the 'super' keyword.", + Numeric_indexer_type_0_must_be_assignable_to_string_indexer_type_1: "Numeric indexer type '{0}' must be assignable to string indexer type '{1}'.", + Numeric_indexer_type_0_must_be_assignable_to_string_indexer_type_1_NL_2: "Numeric indexer type '{0}' must be assignable to string indexer type '{1}':{NL}{2}", + All_numerically_named_properties_must_be_assignable_to_numeric_indexer_type_0: "All numerically named properties must be assignable to numeric indexer type '{0}'.", + All_numerically_named_properties_must_be_assignable_to_numeric_indexer_type_0_NL_1: "All numerically named properties must be assignable to numeric indexer type '{0}':{NL}{1}", + All_named_properties_must_be_assignable_to_string_indexer_type_0: "All named properties must be assignable to string indexer type '{0}'.", + All_named_properties_must_be_assignable_to_string_indexer_type_0_NL_1: "All named properties must be assignable to string indexer type '{0}':{NL}{1}", + A_parameter_initializer_is_only_allowed_in_a_function_or_constructor_implementation: "A parameter initializer is only allowed in a function or constructor implementation.", + Function_expression_declared_a_non_void_return_type_but_has_no_return_expression: "Function expression declared a non-void return type, but has no return expression.", + Import_declaration_referencing_identifier_from_internal_module_can_only_be_made_with_variables_functions_classes_interfaces_enums_and_internal_modules: "Import declaration referencing identifier from internal module can only be made with variables, functions, classes, interfaces, enums and internal modules.", + Module_0_has_no_exported_member_1: "Module '{0}' has no exported member '{1}'.", + Unable_to_resolve_module_reference_0: "Unable to resolve module reference '{0}'.", + Could_not_find_module_0_in_module_1: "Could not find module '{0}' in module '{1}'.", + Exported_import_declaration_0_is_assigned_value_with_type_that_has_or_is_using_private_type_1: "Exported import declaration '{0}' is assigned value with type that has or is using private type '{1}'.", + Exported_import_declaration_0_is_assigned_value_with_type_that_is_using_inaccessible_module_1: "Exported import declaration '{0}' is assigned value with type that is using inaccessible module '{1}'.", + Exported_import_declaration_0_is_assigned_type_that_has_or_is_using_private_type_1: "Exported import declaration '{0}' is assigned type that has or is using private type '{1}'.", + Exported_import_declaration_0_is_assigned_type_that_is_using_inaccessible_module_1: "Exported import declaration '{0}' is assigned type that is using inaccessible module '{1}'.", + Exported_import_declaration_0_is_assigned_container_that_is_or_is_using_inaccessible_module_1: "Exported import declaration '{0}' is assigned container that is or is using inaccessible module '{1}'.", + Type_name_0_in_extends_clause_does_not_reference_constructor_function_for_1: "Type name '{0}' in extends clause does not reference constructor function for '{1}'.", + Internal_module_reference_0_in_import_declaration_does_not_reference_module_instance_for_1: "Internal module reference '{0}' in import declaration does not reference module instance for '{1}'.", + Module_0_cannot_merge_with_previous_declaration_of_1_in_a_different_file_2: "Module '{0}' cannot merge with previous declaration of '{1}' in a different file '{2}'.", + Interface_0_cannot_simultaneously_extend_types_1_and_2_NL_3: "Interface '{0}' cannot simultaneously extend types '{1}' and '{2}':{NL}{3}", + Initializer_of_parameter_0_cannot_reference_identifier_1_declared_after_it: "Initializer of parameter '{0}' cannot reference identifier '{1}' declared after it.", + Ambient_external_module_declaration_cannot_be_reopened: "Ambient external module declaration cannot be reopened.", + All_declarations_of_merged_declaration_0_must_be_exported_or_not_exported: "All declarations of merged declaration '{0}' must be exported or not exported.", + super_cannot_be_referenced_in_constructor_arguments: "'super' cannot be referenced in constructor arguments.", + Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class: "Return type of constructor signature must be assignable to the instance type of the class.", + Ambient_external_module_declaration_must_be_defined_in_global_context: "Ambient external module declaration must be defined in global context.", + Ambient_external_module_declaration_cannot_specify_relative_module_name: "Ambient external module declaration cannot specify relative module name.", + Import_declaration_in_an_ambient_external_module_declaration_cannot_reference_external_module_through_relative_external_module_name: "Import declaration in an ambient external module declaration cannot reference external module through relative external module name.", + No_best_common_type_exists_among_return_expressions: "No best common type exists among return expressions.", + Import_declaration_cannot_refer_to_external_module_reference_when_noResolve_option_is_set: "Import declaration cannot refer to external module reference when --noResolve option is set.", + Duplicate_identifier_this_Compiler_uses_variable_declaration_this_to_capture_this_reference: "Duplicate identifier '_this'. Compiler uses variable declaration '_this' to capture 'this' reference.", + Duplicate_identifier_super_Compiler_uses_super_to_capture_base_class_reference: "Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.", + Expression_resolves_to_variable_declaration_this_that_compiler_uses_to_capture_this_reference: "Expression resolves to variable declaration '_this' that compiler uses to capture 'this' reference.", + Expression_resolves_to_super_that_compiler_uses_to_capture_base_class_reference: "Expression resolves to '_super' that compiler uses to capture base class reference.", + TypeParameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_type_1: "TypeParameter '{0}' of constructor signature from exported interface has or is using private type '{1}'.", + TypeParameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_type_1: "TypeParameter '{0}' of call signature from exported interface has or is using private type '{1}'.", + TypeParameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_type_1: "TypeParameter '{0}' of public static method from exported class has or is using private type '{1}'.", + TypeParameter_0_of_public_method_from_exported_class_has_or_is_using_private_type_1: "TypeParameter '{0}' of public method from exported class has or is using private type '{1}'.", + TypeParameter_0_of_method_from_exported_interface_has_or_is_using_private_type_1: "TypeParameter '{0}' of method from exported interface has or is using private type '{1}'.", + TypeParameter_0_of_exported_function_has_or_is_using_private_type_1: "TypeParameter '{0}' of exported function has or is using private type '{1}'.", + TypeParameter_0_of_constructor_signature_from_exported_interface_is_using_inaccessible_module_1: "TypeParameter '{0}' of constructor signature from exported interface is using inaccessible module {1}.", + TypeParameter_0_of_call_signature_from_exported_interface_is_using_inaccessible_module_1: "TypeParameter '{0}' of call signature from exported interface is using inaccessible module {1}", + TypeParameter_0_of_public_static_method_from_exported_class_is_using_inaccessible_module_1: "TypeParameter '{0}' of public static method from exported class is using inaccessible module {1}.", + TypeParameter_0_of_public_method_from_exported_class_is_using_inaccessible_module_1: "TypeParameter '{0}' of public method from exported class is using inaccessible module {1}.", + TypeParameter_0_of_method_from_exported_interface_is_using_inaccessible_module_1: "TypeParameter '{0}' of method from exported interface is using inaccessible module {1}.", + TypeParameter_0_of_exported_function_is_using_inaccessible_module_1: "TypeParameter '{0}' of exported function is using inaccessible module {1}.", + TypeParameter_0_of_exported_class_has_or_is_using_private_type_1: "TypeParameter '{0}' of exported class has or is using private type '{1}'.", + TypeParameter_0_of_exported_interface_has_or_is_using_private_type_1: "TypeParameter '{0}' of exported interface has or is using private type '{1}'.", + TypeParameter_0_of_exported_class_is_using_inaccessible_module_1: "TypeParameter '{0}' of exported class is using inaccessible module {1}.", + TypeParameter_0_of_exported_interface_is_using_inaccessible_module_1: "TypeParameter '{0}' of exported interface is using inaccessible module {1}.", + Duplicate_identifier_i_Compiler_uses_i_to_initialize_rest_parameter: "Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter.", + Duplicate_identifier_arguments_Compiler_uses_arguments_to_initialize_rest_parameters: "Duplicate identifier 'arguments'. Compiler uses 'arguments' to initialize rest parameters.", + No_best_common_type_exists_between_0_and_1: "No best common type exists between '{0}' and '{1}'.", + No_best_common_type_exists_between_0_1_and_2: "No best common type exists between '{0}', '{1}', and '{2}'.", + Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_an_external_module: "Duplicate identifier '{0}'. Compiler reserves name '{1}' in top level scope of an external module.", + Constraint_of_a_type_parameter_cannot_reference_any_type_parameter_from_the_same_type_parameter_list: "Constraint of a type parameter cannot reference any type parameter from the same type parameter list.", + Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor.", + Parameter_0_cannot_be_referenced_in_its_initializer: "Parameter '{0}' cannot be referenced in its initializer.", + Duplicate_string_index_signature: "Duplicate string index signature.", + Duplicate_number_index_signature: "Duplicate number index signature.", + All_declarations_of_an_interface_must_have_identical_type_parameters: "All declarations of an interface must have identical type parameters.", + Expression_resolves_to_variable_declaration_i_that_compiler_uses_to_initialize_rest_parameter: "Expression resolves to variable declaration '_i' that compiler uses to initialize rest parameter.", + Neither_type_0_nor_type_1_is_assignable_to_the_other: "Neither type '{0}' nor type '{1}' is assignable to the other.", + Neither_type_0_nor_type_1_is_assignable_to_the_other_NL_2: "Neither type '{0}' nor type '{1}' is assignable to the other:{NL}{2}", + Duplicate_function_implementation: "Duplicate function implementation.", + Function_implementation_expected: "Function implementation expected.", + Function_overload_name_must_be_0: "Function overload name must be '{0}'.", + Constructor_implementation_expected: "Constructor implementation expected.", + Class_name_cannot_be_0: "Class name cannot be '{0}'.", + Interface_name_cannot_be_0: "Interface name cannot be '{0}'.", + Enum_name_cannot_be_0: "Enum name cannot be '{0}'.", + A_module_cannot_have_multiple_export_assignments: "A module cannot have multiple export assignments.", + Export_assignment_not_allowed_in_module_with_exported_element: "Export assignment not allowed in module with exported element.", + A_parameter_property_is_only_allowed_in_a_constructor_implementation: "A parameter property is only allowed in a constructor implementation.", + Function_overload_must_be_static: "Function overload must be static.", + Function_overload_must_not_be_static: "Function overload must not be static.", + Type_0_is_missing_property_1_from_type_2: "Type '{0}' is missing property '{1}' from type '{2}'.", + Types_of_property_0_of_types_1_and_2_are_incompatible: "Types of property '{0}' of types '{1}' and '{2}' are incompatible.", + Types_of_property_0_of_types_1_and_2_are_incompatible_NL_3: "Types of property '{0}' of types '{1}' and '{2}' are incompatible:{NL}{3}", + Property_0_defined_as_private_in_type_1_is_defined_as_public_in_type_2: "Property '{0}' defined as private in type '{1}' is defined as public in type '{2}'.", + Property_0_defined_as_public_in_type_1_is_defined_as_private_in_type_2: "Property '{0}' defined as public in type '{1}' is defined as private in type '{2}'.", + Types_0_and_1_define_property_2_as_private: "Types '{0}' and '{1}' define property '{2}' as private.", + Call_signatures_of_types_0_and_1_are_incompatible: "Call signatures of types '{0}' and '{1}' are incompatible.", + Call_signatures_of_types_0_and_1_are_incompatible_NL_2: "Call signatures of types '{0}' and '{1}' are incompatible:{NL}{2}", + Type_0_requires_a_call_signature_but_type_1_lacks_one: "Type '{0}' requires a call signature, but type '{1}' lacks one.", + Construct_signatures_of_types_0_and_1_are_incompatible: "Construct signatures of types '{0}' and '{1}' are incompatible.", + Construct_signatures_of_types_0_and_1_are_incompatible_NL_2: "Construct signatures of types '{0}' and '{1}' are incompatible:{NL}{2}", + Type_0_requires_a_construct_signature_but_type_1_lacks_one: "Type '{0}' requires a construct signature, but type '{1}' lacks one.", + Index_signatures_of_types_0_and_1_are_incompatible: "Index signatures of types '{0}' and '{1}' are incompatible.", + Index_signatures_of_types_0_and_1_are_incompatible_NL_2: "Index signatures of types '{0}' and '{1}' are incompatible:{NL}{2}", + Call_signature_expects_0_or_fewer_parameters: "Call signature expects {0} or fewer parameters.", + Could_not_apply_type_0_to_argument_1_which_is_of_type_2: "Could not apply type '{0}' to argument {1} which is of type '{2}'.", + Class_0_defines_instance_member_accessor_1_but_extended_class_2_defines_it_as_instance_member_function: "Class '{0}' defines instance member accessor '{1}', but extended class '{2}' defines it as instance member function.", + Class_0_defines_instance_member_property_1_but_extended_class_2_defines_it_as_instance_member_function: "Class '{0}' defines instance member property '{1}', but extended class '{2}' defines it as instance member function.", + Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_accessor: "Class '{0}' defines instance member function '{1}', but extended class '{2}' defines it as instance member accessor.", + Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_property: "Class '{0}' defines instance member function '{1}', but extended class '{2}' defines it as instance member property.", + Types_of_static_property_0_of_class_1_and_class_2_are_incompatible: "Types of static property '{0}' of class '{1}' and class '{2}' are incompatible.", + Types_of_static_property_0_of_class_1_and_class_2_are_incompatible_NL_3: "Types of static property '{0}' of class '{1}' and class '{2}' are incompatible:{NL}{3}", + Type_reference_cannot_refer_to_container_0: "Type reference cannot refer to container '{0}'.", + Type_reference_must_refer_to_type: "Type reference must refer to type.", + In_enums_with_multiple_declarations_only_one_declaration_can_omit_an_initializer_for_the_first_enum_element: "In enums with multiple declarations only one declaration can omit an initializer for the first enum element.", + _0_overload_s: " (+ {0} overload(s))", + Variable_declaration_cannot_have_the_same_name_as_an_import_declaration: "Variable declaration cannot have the same name as an import declaration.", + Signature_expected_0_type_arguments_got_1_instead: "Signature expected {0} type arguments, got {1} instead.", + Property_0_defined_as_optional_in_type_1_but_is_required_in_type_2: "Property '{0}' defined as optional in type '{1}', but is required in type '{2}'.", + Types_0_and_1_originating_in_infinitely_expanding_type_reference_do_not_refer_to_same_named_type: "Types '{0}' and '{1}' originating in infinitely expanding type reference do not refer to same named type.", + Types_0_and_1_originating_in_infinitely_expanding_type_reference_have_incompatible_type_arguments: "Types '{0}' and '{1}' originating in infinitely expanding type reference have incompatible type arguments.", + Types_0_and_1_originating_in_infinitely_expanding_type_reference_have_incompatible_type_arguments_NL_2: "Types '{0}' and '{1}' originating in infinitely expanding type reference have incompatible type arguments:{NL}{2}", + Named_properties_0_of_types_1_and_2_are_not_identical: "Named properties '{0}' of types '{1}' and '{2}' are not identical.", + Types_of_string_indexer_of_types_0_and_1_are_not_identical: "Types of string indexer of types '{0}' and '{1}' are not identical.", + Types_of_number_indexer_of_types_0_and_1_are_not_identical: "Types of number indexer of types '{0}' and '{1}' are not identical.", + Type_of_number_indexer_in_type_0_is_not_assignable_to_string_indexer_type_in_type_1_NL_2: "Type of number indexer in type '{0}' is not assignable to string indexer type in type '{1}'.{NL}{2}", + Type_of_property_0_in_type_1_is_not_assignable_to_string_indexer_type_in_type_2_NL_3: "Type of property '{0}' in type '{1}' is not assignable to string indexer type in type '{2}'.{NL}{3}", + Type_of_property_0_in_type_1_is_not_assignable_to_number_indexer_type_in_type_2_NL_3: "Type of property '{0}' in type '{1}' is not assignable to number indexer type in type '{2}'.{NL}{3}", + Static_property_0_defined_as_private_in_type_1_is_defined_as_public_in_type_2: "Static property '{0}' defined as private in type '{1}' is defined as public in type '{2}'.", + Static_property_0_defined_as_public_in_type_1_is_defined_as_private_in_type_2: "Static property '{0}' defined as public in type '{1}' is defined as private in type '{2}'.", + Types_0_and_1_define_static_property_2_as_private: "Types '{0}' and '{1}' define static property '{2}' as private.", + Current_host_does_not_support_0_option: "Current host does not support '{0}' option.", + ECMAScript_target_version_0_not_supported_Specify_a_valid_target_version_1_default_or_2: "ECMAScript target version '{0}' not supported. Specify a valid target version: '{1}' (default), or '{2}'", + Argument_for_0_option_must_be_1_or_2: "Argument for '{0}' option must be '{1}' or '{2}'", + Could_not_find_file_0: "Could not find file: '{0}'.", + A_file_cannot_have_a_reference_to_itself: "A file cannot have a reference to itself.", + Cannot_resolve_referenced_file_0: "Cannot resolve referenced file: '{0}'.", + Cannot_find_the_common_subdirectory_path_for_the_input_files: "Cannot find the common subdirectory path for the input files.", + Emit_Error_0: "Emit Error: {0}.", + Cannot_read_file_0_1: "Cannot read file '{0}': {1}", + Unsupported_file_encoding: "Unsupported file encoding.", + Locale_must_be_of_the_form_language_or_language_territory_For_example_0_or_1: "Locale must be of the form or -. For example '{0}' or '{1}'.", + Unsupported_locale_0: "Unsupported locale: '{0}'.", + Execution_Failed_NL: "Execution Failed.{NL}", + Invalid_call_to_up: "Invalid call to 'up'", + Invalid_call_to_down: "Invalid call to 'down'", + Base64_value_0_finished_with_a_continuation_bit: "Base64 value '{0}' finished with a continuation bit.", + Unknown_compiler_option_0: "Unknown compiler option '{0}'", + Expected_0_arguments_to_message_got_1_instead: "Expected {0} arguments to message, got {1} instead.", + Expected_the_message_0_to_have_1_arguments_but_it_had_2: "Expected the message '{0}' to have {1} arguments, but it had {2}", + Could_not_delete_file_0: "Could not delete file '{0}'", + Could_not_create_directory_0: "Could not create directory '{0}'", + Error_while_executing_file_0: "Error while executing file '{0}': ", + Cannot_compile_external_modules_unless_the_module_flag_is_provided: "Cannot compile external modules unless the '--module' flag is provided.", + Option_mapRoot_cannot_be_specified_without_specifying_sourcemap_option: "Option mapRoot cannot be specified without specifying sourcemap option.", + Option_sourceRoot_cannot_be_specified_without_specifying_sourcemap_option: "Option sourceRoot cannot be specified without specifying sourcemap option.", + Options_mapRoot_and_sourceRoot_cannot_be_specified_without_specifying_sourcemap_option: "Options mapRoot and sourceRoot cannot be specified without specifying sourcemap option.", + Option_0_specified_without_1: "Option '{0}' specified without '{1}'", + codepage_option_not_supported_on_current_platform: "'codepage' option not supported on current platform.", + Concatenate_and_emit_output_to_single_file: "Concatenate and emit output to single file.", + Generates_corresponding_0_file: "Generates corresponding {0} file.", + Specifies_the_location_where_debugger_should_locate_map_files_instead_of_generated_locations: "Specifies the location where debugger should locate map files instead of generated locations.", + Specifies_the_location_where_debugger_should_locate_TypeScript_files_instead_of_source_locations: "Specifies the location where debugger should locate TypeScript files instead of source locations.", + Watch_input_files: "Watch input files.", + Redirect_output_structure_to_the_directory: "Redirect output structure to the directory.", + Do_not_emit_comments_to_output: "Do not emit comments to output.", + Skip_resolution_and_preprocessing: "Skip resolution and preprocessing.", + Specify_ECMAScript_target_version_0_default_or_1: "Specify ECMAScript target version: '{0}' (default), or '{1}'", + Specify_module_code_generation_0_or_1: "Specify module code generation: '{0}' or '{1}'", + Print_this_message: "Print this message.", + Print_the_compiler_s_version_0: "Print the compiler's version: {0}", + Allow_use_of_deprecated_0_keyword_when_referencing_an_external_module: "Allow use of deprecated '{0}' keyword when referencing an external module.", + Specify_locale_for_errors_and_messages_For_example_0_or_1: "Specify locale for errors and messages. For example '{0}' or '{1}'", + Syntax_0: "Syntax: {0}", + options: "options", + file1: "file", + Examples: "Examples:", + Options: "Options:", + Insert_command_line_options_and_files_from_a_file: "Insert command line options and files from a file.", + Version_0: "Version {0}", + Use_the_0_flag_to_see_options: "Use the '{0}' flag to see options.", + NL_Recompiling_0: "{NL}Recompiling ({0}):", + STRING: "STRING", + KIND: "KIND", + file2: "FILE", + VERSION: "VERSION", + LOCATION: "LOCATION", + DIRECTORY: "DIRECTORY", + NUMBER: "NUMBER", + Specify_the_codepage_to_use_when_opening_source_files: "Specify the codepage to use when opening source files.", + Additional_locations: "Additional locations:", + This_version_of_the_Javascript_runtime_does_not_support_the_0_function: "This version of the Javascript runtime does not support the '{0}' function.", + Unknown_rule: "Unknown rule.", + Invalid_line_number_0: "Invalid line number ({0})", + Warn_on_expressions_and_declarations_with_an_implied_any_type: "Warn on expressions and declarations with an implied 'any' type.", + Variable_0_implicitly_has_an_any_type: "Variable '{0}' implicitly has an 'any' type.", + Parameter_0_of_1_implicitly_has_an_any_type: "Parameter '{0}' of '{1}' implicitly has an 'any' type.", + Parameter_0_of_function_type_implicitly_has_an_any_type: "Parameter '{0}' of function type implicitly has an 'any' type.", + Member_0_of_object_type_implicitly_has_an_any_type: "Member '{0}' of object type implicitly has an 'any' type.", + new_expression_which_lacks_a_constructor_signature_implicitly_has_an_any_type: "'new' expression, which lacks a constructor signature, implicitly has an 'any' type.", + _0_which_lacks_return_type_annotation_implicitly_has_an_any_return_type: "'{0}', which lacks return-type annotation, implicitly has an 'any' return type.", + Function_expression_which_lacks_return_type_annotation_implicitly_has_an_any_return_type: "Function expression, which lacks return-type annotation, implicitly has an 'any' return type.", + Parameter_0_of_lambda_function_implicitly_has_an_any_type: "Parameter '{0}' of lambda function implicitly has an 'any' type.", + Constructor_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type: "Constructor signature, which lacks return-type annotation, implicitly has an 'any' return type.", + Lambda_Function_which_lacks_return_type_annotation_implicitly_has_an_any_return_type: "Lambda Function, which lacks return-type annotation, implicitly has an 'any' return type.", + Array_Literal_implicitly_has_an_any_type_from_widening: "Array Literal implicitly has an 'any' type from widening.", + _0_which_lacks_get_accessor_and_parameter_type_annotation_on_set_accessor_implicitly_has_an_any_type: "'{0}', which lacks 'get' accessor and parameter type annotation on 'set' accessor, implicitly has an 'any' type.", + Index_signature_of_object_type_implicitly_has_an_any_type: "Index signature of object type implicitly has an 'any' type.", + Object_literal_s_property_0_implicitly_has_an_any_type_from_widening: "Object literal's property '{0}' implicitly has an 'any' type from widening.", + }; +} \ No newline at end of file diff --git a/src/services/resources/diagnosticInformationMap.generated.ts b/src/services/resources/diagnosticInformationMap.generated.ts new file mode 100644 index 00000000000..ed594be6985 --- /dev/null +++ b/src/services/resources/diagnosticInformationMap.generated.ts @@ -0,0 +1,446 @@ +// +/// +module TypeScript { + export var diagnosticInformationMap: IIndexable = { + "error TS{0}: {1}": { "code": 0, "category": DiagnosticCategory.NoPrefix }, + "warning TS{0}: {1}": { "code": 1, "category": DiagnosticCategory.NoPrefix }, + "Unrecognized escape sequence.": { "code": 1000, "category": DiagnosticCategory.Error }, + "Unexpected character {0}.": { "code": 1001, "category": DiagnosticCategory.Error }, + "Missing close quote character.": { "code": 1002, "category": DiagnosticCategory.Error }, + "Identifier expected.": { "code": 1003, "category": DiagnosticCategory.Error }, + "'{0}' keyword expected.": { "code": 1004, "category": DiagnosticCategory.Error }, + "'{0}' expected.": { "code": 1005, "category": DiagnosticCategory.Error }, + "Identifier expected; '{0}' is a keyword.": { "code": 1006, "category": DiagnosticCategory.Error }, + "Automatic semicolon insertion not allowed.": { "code": 1007, "category": DiagnosticCategory.Error }, + "Unexpected token; '{0}' expected.": { "code": 1008, "category": DiagnosticCategory.Error }, + "Trailing comma not allowed.": { "code": 1009, "category": DiagnosticCategory.Error }, + "'*/' expected.": { "code": 1010, "category": DiagnosticCategory.Error }, + "'public' or 'private' modifier must precede 'static'.": { "code": 1011, "category": DiagnosticCategory.Error }, + "Unexpected token.": { "code": 1012, "category": DiagnosticCategory.Error }, + "Catch clause parameter cannot have a type annotation.": { "code": 1013, "category": DiagnosticCategory.Error }, + "A rest parameter must be last in a parameter list.": { "code": 1014, "category": DiagnosticCategory.Error }, + "Parameter cannot have question mark and initializer.": { "code": 1015, "category": DiagnosticCategory.Error }, + "A required parameter cannot follow an optional parameter.": { "code": 1016, "category": DiagnosticCategory.Error }, + "Index signatures cannot have rest parameters.": { "code": 1017, "category": DiagnosticCategory.Error }, + "Index signature parameter cannot have accessibility modifiers.": { "code": 1018, "category": DiagnosticCategory.Error }, + "Index signature parameter cannot have a question mark.": { "code": 1019, "category": DiagnosticCategory.Error }, + "Index signature parameter cannot have an initializer.": { "code": 1020, "category": DiagnosticCategory.Error }, + "Index signature must have a type annotation.": { "code": 1021, "category": DiagnosticCategory.Error }, + "Index signature parameter must have a type annotation.": { "code": 1022, "category": DiagnosticCategory.Error }, + "Index signature parameter type must be 'string' or 'number'.": { "code": 1023, "category": DiagnosticCategory.Error }, + "'extends' clause already seen.": { "code": 1024, "category": DiagnosticCategory.Error }, + "'extends' clause must precede 'implements' clause.": { "code": 1025, "category": DiagnosticCategory.Error }, + "Classes can only extend a single class.": { "code": 1026, "category": DiagnosticCategory.Error }, + "'implements' clause already seen.": { "code": 1027, "category": DiagnosticCategory.Error }, + "Accessibility modifier already seen.": { "code": 1028, "category": DiagnosticCategory.Error }, + "'{0}' modifier must precede '{1}' modifier.": { "code": 1029, "category": DiagnosticCategory.Error }, + "'{0}' modifier already seen.": { "code": 1030, "category": DiagnosticCategory.Error }, + "'{0}' modifier cannot appear on a class element.": { "code": 1031, "category": DiagnosticCategory.Error }, + "Interface declaration cannot have 'implements' clause.": { "code": 1032, "category": DiagnosticCategory.Error }, + "'super' invocation cannot have type arguments.": { "code": 1034, "category": DiagnosticCategory.Error }, + "Only ambient modules can use quoted names.": { "code": 1035, "category": DiagnosticCategory.Error }, + "Statements are not allowed in ambient contexts.": { "code": 1036, "category": DiagnosticCategory.Error }, + "A function implementation cannot be declared in an ambient context.": { "code": 1037, "category": DiagnosticCategory.Error }, + "A 'declare' modifier cannot be used in an already ambient context.": { "code": 1038, "category": DiagnosticCategory.Error }, + "Initializers are not allowed in ambient contexts.": { "code": 1039, "category": DiagnosticCategory.Error }, + "'{0}' modifier cannot appear on a module element.": { "code": 1044, "category": DiagnosticCategory.Error }, + "A 'declare' modifier cannot be used with an interface declaration.": { "code": 1045, "category": DiagnosticCategory.Error }, + "A 'declare' modifier is required for a top level declaration in a .d.ts file.": { "code": 1046, "category": DiagnosticCategory.Error }, + "A rest parameter cannot be optional.": { "code": 1047, "category": DiagnosticCategory.Error }, + "A rest parameter cannot have an initializer.": { "code": 1048, "category": DiagnosticCategory.Error }, + "'set' accessor must have exactly one parameter.": { "code": 1049, "category": DiagnosticCategory.Error }, + "'set' accessor parameter cannot be optional.": { "code": 1051, "category": DiagnosticCategory.Error }, + "'set' accessor parameter cannot have an initializer.": { "code": 1052, "category": DiagnosticCategory.Error }, + "'set' accessor cannot have rest parameter.": { "code": 1053, "category": DiagnosticCategory.Error }, + "'get' accessor cannot have parameters.": { "code": 1054, "category": DiagnosticCategory.Error }, + "Modifiers cannot appear here.": { "code": 1055, "category": DiagnosticCategory.Error }, + "Accessors are only available when targeting ECMAScript 5 and higher.": { "code": 1056, "category": DiagnosticCategory.Error }, + "Enum member must have initializer.": { "code": 1061, "category": DiagnosticCategory.Error }, + "Export assignment cannot be used in internal modules.": { "code": 1063, "category": DiagnosticCategory.Error }, + "Ambient enum elements can only have integer literal initializers.": { "code": 1066, "category": DiagnosticCategory.Error }, + "module, class, interface, enum, import or statement": { "code": 1067, "category": DiagnosticCategory.NoPrefix }, + "constructor, function, accessor or variable": { "code": 1068, "category": DiagnosticCategory.NoPrefix }, + "statement": { "code": 1069, "category": DiagnosticCategory.NoPrefix }, + "case or default clause": { "code": 1070, "category": DiagnosticCategory.NoPrefix }, + "identifier": { "code": 1071, "category": DiagnosticCategory.NoPrefix }, + "call, construct, index, property or function signature": { "code": 1072, "category": DiagnosticCategory.NoPrefix }, + "expression": { "code": 1073, "category": DiagnosticCategory.NoPrefix }, + "type name": { "code": 1074, "category": DiagnosticCategory.NoPrefix }, + "property or accessor": { "code": 1075, "category": DiagnosticCategory.NoPrefix }, + "parameter": { "code": 1076, "category": DiagnosticCategory.NoPrefix }, + "type": { "code": 1077, "category": DiagnosticCategory.NoPrefix }, + "type parameter": { "code": 1078, "category": DiagnosticCategory.NoPrefix }, + "A 'declare' modifier cannot be used with an import declaration.": { "code": 1079, "category": DiagnosticCategory.Error }, + "Invalid 'reference' directive syntax.": { "code": 1084, "category": DiagnosticCategory.Error }, + "Octal literals are not available when targeting ECMAScript 5 and higher.": { "code": 1085, "category": DiagnosticCategory.Error }, + "Accessors are not allowed in ambient contexts.": { "code": 1086, "category": DiagnosticCategory.Error }, + "'{0}' modifier cannot appear on a constructor declaration.": { "code": 1089, "category": DiagnosticCategory.Error }, + "'{0}' modifier cannot appear on a parameter.": { "code": 1090, "category": DiagnosticCategory.Error }, + "Only a single variable declaration is allowed in a 'for...in' statement.": { "code": 1091, "category": DiagnosticCategory.Error }, + "Type parameters cannot appear on a constructor declaration.": { "code": 1092, "category": DiagnosticCategory.Error }, + "Type annotation cannot appear on a constructor declaration.": { "code": 1093, "category": DiagnosticCategory.Error }, + "Type parameters cannot appear on an accessor.": { "code": 1094, "category": DiagnosticCategory.Error }, + "Type annotation cannot appear on a 'set' accessor.": { "code": 1095, "category": DiagnosticCategory.Error }, + "Index signature must have exactly one parameter.": { "code": 1096, "category": DiagnosticCategory.Error }, + "'{0}' list cannot be empty.": { "code": 1097, "category": DiagnosticCategory.Error }, + "variable declaration": { "code": 1098, "category": DiagnosticCategory.NoPrefix }, + "type argument": { "code": 1099, "category": DiagnosticCategory.NoPrefix }, + "Invalid use of '{0}' in strict mode.": { "code": 1100, "category": DiagnosticCategory.Error }, + "'with' statements are not allowed in strict mode.": { "code": 1101, "category": DiagnosticCategory.Error }, + "'delete' cannot be called on an identifier in strict mode.": { "code": 1102, "category": DiagnosticCategory.Error }, + "Invalid left-hand side in 'for...in' statement.": { "code": 1103, "category": DiagnosticCategory.Error }, + "'continue' statement can only be used within an enclosing iteration statement.": { "code": 1104, "category": DiagnosticCategory.Error }, + "'break' statement can only be used within an enclosing iteration or switch statement.": { "code": 1105, "category": DiagnosticCategory.Error }, + "Jump target not found.": { "code": 1106, "category": DiagnosticCategory.Error }, + "Jump target cannot cross function boundary.": { "code": 1107, "category": DiagnosticCategory.Error }, + "'return' statement must be contained within a function body.": { "code": 1108, "category": DiagnosticCategory.Error }, + "Expression expected.": { "code": 1109, "category": DiagnosticCategory.Error }, + "Type expected.": { "code": 1110, "category": DiagnosticCategory.Error }, + "Duplicate identifier '{0}'.": { "code": 2000, "category": DiagnosticCategory.Error }, + "The name '{0}' does not exist in the current scope.": { "code": 2001, "category": DiagnosticCategory.Error }, + "The name '{0}' does not refer to a value.": { "code": 2002, "category": DiagnosticCategory.Error }, + "'super' can only be used inside a class instance method.": { "code": 2003, "category": DiagnosticCategory.Error }, + "The left-hand side of an assignment expression must be a variable, property or indexer.": { "code": 2004, "category": DiagnosticCategory.Error }, + "Value of type '{0}' is not callable. Did you mean to include 'new'?": { "code": 2161, "category": DiagnosticCategory.Error }, + "Value of type '{0}' is not callable.": { "code": 2006, "category": DiagnosticCategory.Error }, + "Value of type '{0}' is not newable.": { "code": 2007, "category": DiagnosticCategory.Error }, + "An index expression argument must be 'string', 'number', or 'any'.": { "code": 2008, "category": DiagnosticCategory.Error }, + "Operator '{0}' cannot be applied to types '{1}' and '{2}'.": { "code": 2009, "category": DiagnosticCategory.Error }, + "Type '{0}' is not assignable to type '{1}'.": { "code": 2011, "category": DiagnosticCategory.Error }, + "Type '{0}' is not assignable to type '{1}':{NL}{2}": { "code": 2012, "category": DiagnosticCategory.Error }, + "Expected var, class, interface, or module.": { "code": 2013, "category": DiagnosticCategory.Error }, + "Getter '{0}' already declared.": { "code": 2015, "category": DiagnosticCategory.Error }, + "Setter '{0}' already declared.": { "code": 2016, "category": DiagnosticCategory.Error }, + "Exported class '{0}' extends private class '{1}'.": { "code": 2018, "category": DiagnosticCategory.Error }, + "Exported class '{0}' implements private interface '{1}'.": { "code": 2019, "category": DiagnosticCategory.Error }, + "Exported interface '{0}' extends private interface '{1}'.": { "code": 2020, "category": DiagnosticCategory.Error }, + "Exported class '{0}' extends class from inaccessible module {1}.": { "code": 2021, "category": DiagnosticCategory.Error }, + "Exported class '{0}' implements interface from inaccessible module {1}.": { "code": 2022, "category": DiagnosticCategory.Error }, + "Exported interface '{0}' extends interface from inaccessible module {1}.": { "code": 2023, "category": DiagnosticCategory.Error }, + "Public static property '{0}' of exported class has or is using private type '{1}'.": { "code": 2024, "category": DiagnosticCategory.Error }, + "Public property '{0}' of exported class has or is using private type '{1}'.": { "code": 2025, "category": DiagnosticCategory.Error }, + "Property '{0}' of exported interface has or is using private type '{1}'.": { "code": 2026, "category": DiagnosticCategory.Error }, + "Exported variable '{0}' has or is using private type '{1}'.": { "code": 2027, "category": DiagnosticCategory.Error }, + "Public static property '{0}' of exported class is using inaccessible module {1}.": { "code": 2028, "category": DiagnosticCategory.Error }, + "Public property '{0}' of exported class is using inaccessible module {1}.": { "code": 2029, "category": DiagnosticCategory.Error }, + "Property '{0}' of exported interface is using inaccessible module {1}.": { "code": 2030, "category": DiagnosticCategory.Error }, + "Exported variable '{0}' is using inaccessible module {1}.": { "code": 2031, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of constructor from exported class has or is using private type '{1}'.": { "code": 2032, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of public static property setter from exported class has or is using private type '{1}'.": { "code": 2033, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of public property setter from exported class has or is using private type '{1}'.": { "code": 2034, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of constructor signature from exported interface has or is using private type '{1}'.": { "code": 2035, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of call signature from exported interface has or is using private type '{1}'.": { "code": 2036, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of public static method from exported class has or is using private type '{1}'.": { "code": 2037, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of public method from exported class has or is using private type '{1}'.": { "code": 2038, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of method from exported interface has or is using private type '{1}'.": { "code": 2039, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of exported function has or is using private type '{1}'.": { "code": 2040, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of constructor from exported class is using inaccessible module {1}.": { "code": 2041, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of public static property setter from exported class is using inaccessible module {1}.": { "code": 2042, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of public property setter from exported class is using inaccessible module {1}.": { "code": 2043, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of constructor signature from exported interface is using inaccessible module {1}.": { "code": 2044, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of call signature from exported interface is using inaccessible module {1}": { "code": 2045, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of public static method from exported class is using inaccessible module {1}.": { "code": 2046, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of public method from exported class is using inaccessible module {1}.": { "code": 2047, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of method from exported interface is using inaccessible module {1}.": { "code": 2048, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of exported function is using inaccessible module {1}.": { "code": 2049, "category": DiagnosticCategory.Error }, + "Return type of public static property getter from exported class has or is using private type '{0}'.": { "code": 2050, "category": DiagnosticCategory.Error }, + "Return type of public property getter from exported class has or is using private type '{0}'.": { "code": 2051, "category": DiagnosticCategory.Error }, + "Return type of constructor signature from exported interface has or is using private type '{0}'.": { "code": 2052, "category": DiagnosticCategory.Error }, + "Return type of call signature from exported interface has or is using private type '{0}'.": { "code": 2053, "category": DiagnosticCategory.Error }, + "Return type of index signature from exported interface has or is using private type '{0}'.": { "code": 2054, "category": DiagnosticCategory.Error }, + "Return type of public static method from exported class has or is using private type '{0}'.": { "code": 2055, "category": DiagnosticCategory.Error }, + "Return type of public method from exported class has or is using private type '{0}'.": { "code": 2056, "category": DiagnosticCategory.Error }, + "Return type of method from exported interface has or is using private type '{0}'.": { "code": 2057, "category": DiagnosticCategory.Error }, + "Return type of exported function has or is using private type '{0}'.": { "code": 2058, "category": DiagnosticCategory.Error }, + "Return type of public static property getter from exported class is using inaccessible module {0}.": { "code": 2059, "category": DiagnosticCategory.Error }, + "Return type of public property getter from exported class is using inaccessible module {0}.": { "code": 2060, "category": DiagnosticCategory.Error }, + "Return type of constructor signature from exported interface is using inaccessible module {0}.": { "code": 2061, "category": DiagnosticCategory.Error }, + "Return type of call signature from exported interface is using inaccessible module {0}.": { "code": 2062, "category": DiagnosticCategory.Error }, + "Return type of index signature from exported interface is using inaccessible module {0}.": { "code": 2063, "category": DiagnosticCategory.Error }, + "Return type of public static method from exported class is using inaccessible module {0}.": { "code": 2064, "category": DiagnosticCategory.Error }, + "Return type of public method from exported class is using inaccessible module {0}.": { "code": 2065, "category": DiagnosticCategory.Error }, + "Return type of method from exported interface is using inaccessible module {0}.": { "code": 2066, "category": DiagnosticCategory.Error }, + "Return type of exported function is using inaccessible module {0}.": { "code": 2067, "category": DiagnosticCategory.Error }, + "'new T[]' cannot be used to create an array. Use 'new Array()' instead.": { "code": 2068, "category": DiagnosticCategory.Error }, + "A parameter list must follow a generic type argument list. '(' expected.": { "code": 2069, "category": DiagnosticCategory.Error }, + "Multiple constructor implementations are not allowed.": { "code": 2070, "category": DiagnosticCategory.Error }, + "Cannot find external module '{0}'.": { "code": 2071, "category": DiagnosticCategory.Error }, + "Module cannot be aliased to a non-module type.": { "code": 2072, "category": DiagnosticCategory.Error }, + "A class may only extend another class.": { "code": 2073, "category": DiagnosticCategory.Error }, + "A class may only implement another class or interface.": { "code": 2074, "category": DiagnosticCategory.Error }, + "An interface may only extend a class or another interface.": { "code": 2075, "category": DiagnosticCategory.Error }, + "Unable to resolve type.": { "code": 2077, "category": DiagnosticCategory.Error }, + "Unable to resolve type of '{0}'.": { "code": 2078, "category": DiagnosticCategory.Error }, + "Unable to resolve type parameter constraint.": { "code": 2079, "category": DiagnosticCategory.Error }, + "Type parameter constraint cannot be a primitive type.": { "code": 2080, "category": DiagnosticCategory.Error }, + "Supplied parameters do not match any signature of call target.": { "code": 2081, "category": DiagnosticCategory.Error }, + "Supplied parameters do not match any signature of call target:{NL}{0}": { "code": 2082, "category": DiagnosticCategory.Error }, + "Cannot use 'new' with an expression whose type lacks a signature.": { "code": 2083, "category": DiagnosticCategory.Error }, + "Only a void function can be called with the 'new' keyword.": { "code": 2084, "category": DiagnosticCategory.Error }, + "Could not select overload for 'new' expression.": { "code": 2085, "category": DiagnosticCategory.Error }, + "Type '{0}' does not satisfy the constraint '{1}'.": { "code": 2086, "category": DiagnosticCategory.Error }, + "Could not select overload for 'call' expression.": { "code": 2087, "category": DiagnosticCategory.Error }, + "Cannot invoke an expression whose type lacks a call signature.": { "code": 2088, "category": DiagnosticCategory.Error }, + "Calls to 'super' are only valid inside a class.": { "code": 2089, "category": DiagnosticCategory.Error }, + "Generic type '{0}' requires {1} type argument(s).": { "code": 2090, "category": DiagnosticCategory.Error }, + "Type of array literal cannot be determined. Best common type could not be found for array elements.": { "code": 2092, "category": DiagnosticCategory.Error }, + "Could not find enclosing symbol for dotted name '{0}'.": { "code": 2093, "category": DiagnosticCategory.Error }, + "Property '{0}' does not exist on value of type '{1}'.": { "code": 2094, "category": DiagnosticCategory.Error }, + "Cannot find name '{0}'.": { "code": 2095, "category": DiagnosticCategory.Error }, + "'get' and 'set' accessor must have the same type.": { "code": 2096, "category": DiagnosticCategory.Error }, + "'this' cannot be referenced in current location.": { "code": 2097, "category": DiagnosticCategory.Error }, + "Static members cannot reference class type parameters.": { "code": 2099, "category": DiagnosticCategory.Error }, + "Type '{0}' recursively references itself as a base type.": { "code": 2100, "category": DiagnosticCategory.Error }, + "'super' property access is permitted only in a constructor, member function, or member accessor of a derived class.": { "code": 2102, "category": DiagnosticCategory.Error }, + "'super' can only be referenced in a derived class.": { "code": 2103, "category": DiagnosticCategory.Error }, + "A 'super' call must be the first statement in the constructor when a class contains initialized properties or has parameter properties.": { "code": 2104, "category": DiagnosticCategory.Error }, + "Constructors for derived classes must contain a 'super' call.": { "code": 2105, "category": DiagnosticCategory.Error }, + "Super calls are not permitted outside constructors or in nested functions inside constructors.": { "code": 2106, "category": DiagnosticCategory.Error }, + "'{0}.{1}' is inaccessible.": { "code": 2107, "category": DiagnosticCategory.Error }, + "'this' cannot be referenced in a module body.": { "code": 2108, "category": DiagnosticCategory.Error }, + "Invalid '+' expression - types not known to support the addition operator.": { "code": 2111, "category": DiagnosticCategory.Error }, + "The right-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.": { "code": 2112, "category": DiagnosticCategory.Error }, + "The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.": { "code": 2113, "category": DiagnosticCategory.Error }, + "An arithmetic operand must be of type 'any', 'number' or an enum type.": { "code": 2114, "category": DiagnosticCategory.Error }, + "Variable declarations of a 'for' statement cannot use a type annotation.": { "code": 2115, "category": DiagnosticCategory.Error }, + "Variable declarations of a 'for' statement must be of types 'string' or 'any'.": { "code": 2116, "category": DiagnosticCategory.Error }, + "The right-hand side of a 'for...in' statement must be of type 'any', an object type or a type parameter.": { "code": 2117, "category": DiagnosticCategory.Error }, + "The left-hand side of an 'in' expression must be of types 'any', 'string' or 'number'.": { "code": 2118, "category": DiagnosticCategory.Error }, + "The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter.": { "code": 2119, "category": DiagnosticCategory.Error }, + "The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter.": { "code": 2120, "category": DiagnosticCategory.Error }, + "The right-hand side of an 'instanceof' expression must be of type 'any' or of a type assignable to the 'Function' interface type.": { "code": 2121, "category": DiagnosticCategory.Error }, + "Setters cannot return a value.": { "code": 2122, "category": DiagnosticCategory.Error }, + "Tried to query type of uninitialized module '{0}'.": { "code": 2123, "category": DiagnosticCategory.Error }, + "Tried to set variable type to uninitialized module type '{0}'.": { "code": 2124, "category": DiagnosticCategory.Error }, + "Type '{0}' is not generic.": { "code": 2125, "category": DiagnosticCategory.Error }, + "Getters must return a value.": { "code": 2126, "category": DiagnosticCategory.Error }, + "Getter and setter accessors do not agree in visibility.": { "code": 2127, "category": DiagnosticCategory.Error }, + "Invalid left-hand side of assignment expression.": { "code": 2130, "category": DiagnosticCategory.Error }, + "Function declared a non-void return type, but has no return expression.": { "code": 2131, "category": DiagnosticCategory.Error }, + "Cannot resolve return type reference.": { "code": 2132, "category": DiagnosticCategory.Error }, + "Constructors cannot have a return type of 'void'.": { "code": 2133, "category": DiagnosticCategory.Error }, + "Subsequent variable declarations must have the same type. Variable '{0}' must be of type '{1}', but here has type '{2}'.": { "code": 2134, "category": DiagnosticCategory.Error }, + "All symbols within a with block will be resolved to 'any'.": { "code": 2135, "category": DiagnosticCategory.Error }, + "Import declarations in an internal module cannot reference an external module.": { "code": 2136, "category": DiagnosticCategory.Error }, + "Class {0} declares interface {1} but does not implement it:{NL}{2}": { "code": 2137, "category": DiagnosticCategory.Error }, + "Class {0} declares class {1} as an interface but does not implement it:{NL}{2}": { "code": 2138, "category": DiagnosticCategory.Error }, + "The operand of an increment or decrement operator must be a variable, property or indexer.": { "code": 2139, "category": DiagnosticCategory.Error }, + "'this' cannot be referenced in a static property initializer.": { "code": 2140, "category": DiagnosticCategory.Error }, + "Class '{0}' cannot extend class '{1}':{NL}{2}": { "code": 2141, "category": DiagnosticCategory.Error }, + "Interface '{0}' cannot extend class '{1}':{NL}{2}": { "code": 2142, "category": DiagnosticCategory.Error }, + "Interface '{0}' cannot extend interface '{1}':{NL}{2}": { "code": 2143, "category": DiagnosticCategory.Error }, + "Overload signature is not compatible with function definition.": { "code": 2148, "category": DiagnosticCategory.Error }, + "Overload signature is not compatible with function definition:{NL}{0}": { "code": 2149, "category": DiagnosticCategory.Error }, + "Overload signatures must all be public or private.": { "code": 2150, "category": DiagnosticCategory.Error }, + "Overload signatures must all be exported or not exported.": { "code": 2151, "category": DiagnosticCategory.Error }, + "Overload signatures must all be ambient or non-ambient.": { "code": 2152, "category": DiagnosticCategory.Error }, + "Overload signatures must all be optional or required.": { "code": 2153, "category": DiagnosticCategory.Error }, + "Specialized overload signature is not assignable to any non-specialized signature.": { "code": 2154, "category": DiagnosticCategory.Error }, + "'this' cannot be referenced in constructor arguments.": { "code": 2155, "category": DiagnosticCategory.Error }, + "Instance member cannot be accessed off a class.": { "code": 2157, "category": DiagnosticCategory.Error }, + "Untyped function calls may not accept type arguments.": { "code": 2158, "category": DiagnosticCategory.Error }, + "Non-generic functions may not accept type arguments.": { "code": 2159, "category": DiagnosticCategory.Error }, + "A generic type may not reference itself with a wrapped form of its own type parameters.": { "code": 2160, "category": DiagnosticCategory.Error }, + "A rest parameter must be of an array type.": { "code": 2162, "category": DiagnosticCategory.Error }, + "Overload signature implementation cannot use specialized type.": { "code": 2163, "category": DiagnosticCategory.Error }, + "Export assignments may only be used at the top-level of external modules.": { "code": 2164, "category": DiagnosticCategory.Error }, + "Export assignments may only be made with variables, functions, classes, interfaces, enums and internal modules.": { "code": 2165, "category": DiagnosticCategory.Error }, + "Only public methods of the base class are accessible via the 'super' keyword.": { "code": 2166, "category": DiagnosticCategory.Error }, + "Numeric indexer type '{0}' must be assignable to string indexer type '{1}'.": { "code": 2167, "category": DiagnosticCategory.Error }, + "Numeric indexer type '{0}' must be assignable to string indexer type '{1}':{NL}{2}": { "code": 2168, "category": DiagnosticCategory.Error }, + "All numerically named properties must be assignable to numeric indexer type '{0}'.": { "code": 2169, "category": DiagnosticCategory.Error }, + "All numerically named properties must be assignable to numeric indexer type '{0}':{NL}{1}": { "code": 2170, "category": DiagnosticCategory.Error }, + "All named properties must be assignable to string indexer type '{0}'.": { "code": 2171, "category": DiagnosticCategory.Error }, + "All named properties must be assignable to string indexer type '{0}':{NL}{1}": { "code": 2172, "category": DiagnosticCategory.Error }, + "A parameter initializer is only allowed in a function or constructor implementation.": { "code": 2174, "category": DiagnosticCategory.Error }, + "Function expression declared a non-void return type, but has no return expression.": { "code": 2176, "category": DiagnosticCategory.Error }, + "Import declaration referencing identifier from internal module can only be made with variables, functions, classes, interfaces, enums and internal modules.": { "code": 2177, "category": DiagnosticCategory.Error }, + "Module '{0}' has no exported member '{1}'.": { "code": 2178, "category": DiagnosticCategory.Error }, + "Unable to resolve module reference '{0}'.": { "code": 2179, "category": DiagnosticCategory.Error }, + "Could not find module '{0}' in module '{1}'.": { "code": 2180, "category": DiagnosticCategory.Error }, + "Exported import declaration '{0}' is assigned value with type that has or is using private type '{1}'.": { "code": 2181, "category": DiagnosticCategory.Error }, + "Exported import declaration '{0}' is assigned value with type that is using inaccessible module '{1}'.": { "code": 2182, "category": DiagnosticCategory.Error }, + "Exported import declaration '{0}' is assigned type that has or is using private type '{1}'.": { "code": 2183, "category": DiagnosticCategory.Error }, + "Exported import declaration '{0}' is assigned type that is using inaccessible module '{1}'.": { "code": 2184, "category": DiagnosticCategory.Error }, + "Exported import declaration '{0}' is assigned container that is or is using inaccessible module '{1}'.": { "code": 2185, "category": DiagnosticCategory.Error }, + "Type name '{0}' in extends clause does not reference constructor function for '{1}'.": { "code": 2186, "category": DiagnosticCategory.Error }, + "Internal module reference '{0}' in import declaration does not reference module instance for '{1}'.": { "code": 2187, "category": DiagnosticCategory.Error }, + "Module '{0}' cannot merge with previous declaration of '{1}' in a different file '{2}'.": { "code": 2188, "category": DiagnosticCategory.Error }, + "Interface '{0}' cannot simultaneously extend types '{1}' and '{2}':{NL}{3}": { "code": 2189, "category": DiagnosticCategory.Error }, + "Initializer of parameter '{0}' cannot reference identifier '{1}' declared after it.": { "code": 2190, "category": DiagnosticCategory.Error }, + "Ambient external module declaration cannot be reopened.": { "code": 2191, "category": DiagnosticCategory.Error }, + "All declarations of merged declaration '{0}' must be exported or not exported.": { "code": 2192, "category": DiagnosticCategory.Error }, + "'super' cannot be referenced in constructor arguments.": { "code": 2193, "category": DiagnosticCategory.Error }, + "Return type of constructor signature must be assignable to the instance type of the class.": { "code": 2194, "category": DiagnosticCategory.Error }, + "Ambient external module declaration must be defined in global context.": { "code": 2195, "category": DiagnosticCategory.Error }, + "Ambient external module declaration cannot specify relative module name.": { "code": 2196, "category": DiagnosticCategory.Error }, + "Import declaration in an ambient external module declaration cannot reference external module through relative external module name.": { "code": 2197, "category": DiagnosticCategory.Error }, + "No best common type exists among return expressions.": { "code": 2198, "category": DiagnosticCategory.Error }, + "Import declaration cannot refer to external module reference when --noResolve option is set.": { "code": 2199, "category": DiagnosticCategory.Error }, + "Duplicate identifier '_this'. Compiler uses variable declaration '_this' to capture 'this' reference.": { "code": 2200, "category": DiagnosticCategory.Error }, + "Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.": { "code": 2205, "category": DiagnosticCategory.Error }, + "Expression resolves to variable declaration '_this' that compiler uses to capture 'this' reference.": { "code": 2206, "category": DiagnosticCategory.Error }, + "Expression resolves to '_super' that compiler uses to capture base class reference.": { "code": 2207, "category": DiagnosticCategory.Error }, + "TypeParameter '{0}' of constructor signature from exported interface has or is using private type '{1}'.": { "code": 2208, "category": DiagnosticCategory.Error }, + "TypeParameter '{0}' of call signature from exported interface has or is using private type '{1}'.": { "code": 2209, "category": DiagnosticCategory.Error }, + "TypeParameter '{0}' of public static method from exported class has or is using private type '{1}'.": { "code": 2210, "category": DiagnosticCategory.Error }, + "TypeParameter '{0}' of public method from exported class has or is using private type '{1}'.": { "code": 2211, "category": DiagnosticCategory.Error }, + "TypeParameter '{0}' of method from exported interface has or is using private type '{1}'.": { "code": 2212, "category": DiagnosticCategory.Error }, + "TypeParameter '{0}' of exported function has or is using private type '{1}'.": { "code": 2213, "category": DiagnosticCategory.Error }, + "TypeParameter '{0}' of constructor signature from exported interface is using inaccessible module {1}.": { "code": 2214, "category": DiagnosticCategory.Error }, + "TypeParameter '{0}' of call signature from exported interface is using inaccessible module {1}": { "code": 2215, "category": DiagnosticCategory.Error }, + "TypeParameter '{0}' of public static method from exported class is using inaccessible module {1}.": { "code": 2216, "category": DiagnosticCategory.Error }, + "TypeParameter '{0}' of public method from exported class is using inaccessible module {1}.": { "code": 2217, "category": DiagnosticCategory.Error }, + "TypeParameter '{0}' of method from exported interface is using inaccessible module {1}.": { "code": 2218, "category": DiagnosticCategory.Error }, + "TypeParameter '{0}' of exported function is using inaccessible module {1}.": { "code": 2219, "category": DiagnosticCategory.Error }, + "TypeParameter '{0}' of exported class has or is using private type '{1}'.": { "code": 2220, "category": DiagnosticCategory.Error }, + "TypeParameter '{0}' of exported interface has or is using private type '{1}'.": { "code": 2221, "category": DiagnosticCategory.Error }, + "TypeParameter '{0}' of exported class is using inaccessible module {1}.": { "code": 2222, "category": DiagnosticCategory.Error }, + "TypeParameter '{0}' of exported interface is using inaccessible module {1}.": { "code": 2223, "category": DiagnosticCategory.Error }, + "Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter.": { "code": 2224, "category": DiagnosticCategory.Error }, + "Duplicate identifier 'arguments'. Compiler uses 'arguments' to initialize rest parameters.": { "code": 2225, "category": DiagnosticCategory.Error }, + "No best common type exists between '{0}' and '{1}'.": { "code": 2226, "category": DiagnosticCategory.Error }, + "No best common type exists between '{0}', '{1}', and '{2}'.": { "code": 2227, "category": DiagnosticCategory.Error }, + "Duplicate identifier '{0}'. Compiler reserves name '{1}' in top level scope of an external module.": { "code": 2228, "category": DiagnosticCategory.Error }, + "Constraint of a type parameter cannot reference any type parameter from the same type parameter list.": { "code": 2229, "category": DiagnosticCategory.Error }, + "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor.": { "code": 2230, "category": DiagnosticCategory.Error }, + "Parameter '{0}' cannot be referenced in its initializer.": { "code": 2231, "category": DiagnosticCategory.Error }, + "Duplicate string index signature.": { "code": 2232, "category": DiagnosticCategory.Error }, + "Duplicate number index signature.": { "code": 2233, "category": DiagnosticCategory.Error }, + "All declarations of an interface must have identical type parameters.": { "code": 2234, "category": DiagnosticCategory.Error }, + "Expression resolves to variable declaration '_i' that compiler uses to initialize rest parameter.": { "code": 2235, "category": DiagnosticCategory.Error }, + "Neither type '{0}' nor type '{1}' is assignable to the other.": { "code": 2236, "category": DiagnosticCategory.Error }, + "Neither type '{0}' nor type '{1}' is assignable to the other:{NL}{2}": { "code": 2237, "category": DiagnosticCategory.Error }, + "Duplicate function implementation.": { "code": 2237, "category": DiagnosticCategory.Error }, + "Function implementation expected.": { "code": 2238, "category": DiagnosticCategory.Error }, + "Function overload name must be '{0}'.": { "code": 2239, "category": DiagnosticCategory.Error }, + "Constructor implementation expected.": { "code": 2240, "category": DiagnosticCategory.Error }, + "Class name cannot be '{0}'.": { "code": 2241, "category": DiagnosticCategory.Error }, + "Interface name cannot be '{0}'.": { "code": 2242, "category": DiagnosticCategory.Error }, + "Enum name cannot be '{0}'.": { "code": 2243, "category": DiagnosticCategory.Error }, + "A module cannot have multiple export assignments.": { "code": 2244, "category": DiagnosticCategory.Error }, + "Export assignment not allowed in module with exported element.": { "code": 2245, "category": DiagnosticCategory.Error }, + "A parameter property is only allowed in a constructor implementation.": { "code": 2246, "category": DiagnosticCategory.Error }, + "Function overload must be static.": { "code": 2247, "category": DiagnosticCategory.Error }, + "Function overload must not be static.": { "code": 2248, "category": DiagnosticCategory.Error }, + "Type '{0}' is missing property '{1}' from type '{2}'.": { "code": 4000, "category": DiagnosticCategory.NoPrefix }, + "Types of property '{0}' of types '{1}' and '{2}' are incompatible.": { "code": 4001, "category": DiagnosticCategory.NoPrefix }, + "Types of property '{0}' of types '{1}' and '{2}' are incompatible:{NL}{3}": { "code": 4002, "category": DiagnosticCategory.NoPrefix }, + "Property '{0}' defined as private in type '{1}' is defined as public in type '{2}'.": { "code": 4003, "category": DiagnosticCategory.NoPrefix }, + "Property '{0}' defined as public in type '{1}' is defined as private in type '{2}'.": { "code": 4004, "category": DiagnosticCategory.NoPrefix }, + "Types '{0}' and '{1}' define property '{2}' as private.": { "code": 4005, "category": DiagnosticCategory.NoPrefix }, + "Call signatures of types '{0}' and '{1}' are incompatible.": { "code": 4006, "category": DiagnosticCategory.NoPrefix }, + "Call signatures of types '{0}' and '{1}' are incompatible:{NL}{2}": { "code": 4007, "category": DiagnosticCategory.NoPrefix }, + "Type '{0}' requires a call signature, but type '{1}' lacks one.": { "code": 4008, "category": DiagnosticCategory.NoPrefix }, + "Construct signatures of types '{0}' and '{1}' are incompatible.": { "code": 4009, "category": DiagnosticCategory.NoPrefix }, + "Construct signatures of types '{0}' and '{1}' are incompatible:{NL}{2}": { "code": 4010, "category": DiagnosticCategory.NoPrefix }, + "Type '{0}' requires a construct signature, but type '{1}' lacks one.": { "code": 4011, "category": DiagnosticCategory.NoPrefix }, + "Index signatures of types '{0}' and '{1}' are incompatible.": { "code": 4012, "category": DiagnosticCategory.NoPrefix }, + "Index signatures of types '{0}' and '{1}' are incompatible:{NL}{2}": { "code": 4013, "category": DiagnosticCategory.NoPrefix }, + "Call signature expects {0} or fewer parameters.": { "code": 4014, "category": DiagnosticCategory.NoPrefix }, + "Could not apply type '{0}' to argument {1} which is of type '{2}'.": { "code": 4015, "category": DiagnosticCategory.NoPrefix }, + "Class '{0}' defines instance member accessor '{1}', but extended class '{2}' defines it as instance member function.": { "code": 4016, "category": DiagnosticCategory.NoPrefix }, + "Class '{0}' defines instance member property '{1}', but extended class '{2}' defines it as instance member function.": { "code": 4017, "category": DiagnosticCategory.NoPrefix }, + "Class '{0}' defines instance member function '{1}', but extended class '{2}' defines it as instance member accessor.": { "code": 4018, "category": DiagnosticCategory.NoPrefix }, + "Class '{0}' defines instance member function '{1}', but extended class '{2}' defines it as instance member property.": { "code": 4019, "category": DiagnosticCategory.NoPrefix }, + "Types of static property '{0}' of class '{1}' and class '{2}' are incompatible.": { "code": 4020, "category": DiagnosticCategory.NoPrefix }, + "Types of static property '{0}' of class '{1}' and class '{2}' are incompatible:{NL}{3}": { "code": 4021, "category": DiagnosticCategory.NoPrefix }, + "Type reference cannot refer to container '{0}'.": { "code": 4022, "category": DiagnosticCategory.Error }, + "Type reference must refer to type.": { "code": 4023, "category": DiagnosticCategory.Error }, + "In enums with multiple declarations only one declaration can omit an initializer for the first enum element.": { "code": 4024, "category": DiagnosticCategory.Error }, + " (+ {0} overload(s))": { "code": 4025, "category": DiagnosticCategory.Message }, + "Variable declaration cannot have the same name as an import declaration.": { "code": 4026, "category": DiagnosticCategory.Error }, + "Signature expected {0} type arguments, got {1} instead.": { "code": 4027, "category": DiagnosticCategory.Error }, + "Property '{0}' defined as optional in type '{1}', but is required in type '{2}'.": { "code": 4028, "category": DiagnosticCategory.NoPrefix }, + "Types '{0}' and '{1}' originating in infinitely expanding type reference do not refer to same named type.": { "code": 4029, "category": DiagnosticCategory.NoPrefix }, + "Types '{0}' and '{1}' originating in infinitely expanding type reference have incompatible type arguments.": { "code": 4030, "category": DiagnosticCategory.NoPrefix }, + "Types '{0}' and '{1}' originating in infinitely expanding type reference have incompatible type arguments:{NL}{2}": { "code": 4031, "category": DiagnosticCategory.NoPrefix }, + "Named properties '{0}' of types '{1}' and '{2}' are not identical.": { "code": 4032, "category": DiagnosticCategory.NoPrefix }, + "Types of string indexer of types '{0}' and '{1}' are not identical.": { "code": 4033, "category": DiagnosticCategory.NoPrefix }, + "Types of number indexer of types '{0}' and '{1}' are not identical.": { "code": 4034, "category": DiagnosticCategory.NoPrefix }, + "Type of number indexer in type '{0}' is not assignable to string indexer type in type '{1}'.{NL}{2}": { "code": 4035, "category": DiagnosticCategory.NoPrefix }, + "Type of property '{0}' in type '{1}' is not assignable to string indexer type in type '{2}'.{NL}{3}": { "code": 4036, "category": DiagnosticCategory.NoPrefix }, + "Type of property '{0}' in type '{1}' is not assignable to number indexer type in type '{2}'.{NL}{3}": { "code": 4037, "category": DiagnosticCategory.NoPrefix }, + "Static property '{0}' defined as private in type '{1}' is defined as public in type '{2}'.": { "code": 4038, "category": DiagnosticCategory.NoPrefix }, + "Static property '{0}' defined as public in type '{1}' is defined as private in type '{2}'.": { "code": 4039, "category": DiagnosticCategory.NoPrefix }, + "Types '{0}' and '{1}' define static property '{2}' as private.": { "code": 4040, "category": DiagnosticCategory.NoPrefix }, + "Current host does not support '{0}' option.": { "code": 5001, "category": DiagnosticCategory.Error }, + "ECMAScript target version '{0}' not supported. Specify a valid target version: '{1}' (default), or '{2}'": { "code": 5002, "category": DiagnosticCategory.Error }, + "Argument for '{0}' option must be '{1}' or '{2}'": { "code": 5003, "category": DiagnosticCategory.Error }, + "Could not find file: '{0}'.": { "code": 5004, "category": DiagnosticCategory.Error }, + "A file cannot have a reference to itself.": { "code": 5006, "category": DiagnosticCategory.Error }, + "Cannot resolve referenced file: '{0}'.": { "code": 5007, "category": DiagnosticCategory.Error }, + "Cannot find the common subdirectory path for the input files.": { "code": 5009, "category": DiagnosticCategory.Error }, + "Emit Error: {0}.": { "code": 5011, "category": DiagnosticCategory.Error }, + "Cannot read file '{0}': {1}": { "code": 5012, "category": DiagnosticCategory.Error }, + "Unsupported file encoding.": { "code": 5013, "category": DiagnosticCategory.NoPrefix }, + "Locale must be of the form or -. For example '{0}' or '{1}'.": { "code": 5014, "category": DiagnosticCategory.Error }, + "Unsupported locale: '{0}'.": { "code": 5015, "category": DiagnosticCategory.Error }, + "Execution Failed.{NL}": { "code": 5016, "category": DiagnosticCategory.Error }, + "Invalid call to 'up'": { "code": 5019, "category": DiagnosticCategory.Error }, + "Invalid call to 'down'": { "code": 5020, "category": DiagnosticCategory.Error }, + "Base64 value '{0}' finished with a continuation bit.": { "code": 5021, "category": DiagnosticCategory.Error }, + "Unknown compiler option '{0}'": { "code": 5023, "category": DiagnosticCategory.Error }, + "Expected {0} arguments to message, got {1} instead.": { "code": 5024, "category": DiagnosticCategory.Error }, + "Expected the message '{0}' to have {1} arguments, but it had {2}": { "code": 5025, "category": DiagnosticCategory.Error }, + "Could not delete file '{0}'": { "code": 5034, "category": DiagnosticCategory.Error }, + "Could not create directory '{0}'": { "code": 5035, "category": DiagnosticCategory.Error }, + "Error while executing file '{0}': ": { "code": 5036, "category": DiagnosticCategory.Error }, + "Cannot compile external modules unless the '--module' flag is provided.": { "code": 5037, "category": DiagnosticCategory.Error }, + "Option mapRoot cannot be specified without specifying sourcemap option.": { "code": 5038, "category": DiagnosticCategory.Error }, + "Option sourceRoot cannot be specified without specifying sourcemap option.": { "code": 5039, "category": DiagnosticCategory.Error }, + "Options mapRoot and sourceRoot cannot be specified without specifying sourcemap option.": { "code": 5040, "category": DiagnosticCategory.Error }, + "Option '{0}' specified without '{1}'": { "code": 5041, "category": DiagnosticCategory.Error }, + "'codepage' option not supported on current platform.": { "code": 5042, "category": DiagnosticCategory.Error }, + "Concatenate and emit output to single file.": { "code": 6001, "category": DiagnosticCategory.Message }, + "Generates corresponding {0} file.": { "code": 6002, "category": DiagnosticCategory.Message }, + "Specifies the location where debugger should locate map files instead of generated locations.": { "code": 6003, "category": DiagnosticCategory.Message }, + "Specifies the location where debugger should locate TypeScript files instead of source locations.": { "code": 6004, "category": DiagnosticCategory.Message }, + "Watch input files.": { "code": 6005, "category": DiagnosticCategory.Message }, + "Redirect output structure to the directory.": { "code": 6006, "category": DiagnosticCategory.Message }, + "Do not emit comments to output.": { "code": 6009, "category": DiagnosticCategory.Message }, + "Skip resolution and preprocessing.": { "code": 6010, "category": DiagnosticCategory.Message }, + "Specify ECMAScript target version: '{0}' (default), or '{1}'": { "code": 6015, "category": DiagnosticCategory.Message }, + "Specify module code generation: '{0}' or '{1}'": { "code": 6016, "category": DiagnosticCategory.Message }, + "Print this message.": { "code": 6017, "category": DiagnosticCategory.Message }, + "Print the compiler's version: {0}": { "code": 6019, "category": DiagnosticCategory.Message }, + "Allow use of deprecated '{0}' keyword when referencing an external module.": { "code": 6021, "category": DiagnosticCategory.Message }, + "Specify locale for errors and messages. For example '{0}' or '{1}'": { "code": 6022, "category": DiagnosticCategory.Message }, + "Syntax: {0}": { "code": 6023, "category": DiagnosticCategory.Message }, + "options": { "code": 6024, "category": DiagnosticCategory.Message }, + "file1": { "code": 6025, "category": DiagnosticCategory.Message }, + "Examples:": { "code": 6026, "category": DiagnosticCategory.Message }, + "Options:": { "code": 6027, "category": DiagnosticCategory.Message }, + "Insert command line options and files from a file.": { "code": 6030, "category": DiagnosticCategory.Message }, + "Version {0}": { "code": 6029, "category": DiagnosticCategory.Message }, + "Use the '{0}' flag to see options.": { "code": 6031, "category": DiagnosticCategory.Message }, + "{NL}Recompiling ({0}):": { "code": 6032, "category": DiagnosticCategory.Message }, + "STRING": { "code": 6033, "category": DiagnosticCategory.Message }, + "KIND": { "code": 6034, "category": DiagnosticCategory.Message }, + "file2": { "code": 6035, "category": DiagnosticCategory.Message }, + "VERSION": { "code": 6036, "category": DiagnosticCategory.Message }, + "LOCATION": { "code": 6037, "category": DiagnosticCategory.Message }, + "DIRECTORY": { "code": 6038, "category": DiagnosticCategory.Message }, + "NUMBER": { "code": 6039, "category": DiagnosticCategory.Message }, + "Specify the codepage to use when opening source files.": { "code": 6040, "category": DiagnosticCategory.Message }, + "Additional locations:": { "code": 6041, "category": DiagnosticCategory.Message }, + "This version of the Javascript runtime does not support the '{0}' function.": { "code": 7000, "category": DiagnosticCategory.Error }, + "Unknown rule.": { "code": 7002, "category": DiagnosticCategory.Error }, + "Invalid line number ({0})": { "code": 7003, "category": DiagnosticCategory.Error }, + "Warn on expressions and declarations with an implied 'any' type.": { "code": 7004, "category": DiagnosticCategory.Message }, + "Variable '{0}' implicitly has an 'any' type.": { "code": 7005, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of '{1}' implicitly has an 'any' type.": { "code": 7006, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of function type implicitly has an 'any' type.": { "code": 7007, "category": DiagnosticCategory.Error }, + "Member '{0}' of object type implicitly has an 'any' type.": { "code": 7008, "category": DiagnosticCategory.Error }, + "'new' expression, which lacks a constructor signature, implicitly has an 'any' type.": { "code": 7009, "category": DiagnosticCategory.Error }, + "'{0}', which lacks return-type annotation, implicitly has an 'any' return type.": { "code": 7010, "category": DiagnosticCategory.Error }, + "Function expression, which lacks return-type annotation, implicitly has an 'any' return type.": { "code": 7011, "category": DiagnosticCategory.Error }, + "Parameter '{0}' of lambda function implicitly has an 'any' type.": { "code": 7012, "category": DiagnosticCategory.Error }, + "Constructor signature, which lacks return-type annotation, implicitly has an 'any' return type.": { "code": 7013, "category": DiagnosticCategory.Error }, + "Lambda Function, which lacks return-type annotation, implicitly has an 'any' return type.": { "code": 7014, "category": DiagnosticCategory.Error }, + "Array Literal implicitly has an 'any' type from widening.": { "code": 7015, "category": DiagnosticCategory.Error }, + "'{0}', which lacks 'get' accessor and parameter type annotation on 'set' accessor, implicitly has an 'any' type.": { "code": 7016, "category": DiagnosticCategory.Error }, + "Index signature of object type implicitly has an 'any' type.": { "code": 7017, "category": DiagnosticCategory.Error }, + "Object literal's property '{0}' implicitly has an 'any' type from widening.": { "code": 7018, "category": DiagnosticCategory.Error }, + }; +} \ No newline at end of file diff --git a/src/services/resources/diagnosticMessages.json b/src/services/resources/diagnosticMessages.json new file mode 100644 index 00000000000..bbca8b3f9ce --- /dev/null +++ b/src/services/resources/diagnosticMessages.json @@ -0,0 +1,1766 @@ +{ + "error TS{0}: {1}": { + "category": "NoPrefix", + "code": 0 + }, + "warning TS{0}: {1}": { + "category": "NoPrefix", + "code": 1 + }, + "Unrecognized escape sequence.": { + "category": "Error", + "code": 1000 + }, + "Unexpected character {0}.": { + "category": "Error", + "code": 1001 + }, + "Missing close quote character.": { + "category": "Error", + "code": 1002 + }, + "Identifier expected.": { + "category": "Error", + "code": 1003 + }, + "'{0}' keyword expected.": { + "category": "Error", + "code": 1004 + }, + "'{0}' expected.": { + "category": "Error", + "code": 1005 + }, + "Identifier expected; '{0}' is a keyword.": { + "category": "Error", + "code": 1006 + }, + "Automatic semicolon insertion not allowed.": { + "category": "Error", + "code": 1007 + }, + "Unexpected token; '{0}' expected.": { + "category": "Error", + "code": 1008 + }, + "Trailing comma not allowed.": { + "category": "Error", + "code": 1009 + }, + "'*/' expected.": { + "category": "Error", + "code": 1010 + }, + "'public' or 'private' modifier must precede 'static'.": { + "category": "Error", + "code": 1011 + }, + "Unexpected token.": { + "category": "Error", + "code": 1012 + }, + "Catch clause parameter cannot have a type annotation.": { + "category": "Error", + "code": 1013 + }, + "A rest parameter must be last in a parameter list.": { + "category": "Error", + "code": 1014 + }, + "Parameter cannot have question mark and initializer.": { + "category": "Error", + "code": 1015 + }, + "A required parameter cannot follow an optional parameter.": { + "category": "Error", + "code": 1016 + }, + "Index signatures cannot have rest parameters.": { + "category": "Error", + "code": 1017 + }, + "Index signature parameter cannot have accessibility modifiers.": { + "category": "Error", + "code": 1018 + }, + "Index signature parameter cannot have a question mark.": { + "category": "Error", + "code": 1019 + }, + "Index signature parameter cannot have an initializer.": { + "category": "Error", + "code": 1020 + }, + "Index signature must have a type annotation.": { + "category": "Error", + "code": 1021 + }, + "Index signature parameter must have a type annotation.": { + "category": "Error", + "code": 1022 + }, + "Index signature parameter type must be 'string' or 'number'.": { + "category": "Error", + "code": 1023 + }, + "'extends' clause already seen.": { + "category": "Error", + "code": 1024 + }, + "'extends' clause must precede 'implements' clause.": { + "category": "Error", + "code": 1025 + }, + "Classes can only extend a single class.": { + "category": "Error", + "code": 1026 + }, + "'implements' clause already seen.": { + "category": "Error", + "code": 1027 + }, + "Accessibility modifier already seen.": { + "category": "Error", + "code": 1028 + }, + "'{0}' modifier must precede '{1}' modifier.": { + "category": "Error", + "code": 1029 + }, + "'{0}' modifier already seen.": { + "category": "Error", + "code": 1030 + }, + "'{0}' modifier cannot appear on a class element.": { + "category": "Error", + "code": 1031 + }, + "Interface declaration cannot have 'implements' clause.": { + "category": "Error", + "code": 1032 + }, + "'super' invocation cannot have type arguments.": { + "category": "Error", + "code": 1034 + }, + "Only ambient modules can use quoted names.": { + "category": "Error", + "code": 1035 + }, + "Statements are not allowed in ambient contexts.": { + "category": "Error", + "code": 1036 + }, + "A function implementation cannot be declared in an ambient context.": { + "category": "Error", + "code": 1037 + }, + "A 'declare' modifier cannot be used in an already ambient context.": { + "category": "Error", + "code": 1038 + }, + "Initializers are not allowed in ambient contexts.": { + "category": "Error", + "code": 1039 + }, + "'{0}' modifier cannot appear on a module element.": { + "category": "Error", + "code": 1044 + }, + "A 'declare' modifier cannot be used with an interface declaration.": { + "category": "Error", + "code": 1045 + }, + "A 'declare' modifier is required for a top level declaration in a .d.ts file.": { + "category": "Error", + "code": 1046 + }, + "A rest parameter cannot be optional.": { + "category": "Error", + "code": 1047 + }, + "A rest parameter cannot have an initializer.": { + "category": "Error", + "code": 1048 + }, + "'set' accessor must have exactly one parameter.": { + "category": "Error", + "code": 1049 + }, + "'set' accessor parameter cannot be optional.": { + "category": "Error", + "code": 1051 + }, + "'set' accessor parameter cannot have an initializer.": { + "category": "Error", + "code": 1052 + }, + "'set' accessor cannot have rest parameter.": { + "category": "Error", + "code": 1053 + }, + "'get' accessor cannot have parameters.": { + "category": "Error", + "code": 1054 + }, + "Modifiers cannot appear here.": { + "category": "Error", + "code": 1055 + }, + "Accessors are only available when targeting ECMAScript 5 and higher.": { + "category": "Error", + "code": 1056 + }, + "Enum member must have initializer.": { + "category": "Error", + "code": 1061 + }, + "Export assignment cannot be used in internal modules.": { + "category": "Error", + "code": 1063 + }, + "Ambient enum elements can only have integer literal initializers.": { + "category": "Error", + "code": 1066 + }, + "module, class, interface, enum, import or statement": { + "category": "NoPrefix", + "code": 1067 + }, + "constructor, function, accessor or variable": { + "category": "NoPrefix", + "code": 1068 + }, + "statement": { + "category": "NoPrefix", + "code": 1069 + }, + "case or default clause": { + "category": "NoPrefix", + "code": 1070 + }, + "identifier": { + "category": "NoPrefix", + "code": 1071 + }, + "call, construct, index, property or function signature": { + "category": "NoPrefix", + "code": 1072 + }, + "expression": { + "category": "NoPrefix", + "code": 1073 + }, + "type name": { + "category": "NoPrefix", + "code": 1074 + }, + "property or accessor": { + "category": "NoPrefix", + "code": 1075 + }, + "parameter": { + "category": "NoPrefix", + "code": 1076 + }, + "type": { + "category": "NoPrefix", + "code": 1077 + }, + "type parameter": { + "category": "NoPrefix", + "code": 1078 + }, + "A 'declare' modifier cannot be used with an import declaration.": { + "category": "Error", + "code": 1079 + }, + "Invalid 'reference' directive syntax.": { + "category": "Error", + "code": 1084 + }, + "Octal literals are not available when targeting ECMAScript 5 and higher.": { + "category": "Error", + "code": 1085 + }, + "Accessors are not allowed in ambient contexts.": { + "category": "Error", + "code": 1086 + }, + "'{0}' modifier cannot appear on a constructor declaration.": { + "category": "Error", + "code": 1089 + }, + "'{0}' modifier cannot appear on a parameter.": { + "category": "Error", + "code": 1090 + }, + "Only a single variable declaration is allowed in a 'for...in' statement.": { + "category": "Error", + "code": 1091 + }, + "Type parameters cannot appear on a constructor declaration.": { + "category": "Error", + "code": 1092 + }, + "Type annotation cannot appear on a constructor declaration.": { + "category": "Error", + "code": 1093 + }, + "Type parameters cannot appear on an accessor.": { + "category": "Error", + "code": 1094 + }, + "Type annotation cannot appear on a 'set' accessor.": { + "category": "Error", + "code": 1095 + }, + "Index signature must have exactly one parameter.": { + "category": "Error", + "code": 1096 + }, + "'{0}' list cannot be empty.": { + "category": "Error", + "code": 1097 + }, + "variable declaration": { + "category": "NoPrefix", + "code": 1098 + }, + "type argument": { + "category": "NoPrefix", + "code": 1099 + }, + "Invalid use of '{0}' in strict mode.": { + "category": "Error", + "code": 1100 + }, + "'with' statements are not allowed in strict mode.": { + "category": "Error", + "code": 1101 + }, + "'delete' cannot be called on an identifier in strict mode.": { + "category": "Error", + "code": 1102 + }, + "Invalid left-hand side in 'for...in' statement.": { + "category": "Error", + "code": 1103 + }, + "'continue' statement can only be used within an enclosing iteration statement.": { + "category": "Error", + "code": 1104 + }, + "'break' statement can only be used within an enclosing iteration or switch statement.": { + "category": "Error", + "code": 1105 + }, + "Jump target not found.": { + "category": "Error", + "code": 1106 + }, + "Jump target cannot cross function boundary.": { + "category": "Error", + "code": 1107 + }, + "'return' statement must be contained within a function body.": { + "category": "Error", + "code": 1108 + }, + "Expression expected.": { + "category": "Error", + "code": 1109 + }, + "Type expected.": { + "category": "Error", + "code": 1110 + }, + "Duplicate identifier '{0}'.": { + "category": "Error", + "code": 2000 + }, + "The name '{0}' does not exist in the current scope.": { + "category": "Error", + "code": 2001 + }, + "The name '{0}' does not refer to a value.": { + "category": "Error", + "code": 2002 + }, + "'super' can only be used inside a class instance method.": { + "category": "Error", + "code": 2003 + }, + "The left-hand side of an assignment expression must be a variable, property or indexer.": { + "category": "Error", + "code": 2004 + }, + "Value of type '{0}' is not callable. Did you mean to include 'new'?": { + "category": "Error", + "code": 2161 + }, + "Value of type '{0}' is not callable.": { + "category": "Error", + "code": 2006 + }, + "Value of type '{0}' is not newable.": { + "category": "Error", + "code": 2007 + }, + "An index expression argument must be 'string', 'number', or 'any'.": { + "category": "Error", + "code": 2008 + }, + "Operator '{0}' cannot be applied to types '{1}' and '{2}'.": { + "category": "Error", + "code": 2009 + }, + "Type '{0}' is not assignable to type '{1}'.": { + "category": "Error", + "code": 2011 + }, + "Type '{0}' is not assignable to type '{1}':{NL}{2}": { + "category": "Error", + "code": 2012 + }, + "Expected var, class, interface, or module.": { + "category": "Error", + "code": 2013 + }, + "Getter '{0}' already declared.": { + "category": "Error", + "code": 2015 + }, + "Setter '{0}' already declared.": { + "category": "Error", + "code": 2016 + }, + "Exported class '{0}' extends private class '{1}'.": { + "category": "Error", + "code": 2018 + }, + "Exported class '{0}' implements private interface '{1}'.": { + "category": "Error", + "code": 2019 + }, + "Exported interface '{0}' extends private interface '{1}'.": { + "category": "Error", + "code": 2020 + }, + "Exported class '{0}' extends class from inaccessible module {1}.": { + "category": "Error", + "code": 2021 + }, + "Exported class '{0}' implements interface from inaccessible module {1}.": { + "category": "Error", + "code": 2022 + }, + "Exported interface '{0}' extends interface from inaccessible module {1}.": { + "category": "Error", + "code": 2023 + }, + "Public static property '{0}' of exported class has or is using private type '{1}'.": { + "category": "Error", + "code": 2024 + }, + "Public property '{0}' of exported class has or is using private type '{1}'.": { + "category": "Error", + "code": 2025 + }, + "Property '{0}' of exported interface has or is using private type '{1}'.": { + "category": "Error", + "code": 2026 + }, + "Exported variable '{0}' has or is using private type '{1}'.": { + "category": "Error", + "code": 2027 + }, + "Public static property '{0}' of exported class is using inaccessible module {1}.": { + "category": "Error", + "code": 2028 + }, + "Public property '{0}' of exported class is using inaccessible module {1}.": { + "category": "Error", + "code": 2029 + }, + "Property '{0}' of exported interface is using inaccessible module {1}.": { + "category": "Error", + "code": 2030 + }, + "Exported variable '{0}' is using inaccessible module {1}.": { + "category": "Error", + "code": 2031 + }, + "Parameter '{0}' of constructor from exported class has or is using private type '{1}'.": { + "category": "Error", + "code": 2032 + }, + "Parameter '{0}' of public static property setter from exported class has or is using private type '{1}'.": { + "category": "Error", + "code": 2033 + }, + "Parameter '{0}' of public property setter from exported class has or is using private type '{1}'.": { + "category": "Error", + "code": 2034 + }, + "Parameter '{0}' of constructor signature from exported interface has or is using private type '{1}'.": { + "category": "Error", + "code": 2035 + }, + "Parameter '{0}' of call signature from exported interface has or is using private type '{1}'.": { + "category": "Error", + "code": 2036 + }, + "Parameter '{0}' of public static method from exported class has or is using private type '{1}'.": { + "category": "Error", + "code": 2037 + }, + "Parameter '{0}' of public method from exported class has or is using private type '{1}'.": { + "category": "Error", + "code": 2038 + }, + "Parameter '{0}' of method from exported interface has or is using private type '{1}'.": { + "category": "Error", + "code": 2039 + }, + "Parameter '{0}' of exported function has or is using private type '{1}'.": { + "category": "Error", + "code": 2040 + }, + "Parameter '{0}' of constructor from exported class is using inaccessible module {1}.": { + "category": "Error", + "code": 2041 + }, + "Parameter '{0}' of public static property setter from exported class is using inaccessible module {1}.": { + "category": "Error", + "code": 2042 + }, + "Parameter '{0}' of public property setter from exported class is using inaccessible module {1}.": { + "category": "Error", + "code": 2043 + }, + "Parameter '{0}' of constructor signature from exported interface is using inaccessible module {1}.": { + "category": "Error", + "code": 2044 + }, + "Parameter '{0}' of call signature from exported interface is using inaccessible module {1}": { + "category": "Error", + "code": 2045 + }, + "Parameter '{0}' of public static method from exported class is using inaccessible module {1}.": { + "category": "Error", + "code": 2046 + }, + "Parameter '{0}' of public method from exported class is using inaccessible module {1}.": { + "category": "Error", + "code": 2047 + }, + "Parameter '{0}' of method from exported interface is using inaccessible module {1}.": { + "category": "Error", + "code": 2048 + }, + "Parameter '{0}' of exported function is using inaccessible module {1}.": { + "category": "Error", + "code": 2049 + }, + "Return type of public static property getter from exported class has or is using private type '{0}'.": { + "category": "Error", + "code": 2050 + }, + "Return type of public property getter from exported class has or is using private type '{0}'.": { + "category": "Error", + "code": 2051 + }, + "Return type of constructor signature from exported interface has or is using private type '{0}'.": { + "category": "Error", + "code": 2052 + }, + "Return type of call signature from exported interface has or is using private type '{0}'.": { + "category": "Error", + "code": 2053 + }, + "Return type of index signature from exported interface has or is using private type '{0}'.": { + "category": "Error", + "code": 2054 + }, + "Return type of public static method from exported class has or is using private type '{0}'.": { + "category": "Error", + "code": 2055 + }, + "Return type of public method from exported class has or is using private type '{0}'.": { + "category": "Error", + "code": 2056 + }, + "Return type of method from exported interface has or is using private type '{0}'.": { + "category": "Error", + "code": 2057 + }, + "Return type of exported function has or is using private type '{0}'.": { + "category": "Error", + "code": 2058 + }, + "Return type of public static property getter from exported class is using inaccessible module {0}.": { + "category": "Error", + "code": 2059 + }, + "Return type of public property getter from exported class is using inaccessible module {0}.": { + "category": "Error", + "code": 2060 + }, + "Return type of constructor signature from exported interface is using inaccessible module {0}.": { + "category": "Error", + "code": 2061 + }, + "Return type of call signature from exported interface is using inaccessible module {0}.": { + "category": "Error", + "code": 2062 + }, + "Return type of index signature from exported interface is using inaccessible module {0}.": { + "category": "Error", + "code": 2063 + }, + "Return type of public static method from exported class is using inaccessible module {0}.": { + "category": "Error", + "code": 2064 + }, + "Return type of public method from exported class is using inaccessible module {0}.": { + "category": "Error", + "code": 2065 + }, + "Return type of method from exported interface is using inaccessible module {0}.": { + "category": "Error", + "code": 2066 + }, + "Return type of exported function is using inaccessible module {0}.": { + "category": "Error", + "code": 2067 + }, + "'new T[]' cannot be used to create an array. Use 'new Array()' instead.": { + "category": "Error", + "code": 2068 + }, + "A parameter list must follow a generic type argument list. '(' expected.": { + "category": "Error", + "code": 2069 + }, + "Multiple constructor implementations are not allowed.": { + "category": "Error", + "code": 2070 + }, + "Cannot find external module '{0}'.": { + "category": "Error", + "code": 2071 + }, + "Module cannot be aliased to a non-module type.": { + "category": "Error", + "code": 2072 + }, + "A class may only extend another class.": { + "category": "Error", + "code": 2073 + }, + "A class may only implement another class or interface.": { + "category": "Error", + "code": 2074 + }, + "An interface may only extend a class or another interface.": { + "category": "Error", + "code": 2075 + }, + "Unable to resolve type.": { + "category": "Error", + "code": 2077 + }, + "Unable to resolve type of '{0}'.": { + "category": "Error", + "code": 2078 + }, + "Unable to resolve type parameter constraint.": { + "category": "Error", + "code": 2079 + }, + "Type parameter constraint cannot be a primitive type.": { + "category": "Error", + "code": 2080 + }, + "Supplied parameters do not match any signature of call target.": { + "category": "Error", + "code": 2081 + }, + "Supplied parameters do not match any signature of call target:{NL}{0}": { + "category": "Error", + "code": 2082 + }, + "Cannot use 'new' with an expression whose type lacks a signature.": { + "category": "Error", + "code": 2083 + }, + "Only a void function can be called with the 'new' keyword.": { + "category": "Error", + "code": 2084 + }, + "Could not select overload for 'new' expression.": { + "category": "Error", + "code": 2085 + }, + "Type '{0}' does not satisfy the constraint '{1}'.": { + "category": "Error", + "code": 2086 + }, + "Could not select overload for 'call' expression.": { + "category": "Error", + "code": 2087 + }, + "Cannot invoke an expression whose type lacks a call signature.": { + "category": "Error", + "code": 2088 + }, + "Calls to 'super' are only valid inside a class.": { + "category": "Error", + "code": 2089 + }, + "Generic type '{0}' requires {1} type argument(s).": { + "category": "Error", + "code": 2090 + }, + "Type of array literal cannot be determined. Best common type could not be found for array elements.": { + "category": "Error", + "code": 2092 + }, + "Could not find enclosing symbol for dotted name '{0}'.": { + "category": "Error", + "code": 2093 + }, + "Property '{0}' does not exist on value of type '{1}'.": { + "category": "Error", + "code": 2094 + }, + "Cannot find name '{0}'.": { + "category": "Error", + "code": 2095 + }, + "'get' and 'set' accessor must have the same type.": { + "category": "Error", + "code": 2096 + }, + "'this' cannot be referenced in current location.": { + "category": "Error", + "code": 2097 + }, + "Static members cannot reference class type parameters.": { + "category": "Error", + "code": 2099 + }, + "Type '{0}' recursively references itself as a base type.": { + "category": "Error", + "code": 2100 + }, + "'super' property access is permitted only in a constructor, member function, or member accessor of a derived class.": { + "category": "Error", + "code": 2102 + }, + "'super' can only be referenced in a derived class.": { + "category": "Error", + "code": 2103 + }, + "A 'super' call must be the first statement in the constructor when a class contains initialized properties or has parameter properties.": { + "category": "Error", + "code": 2104 + }, + "Constructors for derived classes must contain a 'super' call.": { + "category": "Error", + "code": 2105 + }, + "Super calls are not permitted outside constructors or in nested functions inside constructors.": { + "category": "Error", + "code": 2106 + }, + "'{0}.{1}' is inaccessible.": { + "category": "Error", + "code": 2107 + }, + "'this' cannot be referenced in a module body.": { + "category": "Error", + "code": 2108 + }, + "Invalid '+' expression - types not known to support the addition operator.": { + "category": "Error", + "code": 2111 + }, + "The right-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.": { + "category": "Error", + "code": 2112 + }, + "The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.": { + "category": "Error", + "code": 2113 + }, + "An arithmetic operand must be of type 'any', 'number' or an enum type.": { + "category": "Error", + "code": 2114 + }, + "Variable declarations of a 'for' statement cannot use a type annotation.": { + "category": "Error", + "code": 2115 + }, + "Variable declarations of a 'for' statement must be of types 'string' or 'any'.": { + "category": "Error", + "code": 2116 + }, + "The right-hand side of a 'for...in' statement must be of type 'any', an object type or a type parameter.": { + "category": "Error", + "code": 2117 + }, + "The left-hand side of an 'in' expression must be of types 'any', 'string' or 'number'.": { + "category": "Error", + "code": 2118 + }, + "The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter.": { + "category": "Error", + "code": 2119 + }, + "The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter.": { + "category": "Error", + "code": 2120 + }, + "The right-hand side of an 'instanceof' expression must be of type 'any' or of a type assignable to the 'Function' interface type.": { + "category": "Error", + "code": 2121 + }, + "Setters cannot return a value.": { + "category": "Error", + "code": 2122 + }, + "Tried to query type of uninitialized module '{0}'.": { + "category": "Error", + "code": 2123 + }, + "Tried to set variable type to uninitialized module type '{0}'.": { + "category": "Error", + "code": 2124 + }, + "Type '{0}' is not generic.": { + "category": "Error", + "code": 2125 + }, + "Getters must return a value.": { + "category": "Error", + "code": 2126 + }, + "Getter and setter accessors do not agree in visibility.": { + "category": "Error", + "code": 2127 + }, + "Invalid left-hand side of assignment expression.": { + "category": "Error", + "code": 2130 + }, + "Function declared a non-void return type, but has no return expression.": { + "category": "Error", + "code": 2131 + }, + "Cannot resolve return type reference.": { + "category": "Error", + "code": 2132 + }, + "Constructors cannot have a return type of 'void'.": { + "category": "Error", + "code": 2133 + }, + "Subsequent variable declarations must have the same type. Variable '{0}' must be of type '{1}', but here has type '{2}'.": { + "category": "Error", + "code": 2134 + }, + "All symbols within a with block will be resolved to 'any'.": { + "category": "Error", + "code": 2135 + }, + "Import declarations in an internal module cannot reference an external module.": { + "category": "Error", + "code": 2136 + }, + "Class {0} declares interface {1} but does not implement it:{NL}{2}": { + "category": "Error", + "code": 2137 + }, + "Class {0} declares class {1} as an interface but does not implement it:{NL}{2}": { + "category": "Error", + "code": 2138 + }, + "The operand of an increment or decrement operator must be a variable, property or indexer.": { + "category": "Error", + "code": 2139 + }, + "'this' cannot be referenced in a static property initializer.": { + "category": "Error", + "code": 2140 + }, + "Class '{0}' cannot extend class '{1}':{NL}{2}": { + "category": "Error", + "code": 2141 + }, + "Interface '{0}' cannot extend class '{1}':{NL}{2}": { + "category": "Error", + "code": 2142 + }, + "Interface '{0}' cannot extend interface '{1}':{NL}{2}": { + "category": "Error", + "code": 2143 + }, + "Overload signature is not compatible with function definition.": { + "category": "Error", + "code": 2148 + }, + "Overload signature is not compatible with function definition:{NL}{0}": { + "category": "Error", + "code": 2149 + }, + "Overload signatures must all be public or private.": { + "category": "Error", + "code": 2150 + }, + "Overload signatures must all be exported or not exported.": { + "category": "Error", + "code": 2151 + }, + "Overload signatures must all be ambient or non-ambient.": { + "category": "Error", + "code": 2152 + }, + "Overload signatures must all be optional or required.": { + "category": "Error", + "code": 2153 + }, + "Specialized overload signature is not assignable to any non-specialized signature.": { + "category": "Error", + "code": 2154 + }, + "'this' cannot be referenced in constructor arguments.": { + "category": "Error", + "code": 2155 + }, + "Instance member cannot be accessed off a class.": { + "category": "Error", + "code": 2157 + }, + "Untyped function calls may not accept type arguments.": { + "category": "Error", + "code": 2158 + }, + "Non-generic functions may not accept type arguments.": { + "category": "Error", + "code": 2159 + }, + "A generic type may not reference itself with a wrapped form of its own type parameters.": { + "category": "Error", + "code": 2160 + }, + "A rest parameter must be of an array type.": { + "category": "Error", + "code": 2162 + }, + "Overload signature implementation cannot use specialized type.": { + "category": "Error", + "code": 2163 + }, + "Export assignments may only be used at the top-level of external modules.": { + "category": "Error", + "code": 2164 + }, + "Export assignments may only be made with variables, functions, classes, interfaces, enums and internal modules.": { + "category": "Error", + "code": 2165 + }, + "Only public methods of the base class are accessible via the 'super' keyword.": { + "category": "Error", + "code": 2166 + }, + "Numeric indexer type '{0}' must be assignable to string indexer type '{1}'.": { + "category": "Error", + "code": 2167 + }, + "Numeric indexer type '{0}' must be assignable to string indexer type '{1}':{NL}{2}": { + "category": "Error", + "code": 2168 + }, + "All numerically named properties must be assignable to numeric indexer type '{0}'.": { + "category": "Error", + "code": 2169 + }, + "All numerically named properties must be assignable to numeric indexer type '{0}':{NL}{1}": { + "category": "Error", + "code": 2170 + }, + "All named properties must be assignable to string indexer type '{0}'.": { + "category": "Error", + "code": 2171 + }, + "All named properties must be assignable to string indexer type '{0}':{NL}{1}": { + "category": "Error", + "code": 2172 + }, + "A parameter initializer is only allowed in a function or constructor implementation.": { + "category": "Error", + "code": 2174 + }, + "Function expression declared a non-void return type, but has no return expression.": { + "category": "Error", + "code": 2176 + }, + "Import declaration referencing identifier from internal module can only be made with variables, functions, classes, interfaces, enums and internal modules.": { + "category": "Error", + "code": 2177 + }, + "Module '{0}' has no exported member '{1}'.": { + "category": "Error", + "code": 2178 + }, + "Unable to resolve module reference '{0}'.": { + "category": "Error", + "code": 2179 + }, + "Could not find module '{0}' in module '{1}'.": { + "category": "Error", + "code": 2180 + }, + "Exported import declaration '{0}' is assigned value with type that has or is using private type '{1}'.": { + "category": "Error", + "code": 2181 + }, + "Exported import declaration '{0}' is assigned value with type that is using inaccessible module '{1}'.": { + "category": "Error", + "code": 2182 + }, + "Exported import declaration '{0}' is assigned type that has or is using private type '{1}'.": { + "category": "Error", + "code": 2183 + }, + "Exported import declaration '{0}' is assigned type that is using inaccessible module '{1}'.": { + "category": "Error", + "code": 2184 + }, + "Exported import declaration '{0}' is assigned container that is or is using inaccessible module '{1}'.": { + "category": "Error", + "code": 2185 + }, + "Type name '{0}' in extends clause does not reference constructor function for '{1}'.": { + "category": "Error", + "code": 2186 + }, + "Internal module reference '{0}' in import declaration does not reference module instance for '{1}'.": { + "category": "Error", + "code": 2187 + }, + "Module '{0}' cannot merge with previous declaration of '{1}' in a different file '{2}'.": { + "category": "Error", + "code": 2188 + }, + "Interface '{0}' cannot simultaneously extend types '{1}' and '{2}':{NL}{3}": { + "category": "Error", + "code": 2189 + }, + "Initializer of parameter '{0}' cannot reference identifier '{1}' declared after it.": { + "category": "Error", + "code": 2190 + }, + "Ambient external module declaration cannot be reopened.": { + "category": "Error", + "code": 2191 + }, + "All declarations of merged declaration '{0}' must be exported or not exported.": { + "category": "Error", + "code": 2192 + }, + "'super' cannot be referenced in constructor arguments.": { + "category": "Error", + "code": 2193 + }, + "Return type of constructor signature must be assignable to the instance type of the class.":{ + "category": "Error", + "code": 2194 + }, + "Ambient external module declaration must be defined in global context.": { + "category": "Error", + "code": 2195 + }, + "Ambient external module declaration cannot specify relative module name.": { + "category": "Error", + "code": 2196 + }, + "Import declaration in an ambient external module declaration cannot reference external module through relative external module name.": { + "category": "Error", + "code": 2197 + }, + "No best common type exists among return expressions.": { + "category": "Error", + "code": 2198 + }, + "Import declaration cannot refer to external module reference when --noResolve option is set.": { + "category": "Error", + "code": 2199 + }, + "Duplicate identifier '_this'. Compiler uses variable declaration '_this' to capture 'this' reference.": { + "category": "Error", + "code": 2200 + }, + "Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.": { + "category": "Error", + "code": 2205 + }, + "Expression resolves to variable declaration '_this' that compiler uses to capture 'this' reference.": { + "category": "Error", + "code": 2206 + }, + "Expression resolves to '_super' that compiler uses to capture base class reference.": { + "category": "Error", + "code": 2207 + }, + "TypeParameter '{0}' of constructor signature from exported interface has or is using private type '{1}'.": { + "category": "Error", + "code": 2208 + }, + "TypeParameter '{0}' of call signature from exported interface has or is using private type '{1}'.": { + "category": "Error", + "code": 2209 + }, + "TypeParameter '{0}' of public static method from exported class has or is using private type '{1}'.": { + "category": "Error", + "code": 2210 + }, + "TypeParameter '{0}' of public method from exported class has or is using private type '{1}'.": { + "category": "Error", + "code": 2211 + }, + "TypeParameter '{0}' of method from exported interface has or is using private type '{1}'.": { + "category": "Error", + "code": 2212 + }, + "TypeParameter '{0}' of exported function has or is using private type '{1}'.": { + "category": "Error", + "code": 2213 + }, + "TypeParameter '{0}' of constructor signature from exported interface is using inaccessible module {1}.": { + "category": "Error", + "code": 2214 + }, + "TypeParameter '{0}' of call signature from exported interface is using inaccessible module {1}": { + "category": "Error", + "code": 2215 + }, + "TypeParameter '{0}' of public static method from exported class is using inaccessible module {1}.": { + "category": "Error", + "code": 2216 + }, + "TypeParameter '{0}' of public method from exported class is using inaccessible module {1}.": { + "category": "Error", + "code": 2217 + }, + "TypeParameter '{0}' of method from exported interface is using inaccessible module {1}.": { + "category": "Error", + "code": 2218 + }, + "TypeParameter '{0}' of exported function is using inaccessible module {1}.": { + "category": "Error", + "code": 2219 + }, + "TypeParameter '{0}' of exported class has or is using private type '{1}'.": { + "category": "Error", + "code": 2220 + }, + "TypeParameter '{0}' of exported interface has or is using private type '{1}'.": { + "category": "Error", + "code": 2221 + }, + "TypeParameter '{0}' of exported class is using inaccessible module {1}.": { + "category": "Error", + "code": 2222 + }, + "TypeParameter '{0}' of exported interface is using inaccessible module {1}.": { + "category": "Error", + "code": 2223 + }, + "Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter.": { + "category": "Error", + "code": 2224 + }, + "Duplicate identifier 'arguments'. Compiler uses 'arguments' to initialize rest parameters.": { + "category": "Error", + "code": 2225 + }, + "No best common type exists between '{0}' and '{1}'.": { + "category": "Error", + "code": 2226 + }, + "No best common type exists between '{0}', '{1}', and '{2}'.": { + "category": "Error", + "code": 2227 + }, + "Duplicate identifier '{0}'. Compiler reserves name '{1}' in top level scope of an external module.": { + "category": "Error", + "code": 2228 + }, + "Constraint of a type parameter cannot reference any type parameter from the same type parameter list.": { + "category": "Error", + "code": 2229 + }, + "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor.": { + "category": "Error", + "code": 2230 + }, + "Parameter '{0}' cannot be referenced in its initializer.": { + "category": "Error", + "code": 2231 + }, + "Duplicate string index signature.": { + "category": "Error", + "code": 2232 + }, + "Duplicate number index signature.": { + "category": "Error", + "code": 2233 + }, + "All declarations of an interface must have identical type parameters.": { + "category": "Error", + "code": 2234 + }, + "Expression resolves to variable declaration '_i' that compiler uses to initialize rest parameter.": { + "category": "Error", + "code": 2235 + }, + "Neither type '{0}' nor type '{1}' is assignable to the other.": { + "category": "Error", + "code": 2236 + }, + "Neither type '{0}' nor type '{1}' is assignable to the other:{NL}{2}": { + "category": "Error", + "code": 2237 + }, + "Duplicate function implementation.": { + "category": "Error", + "code": 2237 + }, + "Function implementation expected.": { + "category": "Error", + "code": 2238 + }, + "Function overload name must be '{0}'.": { + "category": "Error", + "code": 2239 + }, + "Constructor implementation expected.": { + "category": "Error", + "code": 2240 + }, + "Class name cannot be '{0}'.": { + "category": "Error", + "code": 2241 + }, + "Interface name cannot be '{0}'.": { + "category": "Error", + "code": 2242 + }, + "Enum name cannot be '{0}'.": { + "category": "Error", + "code": 2243 + }, + "A module cannot have multiple export assignments.": { + "category": "Error", + "code": 2244 + }, + "Export assignment not allowed in module with exported element.": { + "category": "Error", + "code": 2245 + }, + "A parameter property is only allowed in a constructor implementation.": { + "category": "Error", + "code": 2246 + }, + "Function overload must be static.": { + "category": "Error", + "code": 2247 + }, + "Function overload must not be static.": { + "category": "Error", + "code": 2248 + }, + "Type '{0}' is missing property '{1}' from type '{2}'.": { + "category": "NoPrefix", + "code": 4000 + }, + "Types of property '{0}' of types '{1}' and '{2}' are incompatible.": { + "category": "NoPrefix", + "code": 4001 + }, + "Types of property '{0}' of types '{1}' and '{2}' are incompatible:{NL}{3}": { + "category": "NoPrefix", + "code": 4002 + }, + "Property '{0}' defined as private in type '{1}' is defined as public in type '{2}'.": { + "category": "NoPrefix", + "code": 4003 + }, + "Property '{0}' defined as public in type '{1}' is defined as private in type '{2}'.": { + "category": "NoPrefix", + "code": 4004 + }, + "Types '{0}' and '{1}' define property '{2}' as private.": { + "category": "NoPrefix", + "code": 4005 + }, + "Call signatures of types '{0}' and '{1}' are incompatible.": { + "category": "NoPrefix", + "code": 4006 + }, + "Call signatures of types '{0}' and '{1}' are incompatible:{NL}{2}": { + "category": "NoPrefix", + "code": 4007 + }, + "Type '{0}' requires a call signature, but type '{1}' lacks one.": { + "category": "NoPrefix", + "code": 4008 + }, + "Construct signatures of types '{0}' and '{1}' are incompatible.": { + "category": "NoPrefix", + "code": 4009 + }, + "Construct signatures of types '{0}' and '{1}' are incompatible:{NL}{2}": { + "category": "NoPrefix", + "code": 4010 + }, + "Type '{0}' requires a construct signature, but type '{1}' lacks one.": { + "category": "NoPrefix", + "code": 4011 + }, + "Index signatures of types '{0}' and '{1}' are incompatible.": { + "category": "NoPrefix", + "code": 4012 + }, + "Index signatures of types '{0}' and '{1}' are incompatible:{NL}{2}": { + "category": "NoPrefix", + "code": 4013 + }, + "Call signature expects {0} or fewer parameters.": { + "category": "NoPrefix", + "code": 4014 + }, + "Could not apply type '{0}' to argument {1} which is of type '{2}'.": { + "category": "NoPrefix", + "code": 4015 + }, + "Class '{0}' defines instance member accessor '{1}', but extended class '{2}' defines it as instance member function.": { + "category": "NoPrefix", + "code": 4016 + }, + "Class '{0}' defines instance member property '{1}', but extended class '{2}' defines it as instance member function.": { + "category": "NoPrefix", + "code": 4017 + }, + "Class '{0}' defines instance member function '{1}', but extended class '{2}' defines it as instance member accessor.": { + "category": "NoPrefix", + "code": 4018 + }, + "Class '{0}' defines instance member function '{1}', but extended class '{2}' defines it as instance member property.": { + "category": "NoPrefix", + "code": 4019 + }, + "Types of static property '{0}' of class '{1}' and class '{2}' are incompatible.": { + "category": "NoPrefix", + "code": 4020 + }, + "Types of static property '{0}' of class '{1}' and class '{2}' are incompatible:{NL}{3}": { + "category": "NoPrefix", + "code": 4021 + }, + "Type reference cannot refer to container '{0}'.": { + "category": "Error", + "code": 4022 + }, + "Type reference must refer to type.": { + "category": "Error", + "code": 4023 + }, + "In enums with multiple declarations only one declaration can omit an initializer for the first enum element.": { + "category": "Error", + "code": 4024 + }, + " (+ {0} overload(s))": { + "category": "Message", + "code": 4025 + }, + "Variable declaration cannot have the same name as an import declaration.": { + "category": "Error", + "code": 4026 + }, + "Signature expected {0} type arguments, got {1} instead.": { + "category": "Error", + "code": 4027 + }, + "Property '{0}' defined as optional in type '{1}', but is required in type '{2}'.": { + "category": "NoPrefix", + "code": 4028 + }, + "Types '{0}' and '{1}' originating in infinitely expanding type reference do not refer to same named type.": { + "category": "NoPrefix", + "code": 4029 + }, + "Types '{0}' and '{1}' originating in infinitely expanding type reference have incompatible type arguments.": { + "category": "NoPrefix", + "code": 4030 + }, + "Types '{0}' and '{1}' originating in infinitely expanding type reference have incompatible type arguments:{NL}{2}": { + "category": "NoPrefix", + "code": 4031 + }, + "Named properties '{0}' of types '{1}' and '{2}' are not identical.": { + "category": "NoPrefix", + "code": 4032 + }, + "Types of string indexer of types '{0}' and '{1}' are not identical.": { + "category": "NoPrefix", + "code": 4033 + }, + "Types of number indexer of types '{0}' and '{1}' are not identical.": { + "category": "NoPrefix", + "code": 4034 + }, + "Type of number indexer in type '{0}' is not assignable to string indexer type in type '{1}'.{NL}{2}": { + "category": "NoPrefix", + "code": 4035 + }, + "Type of property '{0}' in type '{1}' is not assignable to string indexer type in type '{2}'.{NL}{3}": { + "category": "NoPrefix", + "code": 4036 + }, + "Type of property '{0}' in type '{1}' is not assignable to number indexer type in type '{2}'.{NL}{3}": { + "category": "NoPrefix", + "code": 4037 + }, + "Static property '{0}' defined as private in type '{1}' is defined as public in type '{2}'.": { + "category": "NoPrefix", + "code": 4038 + }, + "Static property '{0}' defined as public in type '{1}' is defined as private in type '{2}'.": { + "category": "NoPrefix", + "code": 4039 + }, + "Types '{0}' and '{1}' define static property '{2}' as private.": { + "category": "NoPrefix", + "code": 4040 + }, + "Current host does not support '{0}' option.": { + "category": "Error", + "code": 5001 + }, + "ECMAScript target version '{0}' not supported. Specify a valid target version: '{1}' (default), or '{2}'": { + "category": "Error", + "code": 5002 + }, + "Argument for '{0}' option must be '{1}' or '{2}'": { + "category": "Error", + "code": 5003 + }, + "Could not find file: '{0}'.": { + "category": "Error", + "code": 5004 + }, + "A file cannot have a reference to itself.": { + "category": "Error", + "code": 5006 + }, + "Cannot resolve referenced file: '{0}'.": { + "category": "Error", + "code": 5007 + }, + "Cannot find the common subdirectory path for the input files.": { + "category": "Error", + "code": 5009 + }, + "Emit Error: {0}.": { + "category": "Error", + "code": 5011 + }, + "Cannot read file '{0}': {1}": { + "category": "Error", + "code": 5012 + }, + "Unsupported file encoding.": { + "category": "NoPrefix", + "code": 5013 + }, + "Locale must be of the form or -. For example '{0}' or '{1}'.": { + "category": "Error", + "code": 5014 + }, + "Unsupported locale: '{0}'.": { + "category": "Error", + "code": 5015 + }, + "Execution Failed.{NL}": { + "category": "Error", + "code": 5016 + }, + "Invalid call to 'up'": { + "category": "Error", + "code": 5019 + }, + "Invalid call to 'down'": { + "category": "Error", + "code": 5020 + }, + "Base64 value '{0}' finished with a continuation bit.": { + "category": "Error", + "code": 5021 + }, + "Unknown compiler option '{0}'": { + "category": "Error", + "code": 5023 + }, + "Expected {0} arguments to message, got {1} instead.": { + "category": "Error", + "code": 5024 + }, + "Expected the message '{0}' to have {1} arguments, but it had {2}": { + "category": "Error", + "code": 5025 + }, + "Could not delete file '{0}'": { + "category": "Error", + "code": 5034 + }, + "Could not create directory '{0}'": { + "category": "Error", + "code": 5035 + }, + "Error while executing file '{0}': ": { + "category": "Error", + "code": 5036 + }, + "Cannot compile external modules unless the '--module' flag is provided.": { + "category": "Error", + "code": 5037 + }, + "Option mapRoot cannot be specified without specifying sourcemap option.": { + "category": "Error", + "code": 5038 + }, + "Option sourceRoot cannot be specified without specifying sourcemap option.": { + "category": "Error", + "code": 5039 + }, + "Options mapRoot and sourceRoot cannot be specified without specifying sourcemap option.": { + "category": "Error", + "code": 5040 + }, + "Option '{0}' specified without '{1}'": { + "category": "Error", + "code": 5041 + }, + "'codepage' option not supported on current platform.": { + "category": "Error", + "code": 5042 + }, + "Concatenate and emit output to single file.": { + "category": "Message", + "code": 6001 + }, + "Generates corresponding {0} file.": { + "category": "Message", + "code": 6002 + }, + "Specifies the location where debugger should locate map files instead of generated locations.": { + "category": "Message", + "code": 6003 + }, + "Specifies the location where debugger should locate TypeScript files instead of source locations.": { + "category": "Message", + "code": 6004 + }, + "Watch input files.": { + "category": "Message", + "code": 6005 + }, + "Redirect output structure to the directory.": { + "category": "Message", + "code": 6006 + }, + "Do not emit comments to output.": { + "category": "Message", + "code": 6009 + }, + "Skip resolution and preprocessing.": { + "category": "Message", + "code": 6010 + }, + "Specify ECMAScript target version: '{0}' (default), or '{1}'": { + "category": "Message", + "code": 6015 + }, + "Specify module code generation: '{0}' or '{1}'": { + "category": "Message", + "code": 6016 + }, + "Print this message.": { + "category": "Message", + "code": 6017 + }, + "Print the compiler's version: {0}": { + "category": "Message", + "code": 6019 + }, + "Allow use of deprecated '{0}' keyword when referencing an external module.": { + "category": "Message", + "code": 6021 + }, + "Specify locale for errors and messages. For example '{0}' or '{1}'": { + "category": "Message", + "code": 6022 + }, + "Syntax: {0}": { + "category": "Message", + "code": 6023 + }, + "options": { + "category": "Message", + "code": 6024 + }, + "file": { + "category": "Message", + "code": 6025 + }, + "Examples:": { + "category": "Message", + "code": 6026 + }, + "Options:": { + "category": "Message", + "code": 6027 + }, + "Insert command line options and files from a file.": { + "category": "Message", + "code": 6028 + }, + "Version {0}": { + "category": "Message", + "code": 6029 + }, + "Insert command line options and files from a file.": { + "category": "Message", + "code": 6030 + }, + "Use the '{0}' flag to see options.": { + "category": "Message", + "code": 6031 + }, + "{NL}Recompiling ({0}):": { + "category": "Message", + "code": 6032 + }, + "STRING": { + "category": "Message", + "code": 6033 + }, + "KIND": { + "category": "Message", + "code": 6034 + }, + "FILE": { + "category": "Message", + "code": 6035 + }, + "VERSION": { + "category": "Message", + "code": 6036 + }, + "LOCATION": { + "category": "Message", + "code": 6037 + }, + "DIRECTORY": { + "category": "Message", + "code": 6038 + }, + "NUMBER": { + "category": "Message", + "code": 6039 + }, + "Specify the codepage to use when opening source files.": { + "category": "Message", + "code": 6040 + }, + "Additional locations:": { + "category": "Message", + "code": 6041 + }, + "This version of the Javascript runtime does not support the '{0}' function.": { + "category": "Error", + "code": 7000 + }, + "Unknown rule.": { + "category": "Error", + "code": 7002 + }, + "Invalid line number ({0})": { + "category": "Error", + "code": 7003 + }, + "Warn on expressions and declarations with an implied 'any' type.": { + "category": "Message", + "code": 7004 + }, + "Variable '{0}' implicitly has an 'any' type.": { + "category": "Error", + "code": 7005 + }, + "Parameter '{0}' of '{1}' implicitly has an 'any' type.": { + "category": "Error", + "code": 7006 + }, + "Parameter '{0}' of function type implicitly has an 'any' type.": { + "category": "Error", + "code": 7007 + }, + "Member '{0}' of object type implicitly has an 'any' type.": { + "category": "Error", + "code": 7008 + }, + "'new' expression, which lacks a constructor signature, implicitly has an 'any' type.": { + "category": "Error", + "code": 7009 + }, + "'{0}', which lacks return-type annotation, implicitly has an 'any' return type.":{ + "category": "Error", + "code": 7010 + }, + "Function expression, which lacks return-type annotation, implicitly has an 'any' return type.":{ + "category": "Error", + "code": 7011 + }, + "Parameter '{0}' of lambda function implicitly has an 'any' type.":{ + "category": "Error", + "code": 7012 + }, + "Constructor signature, which lacks return-type annotation, implicitly has an 'any' return type.":{ + "category": "Error", + "code": 7013 + }, + "Lambda Function, which lacks return-type annotation, implicitly has an 'any' return type.":{ + "category": "Error", + "code": 7014 + }, + "Array Literal implicitly has an 'any' type from widening.":{ + "category": "Error", + "code": 7015 + }, + "'{0}', which lacks 'get' accessor and parameter type annotation on 'set' accessor, implicitly has an 'any' type.":{ + "category": "Error", + "code": 7016 + }, + "Index signature of object type implicitly has an 'any' type.": { + "category": "Error", + "code": 7017 + }, + "Object literal's property '{0}' implicitly has an 'any' type from widening.":{ + "category": "Error", + "code": 7018 + }, +} \ No newline at end of file diff --git a/src/services/resources/references.ts b/src/services/resources/references.ts new file mode 100644 index 00000000000..0624c396fb3 --- /dev/null +++ b/src/services/resources/references.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/src/services/shims.ts b/src/services/shims.ts index 68e15ff6095..48026856d14 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -1,19 +1,23 @@ -/// +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// -module ts { - export interface LanguageServiceShimHost { - log(s: string): void; - getCompilationSettings(): string; - getScriptFileNames(): string; - getScriptVersion(fileName: string): string; - getScriptIsOpen(fileName: string): boolean; - getScriptByteOrderMark(fileName: string): number; - getScriptSnapshot(fileName: string): ScriptSnapshotShim; - getLocalizedDiagnosticMessages(): string; - // getCancellationToken(): CancellationToken - } +/// - export interface ScriptSnapshotShim { +module TypeScript.Services { + + export interface IScriptSnapshotShim { // Get's a portion of the script snapshot specified by [start, end). getText(start: number, end: number): string; @@ -28,13 +32,227 @@ module ts { // { span: { start: number; length: number }; newLength: number } // // Or null value if there was no change. - getChangeRange(oldSnapshot: ScriptSnapshotShim): string; + getTextChangeRangeSinceVersion(scriptVersion: number): string; } - class ScriptSnapshotShimAdapter implements IScriptSnapshot { + // + // Public interface of the host of a language service shim instance. + // + export interface ILanguageServiceShimHost extends TypeScript.ILogger { + getCompilationSettings(): string; + + // Returns a JSON encoded value of the type: + // string[] + getScriptFileNames(): string; + getScriptVersion(fileName: string): number; + getScriptIsOpen(fileName: string): boolean; + getScriptByteOrderMark(fileName: string): number; + getScriptSnapshot(fileName: string): IScriptSnapshotShim; + resolveRelativePath(path: string, directory: string): string; + fileExists(path: string): boolean; + directoryExists(path: string): boolean; + getParentDirectory(path: string): string; + getDiagnosticsObject(): TypeScript.Services.ILanguageServicesDiagnostics; + getLocalizedDiagnosticMessages(): string; + getCancellationToken(): TypeScript.ICancellationToken + } + + // + // Public interface of of a language service instance shim. + // + export interface IShimFactory { + registerShim(shim: IShim): void; + unregisterShim(shim: IShim): void; + } + + export interface IShim { + dispose(dummy: any): void; + } + + export class ShimBase implements IShim { + constructor(private factory: IShimFactory) { + factory.registerShim(this); + } + public dispose(dummy: any): void { + this.factory.unregisterShim(this); + } + } + + export interface ILanguageServiceShim extends IShim { + languageService: TypeScript.Services.ILanguageService; + + dispose(dummy: any): void; + + refresh(throwOnError: boolean): void; + + cleanupSemanticCache(): void; + + getSyntacticDiagnostics(fileName: string): string; + getSemanticDiagnostics(fileName: string): string; + getCompilerOptionsDiagnostics(): string; + + getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean): string; + getCompletionEntryDetails(fileName: string, position: number, entryName: string): string; + + getTypeAtPosition(fileName: string, position: number): string; + getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): string; + getBreakpointStatementAtPosition(fileName: string, position: number): string; + getSignatureAtPosition(fileName: string, position: number): string; + + // Returns a JSON encoded value of the type: + // { fileName: string; minChar: number; limChar: number; kind: string; name: string; containerKind: string; containerName: string } + // + // Or null value if no definition can be found. + getDefinitionAtPosition(fileName: string, position: number): string; + + // Returns a JSON encoded value of the type: + // { fileName: string; minChar: number; limChar: number; isWriteAccess: boolean }[] + getReferencesAtPosition(fileName: string, position: number): string; + + // Returns a JSON encoded value of the type: + // { fileName: string; minChar: number; limChar: number; isWriteAccess: boolean }[] + getOccurrencesAtPosition(fileName: string, position: number): string; + + // Returns a JSON encoded value of the type: + // { fileName: string; minChar: number; limChar: number; isWriteAccess: boolean }[] + getImplementorsAtPosition(fileName: string, position: number): string; + + // Returns a JSON encoded value of the type: + // { name: string; kind: string; kindModifiers: string; containerName: string; containerKind: string; matchKind: string; fileName: string; minChar: number; limChar: number; } [] = []; + getNavigateToItems(searchValue: string): string; + + // Returns a JSON encoded value of the type: + // { name: string; kind: string; kindModifiers: string; containerName: string; containerKind: string; matchKind: string; fileName: string; minChar: number; limChar: number; } [] = []; + getScriptLexicalStructure(fileName: string): string; + + // Returns a JSON encoded value of the type: + // { name: string; kind: string; kindModifiers: string; containerName: string; containerKind: string; matchKind: string; fileName: string; minChar: number; limChar: number; } [] = []; + getOutliningRegions(fileName: string): string; + + getBraceMatchingAtPosition(fileName: string, position: number): string; + getIndentationAtPosition(fileName: string, position: number, options: string/*Services.EditorOptions*/): string; + + getFormattingEditsForRange(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string; + getFormattingEditsForDocument(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string; + getFormattingEditsOnPaste(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string; + getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: string/*Services.FormatCodeOptions*/): string; + + getEmitOutput(fileName: string): string; + } + + /// TODO: delete this, it is only needed untill the VS interface is updated + + enum LanguageVersion { + EcmaScript3 = 0, + EcmaScript5 = 1, + } + + enum ModuleGenTarget { + Unspecified = 0, + Synchronous = 1, + Asynchronous = 2, + } + + interface CompilationSettings { + propagateEnumConstants?: boolean; + removeComments?: boolean; + watch?: boolean; + noResolve?: boolean; + allowAutomaticSemicolonInsertion?: boolean; + noImplicitAny?: boolean; + noLib?: boolean; + codeGenTarget?: LanguageVersion; + moduleGenTarget?: ModuleGenTarget; + outFileOption?: string; + outDirOption?: string; + mapSourceFiles?: boolean; + mapRoot?: string; + sourceRoot?: string; + generateDeclarationFiles?: boolean; + useCaseSensitiveFileResolution?: boolean; + gatherDiagnostics?: boolean; + codepage?: number; + } + + function languageVersionToScriptTarget(languageVersion: LanguageVersion): ts.ScriptTarget { + switch (languageVersion) { + case LanguageVersion.EcmaScript3: return ts.ScriptTarget.ES3; + case LanguageVersion.EcmaScript5: return ts.ScriptTarget.ES5; + default: throw Error("unsuported LanguageVersion value: " + languageVersion); + } + } + + function moduleGenTargetToModuleKind(moduleGenTarget: ModuleGenTarget): ts.ModuleKind { + switch (moduleGenTarget) { + case ModuleGenTarget.Asynchronous: return ts.ModuleKind.AMD; + case ModuleGenTarget.Synchronous: return ts.ModuleKind.CommonJS; + case ModuleGenTarget.Unspecified: return ts.ModuleKind.None; + default: throw Error("unsuported ModuleGenTarget value: " + moduleGenTarget); + } + } + + function scriptTargetTolanguageVersion(scriptTarget: ts.ScriptTarget): LanguageVersion { + switch (scriptTarget) { + case ts.ScriptTarget.ES3: return LanguageVersion.EcmaScript3; + case ts.ScriptTarget.ES5: return LanguageVersion.EcmaScript5; + default: throw Error("unsuported ScriptTarget value: " + scriptTarget); + } + } + + function moduleKindToModuleGenTarget(moduleKind: ts.ModuleKind): ModuleGenTarget { + switch (moduleKind) { + case ts.ModuleKind.AMD: return ModuleGenTarget.Asynchronous; + case ts.ModuleKind.CommonJS: return ModuleGenTarget.Synchronous; + case ts.ModuleKind.None: return ModuleGenTarget.Unspecified; + default: throw Error("unsuported ModuleKind value: " + moduleKind); + } + } + + function compilationSettingsToCompilerOptions(settings: CompilationSettings): ts.CompilerOptions { + // TODO: we should not be converting, but use options all the way + var options: ts.CompilerOptions = {}; + //options.propagateEnumConstants = settings.propagateEnumConstants; + options.removeComments = settings.removeComments; + options.noResolve = settings.noResolve; + options.noImplicitAny = settings.noImplicitAny; + options.noLib = settings.noLib; + options.target = languageVersionToScriptTarget(settings.codeGenTarget); + options.module = moduleGenTargetToModuleKind(settings.moduleGenTarget); + options.out = settings.outFileOption; + options.outDir = settings.outDirOption; + options.sourceMap = settings.mapSourceFiles; + options.mapRoot = settings.mapRoot; + options.sourceRoot = settings.sourceRoot; + options.declaration = settings.generateDeclarationFiles; + //options.useCaseSensitiveFileResolution = settings.useCaseSensitiveFileResolution; + options.codepage = settings.codepage; + return options; + } + + function compilerOptionsToCompilationSettings(options: ts.CompilerOptions): CompilationSettings { + var settings: CompilationSettings = {}; + //options.propagateEnumConstants = settings.propagateEnumConstants; + settings.removeComments = options.removeComments; + settings.noResolve = options.noResolve; + settings.noImplicitAny = options.noImplicitAny; + settings.noLib = options.noLib; + settings.codeGenTarget = scriptTargetTolanguageVersion(options.target); + settings.moduleGenTarget = moduleKindToModuleGenTarget(options.module); + settings.outFileOption = options.out; + settings.outDirOption = options.outDir; + settings.mapSourceFiles = options.sourceMap; + settings.mapRoot = options.mapRoot; + settings.sourceRoot = options.sourceRoot; + settings.generateDeclarationFiles = options.declaration; + // settings.useCaseSensitiveFileResolution = options.useCaseSensitiveFileResolution; + settings.codepage = options.codepage; + return settings; + } + + class ScriptSnapshotShimAdapter implements TypeScript.IScriptSnapshot { private lineStartPositions: number[] = null; - constructor(private scriptSnapshotShim: ScriptSnapshotShim) { + constructor(private scriptSnapshotShim: IScriptSnapshotShim) { } public getText(start: number, end: number): string { @@ -45,7 +263,7 @@ module ts { return this.scriptSnapshotShim.getLength(); } - public getLineStartPositions(): number[] { + public getLineStartPositions(): number[]{ if (this.lineStartPositions == null) { this.lineStartPositions = JSON.parse(this.scriptSnapshotShim.getLineStartPositions()); } @@ -53,52 +271,53 @@ module ts { return this.lineStartPositions; } - - public getChangeRange(scriptSnapshot: IScriptSnapshot): TextChangeRange { - function createTextRange(start: number, length: number) { - function createSpan(start: number, length: number) { - return { - start: () => start, - end: () => start + length, - lenth: () => length, - isEmpty: () => length === 0 - }; - } - - return { - span: () => createSpan(start, length), - newLength: () => length, - newSpan: () => createSpan(start, length), - isUnchanged: () => length === 0 - }; - } - - var encoded = this.scriptSnapshotShim.getChangeRange((scriptSnapshot).scriptSnapshotShim); + public getTextChangeRangeSinceVersion(scriptVersion: number): TypeScript.TextChangeRange { + var encoded = this.scriptSnapshotShim.getTextChangeRangeSinceVersion(scriptVersion); if (encoded == null) { return null; } var decoded: { span: { start: number; length: number; }; newLength: number; } = JSON.parse(encoded); - - return createTextRange(decoded.span.start, decoded.span.length); + return new TypeScript.TextChangeRange( + new TypeScript.TextSpan(decoded.span.start, decoded.span.length), decoded.newLength); } } - export class LanguageServiceShimHostAdapter implements LanguageServiceHost { - constructor(private shimHost: LanguageServiceShimHost) { + export class LanguageServiceShimHostAdapter implements TypeScript.Services.ILanguageServiceHost { + constructor(private shimHost: ILanguageServiceShimHost) { + } + + public information(): boolean { + return this.shimHost.information(); + } + + public debug(): boolean { + return this.shimHost.debug(); + } + + public warning(): boolean { + return this.shimHost.warning(); + } + + public error(): boolean { + return this.shimHost.error(); + } + + public fatal(): boolean { + return this.shimHost.fatal(); } public log(s: string): void { this.shimHost.log(s); } - public getCompilationSettings(): CompilerOptions { + public getCompilationSettings(): ts.CompilerOptions { var settingsJson = this.shimHost.getCompilationSettings(); if (settingsJson == null || settingsJson == "") { - return {}; + throw Error("LanguageServiceShimHostAdapter.getCompilationSettings: empty compilationSettings"); + return null; } - var settings: CompilerOptions = JSON.parse(settingsJson); - return settings; + return compilationSettingsToCompilerOptions(JSON.parse(settingsJson)); } public getScriptFileNames(): string[] { @@ -106,11 +325,11 @@ module ts { return JSON.parse(encoded); } - public getScriptSnapshot(fileName: string): IScriptSnapshot { + public getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot { return new ScriptSnapshotShimAdapter(this.shimHost.getScriptSnapshot(fileName)); } - public getScriptVersion(fileName: string): string { + public getScriptVersion(fileName: string): number { return this.shimHost.getScriptVersion(fileName); } @@ -118,10 +337,14 @@ module ts { return this.shimHost.getScriptIsOpen(fileName); } - public getScriptByteOrderMark(fileName: string): ByteOrderMark { + public getScriptByteOrderMark(fileName: string): TypeScript.ByteOrderMark { return this.shimHost.getScriptByteOrderMark(fileName); } + public getDiagnosticsObject(): ILanguageServicesDiagnostics { + return this.shimHost.getDiagnosticsObject(); + } + public getLocalizedDiagnosticMessages(): any { var diagnosticMessagesJson = this.shimHost.getLocalizedDiagnosticMessages(); if (diagnosticMessagesJson == null || diagnosticMessagesJson == "") { @@ -136,10 +359,475 @@ module ts { } } - //public getCancellationToken(): CancellationToken { - // return this.shimHost.getCancellationToken(); - //} + public getCancellationToken(): ICancellationToken { + return this.shimHost.getCancellationToken(); + } + // IReferenceResolverHost methods + public resolveRelativePath(path: string, directory: string): string { + return this.shimHost.resolveRelativePath(path, directory); + } + public fileExists(path: string): boolean { + return this.shimHost.fileExists(path); + } + + public directoryExists(path: string): boolean { + return this.shimHost.directoryExists(path); + } + + public getParentDirectory(path: string): string { + return this.shimHost.getParentDirectory(path); + } } -} \ No newline at end of file + + export function simpleForwardCall(logger: TypeScript.ILogger, actionDescription: string, action: () =>any): any { + logger.log(actionDescription); + var start = Date.now(); + var result = action(); + var end = Date.now(); + logger.log(actionDescription + " completed in " + (end - start) + " msec"); + if (typeof (result) === "string") { + var str = result; + if (str.length > 128) { + str = str.substring(0, 128) + "..."; + } + logger.log(" result.length=" + str.length + ", result='" + JSON.stringify(str) + "'"); + } + return result; + } + + export function forwardJSONCall(logger: TypeScript.ILogger, actionDescription: string, action: () =>any): string { + try { + var result = simpleForwardCall(logger, actionDescription, action); + return JSON.stringify({ result: result }); + } + catch (err) { + if (err instanceof OperationCanceledException) { + return JSON.stringify({ canceled: true }); + } + TypeScript.Services.logInternalError(logger, err); + err.description = actionDescription; + return JSON.stringify({ error: err }); + } + } + + export class LanguageServiceShim extends ShimBase implements ILanguageServiceShim { + private logger: TypeScript.ILogger; + + constructor(factory: IShimFactory, + private host: ILanguageServiceShimHost, + public languageService: TypeScript.Services.ILanguageService) { + super(factory); + this.logger = this.host; + } + + public forwardJSONCall(actionDescription: string, action: () =>any): string { + return TypeScript.Services.forwardJSONCall(this.logger, actionDescription, action); + } + + // DISPOSE + // Ensure (almost) determinstic release of internal Javascript resources when + // some external native objects holds onto us (e.g. Com/Interop). + public dispose(dummy: any): void { + this.logger.log("dispose()"); + this.languageService.dispose(); + this.languageService = null; + + // force a GC + if (debugObjectHost && debugObjectHost.CollectGarbage) { + debugObjectHost.CollectGarbage(); + this.logger.log("CollectGarbage()"); + } + + this.logger = null; + + super.dispose(dummy); + } + + // REFRESH + // Update the list of scripts known to the compiler + public refresh(throwOnError: boolean): void { + this.forwardJSONCall( + "refresh(" + throwOnError + ")", + () => { + this.languageService.refresh(); + return null; + }); + } + + public cleanupSemanticCache(): void { + this.forwardJSONCall( + "cleanupSemanticCache()", + () => { + this.languageService.cleanupSemanticCache(); + return null; + }); + } + /// SQUIGGLES + /// + + private static realizeDiagnostic(diagnostic: ts.Diagnostic): { message: string; start: number; length: number; category: string; } { + return { + message: diagnostic.messageText, + start: diagnostic.start, + length: diagnostic.length, + /// TODO: no need for the tolowerCase call + category: ts.DiagnosticCategory[diagnostic.category].toLowerCase() + }; + } + + private realizeDiagnosticWithFileName(diagnostic: ts.Diagnostic): { fileName: string; message: string; start: number; length: number; category: string; } { + return { + fileName:diagnostic.file.filename, + message: diagnostic.messageText, + start: diagnostic.start, + length: diagnostic.length, + /// TODO: no need for the tolowerCase call + category: ts.DiagnosticCategory[diagnostic.category].toLowerCase() + }; + } + + public getSyntacticDiagnostics(fileName: string): string { + return this.forwardJSONCall( + "getSyntacticDiagnostics(\"" + fileName + "\")", + () => { + var errors = this.languageService.getSyntacticDiagnostics(fileName); + return errors.map(LanguageServiceShim.realizeDiagnostic); + }); + } + + public getSemanticDiagnostics(fileName: string): string { + return this.forwardJSONCall( + "getSemanticDiagnostics(\"" + fileName + "\")", + () => { + var errors = this.languageService.getSemanticDiagnostics(fileName); + return errors.map(LanguageServiceShim.realizeDiagnostic); + }); + } + + public getCompilerOptionsDiagnostics(): string { + return this.forwardJSONCall( + "getCompilerOptionsDiagnostics()", + () => { + var errors = this.languageService.getCompilerOptionsDiagnostics(); + return errors.map(d => this.realizeDiagnosticWithFileName(d)) + }); + } + + /// QUICKINFO + /// Computes a string representation of the type at the requested position + /// in the active file. + public getTypeAtPosition(fileName: string, position: number): string { + return this.forwardJSONCall( + "getTypeAtPosition(\"" + fileName + "\", " + position + ")", + () => { + var typeInfo = this.languageService.getTypeAtPosition(fileName, position); + return typeInfo; + }); + } + + /// NAMEORDOTTEDNAMESPAN + /// Computes span information of the name or dotted name at the requested position + // in the active file. + public getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): string { + return this.forwardJSONCall( + "getNameOrDottedNameSpan(\"" + fileName + "\", " + startPos + ", " + endPos + ")", + () => { + var spanInfo = this.languageService.getNameOrDottedNameSpan(fileName, startPos, endPos); + return spanInfo; + }); + } + + /// STATEMENTSPAN + /// Computes span information of statement at the requested position in the active file. + public getBreakpointStatementAtPosition(fileName: string, position: number): string { + return this.forwardJSONCall( + "getBreakpointStatementAtPosition(\"" + fileName + "\", " + position + ")", + () => { + var spanInfo = this.languageService.getBreakpointStatementAtPosition(fileName, position); + return spanInfo; + }); + } + + /// SIGNATUREHELP + /// Computes a string representation of the signatures at the requested position + /// in the active file. + public getSignatureAtPosition(fileName: string, position: number): string { + return this.forwardJSONCall( + "getSignatureAtPosition(\"" + fileName + "\", " + position + ")", + () => { + var signatureInfo = this.languageService.getSignatureAtPosition(fileName, position); + return signatureInfo; + }); + } + + /// GOTO DEFINITION + /// Computes the definition location and file for the symbol + /// at the requested position. + public getDefinitionAtPosition(fileName: string, position: number): string { + return this.forwardJSONCall( + "getDefinitionAtPosition(\"" + fileName + "\", " + position + ")", + () => { + return this.languageService.getDefinitionAtPosition(fileName, position); + }); + } + + /// GET BRACE MATCHING + public getBraceMatchingAtPosition(fileName: string, position: number): string { + return this.forwardJSONCall( + "getBraceMatchingAtPosition(\"" + fileName + "\", " + position + ")", + () => { + var textRanges = this.languageService.getBraceMatchingAtPosition(fileName, position); + return textRanges; + }); + } + + /// GET SMART INDENT + public getIndentationAtPosition(fileName: string, position: number, options: string /*Services.EditorOptions*/): string { + return this.forwardJSONCall( + "getIndentationAtPosition(\"" + fileName + "\", " + position + ")", + () => { + var localOptions: TypeScript.Services.EditorOptions = JSON.parse(options); + var columnOffset = this.languageService.getIndentationAtPosition(fileName, position, localOptions); + return { value: columnOffset }; + }); + } + + /// GET REFERENCES + /// Return references to a symbol at the requested position. + /// References are separated by "\n". + /// Each reference is a "fileindex min lim" sub-string. + public getReferencesAtPosition(fileName: string, position: number): string { + return this.forwardJSONCall( + "getReferencesAtPosition(\"" + fileName + "\", " + position + ")", + () => { + return this.languageService.getReferencesAtPosition(fileName, position); + }); + } + + public getOccurrencesAtPosition(fileName: string, position: number): string { + return this.forwardJSONCall( + "getOccurrencesAtPosition(\"" + fileName + "\", " + position + ")", + () => { + return this.languageService.getOccurrencesAtPosition(fileName, position); + }); + } + + /// GET IMPLEMENTORS + public getImplementorsAtPosition(fileName: string, position: number): string { + return this.forwardJSONCall( + "getImplementorsAtPosition(\"" + fileName + "\", " + position + ")", + () => { + return this.languageService.getImplementorsAtPosition(fileName, position); + }); + } + + + /// COMPLETION LISTS + /// Get a string based representation of the completions + /// to provide at the given source position and providing a member completion + /// list if requested. + public getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean) { + return this.forwardJSONCall( + "getCompletionsAtPosition(\"" + fileName + "\", " + position + ", " + isMemberCompletion + ")", + () => { + var completion = this.languageService.getCompletionsAtPosition(fileName, position, isMemberCompletion); + return completion; + }); + } + + /// Get a string based representation of a completion list entry details + public getCompletionEntryDetails(fileName: string, position: number, entryName: string) { + return this.forwardJSONCall( + "getCompletionEntryDetails(\"" + fileName + "\", " + position + ", " + entryName + ")", + () => { + var details = this.languageService.getCompletionEntryDetails(fileName, position, entryName); + return details; + }); + } + + /// FORMAT SELECTION + public getFormattingEditsForRange(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string { + return this.forwardJSONCall( + "getFormattingEditsForRange(\"" + fileName + "\", " + minChar + ", " + limChar + ")", + () => { + var localOptions: TypeScript.Services.FormatCodeOptions = JSON.parse(options); + var edits = this.languageService.getFormattingEditsForRange(fileName, minChar, limChar, localOptions); + return edits; + }); + } + + /// FORMAT DOCUMENT + public getFormattingEditsForDocument(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string { + return this.forwardJSONCall( + "getFormattingEditsForDocument(\"" + fileName + "\", " + minChar + ", " + limChar + ")", + () => { + var localOptions: TypeScript.Services.FormatCodeOptions = JSON.parse(options); + var edits = this.languageService.getFormattingEditsForDocument(fileName, minChar, limChar, localOptions); + return edits; + }); + } + + /// FORMAT ON PASTE + public getFormattingEditsOnPaste(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string { + return this.forwardJSONCall( + "getFormattingEditsOnPaste(\"" + fileName + "\", " + minChar + ", " + limChar + ")", + () => { + var localOptions: TypeScript.Services.FormatCodeOptions = JSON.parse(options); + var edits = this.languageService.getFormattingEditsOnPaste(fileName, minChar, limChar, localOptions); + return edits; + }); + } + + /// FORMAT + public getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: string/*Services.FormatCodeOptions*/): string { + return this.forwardJSONCall( + "getFormattingEditsAfterKeystroke(\"" + fileName + "\", " + position + ", \"" + key + "\")", + () => { + var localOptions: TypeScript.Services.FormatCodeOptions = JSON.parse(options); + var edits = this.languageService.getFormattingEditsAfterKeystroke(fileName, position, key, localOptions); + return edits; + }); + } + + /// NAVIGATE TO + /// Return a list of symbols that are interesting to navigate to + public getNavigateToItems(searchValue: string): string { + return this.forwardJSONCall( + "getNavigateToItems(\"" + searchValue + "\")", + () => { + var items = this.languageService.getNavigateToItems(searchValue); + var result = this._navigateToItemsToString(items); + return result; + }); + } + + // GET SCRIPT LEXICAL STRUCTURE + // + public getScriptLexicalStructure(fileName: string): string { + return this.forwardJSONCall( + "getScriptLexicalStructure(\"" + fileName + "\")", + () => { + var items = this.languageService.getScriptLexicalStructure(fileName); + var result = this._navigateToItemsToString(items); + return result; + }); + } + + // GET OUTLINING REGIONS + // + public getOutliningRegions(fileName: string): string { + return this.forwardJSONCall( + "getOutliningRegions(\"" + fileName + "\")", + () => { + var items = this.languageService.getOutliningRegions(fileName); + return items; + }); + } + + /// Emit + public getEmitOutput(fileName: string): string { + return this.forwardJSONCall( + "getEmitOutput(\"" + fileName + "\")", + () => { + var output = this.languageService.getEmitOutput(fileName); + return output; + }); + } + + private _navigateToItemsToString(items: TypeScript.Services.NavigateToItem[]): any { + var result: { + name: string; + kind: string; + kindModifiers: string; + containerName: string; + containerKind: string; + matchKind: string; + fileName: string; + minChar: number; + limChar: number; + additionalSpans?: { start: number; end: number; }[]; + }[] = []; + + for (var i = 0; i < items.length; i++) { + var item = items[i]; + + result.push({ + name: item.name, + kind: item.kind, + kindModifiers: item.kindModifiers, + containerName: item.containerName, + containerKind: item.containerKind, + matchKind: item.matchKind, + fileName: item.fileName, + minChar: item.minChar, + limChar: item.limChar, + additionalSpans: item.additionalSpans ? item.additionalSpans.map(i => { return { start: i.minChar, end: i.limChar }; }) : undefined + }); + } + + return result; + } + } + + export class ClassifierShim extends ShimBase { + public classifier: TypeScript.Services.Classifier; + + constructor(factory: IShimFactory, public host: TypeScript.Services.IClassifierHost) { + super(factory); + this.classifier = new TypeScript.Services.Classifier(this.host); + } + + /// COLORIZATION + public getClassificationsForLine(text: string, lexState: EndOfLineState): string { + var classification = this.classifier.getClassificationsForLine(text, lexState); + var items = classification.entries; + var result = ""; + for (var i = 0; i < items.length; i++) { + result += items[i].length + "\n"; + result += items[i].classification + "\n"; + } + result += classification.finalLexState; + return result; + } + } + + export class CoreServicesShim extends ShimBase { + public logger: TypeScript.ILogger; + public services: TypeScript.Services.CoreServices; + + constructor(factory: IShimFactory, public host: TypeScript.Services.ICoreServicesHost) { + super(factory); + this.logger = this.host.logger; + this.services = new TypeScript.Services.CoreServices(this.host); + } + + private forwardJSONCall(actionDescription: string, action: () =>any): any { + return TypeScript.Services.forwardJSONCall(this.logger, actionDescription, action); + } + + /// + /// getPreProcessedFileInfo + /// + public getPreProcessedFileInfo(fileName: string, sourceText: TypeScript.IScriptSnapshot): string { + return this.forwardJSONCall( + "getPreProcessedFileInfo(\"" + fileName + "\")", + () => { + var result = this.services.getPreProcessedFileInfo(fileName, sourceText); + return result; + }); + } + + /// + /// getDefaultCompilationSettings + /// + public getDefaultCompilationSettings(): string { + return this.forwardJSONCall( + "getDefaultCompilationSettings()", + () => { + return compilerOptionsToCompilationSettings(this.services.getDefaultCompilationSettings()); + }); + } + } +} diff --git a/src/services/signatureInfoHelpers.ts b/src/services/signatureInfoHelpers.ts new file mode 100644 index 00000000000..145dcc02381 --- /dev/null +++ b/src/services/signatureInfoHelpers.ts @@ -0,0 +1,348 @@ +// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0. +// See LICENSE.txt in the project root for complete license information. + +/// + +module TypeScript.Services { + + export interface IPartiallyWrittenTypeArgumentListInformation { + genericIdentifer: TypeScript.ISyntaxToken; + lessThanToken: TypeScript.ISyntaxToken; + argumentIndex: number; + } + + export interface IExpressionWithArgumentListSyntax extends IExpressionSyntax { + expression: IExpressionSyntax; + argumentList: ArgumentListSyntax; + } + + export class SignatureInfoHelpers { + + // A partially written generic type expression is not guaranteed to have the correct syntax tree. the expression could be parsed as less than/greater than expression or a comma expression + // or some other combination depending on what the user has typed so far. For the purposes of signature help we need to consider any location after "<" as a possible generic type reference. + // To do this, the method will back parse the expression starting at the position required. it will try to parse the current expression as a generic type expression, if it did succeed it + // will return the generic identifier that started the expression (e.g. "foo" in "foo 1; + + for (var i = 0, n = signatures.length; i < n; i++) { + var signature = signatures[i]; + + // filter out the definition signature if there are overloads + if (hasOverloads && signature.isDefinition()) { + continue; + } + + var signatureGroupInfo = new FormalSignatureItemInfo(); + var paramIndexInfo: number[] = []; + var functionName = signature.getScopedNameEx(enclosingScopeSymbol).toString(); + if (!functionName && (!symbol.isType() || (symbol).isNamedTypeSymbol())) { + functionName = symbol.getScopedNameEx(enclosingScopeSymbol).toString(); + } + + var signatureMemberName = signature.getSignatureTypeNameEx(functionName, /*shortform*/ false, /*brackets*/ false, enclosingScopeSymbol, /*getParamMarkerInfo*/ true, /*getTypeParameterMarkerInfo*/ true); + signatureGroupInfo.signatureInfo = TypeScript.MemberName.memberNameToString(signatureMemberName, paramIndexInfo); + signatureGroupInfo.docComment = signature.docComments(); + + var parameterMarkerIndex = 0; + + if (signature.isGeneric()) { + var typeParameters = signature.getTypeParameters(); + for (var j = 0, m = typeParameters.length; j < m; j++) { + var typeParameter = typeParameters[j]; + var signatureTypeParameterInfo = new FormalTypeParameterInfo(); + signatureTypeParameterInfo.name = typeParameter.getDisplayName(); + signatureTypeParameterInfo.docComment = typeParameter.docComments(); + signatureTypeParameterInfo.minChar = paramIndexInfo[2 * parameterMarkerIndex]; + signatureTypeParameterInfo.limChar = paramIndexInfo[2 * parameterMarkerIndex + 1]; + parameterMarkerIndex++; + signatureGroupInfo.typeParameters.push(signatureTypeParameterInfo); + } + } + + var parameters = signature.parameters; + for (var j = 0, m = parameters.length; j < m; j++) { + var parameter = parameters[j]; + var signatureParameterInfo = new FormalParameterInfo(); + signatureParameterInfo.isVariable = signature.hasVarArgs && (j === parameters.length - 1); + signatureParameterInfo.name = parameter.getDisplayName(); + signatureParameterInfo.docComment = parameter.docComments(); + signatureParameterInfo.minChar = paramIndexInfo[2 * parameterMarkerIndex]; + signatureParameterInfo.limChar = paramIndexInfo[2 * parameterMarkerIndex + 1]; + parameterMarkerIndex++; + signatureGroupInfo.parameters.push(signatureParameterInfo); + } + + signatureGroup.push(signatureGroupInfo); + } + + return signatureGroup; + } + + public static getSignatureInfoFromGenericSymbol(symbol: TypeScript.PullSymbol, enclosingScopeSymbol: TypeScript.PullSymbol, compilerState: LanguageServiceCompiler) { + var signatureGroupInfo = new FormalSignatureItemInfo(); + + var paramIndexInfo: number[] = []; + var symbolName = symbol.getScopedNameEx(enclosingScopeSymbol, /*skipTypeParametersInName*/ false, /*useConstaintInName*/ true, /*getPrettyTypeName*/ false, /*getTypeParamMarkerInfo*/ true); + + signatureGroupInfo.signatureInfo = TypeScript.MemberName.memberNameToString(symbolName, paramIndexInfo); + signatureGroupInfo.docComment = symbol.docComments(); + + var parameterMarkerIndex = 0; + + var typeSymbol = symbol.type; + + var typeParameters = typeSymbol.getTypeParameters(); + for (var i = 0, n = typeParameters.length; i < n; i++) { + var typeParameter = typeParameters[i]; + var signatureTypeParameterInfo = new FormalTypeParameterInfo(); + signatureTypeParameterInfo.name = typeParameter.getDisplayName(); + signatureTypeParameterInfo.docComment = typeParameter.docComments(); + signatureTypeParameterInfo.minChar = paramIndexInfo[2 * i]; + signatureTypeParameterInfo.limChar = paramIndexInfo[2 * i + 1]; + signatureGroupInfo.typeParameters.push(signatureTypeParameterInfo); + } + + return [signatureGroupInfo]; + } + + public static getActualSignatureInfoFromCallExpression(ast: IExpressionWithArgumentListSyntax, caretPosition: number, typeParameterInformation: IPartiallyWrittenTypeArgumentListInformation): ActualSignatureInfo { + if (!ast) { + return null; + } + + var result = new ActualSignatureInfo(); + + // The expression is not guaranteed to be complete, we need to populate the min and lim with the most accurate information we have about + // type argument and argument lists + var parameterMinChar = caretPosition; + var parameterLimChar = caretPosition; + + if (ast.argumentList.typeArgumentList) { + parameterMinChar = Math.min(start(ast.argumentList.typeArgumentList)); + parameterLimChar = Math.max(Math.max(start(ast.argumentList.typeArgumentList), end(ast.argumentList.typeArgumentList) + trailingTriviaWidth(ast.argumentList.typeArgumentList))); + } + + if (ast.argumentList.arguments) { + parameterMinChar = Math.min(parameterMinChar, end(ast.argumentList.openParenToken)); + parameterLimChar = Math.max(parameterLimChar, + ast.argumentList.closeParenToken.fullWidth() > 0 ? start(ast.argumentList.closeParenToken) : fullEnd(ast.argumentList)); + } + + result.parameterMinChar = parameterMinChar; + result.parameterLimChar = parameterLimChar; + result.currentParameterIsTypeParameter = false; + result.currentParameter = -1; + + if (typeParameterInformation) { + result.currentParameterIsTypeParameter = true; + result.currentParameter = typeParameterInformation.argumentIndex; + } + else if (ast.argumentList.arguments && ast.argumentList.arguments.length > 0) { + result.currentParameter = 0; + for (var index = 0; index < ast.argumentList.arguments.length; index++) { + if (caretPosition > end(ast.argumentList.arguments[index]) + lastToken(ast.argumentList.arguments[index]).trailingTriviaWidth()) { + result.currentParameter++; + } + } + } + + return result; + } + + public static getActualSignatureInfoFromPartiallyWritenGenericExpression(caretPosition: number, typeParameterInformation: IPartiallyWrittenTypeArgumentListInformation): ActualSignatureInfo { + var result = new ActualSignatureInfo(); + + result.parameterMinChar = start(typeParameterInformation.lessThanToken); + result.parameterLimChar = Math.max(fullEnd(typeParameterInformation.lessThanToken), caretPosition); + result.currentParameterIsTypeParameter = true; + result.currentParameter = typeParameterInformation.argumentIndex; + + return result; + } + + public static isSignatureHelpBlocker(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean { + // We shouldn't be getting a possition that is outside the file because + // isEntirelyInsideComment can't handle when the position is out of bounds, + // callers should be fixed, however we should be resiliant to bad inputs + // so we return true (this position is a blocker for getting signature help) + if (position < 0 || position > fullWidth(sourceUnit)) { + return true; + } + + return TypeScript.Syntax.isEntirelyInsideComment(sourceUnit, position); + } + + public static isTargetOfObjectCreationExpression(positionedToken: TypeScript.ISyntaxToken): boolean { + var positionedParent = TypeScript.Syntax.getAncestorOfKind(positionedToken, TypeScript.SyntaxKind.ObjectCreationExpression); + if (positionedParent) { + var objectCreationExpression = positionedParent; + var expressionRelativeStart = objectCreationExpression.newKeyword.fullWidth(); + var tokenRelativeStart = positionedToken.fullStart() - fullStart(positionedParent); + return tokenRelativeStart >= expressionRelativeStart && + tokenRelativeStart <= (expressionRelativeStart + fullWidth(objectCreationExpression.expression)); + } + + return false; + } + + private static moveBackUpTillMatchingTokenKind(token: TypeScript.ISyntaxToken, tokenKind: TypeScript.SyntaxKind, matchingTokenKind: TypeScript.SyntaxKind): TypeScript.ISyntaxToken { + if (!token || token.kind() !== tokenKind) { + throw TypeScript.Errors.invalidOperation(); + } + + // Skip the current token + token = previousToken(token, /*includeSkippedTokens*/ true); + + var stack = 0; + + while (token) { + if (token.kind() === matchingTokenKind) { + if (stack === 0) { + // Found the matching token, return + return token; + } + else if (stack < 0) { + // tokens overlapped.. bail out. + break; + } + else { + stack--; + } + } + else if (token.kind() === tokenKind) { + stack++; + } + + // Move back + token = previousToken(token, /*includeSkippedTokens*/ true); + } + + // Did not find matching token + return null; + } + } +} \ No newline at end of file diff --git a/src/services/syntax/SyntaxGenerator.d.ts b/src/services/syntax/SyntaxGenerator.d.ts new file mode 100644 index 00000000000..4a833f07587 --- /dev/null +++ b/src/services/syntax/SyntaxGenerator.d.ts @@ -0,0 +1,1139 @@ +declare var require: any; +declare var module: any; +declare module TypeScript { + var DiagnosticCode: { + error_TS_0_1: string; + warning_TS_0_1: string; + Unrecognized_escape_sequence: string; + Unexpected_character_0: string; + Missing_close_quote_character: string; + Identifier_expected: string; + _0_keyword_expected: string; + _0_expected: string; + Identifier_expected_0_is_a_keyword: string; + Automatic_semicolon_insertion_not_allowed: string; + Unexpected_token_0_expected: string; + Trailing_separator_not_allowed: string; + AsteriskSlash_expected: string; + public_or_private_modifier_must_precede_static: string; + Unexpected_token: string; + Catch_clause_parameter_cannot_have_a_type_annotation: string; + Rest_parameter_must_be_last_in_list: string; + Parameter_cannot_have_question_mark_and_initializer: string; + Required_parameter_cannot_follow_optional_parameter: string; + Index_signatures_cannot_have_rest_parameters: string; + Index_signature_parameter_cannot_have_accessibility_modifiers: string; + Index_signature_parameter_cannot_have_a_question_mark: string; + Index_signature_parameter_cannot_have_an_initializer: string; + Index_signature_must_have_a_type_annotation: string; + Index_signature_parameter_must_have_a_type_annotation: string; + Index_signature_parameter_type_must_be_string_or_number: string; + extends_clause_already_seen: string; + extends_clause_must_precede_implements_clause: string; + Classes_can_only_extend_a_single_class: string; + implements_clause_already_seen: string; + Accessibility_modifier_already_seen: string; + _0_modifier_must_precede_1_modifier: string; + _0_modifier_already_seen: string; + _0_modifier_cannot_appear_on_a_class_element: string; + Interface_declaration_cannot_have_implements_clause: string; + super_invocation_cannot_have_type_arguments: string; + Only_ambient_modules_can_use_quoted_names: string; + Statements_are_not_allowed_in_ambient_contexts: string; + Implementations_are_not_allowed_in_ambient_contexts: string; + declare_modifier_not_allowed_for_code_already_in_an_ambient_context: string; + Initializers_are_not_allowed_in_ambient_contexts: string; + Parameter_property_declarations_can_only_be_used_in_a_non_ambient_constructor_declaration: string; + Function_implementation_expected: string; + Constructor_implementation_expected: string; + Function_overload_name_must_be_0: string; + _0_modifier_cannot_appear_on_a_module_element: string; + declare_modifier_cannot_appear_on_an_interface_declaration: string; + declare_modifier_required_for_top_level_element: string; + Rest_parameter_cannot_be_optional: string; + Rest_parameter_cannot_have_an_initializer: string; + set_accessor_must_have_one_and_only_one_parameter: string; + set_accessor_parameter_cannot_be_optional: string; + set_accessor_parameter_cannot_have_an_initializer: string; + set_accessor_cannot_have_rest_parameter: string; + get_accessor_cannot_have_parameters: string; + Modifiers_cannot_appear_here: string; + Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher: string; + Class_name_cannot_be_0: string; + Interface_name_cannot_be_0: string; + Enum_name_cannot_be_0: string; + Module_name_cannot_be_0: string; + Enum_member_must_have_initializer: string; + Export_assignment_cannot_be_used_in_internal_modules: string; + Export_assignment_not_allowed_in_module_with_exported_element: string; + Module_cannot_have_multiple_export_assignments: string; + Ambient_enum_elements_can_only_have_integer_literal_initializers: string; + module_class_interface_enum_import_or_statement: string; + constructor_function_accessor_or_variable: string; + statement: string; + case_or_default_clause: string; + identifier: string; + call_construct_index_property_or_function_signature: string; + expression: string; + type_name: string; + property_or_accessor: string; + parameter: string; + type: string; + type_parameter: string; + declare_modifier_not_allowed_on_import_declaration: string; + Function_overload_must_be_static: string; + Function_overload_must_not_be_static: string; + Parameter_property_declarations_cannot_be_used_in_a_constructor_overload: string; + Invalid_reference_directive_syntax: string; + Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher: string; + Accessors_are_not_allowed_in_ambient_contexts: string; + _0_modifier_cannot_appear_on_a_constructor_declaration: string; + _0_modifier_cannot_appear_on_a_parameter: string; + Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement: string; + Type_parameters_cannot_appear_on_a_constructor_declaration: string; + Type_annotation_cannot_appear_on_a_constructor_declaration: string; + Duplicate_identifier_0: string; + The_name_0_does_not_exist_in_the_current_scope: string; + The_name_0_does_not_refer_to_a_value: string; + super_can_only_be_used_inside_a_class_instance_method: string; + The_left_hand_side_of_an_assignment_expression_must_be_a_variable_property_or_indexer: string; + Value_of_type_0_is_not_callable_Did_you_mean_to_include_new: string; + Value_of_type_0_is_not_callable: string; + Value_of_type_0_is_not_newable: string; + Value_of_type_0_is_not_indexable_by_type_1: string; + Operator_0_cannot_be_applied_to_types_1_and_2: string; + Operator_0_cannot_be_applied_to_types_1_and_2_3: string; + Cannot_convert_0_to_1: string; + Cannot_convert_0_to_1_NL_2: string; + Expected_var_class_interface_or_module: string; + Operator_0_cannot_be_applied_to_type_1: string; + Getter_0_already_declared: string; + Setter_0_already_declared: string; + Exported_class_0_extends_private_class_1: string; + Exported_class_0_implements_private_interface_1: string; + Exported_interface_0_extends_private_interface_1: string; + Exported_class_0_extends_class_from_inaccessible_module_1: string; + Exported_class_0_implements_interface_from_inaccessible_module_1: string; + Exported_interface_0_extends_interface_from_inaccessible_module_1: string; + Public_static_property_0_of_exported_class_has_or_is_using_private_type_1: string; + Public_property_0_of_exported_class_has_or_is_using_private_type_1: string; + Property_0_of_exported_interface_has_or_is_using_private_type_1: string; + Exported_variable_0_has_or_is_using_private_type_1: string; + Public_static_property_0_of_exported_class_is_using_inaccessible_module_1: string; + Public_property_0_of_exported_class_is_using_inaccessible_module_1: string; + Property_0_of_exported_interface_is_using_inaccessible_module_1: string; + Exported_variable_0_is_using_inaccessible_module_1: string; + Parameter_0_of_constructor_from_exported_class_has_or_is_using_private_type_1: string; + Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_private_type_1: string; + Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_private_type_1: string; + Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_type_1: string; + Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_type_1: string; + Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_type_1: string; + Parameter_0_of_public_method_from_exported_class_has_or_is_using_private_type_1: string; + Parameter_0_of_method_from_exported_interface_has_or_is_using_private_type_1: string; + Parameter_0_of_exported_function_has_or_is_using_private_type_1: string; + Parameter_0_of_constructor_from_exported_class_is_using_inaccessible_module_1: string; + Parameter_0_of_public_static_property_setter_from_exported_class_is_using_inaccessible_module_1: string; + Parameter_0_of_public_property_setter_from_exported_class_is_using_inaccessible_module_1: string; + Parameter_0_of_constructor_signature_from_exported_interface_is_using_inaccessible_module_1: string; + Parameter_0_of_call_signature_from_exported_interface_is_using_inaccessible_module_1: string; + Parameter_0_of_public_static_method_from_exported_class_is_using_inaccessible_module_1: string; + Parameter_0_of_public_method_from_exported_class_is_using_inaccessible_module_1: string; + Parameter_0_of_method_from_exported_interface_is_using_inaccessible_module_1: string; + Parameter_0_of_exported_function_is_using_inaccessible_module_1: string; + Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_private_type_0: string; + Return_type_of_public_property_getter_from_exported_class_has_or_is_using_private_type_0: string; + Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_private_type_0: string; + Return_type_of_call_signature_from_exported_interface_has_or_is_using_private_type_0: string; + Return_type_of_index_signature_from_exported_interface_has_or_is_using_private_type_0: string; + Return_type_of_public_static_method_from_exported_class_has_or_is_using_private_type_0: string; + Return_type_of_public_method_from_exported_class_has_or_is_using_private_type_0: string; + Return_type_of_method_from_exported_interface_has_or_is_using_private_type_0: string; + Return_type_of_exported_function_has_or_is_using_private_type_0: string; + Return_type_of_public_static_property_getter_from_exported_class_is_using_inaccessible_module_0: string; + Return_type_of_public_property_getter_from_exported_class_is_using_inaccessible_module_0: string; + Return_type_of_constructor_signature_from_exported_interface_is_using_inaccessible_module_0: string; + Return_type_of_call_signature_from_exported_interface_is_using_inaccessible_module_0: string; + Return_type_of_index_signature_from_exported_interface_is_using_inaccessible_module_0: string; + Return_type_of_public_static_method_from_exported_class_is_using_inaccessible_module_0: string; + Return_type_of_public_method_from_exported_class_is_using_inaccessible_module_0: string; + Return_type_of_method_from_exported_interface_is_using_inaccessible_module_0: string; + Return_type_of_exported_function_is_using_inaccessible_module_0: string; + new_T_cannot_be_used_to_create_an_array_Use_new_Array_T_instead: string; + A_parameter_list_must_follow_a_generic_type_argument_list_expected: string; + Multiple_constructor_implementations_are_not_allowed: string; + Unable_to_resolve_external_module_0: string; + Module_cannot_be_aliased_to_a_non_module_type: string; + A_class_may_only_extend_another_class: string; + A_class_may_only_implement_another_class_or_interface: string; + An_interface_may_only_extend_another_class_or_interface: string; + Unable_to_resolve_type: string; + Unable_to_resolve_type_of_0: string; + Unable_to_resolve_type_parameter_constraint: string; + Type_parameter_constraint_cannot_be_a_primitive_type: string; + Supplied_parameters_do_not_match_any_signature_of_call_target: string; + Supplied_parameters_do_not_match_any_signature_of_call_target_NL_0: string; + Invalid_new_expression: string; + Call_signatures_used_in_a_new_expression_must_have_a_void_return_type: string; + Could_not_select_overload_for_new_expression: string; + Type_0_does_not_satisfy_the_constraint_1_for_type_parameter_2: string; + Could_not_select_overload_for_call_expression: string; + Cannot_invoke_an_expression_whose_type_lacks_a_call_signature: string; + Calls_to_super_are_only_valid_inside_a_class: string; + Generic_type_0_requires_1_type_argument_s: string; + Type_of_array_literal_cannot_be_determined_Best_common_type_could_not_be_found_for_array_elements: string; + Could_not_find_enclosing_symbol_for_dotted_name_0: string; + The_property_0_does_not_exist_on_value_of_type_1: string; + Could_not_find_symbol_0: string; + get_and_set_accessor_must_have_the_same_type: string; + this_cannot_be_referenced_in_current_location: string; + Static_members_cannot_reference_class_type_parameters: string; + Class_0_is_recursively_referenced_as_a_base_type_of_itself: string; + Interface_0_is_recursively_referenced_as_a_base_type_of_itself: string; + super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class: string; + super_cannot_be_referenced_in_non_derived_classes: string; + A_super_call_must_be_the_first_statement_in_the_constructor_when_a_class_contains_initialized_properties_or_has_parameter_properties: string; + Constructors_for_derived_classes_must_contain_a_super_call: string; + Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors: string; + _0_1_is_inaccessible: string; + this_cannot_be_referenced_within_module_bodies: string; + Invalid_expression_types_not_known_to_support_the_addition_operator: string; + The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type: string; + The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type: string; + The_type_of_a_unary_arithmetic_operation_operand_must_be_of_type_any_number_or_an_enum_type: string; + Variable_declarations_of_a_for_statement_cannot_use_a_type_annotation: string; + Variable_declarations_of_a_for_statement_must_be_of_types_string_or_any: string; + The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter: string; + The_left_hand_side_of_an_in_expression_must_be_of_types_any_string_or_number: string; + The_right_hand_side_of_an_in_expression_must_be_of_type_any_an_object_type_or_a_type_parameter: string; + The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter: string; + The_right_hand_side_of_an_instanceof_expression_must_be_of_type_any_or_of_a_type_assignable_to_the_Function_interface_type: string; + Setters_cannot_return_a_value: string; + Tried_to_query_type_of_uninitialized_module_0: string; + Tried_to_set_variable_type_to_uninitialized_module_type_0: string; + Type_0_does_not_have_type_parameters: string; + Getters_must_return_a_value: string; + Getter_and_setter_accessors_do_not_agree_in_visibility: string; + Invalid_left_hand_side_of_assignment_expression: string; + Function_declared_a_non_void_return_type_but_has_no_return_expression: string; + Cannot_resolve_return_type_reference: string; + Constructors_cannot_have_a_return_type_of_void: string; + Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2: string; + All_symbols_within_a_with_block_will_be_resolved_to_any: string; + Import_declarations_in_an_internal_module_cannot_reference_an_external_module: string; + Class_0_declares_interface_1_but_does_not_implement_it_NL_2: string; + Class_0_declares_class_1_as_an_interface_but_does_not_implement_it_NL_2: string; + The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_property_or_indexer: string; + this_cannot_be_referenced_in_static_initializers_in_a_class_body: string; + Class_0_cannot_extend_class_1_NL_2: string; + Interface_0_cannot_extend_class_1_NL_2: string; + Interface_0_cannot_extend_interface_1_NL_2: string; + Overload_signature_is_not_compatible_with_function_definition: string; + Overload_signature_is_not_compatible_with_function_definition_NL_0: string; + Overload_signatures_must_all_be_public_or_private: string; + Overload_signatures_must_all_be_exported_or_not_exported: string; + Overload_signatures_must_all_be_ambient_or_non_ambient: string; + Overload_signatures_must_all_be_optional_or_required: string; + Specialized_overload_signature_is_not_assignable_to_any_non_specialized_signature: string; + this_cannot_be_referenced_in_constructor_arguments: string; + Instance_member_cannot_be_accessed_off_a_class: string; + Untyped_function_calls_may_not_accept_type_arguments: string; + Non_generic_functions_may_not_accept_type_arguments: string; + A_generic_type_may_not_reference_itself_with_a_wrapped_form_of_its_own_type_parameters: string; + Rest_parameters_must_be_array_types: string; + Overload_signature_implementation_cannot_use_specialized_type: string; + Export_assignments_may_only_be_used_at_the_top_level_of_external_modules: string; + Export_assignments_may_only_be_made_with_variables_functions_classes_interfaces_enums_and_internal_modules: string; + Only_public_methods_of_the_base_class_are_accessible_via_the_super_keyword: string; + Numeric_indexer_type_0_must_be_assignable_to_string_indexer_type_1: string; + Numeric_indexer_type_0_must_be_assignable_to_string_indexer_type_1_NL_2: string; + All_numerically_named_properties_must_be_assignable_to_numeric_indexer_type_0: string; + All_numerically_named_properties_must_be_assignable_to_numeric_indexer_type_0_NL_1: string; + All_named_properties_must_be_assignable_to_string_indexer_type_0: string; + All_named_properties_must_be_assignable_to_string_indexer_type_0_NL_1: string; + Generic_type_references_must_include_all_type_arguments: string; + Default_arguments_are_only_allowed_in_implementation: string; + Function_expression_declared_a_non_void_return_type_but_has_no_return_expression: string; + Import_declaration_referencing_identifier_from_internal_module_can_only_be_made_with_variables_functions_classes_interfaces_enums_and_internal_modules: string; + Could_not_find_symbol_0_in_module_1: string; + Unable_to_resolve_module_reference_0: string; + Could_not_find_module_0_in_module_1: string; + Exported_import_declaration_0_is_assigned_value_with_type_that_has_or_is_using_private_type_1: string; + Exported_import_declaration_0_is_assigned_value_with_type_that_is_using_inaccessible_module_1: string; + Exported_import_declaration_0_is_assigned_type_that_has_or_is_using_private_type_1: string; + Exported_import_declaration_0_is_assigned_type_that_is_using_inaccessible_module_1: string; + Exported_import_declaration_0_is_assigned_container_that_is_or_is_using_inaccessible_module_1: string; + Type_name_0_in_extends_clause_does_not_reference_constructor_function_for_1: string; + Internal_module_reference_0_in_import_declaration_does_not_reference_module_instance_for_1: string; + Module_0_cannot_merge_with_previous_declaration_of_1_in_a_different_file_2: string; + Interface_0_cannot_simultaneously_extend_types_1_and_2_NL_3: string; + Initializer_of_parameter_0_cannot_reference_identifier_1_declared_after_it: string; + Ambient_external_module_declaration_cannot_be_reopened: string; + All_declarations_of_merged_declaration_0_must_be_exported_or_not_exported: string; + super_cannot_be_referenced_in_constructor_arguments: string; + Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class: string; + Ambient_external_module_declaration_must_be_defined_in_global_context: string; + Ambient_external_module_declaration_cannot_specify_relative_module_name: string; + Import_declaration_in_an_ambient_external_module_declaration_cannot_reference_external_module_through_relative_external_module_name: string; + Could_not_find_the_best_common_type_of_types_of_all_return_statement_expressions: string; + Import_declaration_cannot_refer_to_external_module_reference_when_noResolve_option_is_set: string; + Duplicate_identifier_this_Compiler_uses_variable_declaration_this_to_capture_this_reference: string; + continue_statement_can_only_be_used_within_an_enclosing_iteration_statement: string; + break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement: string; + Jump_target_not_found: string; + Jump_target_cannot_cross_function_boundary: string; + Duplicate_identifier_super_Compiler_uses_super_to_capture_base_class_reference: string; + Expression_resolves_to_variable_declaration_this_that_compiler_uses_to_capture_this_reference: string; + Expression_resolves_to_super_that_compiler_uses_to_capture_base_class_reference: string; + TypeParameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_type_1: string; + TypeParameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_type_1: string; + TypeParameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_type_1: string; + TypeParameter_0_of_public_method_from_exported_class_has_or_is_using_private_type_1: string; + TypeParameter_0_of_method_from_exported_interface_has_or_is_using_private_type_1: string; + TypeParameter_0_of_exported_function_has_or_is_using_private_type_1: string; + TypeParameter_0_of_constructor_signature_from_exported_interface_is_using_inaccessible_module_1: string; + TypeParameter_0_of_call_signature_from_exported_interface_is_using_inaccessible_module_1: string; + TypeParameter_0_of_public_static_method_from_exported_class_is_using_inaccessible_module_1: string; + TypeParameter_0_of_public_method_from_exported_class_is_using_inaccessible_module_1: string; + TypeParameter_0_of_method_from_exported_interface_is_using_inaccessible_module_1: string; + TypeParameter_0_of_exported_function_is_using_inaccessible_module_1: string; + TypeParameter_0_of_exported_class_has_or_is_using_private_type_1: string; + TypeParameter_0_of_exported_interface_has_or_is_using_private_type_1: string; + TypeParameter_0_of_exported_class_is_using_inaccessible_module_1: string; + TypeParameter_0_of_exported_interface_is_using_inaccessible_module_1: string; + Duplicate_identifier_i_Compiler_uses_i_to_initialize_rest_parameter: string; + Duplicate_identifier_arguments_Compiler_uses_arguments_to_initialize_rest_parameters: string; + Type_of_conditional_0_must_be_identical_to_1_or_2: string; + Type_of_conditional_0_must_be_identical_to_1_2_or_3: string; + Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_an_external_module: string; + Constraint_of_a_type_parameter_cannot_reference_any_type_parameter_from_the_same_type_parameter_list: string; + Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: string; + Parameter_0_cannot_be_referenced_in_its_initializer: string; + Duplicate_string_index_signature: string; + Duplicate_number_index_signature: string; + All_declarations_of_an_interface_must_have_identical_type_parameters: string; + Expression_resolves_to_variable_declaration_i_that_compiler_uses_to_initialize_rest_parameter: string; + Type_0_is_missing_property_1_from_type_2: string; + Types_of_property_0_of_types_1_and_2_are_incompatible: string; + Types_of_property_0_of_types_1_and_2_are_incompatible_NL_3: string; + Property_0_defined_as_private_in_type_1_is_defined_as_public_in_type_2: string; + Property_0_defined_as_public_in_type_1_is_defined_as_private_in_type_2: string; + Types_0_and_1_define_property_2_as_private: string; + Call_signatures_of_types_0_and_1_are_incompatible: string; + Call_signatures_of_types_0_and_1_are_incompatible_NL_2: string; + Type_0_requires_a_call_signature_but_type_1_lacks_one: string; + Construct_signatures_of_types_0_and_1_are_incompatible: string; + Construct_signatures_of_types_0_and_1_are_incompatible_NL_2: string; + Type_0_requires_a_construct_signature_but_type_1_lacks_one: string; + Index_signatures_of_types_0_and_1_are_incompatible: string; + Index_signatures_of_types_0_and_1_are_incompatible_NL_2: string; + Call_signature_expects_0_or_fewer_parameters: string; + Could_not_apply_type_0_to_argument_1_which_is_of_type_2: string; + Class_0_defines_instance_member_accessor_1_but_extended_class_2_defines_it_as_instance_member_function: string; + Class_0_defines_instance_member_property_1_but_extended_class_2_defines_it_as_instance_member_function: string; + Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_accessor: string; + Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_property: string; + Types_of_static_property_0_of_class_1_and_class_2_are_incompatible: string; + Types_of_static_property_0_of_class_1_and_class_2_are_incompatible_NL_3: string; + Type_reference_cannot_refer_to_container_0: string; + Type_reference_must_refer_to_type: string; + In_enums_with_multiple_declarations_only_one_declaration_can_omit_an_initializer_for_the_first_enum_element: string; + _0_overload_s: string; + Variable_declaration_cannot_have_the_same_name_as_an_import_declaration: string; + Signature_expected_0_type_arguments_got_1_instead: string; + Property_0_defined_as_optional_in_type_1_but_is_required_in_type_2: string; + Types_0_and_1_originating_in_infinitely_expanding_type_reference_do_not_refer_to_same_named_type: string; + Types_0_and_1_originating_in_infinitely_expanding_type_reference_have_incompatible_type_arguments: string; + Types_0_and_1_originating_in_infinitely_expanding_type_reference_have_incompatible_type_arguments_NL_2: string; + Named_properties_0_of_types_1_and_2_are_not_identical: string; + Types_of_string_indexer_of_types_0_and_1_are_not_identical: string; + Types_of_number_indexer_of_types_0_and_1_are_not_identical: string; + Type_of_number_indexer_in_type_0_is_not_assignable_to_string_indexer_type_in_type_1_NL_2: string; + Type_of_property_0_in_type_1_is_not_assignable_to_string_indexer_type_in_type_2_NL_3: string; + Type_of_property_0_in_type_1_is_not_assignable_to_number_indexer_type_in_type_2_NL_3: string; + Static_property_0_defined_as_private_in_type_1_is_defined_as_public_in_type_2: string; + Static_property_0_defined_as_public_in_type_1_is_defined_as_private_in_type_2: string; + Types_0_and_1_define_static_property_2_as_private: string; + Current_host_does_not_support_0_option: string; + ECMAScript_target_version_0_not_supported_Specify_a_valid_target_version_1_default_or_2: string; + Module_code_generation_0_not_supported: string; + Could_not_find_file_0: string; + A_file_cannot_have_a_reference_to_itself: string; + Cannot_resolve_referenced_file_0: string; + Cannot_find_the_common_subdirectory_path_for_the_input_files: string; + Emit_Error_0: string; + Cannot_read_file_0_1: string; + Unsupported_file_encoding: string; + Locale_must_be_of_the_form_language_or_language_territory_For_example_0_or_1: string; + Unsupported_locale_0: string; + Execution_Failed_NL: string; + Invalid_call_to_up: string; + Invalid_call_to_down: string; + Base64_value_0_finished_with_a_continuation_bit: string; + Unknown_option_0: string; + Expected_0_arguments_to_message_got_1_instead: string; + Expected_the_message_0_to_have_1_arguments_but_it_had_2: string; + Could_not_delete_file_0: string; + Could_not_create_directory_0: string; + Error_while_executing_file_0: string; + Cannot_compile_external_modules_unless_the_module_flag_is_provided: string; + Option_mapRoot_cannot_be_specified_without_specifying_sourcemap_option: string; + Option_sourceRoot_cannot_be_specified_without_specifying_sourcemap_option: string; + Options_mapRoot_and_sourceRoot_cannot_be_specified_without_specifying_sourcemap_option: string; + Option_0_specified_without_1: string; + codepage_option_not_supported_on_current_platform: string; + Concatenate_and_emit_output_to_single_file: string; + Generates_corresponding_0_file: string; + Specifies_the_location_where_debugger_should_locate_map_files_instead_of_generated_locations: string; + Specifies_the_location_where_debugger_should_locate_TypeScript_files_instead_of_source_locations: string; + Watch_input_files: string; + Redirect_output_structure_to_the_directory: string; + Do_not_emit_comments_to_output: string; + Skip_resolution_and_preprocessing: string; + Specify_ECMAScript_target_version_0_default_or_1: string; + Specify_module_code_generation_0_or_1: string; + Print_this_message: string; + Print_the_compiler_s_version_0: string; + Allow_use_of_deprecated_0_keyword_when_referencing_an_external_module: string; + Specify_locale_for_errors_and_messages_For_example_0_or_1: string; + Syntax_0: string; + options: string; + file1: string; + Examples: string; + Options: string; + Insert_command_line_options_and_files_from_a_file: string; + Version_0: string; + Use_the_0_flag_to_see_options: string; + NL_Recompiling_0: string; + STRING: string; + KIND: string; + file2: string; + VERSION: string; + LOCATION: string; + DIRECTORY: string; + NUMBER: string; + Specify_the_codepage_to_use_when_opening_source_files: string; + Additional_locations: string; + This_version_of_the_Javascript_runtime_does_not_support_the_0_function: string; + Unknown_rule: string; + Invalid_line_number_0: string; + Warn_on_expressions_and_declarations_with_an_implied_any_type: string; + Variable_0_implicitly_has_an_any_type: string; + Parameter_0_of_1_implicitly_has_an_any_type: string; + Parameter_0_of_function_type_implicitly_has_an_any_type: string; + Member_0_of_object_type_implicitly_has_an_any_type: string; + new_expression_which_lacks_a_constructor_signature_implicitly_has_an_any_type: string; + _0_which_lacks_return_type_annotation_implicitly_has_an_any_return_type: string; + Function_expression_which_lacks_return_type_annotation_implicitly_has_an_any_return_type: string; + Parameter_0_of_lambda_function_implicitly_has_an_any_type: string; + Constructor_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type: string; + Lambda_Function_which_lacks_return_type_annotation_implicitly_has_an_any_return_type: string; + Array_Literal_implicitly_has_an_any_type_from_widening: string; + _0_which_lacks_get_accessor_and_parameter_type_annotation_on_set_accessor_implicitly_has_an_any_type: string; + Index_signature_of_object_type_implicitly_has_an_any_type: string; + Object_literal_s_property_0_implicitly_has_an_any_type_from_widening: string; + }; +} +declare module TypeScript { + enum DiagnosticCategory { + Warning = 0, + Error = 1, + Message = 2, + NoPrefix = 3, + } +} +declare module TypeScript { + var diagnosticInformationMap: IIndexable; +} +declare module TypeScript { + class ArrayUtilities { + static isArray(value: any): boolean; + static sequenceEquals(array1: T[], array2: T[], equals: (v1: T, v2: T) => boolean): boolean; + static contains(array: T[], value: T): boolean; + static groupBy(array: T[], func: (v: T) => string): any; + static distinct(array: T[], equalsFn?: (a: T, b: T) => boolean): T[]; + static min(array: T[], func: (v: T) => number): number; + static max(array: T[], func: (v: T) => number): number; + static last(array: T[]): T; + static lastOrDefault(array: T[], predicate: (v: T, index: number) => boolean): T; + static firstOrDefault(array: T[], func: (v: T, index: number) => boolean): T; + static first(array: T[], func?: (v: T, index: number) => boolean): T; + static sum(array: T[], func: (v: T) => number): number; + static select(values: T[], func: (v: T) => S): S[]; + static where(values: T[], func: (v: T) => boolean): T[]; + static any(array: T[], func: (v: T) => boolean): boolean; + static all(array: T[], func: (v: T) => boolean): boolean; + static binarySearch(array: number[], value: number): number; + static createArray(length: number, defaultValue: any): T[]; + static grow(array: T[], length: number, defaultValue: T): void; + static copy(sourceArray: T[], sourceIndex: number, destinationArray: T[], destinationIndex: number, length: number): void; + static indexOf(array: T[], predicate: (v: T) => boolean): number; + } +} +declare module TypeScript { + interface IBitVector { + valueAt(index: number): boolean; + setValueAt(index: number, value: boolean): void; + release(): void; + } + module BitVector { + function getBitVector(allowUndefinedValues: boolean): IBitVector; + } +} +declare module TypeScript { + interface IBitMatrix { + valueAt(x: number, y: number): boolean; + setValueAt(x: number, y: number, value: boolean): void; + release(): void; + } + module BitMatrix { + function getBitMatrix(allowUndefinedValues: boolean): IBitMatrix; + } +} +declare module TypeScript { + enum Constants { + Max31BitInteger = 1073741823, + Min31BitInteger = -1073741824, + } +} +declare module TypeScript { + enum AssertionLevel { + None = 0, + Normal = 1, + Aggressive = 2, + VeryAggressive = 3, + } + class Debug { + private static currentAssertionLevel; + static shouldAssert(level: AssertionLevel): boolean; + static assert(expression: any, message?: string, verboseDebugInfo?: () => string): void; + static fail(message?: string): void; + } +} +declare module TypeScript { + var LocalizedDiagnosticMessages: IIndexable; + class Location { + private _fileName; + private _lineMap; + private _start; + private _length; + constructor(fileName: string, lineMap: LineMap, start: number, length: number); + public fileName(): string; + public lineMap(): LineMap; + public line(): number; + public character(): number; + public start(): number; + public length(): number; + static equals(location1: Location, location2: Location): boolean; + } + class Diagnostic extends Location { + private _diagnosticKey; + private _arguments; + private _additionalLocations; + constructor(fileName: string, lineMap: LineMap, start: number, length: number, diagnosticKey: string, _arguments?: any[], additionalLocations?: Location[]); + public toJSON(key: any): any; + public diagnosticKey(): string; + public arguments(): any[]; + public text(): string; + public message(): string; + public additionalLocations(): Location[]; + static equals(diagnostic1: Diagnostic, diagnostic2: Diagnostic): boolean; + public info(): DiagnosticInfo; + } + function newLine(): string; + function getLocalizedText(diagnosticKey: string, args: any[]): string; + function getDiagnosticMessage(diagnosticKey: string, args: any[]): string; +} +declare module TypeScript { + interface DiagnosticInfo { + category: DiagnosticCategory; + message: string; + code: number; + } +} +declare module TypeScript { + class Errors { + static argument(argument: string, message?: string): Error; + static argumentOutOfRange(argument: string): Error; + static argumentNull(argument: string): Error; + static abstract(): Error; + static notYetImplemented(): Error; + static invalidOperation(message?: string): Error; + } +} +declare module TypeScript { + class Hash { + private static FNV_BASE; + private static FNV_PRIME; + private static computeFnv1aCharArrayHashCode(text, start, len); + static computeSimple31BitCharArrayHashCode(key: number[], start: number, len: number): number; + static computeSimple31BitStringHashCode(key: string): number; + static computeMurmur2StringHashCode(key: string, seed: number): number; + private static primes; + static getPrime(min: number): number; + static expandPrime(oldSize: number): number; + static combine(value: number, currentHash: number): number; + } +} +declare module TypeScript.Collections { + var DefaultHashTableCapacity: number; + class HashTable { + private hash; + private entries; + private count; + constructor(capacity: number, hash: (k: TKey) => number); + public set(key: TKey, value: TValue): void; + public add(key: TKey, value: TValue): void; + public containsKey(key: TKey): boolean; + public get(key: TKey): TValue; + private computeHashCode(key); + private addOrSet(key, value, throwOnExistingEntry); + private findEntry(key, hashCode); + private addEntry(key, value, hashCode); + private grow(); + } + function createHashTable(capacity?: number, hash?: (k: TKey) => number): HashTable; + function identityHashCode(value: any): number; +} +declare class Enumerator { + public atEnd(): boolean; + public moveNext(): boolean; + public item(): any; + constructor(o: any); +} +declare module process { + var argv: string[]; + var platform: string; + function on(event: string, handler: (arg: any) => void): void; + module stdout { + function write(str: string): any; + function on(event: string, action: () => void): void; + } + module stderr { + function write(str: string): any; + function on(event: string, action: () => void): void; + } + module mainModule { + var filename: string; + } + function exit(exitCode?: number): any; +} +declare var Buffer: new(str: string, encoding?: string) => any; +declare module TypeScript { + var nodeMakeDirectoryTime: number; + var nodeCreateBufferTime: number; + var nodeWriteFileSyncTime: number; + enum ByteOrderMark { + None = 0, + Utf8 = 1, + Utf16BigEndian = 2, + Utf16LittleEndian = 3, + } + class FileInformation { + public contents: string; + public byteOrderMark: ByteOrderMark; + constructor(contents: string, byteOrderMark: ByteOrderMark); + } + interface IEnvironment { + supportsCodePage(): boolean; + readFile(path: string, codepage: number): FileInformation; + writeFile(path: string, contents: string, writeByteOrderMark: boolean): void; + deleteFile(path: string): void; + fileExists(path: string): boolean; + directoryExists(path: string): boolean; + listFiles(path: string, re?: RegExp, options?: { + recursive?: boolean; + }): string[]; + arguments: string[]; + standardOut: ITextWriter; + currentDirectory(): string; + newLine: string; + } + var Environment: IEnvironment; +} +declare module TypeScript { + interface IIndexable { + [s: string]: T; + } +} +declare module TypeScript { + module IntegerUtilities { + function integerDivide(numerator: number, denominator: number): number; + function integerMultiplyLow32Bits(n1: number, n2: number): number; + function integerMultiplyHigh32Bits(n1: number, n2: number): number; + function isInteger(text: string): boolean; + function isHexInteger(text: string): boolean; + } +} +declare module TypeScript { + interface Iterator { + moveNext(): boolean; + current(): T; + } +} +declare module TypeScript { + interface ILineAndCharacter { + line: number; + character: number; + } +} +declare module TypeScript { + class LineMap { + private _computeLineStarts; + private length; + static empty: LineMap; + private _lineStarts; + constructor(_computeLineStarts: () => number[], length: number); + public toJSON(key: any): { + lineStarts: number[]; + length: number; + }; + public equals(other: LineMap): boolean; + public lineStarts(): number[]; + public lineCount(): number; + public getPosition(line: number, character: number): number; + public getLineNumberFromPosition(position: number): number; + public getLineStartPosition(lineNumber: number): number; + public fillLineAndCharacterFromPosition(position: number, lineAndCharacter: ILineAndCharacter): void; + public getLineAndCharacterFromPosition(position: number): LineAndCharacter; + } +} +declare module TypeScript { + class LineAndCharacter { + private _line; + private _character; + constructor(line: number, character: number); + public line(): number; + public character(): number; + } +} +declare module TypeScript { + class MathPrototype { + static max(a: number, b: number): number; + static min(a: number, b: number): number; + } +} +declare module TypeScript.Collections { + var DefaultStringTableCapacity: number; + class StringTable { + private entries; + private count; + constructor(capacity: number); + public addCharArray(key: number[], start: number, len: number): string; + private findCharArrayEntry(key, start, len, hashCode); + private addEntry(text, hashCode); + private grow(); + private static textCharArrayEquals(text, array, start, length); + } + var DefaultStringTable: StringTable; +} +declare module TypeScript { + class StringUtilities { + static isString(value: any): boolean; + static fromCharCodeArray(array: number[]): string; + static endsWith(string: string, value: string): boolean; + static startsWith(string: string, value: string): boolean; + static copyTo(source: string, sourceIndex: number, destination: number[], destinationIndex: number, count: number): void; + static repeat(value: string, count: number): string; + static stringEquals(val1: string, val2: string): boolean; + } +} +declare var global: any; +declare module TypeScript { + class Timer { + public startTime: number; + public time: number; + public start(): void; + public end(): void; + } +} +declare module TypeScript { + enum SyntaxKind { + None = 0, + List = 1, + SeparatedList = 2, + TriviaList = 3, + WhitespaceTrivia = 4, + NewLineTrivia = 5, + MultiLineCommentTrivia = 6, + SingleLineCommentTrivia = 7, + SkippedTokenTrivia = 8, + ErrorToken = 9, + EndOfFileToken = 10, + IdentifierName = 11, + RegularExpressionLiteral = 12, + NumericLiteral = 13, + StringLiteral = 14, + NoSubstitutionStringTemplateLiteral = 15, + StringTemplateHead = 16, + StringTemplateMiddle = 17, + StringTemplateTail = 18, + DollarSignOpenBraceToken = 19, + BreakKeyword = 20, + CaseKeyword = 21, + CatchKeyword = 22, + ContinueKeyword = 23, + DebuggerKeyword = 24, + DefaultKeyword = 25, + DeleteKeyword = 26, + DoKeyword = 27, + ElseKeyword = 28, + FalseKeyword = 29, + FinallyKeyword = 30, + ForKeyword = 31, + FunctionKeyword = 32, + IfKeyword = 33, + InKeyword = 34, + InstanceOfKeyword = 35, + NewKeyword = 36, + NullKeyword = 37, + ReturnKeyword = 38, + SwitchKeyword = 39, + ThisKeyword = 40, + ThrowKeyword = 41, + TrueKeyword = 42, + TryKeyword = 43, + TypeOfKeyword = 44, + VarKeyword = 45, + VoidKeyword = 46, + WhileKeyword = 47, + WithKeyword = 48, + ClassKeyword = 49, + ConstKeyword = 50, + EnumKeyword = 51, + ExportKeyword = 52, + ExtendsKeyword = 53, + ImportKeyword = 54, + SuperKeyword = 55, + ImplementsKeyword = 56, + InterfaceKeyword = 57, + LetKeyword = 58, + PackageKeyword = 59, + PrivateKeyword = 60, + ProtectedKeyword = 61, + PublicKeyword = 62, + StaticKeyword = 63, + YieldKeyword = 64, + AnyKeyword = 65, + BooleanKeyword = 66, + ConstructorKeyword = 67, + DeclareKeyword = 68, + GetKeyword = 69, + ModuleKeyword = 70, + RequireKeyword = 71, + NumberKeyword = 72, + SetKeyword = 73, + StringKeyword = 74, + OpenBraceToken = 75, + CloseBraceToken = 76, + OpenParenToken = 77, + CloseParenToken = 78, + OpenBracketToken = 79, + CloseBracketToken = 80, + DotToken = 81, + DotDotDotToken = 82, + SemicolonToken = 83, + CommaToken = 84, + LessThanToken = 85, + GreaterThanToken = 86, + LessThanEqualsToken = 87, + GreaterThanEqualsToken = 88, + EqualsEqualsToken = 89, + EqualsGreaterThanToken = 90, + ExclamationEqualsToken = 91, + EqualsEqualsEqualsToken = 92, + ExclamationEqualsEqualsToken = 93, + PlusToken = 94, + MinusToken = 95, + AsteriskToken = 96, + PercentToken = 97, + PlusPlusToken = 98, + MinusMinusToken = 99, + LessThanLessThanToken = 100, + GreaterThanGreaterThanToken = 101, + GreaterThanGreaterThanGreaterThanToken = 102, + AmpersandToken = 103, + BarToken = 104, + CaretToken = 105, + ExclamationToken = 106, + TildeToken = 107, + AmpersandAmpersandToken = 108, + BarBarToken = 109, + QuestionToken = 110, + ColonToken = 111, + EqualsToken = 112, + PlusEqualsToken = 113, + MinusEqualsToken = 114, + AsteriskEqualsToken = 115, + PercentEqualsToken = 116, + LessThanLessThanEqualsToken = 117, + GreaterThanGreaterThanEqualsToken = 118, + GreaterThanGreaterThanGreaterThanEqualsToken = 119, + AmpersandEqualsToken = 120, + BarEqualsToken = 121, + CaretEqualsToken = 122, + SlashToken = 123, + SlashEqualsToken = 124, + SourceUnit = 125, + QualifiedName = 126, + ObjectType = 127, + FunctionType = 128, + ArrayType = 129, + ConstructorType = 130, + GenericType = 131, + TypeQuery = 132, + InterfaceDeclaration = 133, + FunctionDeclaration = 134, + ModuleDeclaration = 135, + ClassDeclaration = 136, + EnumDeclaration = 137, + ImportDeclaration = 138, + ExportAssignment = 139, + MemberFunctionDeclaration = 140, + MemberVariableDeclaration = 141, + ConstructorDeclaration = 142, + IndexMemberDeclaration = 143, + GetAccessor = 144, + SetAccessor = 145, + PropertySignature = 146, + CallSignature = 147, + ConstructSignature = 148, + IndexSignature = 149, + MethodSignature = 150, + Block = 151, + IfStatement = 152, + VariableStatement = 153, + ExpressionStatement = 154, + ReturnStatement = 155, + SwitchStatement = 156, + BreakStatement = 157, + ContinueStatement = 158, + ForStatement = 159, + ForInStatement = 160, + EmptyStatement = 161, + ThrowStatement = 162, + WhileStatement = 163, + TryStatement = 164, + LabeledStatement = 165, + DoStatement = 166, + DebuggerStatement = 167, + WithStatement = 168, + PlusExpression = 169, + NegateExpression = 170, + BitwiseNotExpression = 171, + LogicalNotExpression = 172, + PreIncrementExpression = 173, + PreDecrementExpression = 174, + DeleteExpression = 175, + TypeOfExpression = 176, + VoidExpression = 177, + CommaExpression = 178, + AssignmentExpression = 179, + AddAssignmentExpression = 180, + SubtractAssignmentExpression = 181, + MultiplyAssignmentExpression = 182, + DivideAssignmentExpression = 183, + ModuloAssignmentExpression = 184, + AndAssignmentExpression = 185, + ExclusiveOrAssignmentExpression = 186, + OrAssignmentExpression = 187, + LeftShiftAssignmentExpression = 188, + SignedRightShiftAssignmentExpression = 189, + UnsignedRightShiftAssignmentExpression = 190, + ConditionalExpression = 191, + LogicalOrExpression = 192, + LogicalAndExpression = 193, + BitwiseOrExpression = 194, + BitwiseExclusiveOrExpression = 195, + BitwiseAndExpression = 196, + EqualsWithTypeConversionExpression = 197, + NotEqualsWithTypeConversionExpression = 198, + EqualsExpression = 199, + NotEqualsExpression = 200, + LessThanExpression = 201, + GreaterThanExpression = 202, + LessThanOrEqualExpression = 203, + GreaterThanOrEqualExpression = 204, + InstanceOfExpression = 205, + InExpression = 206, + LeftShiftExpression = 207, + SignedRightShiftExpression = 208, + UnsignedRightShiftExpression = 209, + MultiplyExpression = 210, + DivideExpression = 211, + ModuloExpression = 212, + AddExpression = 213, + SubtractExpression = 214, + PostIncrementExpression = 215, + PostDecrementExpression = 216, + MemberAccessExpression = 217, + InvocationExpression = 218, + ArrayLiteralExpression = 219, + ObjectLiteralExpression = 220, + ObjectCreationExpression = 221, + ParenthesizedExpression = 222, + ParenthesizedArrowFunctionExpression = 223, + SimpleArrowFunctionExpression = 224, + CastExpression = 225, + ElementAccessExpression = 226, + FunctionExpression = 227, + StringTemplateSubstitutionExpression = 228, + SubstitutionStringTemplate = 229, + NoSubstitutionStringTemplateInvocationExpression = 230, + SubstitutionStringTemplateInvocationExpression = 231, + OmittedExpression = 232, + VariableDeclaration = 233, + VariableDeclarator = 234, + ArgumentList = 235, + ParameterList = 236, + TypeArgumentList = 237, + TypeParameterList = 238, + ExtendsHeritageClause = 239, + ImplementsHeritageClause = 240, + EqualsValueClause = 241, + CaseSwitchClause = 242, + DefaultSwitchClause = 243, + ElseClause = 244, + CatchClause = 245, + FinallyClause = 246, + TypeParameter = 247, + Constraint = 248, + SimplePropertyAssignment = 249, + FunctionPropertyAssignment = 250, + Parameter = 251, + EnumElement = 252, + TypeAnnotation = 253, + ExternalModuleReference = 254, + ModuleNameModuleReference = 255, + Last = 255, + FirstStandardKeyword = 20, + LastStandardKeyword = 48, + FirstFutureReservedKeyword = 49, + LastFutureReservedKeyword = 55, + FirstFutureReservedStrictKeyword = 56, + LastFutureReservedStrictKeyword = 64, + FirstTypeScriptKeyword = 65, + LastTypeScriptKeyword = 74, + FirstKeyword = 20, + LastKeyword = 74, + FirstToken = 9, + LastToken = 124, + FirstPunctuation = 75, + LastPunctuation = 124, + FirstFixedWidth = 20, + LastFixedWidth = 124, + FirstTrivia = 4, + LastTrivia = 8, + } +} +declare module TypeScript.SyntaxFacts { + function getTokenKind(text: string): SyntaxKind; + function getText(kind: SyntaxKind): string; + function isTokenKind(kind: SyntaxKind): boolean; + function isAnyKeyword(kind: SyntaxKind): boolean; + function isStandardKeyword(kind: SyntaxKind): boolean; + function isFutureReservedKeyword(kind: SyntaxKind): boolean; + function isFutureReservedStrictKeyword(kind: SyntaxKind): boolean; + function isAnyPunctuation(kind: SyntaxKind): boolean; + function isPrefixUnaryExpressionOperatorToken(tokenKind: SyntaxKind): boolean; + function isBinaryExpressionOperatorToken(tokenKind: SyntaxKind): boolean; + function getPrefixUnaryExpressionFromOperatorToken(tokenKind: SyntaxKind): SyntaxKind; + function getPostfixUnaryExpressionFromOperatorToken(tokenKind: SyntaxKind): SyntaxKind; + function getBinaryExpressionFromOperatorToken(tokenKind: SyntaxKind): SyntaxKind; + function getOperatorTokenFromBinaryExpression(tokenKind: SyntaxKind): SyntaxKind; + function isAnyDivideToken(kind: SyntaxKind): boolean; + function isAnyDivideOrRegularExpressionToken(kind: SyntaxKind): boolean; +} +declare var argumentChecks: boolean; +declare var forPrettyPrinter: boolean; +interface ITypeDefinition { + name: string; + baseType: string; + interfaces?: string[]; + children: IMemberDefinition[]; + isTypeScriptSpecific: boolean; +} +interface IMemberDefinition { + name: string; + type?: string; + isToken?: boolean; + isList?: boolean; + isSeparatedList?: boolean; + requiresAtLeastOneItem?: boolean; + isOptional?: boolean; + tokenKinds?: string[]; + isTypeScriptSpecific: boolean; + elementType?: string; +} +declare var interfaces: TypeScript.IIndexable; +declare var definitions: ITypeDefinition[]; +declare function getStringWithoutSuffix(definition: string): string; +declare function getNameWithoutSuffix(definition: ITypeDefinition): string; +declare function getType(child: IMemberDefinition): string; +declare var hasKind: boolean; +declare function pascalCase(value: string): string; +declare function camelCase(value: string): string; +declare function getSafeName(child: IMemberDefinition): string; +declare function getPropertyAccess(child: IMemberDefinition): string; +declare function generateProperties(definition: ITypeDefinition): string; +declare function generateNullChecks(definition: ITypeDefinition): string; +declare function generateIfKindCheck(child: IMemberDefinition, tokenKinds: string[], indent: string): string; +declare function generateSwitchCase(tokenKind: string, indent: string): string; +declare function generateBreakStatement(indent: string): string; +declare function generateSwitchCases(tokenKinds: string[], indent: string): string; +declare function generateDefaultCase(child: IMemberDefinition, indent: string): string; +declare function generateSwitchKindCheck(child: IMemberDefinition, tokenKinds: string[], indent: string): string; +declare function tokenKinds(child: IMemberDefinition): string[]; +declare function generateKindCheck(child: IMemberDefinition): string; +declare function generateKindChecks(definition: ITypeDefinition): string; +declare function generateArgumentChecks(definition: ITypeDefinition): string; +declare function generateConstructor(definition: ITypeDefinition): string; +declare function isOptional(child: IMemberDefinition): boolean; +declare function generateFactory1Method(definition: ITypeDefinition): string; +declare function isKeywordOrPunctuation(kind: string): boolean; +declare function isDefaultConstructable(definition: ITypeDefinition): boolean; +declare function isMandatory(child: IMemberDefinition): boolean; +declare function generateFactory2Method(definition: ITypeDefinition): string; +declare function generateFactoryMethod(definition: ITypeDefinition): string; +declare function generateAcceptMethods(definition: ITypeDefinition): string; +declare function generateIsMethod(definition: ITypeDefinition): string; +declare function generateKindMethod(definition: ITypeDefinition): string; +declare function generateSlotMethods(definition: ITypeDefinition): string; +declare function generateFirstTokenMethod(definition: ITypeDefinition): string; +declare function generateLastTokenMethod(definition: ITypeDefinition): string; +declare function generateInsertChildrenIntoMethod(definition: ITypeDefinition): string; +declare function baseType(definition: ITypeDefinition): ITypeDefinition; +declare function memberDefinitionType(child: IMemberDefinition): ITypeDefinition; +declare function derivesFrom(def1: ITypeDefinition, def2: ITypeDefinition): boolean; +declare function contains(definition: ITypeDefinition, child: IMemberDefinition): boolean; +declare function generateAccessors(definition: ITypeDefinition): string; +declare function generateWithMethod(definition: ITypeDefinition, child: IMemberDefinition): string; +declare function generateWithMethods(definition: ITypeDefinition): string; +declare function generateTriviaMethods(definition: ITypeDefinition): string; +declare function generateUpdateMethod(definition: ITypeDefinition): string; +declare function generateIsTypeScriptSpecificMethod(definition: ITypeDefinition): string; +declare function couldBeRegularExpressionToken(child: IMemberDefinition): boolean; +declare function generateStructuralEqualsMethod(definition: ITypeDefinition): string; +declare function generateNode(definition: ITypeDefinition): string; +declare function generateNodes(): string; +declare function isInterface(name: string): boolean; +declare function isNodeOrToken(child: IMemberDefinition): boolean; +declare function generateRewriter(): string; +declare function generateToken(isFixedWidth: boolean, leading: boolean, trailing: boolean): string; +declare function generateTokens(): string; +declare function generateWalker(): string; +declare function firstEnumName(e: any, value: number): any; +declare function generateKeywordCondition(keywords: { + text: string; + kind: TypeScript.SyntaxKind; +}[], currentCharacter: number, indent: string): string; +declare function generateScannerUtilities(): string; +declare function generateVisitor(): string; +declare function generateFactory(): string; +declare var syntaxNodes: string; +declare var rewriter: string; +declare var tokens: string; +declare var walker: string; +declare var scannerUtilities: string; +declare var visitor: string; +declare var factory: string; diff --git a/src/services/syntax/characterInfo.ts b/src/services/syntax/characterInfo.ts new file mode 100644 index 00000000000..6ab4a91ddc8 --- /dev/null +++ b/src/services/syntax/characterInfo.ts @@ -0,0 +1,70 @@ +/// + +module TypeScript { + export module CharacterInfo { + export function isDecimalDigit(c: number): boolean { + return c >= CharacterCodes._0 && c <= CharacterCodes._9; + } + + export function isOctalDigit(c: number): boolean { + return c >= CharacterCodes._0 && c <= CharacterCodes._7; + } + + export function isHexDigit(c: number): boolean { + return CharacterInfo.isDecimalDigit(c) || + (c >= CharacterCodes.A && c <= CharacterCodes.F) || + (c >= CharacterCodes.a && c <= CharacterCodes.f); + } + + export function hexValue(c: number): number { + // Debug.assert(isHexDigit(c)); + return CharacterInfo.isDecimalDigit(c) + ? (c - CharacterCodes._0) + : (c >= CharacterCodes.A && c <= CharacterCodes.F) + ? c - CharacterCodes.A + 10 + : c - CharacterCodes.a + 10; + } + + export function isWhitespace(ch: number): boolean { + switch (ch) { + // Unicode 3.0 space characters. + case CharacterCodes.space: + case CharacterCodes.nonBreakingSpace: + case CharacterCodes.enQuad: + case CharacterCodes.emQuad: + case CharacterCodes.enSpace: + case CharacterCodes.emSpace: + case CharacterCodes.threePerEmSpace: + case CharacterCodes.fourPerEmSpace: + case CharacterCodes.sixPerEmSpace: + case CharacterCodes.figureSpace: + case CharacterCodes.punctuationSpace: + case CharacterCodes.thinSpace: + case CharacterCodes.hairSpace: + case CharacterCodes.zeroWidthSpace: + case CharacterCodes.narrowNoBreakSpace: + case CharacterCodes.ideographicSpace: + + case CharacterCodes.tab: + case CharacterCodes.verticalTab: + case CharacterCodes.formFeed: + case CharacterCodes.byteOrderMark: + return true; + } + + return false; + } + + export function isLineTerminator(ch: number): boolean { + switch (ch) { + case CharacterCodes.carriageReturn: + case CharacterCodes.lineFeed: + case CharacterCodes.paragraphSeparator: + case CharacterCodes.lineSeparator: + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/services/syntax/constants.ts b/src/services/syntax/constants.ts new file mode 100644 index 00000000000..13b3d8ad754 --- /dev/null +++ b/src/services/syntax/constants.ts @@ -0,0 +1,26 @@ +/// + +module TypeScript { + export enum SyntaxConstants { + None = 0, + + // Masks that we use to place information about a node into a single int. The first bit tells + // us if we've computed the data for a node. + // + // The second bit tells us if the node is incrementally reusable if it does not + // containe any skipped tokens, zero width tokens, regex tokens in it ("/", "/=" or "/.../"), + // and contains no tokens that were parser generated. + // + // The next bit lets us know if the nodes was parsed in a strict context or node. A node can + // only be used by the incremental parser if it is parsed in the same strict context as before. + // last masks off the part of the int + // + // The width of the node is stored in the remainder of the int. This allows us up to 512MB + // for a node by using all 29 bits. However, in the common case, we'll use less than 29 bits + // for the width. Thus, the info will be stored in a single int in chakra. + NodeDataComputed = 0x00000001, // 0000 0000 0000 0000 0000 0000 0000 0001 + NodeIncrementallyUnusableMask = 0x00000002, // 0000 0000 0000 0000 0000 0000 0000 0010 + NodeParsedInStrictModeMask = 0x00000004, // 0000 0000 0000 0000 0000 0000 0000 0100 + NodeFullWidthShift = 3, // 1111 1111 1111 1111 1111 1111 1111 1000 + } +} \ No newline at end of file diff --git a/src/services/syntax/defaultSyntaxVisitor.generated.ts b/src/services/syntax/defaultSyntaxVisitor.generated.ts new file mode 100644 index 00000000000..041b72b9359 --- /dev/null +++ b/src/services/syntax/defaultSyntaxVisitor.generated.ts @@ -0,0 +1,353 @@ +/// + +module TypeScript { + export class SyntaxVisitor implements ISyntaxVisitor { + public defaultVisit(node: ISyntaxNodeOrToken): any { + return null; + } + + public visitToken(token: ISyntaxToken): any { + return this.defaultVisit(token); + } + + public visitSourceUnit(node: SourceUnitSyntax): any { + return this.defaultVisit(node); + } + + public visitQualifiedName(node: QualifiedNameSyntax): any { + return this.defaultVisit(node); + } + + public visitObjectType(node: ObjectTypeSyntax): any { + return this.defaultVisit(node); + } + + public visitFunctionType(node: FunctionTypeSyntax): any { + return this.defaultVisit(node); + } + + public visitArrayType(node: ArrayTypeSyntax): any { + return this.defaultVisit(node); + } + + public visitConstructorType(node: ConstructorTypeSyntax): any { + return this.defaultVisit(node); + } + + public visitGenericType(node: GenericTypeSyntax): any { + return this.defaultVisit(node); + } + + public visitTypeQuery(node: TypeQuerySyntax): any { + return this.defaultVisit(node); + } + + public visitInterfaceDeclaration(node: InterfaceDeclarationSyntax): any { + return this.defaultVisit(node); + } + + public visitFunctionDeclaration(node: FunctionDeclarationSyntax): any { + return this.defaultVisit(node); + } + + public visitModuleDeclaration(node: ModuleDeclarationSyntax): any { + return this.defaultVisit(node); + } + + public visitClassDeclaration(node: ClassDeclarationSyntax): any { + return this.defaultVisit(node); + } + + public visitEnumDeclaration(node: EnumDeclarationSyntax): any { + return this.defaultVisit(node); + } + + public visitImportDeclaration(node: ImportDeclarationSyntax): any { + return this.defaultVisit(node); + } + + public visitExportAssignment(node: ExportAssignmentSyntax): any { + return this.defaultVisit(node); + } + + public visitMemberFunctionDeclaration(node: MemberFunctionDeclarationSyntax): any { + return this.defaultVisit(node); + } + + public visitMemberVariableDeclaration(node: MemberVariableDeclarationSyntax): any { + return this.defaultVisit(node); + } + + public visitConstructorDeclaration(node: ConstructorDeclarationSyntax): any { + return this.defaultVisit(node); + } + + public visitIndexMemberDeclaration(node: IndexMemberDeclarationSyntax): any { + return this.defaultVisit(node); + } + + public visitGetAccessor(node: GetAccessorSyntax): any { + return this.defaultVisit(node); + } + + public visitSetAccessor(node: SetAccessorSyntax): any { + return this.defaultVisit(node); + } + + public visitPropertySignature(node: PropertySignatureSyntax): any { + return this.defaultVisit(node); + } + + public visitCallSignature(node: CallSignatureSyntax): any { + return this.defaultVisit(node); + } + + public visitConstructSignature(node: ConstructSignatureSyntax): any { + return this.defaultVisit(node); + } + + public visitIndexSignature(node: IndexSignatureSyntax): any { + return this.defaultVisit(node); + } + + public visitMethodSignature(node: MethodSignatureSyntax): any { + return this.defaultVisit(node); + } + + public visitBlock(node: BlockSyntax): any { + return this.defaultVisit(node); + } + + public visitIfStatement(node: IfStatementSyntax): any { + return this.defaultVisit(node); + } + + public visitVariableStatement(node: VariableStatementSyntax): any { + return this.defaultVisit(node); + } + + public visitExpressionStatement(node: ExpressionStatementSyntax): any { + return this.defaultVisit(node); + } + + public visitReturnStatement(node: ReturnStatementSyntax): any { + return this.defaultVisit(node); + } + + public visitSwitchStatement(node: SwitchStatementSyntax): any { + return this.defaultVisit(node); + } + + public visitBreakStatement(node: BreakStatementSyntax): any { + return this.defaultVisit(node); + } + + public visitContinueStatement(node: ContinueStatementSyntax): any { + return this.defaultVisit(node); + } + + public visitForStatement(node: ForStatementSyntax): any { + return this.defaultVisit(node); + } + + public visitForInStatement(node: ForInStatementSyntax): any { + return this.defaultVisit(node); + } + + public visitEmptyStatement(node: EmptyStatementSyntax): any { + return this.defaultVisit(node); + } + + public visitThrowStatement(node: ThrowStatementSyntax): any { + return this.defaultVisit(node); + } + + public visitWhileStatement(node: WhileStatementSyntax): any { + return this.defaultVisit(node); + } + + public visitTryStatement(node: TryStatementSyntax): any { + return this.defaultVisit(node); + } + + public visitLabeledStatement(node: LabeledStatementSyntax): any { + return this.defaultVisit(node); + } + + public visitDoStatement(node: DoStatementSyntax): any { + return this.defaultVisit(node); + } + + public visitDebuggerStatement(node: DebuggerStatementSyntax): any { + return this.defaultVisit(node); + } + + public visitWithStatement(node: WithStatementSyntax): any { + return this.defaultVisit(node); + } + + public visitPrefixUnaryExpression(node: PrefixUnaryExpressionSyntax): any { + return this.defaultVisit(node); + } + + public visitDeleteExpression(node: DeleteExpressionSyntax): any { + return this.defaultVisit(node); + } + + public visitTypeOfExpression(node: TypeOfExpressionSyntax): any { + return this.defaultVisit(node); + } + + public visitVoidExpression(node: VoidExpressionSyntax): any { + return this.defaultVisit(node); + } + + public visitConditionalExpression(node: ConditionalExpressionSyntax): any { + return this.defaultVisit(node); + } + + public visitBinaryExpression(node: BinaryExpressionSyntax): any { + return this.defaultVisit(node); + } + + public visitPostfixUnaryExpression(node: PostfixUnaryExpressionSyntax): any { + return this.defaultVisit(node); + } + + public visitMemberAccessExpression(node: MemberAccessExpressionSyntax): any { + return this.defaultVisit(node); + } + + public visitInvocationExpression(node: InvocationExpressionSyntax): any { + return this.defaultVisit(node); + } + + public visitArrayLiteralExpression(node: ArrayLiteralExpressionSyntax): any { + return this.defaultVisit(node); + } + + public visitObjectLiteralExpression(node: ObjectLiteralExpressionSyntax): any { + return this.defaultVisit(node); + } + + public visitObjectCreationExpression(node: ObjectCreationExpressionSyntax): any { + return this.defaultVisit(node); + } + + public visitParenthesizedExpression(node: ParenthesizedExpressionSyntax): any { + return this.defaultVisit(node); + } + + public visitParenthesizedArrowFunctionExpression(node: ParenthesizedArrowFunctionExpressionSyntax): any { + return this.defaultVisit(node); + } + + public visitSimpleArrowFunctionExpression(node: SimpleArrowFunctionExpressionSyntax): any { + return this.defaultVisit(node); + } + + public visitCastExpression(node: CastExpressionSyntax): any { + return this.defaultVisit(node); + } + + public visitElementAccessExpression(node: ElementAccessExpressionSyntax): any { + return this.defaultVisit(node); + } + + public visitFunctionExpression(node: FunctionExpressionSyntax): any { + return this.defaultVisit(node); + } + + public visitOmittedExpression(node: OmittedExpressionSyntax): any { + return this.defaultVisit(node); + } + + public visitVariableDeclaration(node: VariableDeclarationSyntax): any { + return this.defaultVisit(node); + } + + public visitVariableDeclarator(node: VariableDeclaratorSyntax): any { + return this.defaultVisit(node); + } + + public visitArgumentList(node: ArgumentListSyntax): any { + return this.defaultVisit(node); + } + + public visitParameterList(node: ParameterListSyntax): any { + return this.defaultVisit(node); + } + + public visitTypeArgumentList(node: TypeArgumentListSyntax): any { + return this.defaultVisit(node); + } + + public visitTypeParameterList(node: TypeParameterListSyntax): any { + return this.defaultVisit(node); + } + + public visitHeritageClause(node: HeritageClauseSyntax): any { + return this.defaultVisit(node); + } + + public visitEqualsValueClause(node: EqualsValueClauseSyntax): any { + return this.defaultVisit(node); + } + + public visitCaseSwitchClause(node: CaseSwitchClauseSyntax): any { + return this.defaultVisit(node); + } + + public visitDefaultSwitchClause(node: DefaultSwitchClauseSyntax): any { + return this.defaultVisit(node); + } + + public visitElseClause(node: ElseClauseSyntax): any { + return this.defaultVisit(node); + } + + public visitCatchClause(node: CatchClauseSyntax): any { + return this.defaultVisit(node); + } + + public visitFinallyClause(node: FinallyClauseSyntax): any { + return this.defaultVisit(node); + } + + public visitTypeParameter(node: TypeParameterSyntax): any { + return this.defaultVisit(node); + } + + public visitConstraint(node: ConstraintSyntax): any { + return this.defaultVisit(node); + } + + public visitSimplePropertyAssignment(node: SimplePropertyAssignmentSyntax): any { + return this.defaultVisit(node); + } + + public visitFunctionPropertyAssignment(node: FunctionPropertyAssignmentSyntax): any { + return this.defaultVisit(node); + } + + public visitParameter(node: ParameterSyntax): any { + return this.defaultVisit(node); + } + + public visitEnumElement(node: EnumElementSyntax): any { + return this.defaultVisit(node); + } + + public visitTypeAnnotation(node: TypeAnnotationSyntax): any { + return this.defaultVisit(node); + } + + public visitExternalModuleReference(node: ExternalModuleReferenceSyntax): any { + return this.defaultVisit(node); + } + + public visitModuleNameModuleReference(node: ModuleNameModuleReferenceSyntax): any { + return this.defaultVisit(node); + } + } +} \ No newline at end of file diff --git a/src/services/syntax/depthLimitedWalker.ts b/src/services/syntax/depthLimitedWalker.ts new file mode 100644 index 00000000000..79df1ebd836 --- /dev/null +++ b/src/services/syntax/depthLimitedWalker.ts @@ -0,0 +1,21 @@ +/// + +module TypeScript { + export class DepthLimitedWalker extends SyntaxWalker { + private _depth: number = 0; + private _maximumDepth: number = 0; + + constructor(maximumDepth: number) { + super(); + this._maximumDepth = maximumDepth; + } + + public visitNode(node: ISyntaxNode): void { + if (this._depth < this._maximumDepth) { + this._depth++; + super.visitNode(node); + this._depth--; + } + } + } +} \ No newline at end of file diff --git a/src/services/syntax/emitter.ts b/src/services/syntax/emitter.ts new file mode 100644 index 00000000000..bfcae7d5bb3 --- /dev/null +++ b/src/services/syntax/emitter.ts @@ -0,0 +1,1246 @@ +/// + +module TypeScript.Emitter1 { + function callSignature(parameter: ParameterSyntax): CallSignatureSyntax { + return CallSignatureSyntax.create1().withParameterList( + ParameterListSyntax.create1().withParameter(parameter)); + } + + // Class that makes sure we're not reusing tokens in a tree + class EnsureTokenUniquenessRewriter extends SyntaxRewriter { + private tokenTable = Collections.createHashTable(Collections.DefaultHashTableCapacity, Collections.identityHashCode); + + public visitToken(token: ISyntaxToken): ISyntaxToken { + if (this.tokenTable.containsKey(token)) { + // already saw this token. so clone it and return a new one. so that the tree stays + // unique/ + return token.clone(); + } + + this.tokenTable.add(token, token); + return token; + } + } + + class EmitterImpl extends SyntaxRewriter { + private space: ISyntaxTriviaList; + private newLine: ISyntaxTriviaList; + private factory: Syntax.IFactory = Syntax.normalModeFactory; + + // A copy of the syntax tree we keep around so that we can determine where tokens were + // before we started moving them around. + private syntaxTreeCopy: SyntaxTree; + + constructor(syntaxTree: SyntaxTree, private options: FormattingOptions) { + super(); + + this.options = options || FormattingOptions.defaultOptions; + + // TODO: use proper new line based on options. + this.space = Syntax.spaceTriviaList; + this.newLine = Syntax.triviaList([Syntax.carriageReturnLineFeedTrivia]); + + this.syntaxTreeCopy = Parser.parse(syntaxTree.fileName(), SimpleText.fromString(syntaxTree.sourceUnit().fullText()), syntaxTree.isDeclaration(), syntaxTree.parseOptions()); + } + + private columnForStartOfToken(token: ISyntaxToken): number { + return Indentation.columnForStartOfTokenAtPosition(this.syntaxTreeCopy, token.fullStart(), this.options); + } + + private columnForEndOfToken(token: ISyntaxToken): number { + return Indentation.columnForEndOfTokenAtPosition(this.syntaxTreeCopy, token.fullStart(), this.options); + } + + private indentationTrivia(column: number): ISyntaxTriviaList { + var triviaArray = column === 0 ? null : [Indentation.indentationTrivia(column, this.options)]; + return Syntax.triviaList(triviaArray); + } + + private indentationTriviaForStartOfNode(node: ISyntaxNodeOrToken): ISyntaxTriviaList { + var column = this.columnForStartOfToken(node.firstToken()); + return this.indentationTrivia(column); + } + + private changeIndentation(node: T, changeFirstToken: boolean, indentAmount: number): T { + if (indentAmount === 0) { + return node; + } + else if (indentAmount > 0) { + return SyntaxIndenter.indentNode(node, + /*indentFirstToken:*/ changeFirstToken, /*indentAmount:*/ indentAmount, + this.options); + } + else { + // Dedent the node. But don't allow it go before the minimum indent amount. + return SyntaxDedenter.dedentNode(node, + /*dedentFirstToken:*/ changeFirstToken, /*dedentAmount:*/-indentAmount, + /*minimumColumn:*/this.options.indentSpaces, this.options); + } + } + + private withNoTrivia(token: ISyntaxToken): ISyntaxToken { + return token.withLeadingTrivia(Syntax.emptyTriviaList).withTrailingTrivia(Syntax.emptyTriviaList); + } + + public visitSourceUnit(node: SourceUnitSyntax): SourceUnitSyntax { + return node.withModuleElements(Syntax.list( + this.convertModuleElements(node.moduleElements))); + } + + private convertModuleElements(list: ISyntaxList): IModuleElementSyntax[] { + var moduleElements: IModuleElementSyntax[] = []; + + for (var i = 0, n = list.childCount(); i < n; i++) { + var moduleElement = list.childAt(i); + + var converted = this.visitNode(moduleElement); + if (converted !== null) { + if (ArrayUtilities.isArray(converted)) { + moduleElements.push.apply(moduleElements, converted); + } + else { + moduleElements.push(converted); + } + } + } + + return moduleElements; + } + + private static splitModuleName(name: INameSyntax): ISyntaxToken[] { + var result: ISyntaxToken[] = []; + while (true) { + if (name.kind() === SyntaxKind.IdentifierName) { + result.unshift(name); + return result; + } + else if (name.kind() === SyntaxKind.QualifiedName) { + var qualifiedName = name; + result.unshift(qualifiedName.right); + name = qualifiedName.left; + } + else { + throw Errors.invalidOperation(); + } + } + } + + private leftmostName(name: INameSyntax): ISyntaxToken { + while (name.kind() === SyntaxKind.QualifiedName) { + name = (name).left; + } + + return name; + } + + private rightmostName(name: INameSyntax): ISyntaxToken { + if (name.kind() === SyntaxKind.QualifiedName) { + return (name).right; + } + + return name; + } + + private containsToken(list: ISyntaxList, kind: SyntaxKind): boolean { + for (var i = 0, n = list.childCount(); i < n; i++) { + if (list.childAt(i).kind() === kind) { + return true; + } + } + + return false; + } + + private exportModuleElement(moduleIdentifier: ISyntaxToken, + moduleElement: IModuleElementSyntax, + elementIdentifier: ISyntaxToken): ExpressionStatementSyntax { + elementIdentifier = this.withNoTrivia(elementIdentifier); + + // M1.e = e; + return ExpressionStatementSyntax.create1( + this.factory.binaryExpression( + SyntaxKind.AssignmentExpression, + MemberAccessExpressionSyntax.create1( + this.withNoTrivia(moduleIdentifier), + elementIdentifier.withTrailingTrivia(Syntax.spaceTriviaList)), + Syntax.token(SyntaxKind.EqualsToken).withTrailingTrivia(this.space), + elementIdentifier)) + .withLeadingTrivia(this.indentationTriviaForStartOfNode(moduleElement)) + .withTrailingTrivia(this.newLine); + } + + private handleExportedModuleElement(parentModule: ISyntaxToken, + moduleElement: IModuleElementSyntax, + elements: IModuleElementSyntax[]): void { + if (moduleElement.kind() === SyntaxKind.VariableStatement) { + var variableStatement = moduleElement; + if (this.containsToken(variableStatement.modifiers, SyntaxKind.ExportKeyword)) { + var declarators = variableStatement.variableDeclaration.variableDeclarators; + for (var i = 0, n = declarators.nonSeparatorCount(); i < n; i++) { + var declarator = declarators.nonSeparatorAt(i); + elements.push(this.exportModuleElement(parentModule, moduleElement, declarator.propertyName)); + } + } + } + else if (moduleElement.kind() === SyntaxKind.FunctionDeclaration) { + var functionDeclaration = moduleElement; + if (this.containsToken(functionDeclaration.modifiers, SyntaxKind.ExportKeyword)) { + elements.push(this.exportModuleElement( + parentModule, moduleElement, functionDeclaration.identifier)); + } + } + else if (moduleElement.kind() === SyntaxKind.ClassDeclaration) { + var classDeclaration = moduleElement; + if (this.containsToken(classDeclaration.modifiers, SyntaxKind.ExportKeyword)) { + elements.push(this.exportModuleElement(parentModule, moduleElement, classDeclaration.identifier)); + } + } + else if (moduleElement.kind() === SyntaxKind.ModuleDeclaration) { + var childModule = moduleElement; + if (this.containsToken(childModule.modifiers, SyntaxKind.ExportKeyword)) { + elements.push(this.exportModuleElement( + parentModule, moduleElement, this.leftmostName(childModule.name))); + } + } + } + + public visitModuleDeclaration(node: ModuleDeclarationSyntax): IModuleElementSyntax[] { + var _this = this; + + // Recurse downwards and get the rewritten children. + var moduleElements = this.convertModuleElements(node.moduleElements); + + if (this.mustCaptureThisInModule(node)) { + // TODO: determine the right column for the 'this capture' statment. + moduleElements.unshift(this.generateThisCaptureStatement(0)); + } + + // Handle the case where the child is an export. + var parentModule = this.rightmostName(node.name); + for (var i = 0, n = node.moduleElements.childCount(); i < n; i++) { + this.handleExportedModuleElement( + parentModule, node.moduleElements.childAt(i), moduleElements); + } + + // Break up the dotted name into pieces. + var names = EmitterImpl.splitModuleName(node.name); + + // Then, for all the names left of that name, wrap what we've created in a larger module. + for (var nameIndex = names.length - 1; nameIndex >= 0; nameIndex--) { + moduleElements = this.convertModuleDeclaration( + node, names[nameIndex], moduleElements, nameIndex === 0); + + if (nameIndex > 0) { + // We're popping out and generate each outer module. As we do so, we have to + // indent whatever we've created so far appropriately. + moduleElements.push(this.exportModuleElement( + names[nameIndex - 1], node, names[nameIndex])); + + moduleElements = ArrayUtilities.select(moduleElements, + e => _this.changeIndentation(e, /*indentFirstToken:*/ true, _this.options.indentSpaces)); + } + } + + return moduleElements; + } + + private initializedVariable(name: ISyntaxToken): BinaryExpressionSyntax { + return this.factory.binaryExpression(SyntaxKind.LogicalOrExpression, + name, + Syntax.token(SyntaxKind.BarBarToken), + ParenthesizedExpressionSyntax.create1( + Syntax.assignmentExpression( + name, + Syntax.token(SyntaxKind.EqualsToken), + ObjectLiteralExpressionSyntax.create1()))); + } + + private convertModuleDeclaration(moduleDeclaration: ModuleDeclarationSyntax, + moduleName: ISyntaxToken, + moduleElements: IModuleElementSyntax[], + outermost: boolean): IModuleElementSyntax[] { + moduleName = moduleName.withLeadingTrivia(Syntax.emptyTriviaList).withTrailingTrivia(Syntax.emptyTriviaList); + var moduleIdentifier = moduleName; + + var moduleIndentation = this.indentationTriviaForStartOfNode(moduleDeclaration); + var leadingTrivia = outermost ? moduleDeclaration.leadingTrivia() : moduleIndentation; + + // var M; + var variableStatement = VariableStatementSyntax.create1(this.factory.variableDeclaration( + Syntax.token(SyntaxKind.VarKeyword).withTrailingTrivia(this.space), + Syntax.separatedList( + [VariableDeclaratorSyntax.create(moduleIdentifier)]))) + .withLeadingTrivia(leadingTrivia).withTrailingTrivia(this.newLine); + + // function(M) { ... } + var functionExpression = FunctionExpressionSyntax.create1() + .withCallSignature(callSignature(ParameterSyntax.create(moduleIdentifier)).withTrailingTrivia(this.space)) + .withBlock(this.factory.block( + Syntax.token(SyntaxKind.OpenBraceToken).withTrailingTrivia(this.newLine), + Syntax.list(moduleElements), + Syntax.token(SyntaxKind.CloseBraceToken).withLeadingTrivia(moduleIndentation))); + + // (function(M) { ... })(M||(M={})); + var expressionStatement = ExpressionStatementSyntax.create1( + this.factory.invocationExpression( + ParenthesizedExpressionSyntax.create1(functionExpression), + ArgumentListSyntax.create1().withArgument(this.initializedVariable(moduleName)))) + .withLeadingTrivia(moduleIndentation).withTrailingTrivia(this.newLine); + + return [variableStatement, expressionStatement]; + } + + public visitExpressionStatement(node: ExpressionStatementSyntax): ExpressionStatementSyntax { + // Can't have an expression statement with an anonymous function expression in it. + var rewritten: ExpressionStatementSyntax = super.visitExpressionStatement(node); + + // convert: function() { ... }; to (function() { ... }); + if (rewritten.expression.kind() === SyntaxKind.FunctionExpression) { + // Wasn a function expression + var functionExpression = rewritten.expression; + if (functionExpression.identifier === null) { + // Was anonymous. + + // Remove the leading trivia from the function keyword. We'll put it on the open paren + // token instead. + + // Now, wrap the function expression in parens to make it legal in javascript. + var parenthesizedExpression = ParenthesizedExpressionSyntax.create1( + functionExpression.withLeadingTrivia(Syntax.emptyTriviaList)).withLeadingTrivia(functionExpression.leadingTrivia()); + + return rewritten.withExpression(parenthesizedExpression); + } + } + + return rewritten; + } + + public visitSimpleArrowFunctionExpression(node: SimpleArrowFunctionExpressionSyntax): FunctionExpressionSyntax { + return FunctionExpressionSyntax.create1() + .withCallSignature(callSignature(ParameterSyntax.create(this.withNoTrivia(node.identifier))).withTrailingTrivia(this.space)) + .withBlock(this.convertArrowFunctionBody(node)).withLeadingTrivia(node.leadingTrivia()); + } + + public visitParenthesizedArrowFunctionExpression(node: ParenthesizedArrowFunctionExpressionSyntax): FunctionExpressionSyntax { + return FunctionExpressionSyntax.create1() + .withCallSignature(CallSignatureSyntax.create(node.callSignature.parameterList.accept(this))) + .withBlock(this.convertArrowFunctionBody(node)).withLeadingTrivia(node.leadingTrivia()); + } + + private convertArrowFunctionBody(arrowFunction: IArrowFunctionExpressionSyntax): BlockSyntax { + var rewrittenBody = arrowFunction.block ? this.visitNode(arrowFunction.block) : this.visitNodeOrToken(arrowFunction.expression); + + if (rewrittenBody.kind() === SyntaxKind.Block) { + return rewrittenBody; + } + + var arrowToken = arrowFunction.equalsGreaterThanToken; + + // first, attach the expression to the return statement + var returnStatement = this.factory.returnStatement( + Syntax.token(SyntaxKind.ReturnKeyword, { trailingTrivia: arrowToken.trailingTrivia().toArray() }), + rewrittenBody, + Syntax.token(SyntaxKind.SemicolonToken)).withTrailingTrivia(this.newLine); + + // We want to adjust the indentation of the expression so that is aligns as it + // did before. For example, if we started with: + // + // a => foo().bar() + // .baz() + // + // Then we want to end up with: + // + // return foo().bar() + // .baz() + // + // To do this we look at where the previous token (=>) used to end and where the new pevious + // token (return) ends. The difference (in this case '2') is our offset. + + var difference = 0; + if (arrowToken.hasTrailingNewLine()) { + // The expression is on the next line. i.e. + // + // foo => + // expr + // + // So we want it to immediately follow the return statement. i.e.: + // + // return + // expr; + // + // and we adjust based on the column difference between the start of the arrow function + // and the start of the expr. + var arrowFunctionStart = this.columnForStartOfToken(arrowFunction.firstToken()); + difference = -arrowFunctionStart; + } + else { + // the expression immediately follows the arrow. i.e.: + // + // foo => expr + // + // So we want it to immediately follow the return statement. i.e.: + // + // return expr; + // + // and we adjust based on the column difference between the end of the arrow token and + // the end of the return statement. + var arrowEndColumn = this.columnForEndOfToken(arrowToken); + var returnKeywordEndColumn = returnStatement.returnKeyword.width(); + difference = returnKeywordEndColumn - arrowEndColumn; + } + + returnStatement = this.changeIndentation( + returnStatement, /*changeFirstToken:*/ false, difference); + + // Next, indent the return statement. It's going in a block, so it needs to be properly + // indented. Note we do this *after* we've ensured the expression aligns properly. + + returnStatement = this.changeIndentation( + returnStatement, /*indentFirstToken:*/ true, this.options.indentSpaces); + + // Now wrap the return statement in a block. + var block = this.factory.block( + Syntax.token(SyntaxKind.OpenBraceToken).withTrailingTrivia(this.newLine), + Syntax.list([returnStatement]), + Syntax.token(SyntaxKind.CloseBraceToken)); + + // Note: if we started with something like: + // + // var v = a => 1; + // + // Then we want to convert that to: + // + // var v = function(a) { + // return 1; + // }; + // + // However, right now what we've created is: + // + // { + // return 1; + // } + // + // So we need to indent the block with our current column indent so that it aligns with the + // parent structure. Note: we don't wan to adjust the leading brace as that's going to go + // after the function sigature. + + return this.changeIndentation(block, /*indentFirstToken:*/ false, + Indentation.columnForStartOfFirstTokenInLineContainingPosition( + this.syntaxTreeCopy, arrowFunction.firstToken().fullStart(), this.options)); + } + + private static methodSignatureDefaultParameters(signature: MethodSignatureSyntax): ParameterSyntax[] { + return EmitterImpl.callSignatureDefaultParameters(signature.callSignature); + } + + private static callSignatureDefaultParameters(callSignature: CallSignatureSyntax): ParameterSyntax[] { + return EmitterImpl.parameterListDefaultParameters(callSignature.parameterList); + } + + private static parameterListDefaultParameters(parameterList: ParameterListSyntax): ParameterSyntax[] { + return ArrayUtilities.where(parameterList.parameters.toNonSeparatorArray(), p => p.equalsValueClause !== null); + } + + private generatePropertyAssignmentStatement(parameter: ParameterSyntax): ExpressionStatementSyntax { + var identifier = this.withNoTrivia(parameter.identifier); + + // this.foo = foo; + return ExpressionStatementSyntax.create1( + Syntax.assignmentExpression( + MemberAccessExpressionSyntax.create1( + Syntax.token(SyntaxKind.ThisKeyword), + identifier.withTrailingTrivia(Syntax.spaceTriviaList)), + Syntax.token(SyntaxKind.EqualsToken).withTrailingTrivia(this.space), + identifier)).withTrailingTrivia(this.newLine); + } + + private generateDefaultValueAssignmentStatement(parameter: ParameterSyntax): IfStatementSyntax { + var identifierName = this.withNoTrivia(parameter.identifier).withTrailingTrivia(this.space); + + // typeof foo === 'undefined' + var condition = this.factory.binaryExpression( + SyntaxKind.EqualsExpression, + this.factory.typeOfExpression( + Syntax.token(SyntaxKind.TypeOfKeyword).withTrailingTrivia(this.space), + identifierName), + Syntax.token(SyntaxKind.EqualsEqualsEqualsToken).withTrailingTrivia(this.space), + Syntax.stringLiteralExpression('"undefined"')); + + // foo = expr; + var assignmentStatement = ExpressionStatementSyntax.create1( + Syntax.assignmentExpression( + identifierName, + Syntax.token(SyntaxKind.EqualsToken).withTrailingTrivia(this.space), + parameter.equalsValueClause.value.accept(this))).withTrailingTrivia(this.space); + + var block = this.factory.block( + Syntax.token(SyntaxKind.OpenBraceToken).withTrailingTrivia(this.space), + Syntax.list([assignmentStatement]), + Syntax.token(SyntaxKind.CloseBraceToken)).withTrailingTrivia(this.newLine); + + // if (typeof foo === 'undefined') { foo = expr; } + return this.factory.ifStatement( + Syntax.token(SyntaxKind.IfKeyword).withTrailingTrivia(this.space), + Syntax.token(SyntaxKind.OpenParenToken), + condition, + Syntax.token(SyntaxKind.CloseParenToken).withTrailingTrivia(this.space), + block, null); + } + + public visitFunctionDeclaration(node: FunctionDeclarationSyntax): FunctionDeclarationSyntax { + if (node.block === null) { + // Function overloads aren't emitted. + return null; + } + + var rewritten = super.visitFunctionDeclaration(node); + var parametersWithDefaults = EmitterImpl.callSignatureDefaultParameters(node.callSignature); + + if (parametersWithDefaults.length !== 0) { + var defaultValueAssignmentStatements = ArrayUtilities.select( + parametersWithDefaults, p => this.generateDefaultValueAssignmentStatement(p)); + + var statementColumn = this.columnForStartOfToken(node.firstToken()) + this.options.indentSpaces; + var statements = ArrayUtilities.select(defaultValueAssignmentStatements, + s => this.changeIndentation(s, /*indentFirstToken:*/ true, statementColumn)); + + // Capture _this if necessary + if (this.mustCaptureThisInFunction(node)) { + statements.push(this.generateThisCaptureStatement(statementColumn)); + } + + statements.push.apply(statements, rewritten.block.statements.toArray()); + + rewritten = rewritten.withBlock(rewritten.block.withStatements( + Syntax.list(statements))); + } + + return rewritten.withModifiers(Syntax.emptyList()) + .withLeadingTrivia(rewritten.leadingTrivia()); + } + + public visitParameter(node: ParameterSyntax): ParameterSyntax { + // transfer the trivia from the first token to the the identifier. + return ParameterSyntax.create(node.identifier) + .withLeadingTrivia(node.leadingTrivia()) + .withTrailingTrivia(node.trailingTrivia()) + } + + private generatePropertyAssignment(classDeclaration: ClassDeclarationSyntax, + static: boolean, + memberDeclaration: MemberVariableDeclarationSyntax): ExpressionStatementSyntax { + var isStatic = this.containsToken(memberDeclaration.modifiers, SyntaxKind.StaticKeyword); + var declarator = memberDeclaration.variableDeclarator; + if (static !== isStatic || declarator.equalsValueClause === null) { + return null; + } + + // this.foo = expr; + var receiver = MemberAccessExpressionSyntax.create1( + static ? this.withNoTrivia(classDeclaration.identifier) + : Syntax.token(SyntaxKind.ThisKeyword), + this.withNoTrivia(declarator.propertyName)).withTrailingTrivia(Syntax.spaceTriviaList); + + return ExpressionStatementSyntax.create1( + Syntax.assignmentExpression( + receiver, + Syntax.token(SyntaxKind.EqualsToken).withTrailingTrivia(this.space), + declarator.equalsValueClause.value.accept(this).withTrailingTrivia(Syntax.emptyTriviaList))) + .withLeadingTrivia(memberDeclaration.leadingTrivia()).withTrailingTrivia(this.newLine); + } + + private generatePropertyAssignments(classDeclaration: ClassDeclarationSyntax, + static: boolean): ExpressionStatementSyntax[] { + var result: ExpressionStatementSyntax[] = []; + + // TODO: handle alignment here. + for (var i = 0, n = classDeclaration.classElements.childCount(); i < n; i++) { + var classElement = classDeclaration.classElements.childAt(i); + + if (classElement.kind() === SyntaxKind.MemberVariableDeclaration) { + var statement = this.generatePropertyAssignment( + classDeclaration, static, classElement); + if (statement !== null) { + result.push(statement); + } + } + } + + return result; + } + + private createDefaultConstructorDeclaration(classDeclaration: ClassDeclarationSyntax): FunctionDeclarationSyntax { + var classIndentationColumn = this.columnForStartOfToken(classDeclaration.firstToken()); + var statementIndentationColumn = classIndentationColumn + this.options.indentSpaces; + + var statements: IStatementSyntax[] = []; + if (classDeclaration.heritageClauses.childCount() > 0) { + statements.push(ExpressionStatementSyntax.create1( + this.factory.invocationExpression( + MemberAccessExpressionSyntax.create1( + Syntax.identifierName("_super"), Syntax.identifierName("apply")), + ArgumentListSyntax.create1().withArguments( + Syntax.separatedList([ + Syntax.token(SyntaxKind.ThisKeyword), + Syntax.token(SyntaxKind.CommaToken).withTrailingTrivia(this.space), + Syntax.identifierName("arguments")]))) + ).withLeadingTrivia(this.indentationTrivia(statementIndentationColumn)) + .withTrailingTrivia(this.newLine)); + } + + if (this.mustCaptureThisInClass(classDeclaration)) { + statements.push(this.generateThisCaptureStatement(statementIndentationColumn)); + } + + statements.push.apply(statements, this.generatePropertyAssignments(classDeclaration, /*static:*/ false)); + + var indentationTrivia = this.indentationTrivia(classIndentationColumn); + + var functionDeclaration = FunctionDeclarationSyntax.create( + Syntax.token(SyntaxKind.FunctionKeyword).withLeadingTrivia(indentationTrivia).withTrailingTrivia(this.space), + this.withNoTrivia(classDeclaration.identifier), + CallSignatureSyntax.create1().withTrailingTrivia(this.space)) + .withBlock(this.factory.block( + Syntax.token(SyntaxKind.OpenBraceToken).withTrailingTrivia(this.newLine), + Syntax.list(statements), + Syntax.token(SyntaxKind.CloseBraceToken).withLeadingTrivia(indentationTrivia))).withTrailingTrivia(this.newLine); + + return this.changeIndentation( + functionDeclaration, /*indentFirstToken:*/ true, this.options.indentSpaces); + } + + private convertConstructorDeclaration(classDeclaration: ClassDeclarationSyntax, + constructorDeclaration: ConstructorDeclarationSyntax): FunctionDeclarationSyntax { + if (constructorDeclaration.block === null) { + return null; + } + + var i: number; + var identifier = this.withNoTrivia(classDeclaration.identifier); + + var constructorIndentationColumn = this.columnForStartOfToken(constructorDeclaration.firstToken()); + var originalParameterListindentation = this.columnForStartOfToken(constructorDeclaration.callSignature.firstToken()); + + // The original indent + "function" + + "ClassName" + var newParameterListIndentation = + constructorIndentationColumn + SyntaxFacts.getText(SyntaxKind.FunctionKeyword).length + 1 + identifier.width(); + + var callSignature = constructorDeclaration.callSignature.accept(this); + callSignature= this.changeIndentation( + callSignature, /*changeFirstToken:*/ false, newParameterListIndentation - originalParameterListindentation); + + var block = constructorDeclaration.block; + var allStatements = block.statements.toArray(); + + var normalStatements: IStatementSyntax[] = ArrayUtilities.select(ArrayUtilities.where(allStatements, + s => !Syntax.isSuperInvocationExpressionStatement(s)), s => s.accept(this)); + + var instanceAssignments = this.generatePropertyAssignments(classDeclaration, /*static:*/ false); + + for (i = instanceAssignments.length - 1; i >= 0; i--) { + normalStatements.unshift(this.changeIndentation( + instanceAssignments[i], /*changeFirstToken:*/ true, this.options.indentSpaces)); + } + + var parameterPropertyAssignments = ArrayUtilities.select( + ArrayUtilities.where(constructorDeclaration.callSignature.parameterList.parameters.toNonSeparatorArray(), p => p.modifiers.childCount() > 0), + p => this.generatePropertyAssignmentStatement(p)); + + for (i = parameterPropertyAssignments.length - 1; i >= 0; i--) { + normalStatements.unshift(this.changeIndentation( + parameterPropertyAssignments[i], /*changeFirstToken:*/ true, this.options.indentSpaces + constructorIndentationColumn)); + } + + var superStatements: IStatementSyntax[] = ArrayUtilities.select(ArrayUtilities.where(allStatements, + s => Syntax.isSuperInvocationExpressionStatement(s)), s => s.accept(this)); + + normalStatements.unshift.apply(normalStatements, superStatements); + + // TODO: use typecheck to determine if 'this' needs to be captured. + if (this.mustCaptureThisInConstructor(constructorDeclaration)) { + normalStatements.unshift(this.generateThisCaptureStatement(this.options.indentSpaces + constructorIndentationColumn)); + } + + var defaultValueAssignments = ArrayUtilities.select( + EmitterImpl.parameterListDefaultParameters(constructorDeclaration.callSignature.parameterList), + p => this.generateDefaultValueAssignmentStatement(p)); + + for (i = defaultValueAssignments.length - 1; i >= 0; i--) { + normalStatements.unshift(this.changeIndentation( + defaultValueAssignments[i], /*changeFirstToken:*/ true, this.options.indentSpaces + constructorIndentationColumn)); + } + + // function C(...) { ... } + return FunctionDeclarationSyntax.create( + Syntax.token(SyntaxKind.FunctionKeyword).withTrailingTrivia(this.space), + identifier, callSignature) + .withBlock(block.withStatements(Syntax.list(normalStatements))).withLeadingTrivia(constructorDeclaration.leadingTrivia()); + } + + private convertMemberFunctionDeclaration(classDeclaration: ClassDeclarationSyntax, + functionDeclaration: MemberFunctionDeclarationSyntax): ExpressionStatementSyntax { + var _this = this; + if (functionDeclaration.block === null) { + return null; + } + + var classIdentifier = this.withNoTrivia(classDeclaration.identifier); + var functionIdentifier = this.withNoTrivia(functionDeclaration.propertyName); + + var receiver: ILeftHandSideExpressionSyntax = classIdentifier.withLeadingTrivia(functionDeclaration.leadingTrivia()); + + receiver = this.containsToken(functionDeclaration.modifiers, SyntaxKind.StaticKeyword) + ? receiver + : MemberAccessExpressionSyntax.create1(receiver, Syntax.identifierName("prototype")); + + receiver = MemberAccessExpressionSyntax.create1( + receiver, functionIdentifier.withTrailingTrivia(Syntax.spaceTriviaList)); + + var block: BlockSyntax = functionDeclaration.block.accept(this); + var blockTrailingTrivia = block.trailingTrivia(); + + block = block.withTrailingTrivia(Syntax.emptyTriviaList); + + var defaultValueAssignments = ArrayUtilities.select( + EmitterImpl.callSignatureDefaultParameters(functionDeclaration.callSignature), + p => _this.generateDefaultValueAssignmentStatement(p)); + + var functionColumn = this.columnForStartOfToken(functionDeclaration.firstToken()); + + var blockStatements = block.statements.toArray(); + for (var i = defaultValueAssignments.length - 1; i >= 0; i--) { + blockStatements.unshift(this.changeIndentation( + defaultValueAssignments[i], /*changeFirstToken:*/ true, functionColumn + this.options.indentSpaces)); + } + + var callSignatureParameterList = functionDeclaration.callSignature.parameterList.accept(this); + if (!callSignatureParameterList.hasTrailingTrivia()) { + callSignatureParameterList = callSignatureParameterList.withTrailingTrivia(Syntax.spaceTriviaList); + } + + // C.prototype.f = function (p1, p2) { ... }; + return ExpressionStatementSyntax.create1(Syntax.assignmentExpression( + receiver, + Syntax.token(SyntaxKind.EqualsToken).withTrailingTrivia(this.space), + FunctionExpressionSyntax.create1() + .withCallSignature(CallSignatureSyntax.create(callSignatureParameterList)) + .withBlock(block.withStatements( + Syntax.list(blockStatements))))).withTrailingTrivia(blockTrailingTrivia); + } + + private convertMemberAccessor(memberAccessor: SyntaxNode): SimplePropertyAssignmentSyntax { + var propertyName = memberAccessor.kind() === SyntaxKind.GetAccessor + ? "get" : "set"; + + var parameterList = (memberAccessor).parameterList.accept(this); + if (!parameterList.hasTrailingTrivia()) { + parameterList = parameterList.withTrailingTrivia(Syntax.spaceTriviaList); + } + + return this.factory.simplePropertyAssignment( + Syntax.identifier(propertyName), + Syntax.token(SyntaxKind.ColonToken).withTrailingTrivia(this.space), + FunctionExpressionSyntax.create( + Syntax.token(SyntaxKind.FunctionKeyword), + CallSignatureSyntax.create(parameterList), + (memberAccessor).block.accept(this).withTrailingTrivia(Syntax.emptyTriviaList))) + .withLeadingTrivia(this.indentationTriviaForStartOfNode(memberAccessor)); + } + + private convertMemberAccessorDeclaration(classDeclaration: ClassDeclarationSyntax, + memberAccessor: SyntaxNode, + classElements: IClassElementSyntax[]): IStatementSyntax { + var name = (memberAccessor).propertyName.valueText(); + var i: number; + + // Find all the accessors with that name. + var accessors: any[] = [memberAccessor]; + + for (i = classElements.length - 1; i >= 0; i--) { + var element = classElements[i]; + if (element.kind() === SyntaxKind.GetAccessor || + element.kind() === SyntaxKind.SetAccessor) { + + var otherAccessor = element; + if ((otherAccessor).propertyName.value() === name && + (otherAccessor).block !== null) { + accessors.push(otherAccessor); + classElements.splice(i, 1); + } + } + } + + var arguments = [ + MemberAccessExpressionSyntax.create1( + this.withNoTrivia(classDeclaration.identifier), Syntax.identifierName("prototype")), + Syntax.token(SyntaxKind.CommaToken).withTrailingTrivia(this.space), + Syntax.stringLiteralExpression('"' + (memberAccessor).propertyName.text() + '"'), + Syntax.token(SyntaxKind.CommaToken).withTrailingTrivia(this.space) + ]; + + var propertyAssignments: ISyntaxNodeOrToken[] = []; + for (i = 0; i < accessors.length; i++) { + var converted = this.convertMemberAccessor(accessors[i]); + converted = this.changeIndentation( + converted, /*changeFirstToken:*/ true, this.options.indentSpaces); + propertyAssignments.push(converted); + propertyAssignments.push( + Syntax.token(SyntaxKind.CommaToken).withTrailingTrivia(this.newLine)); + } + + var accessorColumn = this.columnForStartOfToken(memberAccessor.firstToken()); + var accessorTrivia = this.indentationTrivia(accessorColumn); + var propertyTrivia = this.indentationTrivia(accessorColumn + this.options.indentSpaces); + + propertyAssignments.push(this.factory.simplePropertyAssignment( + Syntax.identifier("enumerable"), + Syntax.token(SyntaxKind.ColonToken).withTrailingTrivia(this.space), + Syntax.trueExpression()).withLeadingTrivia(propertyTrivia)); + propertyAssignments.push(Syntax.token(SyntaxKind.CommaToken).withTrailingTrivia(this.newLine)); + + propertyAssignments.push(this.factory.simplePropertyAssignment( + Syntax.identifier("configurable"), + Syntax.token(SyntaxKind.ColonToken).withTrailingTrivia(this.space), + Syntax.trueExpression()).withLeadingTrivia(propertyTrivia).withTrailingTrivia(this.newLine)); + + arguments.push(this.factory.objectLiteralExpression( + Syntax.token(SyntaxKind.OpenBraceToken).withTrailingTrivia(this.newLine), + Syntax.separatedList(propertyAssignments), + Syntax.token(SyntaxKind.CloseBraceToken).withLeadingTrivia(accessorTrivia))); + + return ExpressionStatementSyntax.create1( + this.factory.invocationExpression( + MemberAccessExpressionSyntax.create1(Syntax.identifierName("Object"), Syntax.identifierName("defineProperty")), + ArgumentListSyntax.create1().withArguments(Syntax.separatedList(arguments)))) + .withLeadingTrivia(memberAccessor.leadingTrivia()).withTrailingTrivia(this.newLine); + } + + private convertClassElements(classDeclaration: ClassDeclarationSyntax): IStatementSyntax[] { + var result: IStatementSyntax[] = []; + + var classElements = classDeclaration.classElements.toArray(); + while (classElements.length > 0) { + var classElement = classElements.shift(); + + var converted: IStatementSyntax = null; + if (classElement.kind() === SyntaxKind.MemberFunctionDeclaration) { + converted = this.convertMemberFunctionDeclaration(classDeclaration, classElement); + } + else if (classElement.kind() === SyntaxKind.MemberVariableDeclaration) { + converted = this.generatePropertyAssignment(classDeclaration, /*static:*/ true, classElement); + } + else if (classElement.kind() === SyntaxKind.GetAccessor || + classElement.kind() === SyntaxKind.SetAccessor) { + converted = this.convertMemberAccessorDeclaration(classDeclaration, classElement, classElements); + } + + if (converted !== null) { + result.push(converted); + } + } + + return result; + } + + public visitClassDeclaration(node: ClassDeclarationSyntax): VariableStatementSyntax { + var identifier = this.withNoTrivia(node.identifier); + + var statements: IStatementSyntax[] = []; + var statementIndentation = this.indentationTrivia(this.options.indentSpaces + this.columnForStartOfToken(node.firstToken())); + + if (node.heritageClauses.childCount() > 0) { + // __extends(C, _super); + statements.push(ExpressionStatementSyntax.create1( + this.factory.invocationExpression( + Syntax.identifierName("__extends"), + ArgumentListSyntax.create1().withArguments(Syntax.separatedList([ + identifier, + Syntax.token(SyntaxKind.CommaToken).withTrailingTrivia(this.space), + Syntax.identifierName("_super")])))).withLeadingTrivia(statementIndentation).withTrailingTrivia(this.newLine)); + } + + var constructorDeclaration = ArrayUtilities.firstOrDefault( + node.classElements.toArray(), c => c.kind() === SyntaxKind.ConstructorDeclaration); + + var constructorFunctionDeclaration = constructorDeclaration === null + ? this.createDefaultConstructorDeclaration(node) + : this.convertConstructorDeclaration(node, constructorDeclaration); + + if (constructorFunctionDeclaration !== null) { + statements.push(constructorFunctionDeclaration) + } + + statements.push.apply(statements, this.convertClassElements(node)); + + // return C; + statements.push(this.factory.returnStatement( + Syntax.token(SyntaxKind.ReturnKeyword).withTrailingTrivia(this.space), + identifier, + Syntax.token(SyntaxKind.SemicolonToken)) + .withLeadingTrivia(statementIndentation).withTrailingTrivia(this.newLine)); + + var block = this.factory.block( + Syntax.token(SyntaxKind.OpenBraceToken).withTrailingTrivia(this.newLine), + Syntax.list(statements), + Syntax.token(SyntaxKind.CloseBraceToken).withLeadingTrivia(this.indentationTriviaForStartOfNode(node))); + + var callParameters: ParameterSyntax[] = []; + if (node.heritageClauses.childCount() > 0) { + callParameters.push(ParameterSyntax.create(Syntax.identifier("_super"))); + } + + var callSignature = CallSignatureSyntax.create( + ParameterListSyntax.create1().withParameters( + Syntax.separatedList(callParameters))).withTrailingTrivia(this.space); + + var invocationParameters: ISyntaxNodeOrToken[] = []; + if (node.heritageClauses.childCount() > 0) { + var heritageClause = node.heritageClauses.childAt(0); + if (heritageClause.typeNames.nonSeparatorCount() > 0) { + invocationParameters.push(heritageClause.typeNames.nonSeparatorAt(0) + .withLeadingTrivia(Syntax.emptyTriviaList) + .withTrailingTrivia(Syntax.emptyTriviaList)); + } + } + + // (function(_super) { ... })(BaseType) + var invocationExpression = this.factory.invocationExpression( + ParenthesizedExpressionSyntax.create1(FunctionExpressionSyntax.create1() + .withCallSignature(callSignature) + .withBlock(block)), + ArgumentListSyntax.create1().withArguments( + Syntax.separatedList(invocationParameters))); + + // C = (function(_super) { ... })(BaseType) + var variableDeclarator = VariableDeclaratorSyntax.create( + identifier.withTrailingTrivia(Syntax.spaceTriviaList)).withEqualsValueClause( + this.factory.equalsValueClause( + Syntax.token(SyntaxKind.EqualsToken).withTrailingTrivia(this.space), + invocationExpression)); + + // var C = (function(_super) { ... })(BaseType); + return VariableStatementSyntax.create1(this.factory.variableDeclaration( + Syntax.token(SyntaxKind.VarKeyword).withTrailingTrivia(this.space), + Syntax.separatedList([variableDeclarator]))) + .withLeadingTrivia(node.leadingTrivia()).withTrailingTrivia(this.newLine); + } + + public visitVariableDeclarator(node: VariableDeclaratorSyntax): VariableDeclaratorSyntax { + var result: VariableDeclaratorSyntax = super.visitVariableDeclarator(node); + if (result.typeAnnotation === null) { + return result; + } + + var newTrailingTrivia = result.propertyName.trailingTrivia().concat(result.typeAnnotation.trailingTrivia()); + + return result.withTypeAnnotation(null) + .withPropertyName(result.propertyName.withTrailingTrivia(newTrailingTrivia)); + } + + public visitCallSignature(node: CallSignatureSyntax): CallSignatureSyntax { + var result: CallSignatureSyntax = super.visitCallSignature(node); + if (result.typeAnnotation === null) { + return result; + } + + var newTrailingTrivia = result.parameterList.trailingTrivia().concat( + result.typeAnnotation.trailingTrivia()); + + return result.withTypeAnnotation(null).withTrailingTrivia(newTrailingTrivia); + } + + public visitCastExpression(node: CastExpressionSyntax): IExpressionSyntax { + var result: CastExpressionSyntax = super.visitCastExpression(node); + + var subExpression = result.expression; + var totalTrivia = result.leadingTrivia().concat(subExpression.leadingTrivia()); + + return subExpression.withLeadingTrivia(totalTrivia); + } + + public visitInterfaceDeclaration(node: InterfaceDeclarationSyntax): InterfaceDeclarationSyntax { + // TODO: transfer trivia if important. + return null; + } + + public visitTypeParameterList(node: TypeParameterListSyntax): TypeParameterListSyntax { + return null; + } + + private generateEnumValueExpression(enumDeclaration: EnumDeclarationSyntax, + enumElement: EnumElementSyntax, + assignDefaultValues: boolean, + index: number): IExpressionSyntax { + if (enumElement.equalsValueClause !== null) { + // Use the value if one is provided. + return enumElement.equalsValueClause.value.accept(this).withTrailingTrivia(Syntax.emptyTriviaList); + } + + // Didn't have a value. Synthesize one if we're doing that, or use the previous item's value + // (plus one). + if (assignDefaultValues) { + return Syntax.numericLiteralExpression(index.toString()); + } + + // Add one to the previous value. + var enumIdentifier = this.withNoTrivia(enumDeclaration.identifier); + var previousEnumElement = enumDeclaration.enumElements.nonSeparatorAt(index - 1); + var variableIdentifier = this.withNoTrivia(previousEnumElement.propertyName); + + var receiver = variableIdentifier.kind() === SyntaxKind.StringLiteral + ? ElementAccessExpressionSyntax.create1(enumIdentifier, variableIdentifier) + : MemberAccessExpressionSyntax.create1(enumIdentifier, variableIdentifier); + + return this.factory.binaryExpression(SyntaxKind.PlusExpression, + receiver.withTrailingTrivia(Syntax.spaceTriviaList), + Syntax.token(SyntaxKind.PlusToken).withTrailingTrivia(this.space), + Syntax.numericLiteralExpression("1")); + } + + private generateEnumFunctionExpression(node: EnumDeclarationSyntax): FunctionExpressionSyntax { + var identifier = this.withNoTrivia(node.identifier); + + var enumColumn = this.columnForStartOfToken(node.firstToken()); + + var statements: IStatementSyntax[] = []; + + var initIndentationColumn = enumColumn + this.options.indentSpaces; + var initIndentationTrivia = this.indentationTrivia(initIndentationColumn); + + if (node.enumElements.nonSeparatorCount() > 0) { + var assignDefaultValues = { value: true }; + for (var i = 0, n = node.enumElements.nonSeparatorCount(); i < n; i++) { + var enumElement = node.enumElements.nonSeparatorAt(i) + var variableIdentifier = this.withNoTrivia(enumElement.propertyName); + + assignDefaultValues.value = assignDefaultValues.value && (enumElement.equalsValueClause === null); + + // "E.Foo = 1" or "E['A B'] = 1" + var left = variableIdentifier.kind() === SyntaxKind.StringLiteral + ? ElementAccessExpressionSyntax.create1(identifier, variableIdentifier) + : MemberAccessExpressionSyntax.create1(identifier, variableIdentifier); + var innerAssign = Syntax.assignmentExpression( + left.withTrailingTrivia(this.space), + Syntax.token(SyntaxKind.EqualsToken).withTrailingTrivia(this.space), + this.generateEnumValueExpression(node, enumElement, assignDefaultValues.value, i)) + + // E[E.Foo = 1] + var elementAccessExpression = ElementAccessExpressionSyntax.create1(identifier, innerAssign) + .withLeadingTrivia(enumElement.leadingTrivia()).withTrailingTrivia(this.space); + + // E[E.Foo = 1] = "Foo" + var outerAssign = Syntax.assignmentExpression( + elementAccessExpression, + Syntax.token(SyntaxKind.EqualsToken).withTrailingTrivia(this.space), + variableIdentifier.kind() === SyntaxKind.StringLiteral + ? variableIdentifier + : Syntax.stringLiteralExpression('"' + variableIdentifier.text() + '"')); + + var expressionStatement = ExpressionStatementSyntax.create1( + outerAssign).withTrailingTrivia(this.newLine); + + statements.push(expressionStatement); + } + } + + var block = this.factory.block( + Syntax.token(SyntaxKind.OpenBraceToken).withTrailingTrivia(this.newLine), + Syntax.list(statements), + Syntax.token(SyntaxKind.CloseBraceToken) + .withLeadingTrivia(this.indentationTrivia(enumColumn))); + + var parameterList = ParameterListSyntax.create1().withParameter(ParameterSyntax.create1(identifier)).withTrailingTrivia(this.space); + + return FunctionExpressionSyntax.create1() + .withCallSignature(CallSignatureSyntax.create(parameterList)) + .withBlock(block); + } + + public visitEnumDeclaration(node: EnumDeclarationSyntax): IStatementSyntax[] { + var identifier = this.withNoTrivia(node.identifier); + + // Copy existing leading trivia of the enum declaration to this node. + // var E; + var variableStatement: IStatementSyntax = VariableStatementSyntax.create1(this.factory.variableDeclaration( + Syntax.token(SyntaxKind.VarKeyword).withTrailingTrivia(this.space), + Syntax.separatedList([VariableDeclaratorSyntax.create(identifier)]))) + .withLeadingTrivia(node.leadingTrivia()).withTrailingTrivia(this.newLine); + + // (function(E) { E[E.e1 = ... })(E||(E={})); + var expressionStatement: IStatementSyntax = ExpressionStatementSyntax.create1( + this.factory.invocationExpression( + ParenthesizedExpressionSyntax.create1(this.generateEnumFunctionExpression(node)), + ArgumentListSyntax.create1().withArgument(this.initializedVariable(identifier)))) + .withLeadingTrivia(this.indentationTriviaForStartOfNode(node)) + .withTrailingTrivia(this.newLine); + + return [variableStatement, expressionStatement]; + } + + private convertSuperInvocationExpression(node: InvocationExpressionSyntax): InvocationExpressionSyntax { + var result: InvocationExpressionSyntax = super.visitInvocationExpression(node); + + var expression = MemberAccessExpressionSyntax.create1(Syntax.identifierName("_super"), Syntax.identifierName("call")); + + var arguments = result.argumentList.arguments.toArray(); + if (arguments.length > 0) { + arguments.unshift(Syntax.token(SyntaxKind.CommaToken).withTrailingTrivia(this.space)); + } + + arguments.unshift(Syntax.token(SyntaxKind.ThisKeyword)); + + return result.withExpression(expression) + .withArgumentList(result.argumentList.withArguments(Syntax.separatedList(arguments))) + .withLeadingTrivia(result.leadingTrivia()); + } + + private convertSuperMemberAccessInvocationExpression(node: InvocationExpressionSyntax): InvocationExpressionSyntax { + var result: InvocationExpressionSyntax = super.visitInvocationExpression(node); + + var arguments = result.argumentList.arguments.toArray(); + if (arguments.length > 0) { + arguments.unshift(Syntax.token(SyntaxKind.CommaToken).withTrailingTrivia(this.space)); + } + + arguments.unshift(Syntax.token(SyntaxKind.ThisKeyword)); + + var expression = MemberAccessExpressionSyntax.create1(result.expression, Syntax.identifierName("call")); + return result.withExpression(expression) + .withArgumentList(result.argumentList.withArguments(Syntax.separatedList(arguments))); + } + + public visitInvocationExpression(node: InvocationExpressionSyntax): InvocationExpressionSyntax { + if (Syntax.isSuperInvocationExpression(node)) { + return this.convertSuperInvocationExpression(node); + } + else if (Syntax.isSuperMemberAccessInvocationExpression(node)) { + return this.convertSuperMemberAccessInvocationExpression(node); + } + + return super.visitInvocationExpression(node); + } + + public visitVariableStatement(node: VariableStatementSyntax): VariableStatementSyntax { + var result: VariableStatementSyntax = super.visitVariableStatement(node); + + return result.withModifiers(Syntax.emptyList()) + .withLeadingTrivia(result.leadingTrivia()); + } + + public visitMemberAccessExpression(node: MemberAccessExpressionSyntax): MemberAccessExpressionSyntax { + var result: MemberAccessExpressionSyntax = super.visitMemberAccessExpression(node); + + if (Syntax.isSuperMemberAccessExpression(result)) { + return MemberAccessExpressionSyntax.create1( + MemberAccessExpressionSyntax.create1(Syntax.identifierName("_super"), Syntax.identifierName("prototype")), + result.name).withLeadingTrivia(result.leadingTrivia()); + } + + return result; + } + + public visitToken(token: ISyntaxToken): ISyntaxToken { + if (token.kind() === SyntaxKind.IdentifierName) { + return this.visitIdentifierName(token); + } + + if (token.kind() === SyntaxKind.ThisKeyword) { + return this.visitThisKeyword(token); + } + + return token; + } + + public visitThisKeyword(token: ISyntaxToken): ISyntaxToken { + // TODO: use typecheck information to tell if we're accessing 'this' in a lambda and + // should use "_this" instead. + return token; + } + + public visitIdentifierName(token: ISyntaxToken): INameSyntax { + // Check if a name token needs to become fully qualified. + var parent = token.parent; + + // We never qualify in a qualified name. A qualified name only shows up in type + // contexts, and will be removed anyways. + if (parent.kind() === SyntaxKind.QualifiedName) { + return token; + } + + // Same issue for a generic name. + if (parent.kind() === SyntaxKind.GenericType) { + return token; + } + + // We never qualify the right hand side of a dot. + if (parent.kind() === SyntaxKind.MemberAccessExpression && (parent).name === token) { + return token; + } + + // TODO(cyrusn): Implement this when we have type check support. + + // Ok. We're a name token that isn't on the right side of a dot. We may need to be + // qualified. Get the symbol that this token binds to. If it is a module/class and + // has a full name that is larger than this token, then return the full name as a + // member access expression. + return token; + } + + private generateThisCaptureStatement(indentationColumn: number): VariableStatementSyntax { + // var _this = this; + return VariableStatementSyntax.create1(this.factory.variableDeclaration( + Syntax.token(SyntaxKind.VarKeyword).withTrailingTrivia(this.space), + Syntax.separatedList([ + this.factory.variableDeclarator( + Syntax.identifier("_this").withTrailingTrivia(this.space), + null, + this.factory.equalsValueClause( + Syntax.token(SyntaxKind.EqualsToken).withTrailingTrivia(this.space), + Syntax.token(SyntaxKind.ThisKeyword))) + ]))).withLeadingTrivia(this.indentationTrivia(indentationColumn)).withTrailingTrivia(this.newLine); + } + + private mustCaptureThisInConstructor(constructorDeclaration: ConstructorDeclarationSyntax): boolean { + // TODO: use typecheck to answer this question properly. + return false; + } + + private mustCaptureThisInClass(classDeclaratoin: ClassDeclarationSyntax): boolean { + // TODO: use typecheck to answer this question properly. + return false; + } + + private mustCaptureThisInModule(moduleDeclaration: ModuleDeclarationSyntax): boolean { + // TODO: use typecheck to answer this question properly. + return false; + } + + private mustCaptureThisInFunction(functionDeclaration: FunctionDeclarationSyntax): boolean { + // TODO: use typecheck to answer this question properly. + return false; + } + } + + export function emit(input: SourceUnitSyntax, options: FormattingOptions = null): SourceUnitSyntax { + // Make sure no one is passing us a bogus tree. + SyntaxNodeInvariantsChecker.checkInvariants(input); + + // If there's nothing typescript specific about this node, then just return it as is. + if (!input.isTypeScriptSpecific()) { + return input; + } + + // Do the initial conversion. Note: the result at this point may be 'bogus'. For example, + // it make contain the same token instance multiple times in the tree. + var output: SourceUnitSyntax = input.accept(new EmitterImpl(input.syntaxTree(), options)); + + // Make sure we clone any nodes/tokens we used in multiple places in the result. That way + // we don't break the invariant that all tokens in a tree are unique. + output = output.accept(new EnsureTokenUniquenessRewriter()); + + SyntaxNodeInvariantsChecker.checkInvariants(output); + Debug.assert(!output.isTypeScriptSpecific()); + + return output; + } +} \ No newline at end of file diff --git a/src/services/syntax/formattingOptions.ts b/src/services/syntax/formattingOptions.ts new file mode 100644 index 00000000000..ddbf7af9301 --- /dev/null +++ b/src/services/syntax/formattingOptions.ts @@ -0,0 +1,13 @@ +/// + +module TypeScript { + export class FormattingOptions { + constructor(public useTabs: boolean, + public spacesPerTab: number, + public indentSpaces: number, + public newLineCharacter: string) { + } + + public static defaultOptions = new FormattingOptions(/*useTabs:*/ false, /*spacesPerTab:*/ 4, /*indentSpaces:*/ 4, /*newLineCharacter*/ "\r\n"); + } +} \ No newline at end of file diff --git a/src/services/syntax/incrementalParser.ts b/src/services/syntax/incrementalParser.ts new file mode 100644 index 00000000000..94423418f42 --- /dev/null +++ b/src/services/syntax/incrementalParser.ts @@ -0,0 +1,865 @@ +/// + +module TypeScript.IncrementalParser { + interface IParserRewindPoint { + // Information used by the incremental parser source. + oldSourceUnitCursor: SyntaxCursor; + changeDelta: number; + changeRange: TextChangeRange; + } + + // Parser source used in incremental scenarios. This parser source wraps an old tree, text + // change and new text, and uses all three to provide nodes and tokens to the parser. In + // general, nodes from the old tree are returned as long as they do not intersect with the text + // change. Then, once the text change is reached, tokens from the old tree are returned as + // long as they do not intersect with the text change. Then, the text that is actually changed + // will be scanned using a normal scanner. Then, once the new text is scanned, the source will + // attempt to sync back up with nodes or tokens that started where the new tokens end. Once it + // can do that, then all subsequent data will come from the original tree. + // + // This allows for an enormous amount of tree reuse in common scenarios. Situations that + // prevent this level of reuse include substantially destructive operations like introducing + // "/*" without a "*/" nearby to terminate the comment. + function createParserSource(oldSyntaxTree: SyntaxTree, textChangeRange: TextChangeRange, text: ISimpleText): Parser.IParserSource { + var fileName = oldSyntaxTree.fileName(); + var languageVersion = oldSyntaxTree.languageVersion(); + + // The underlying source that we will use to scan tokens from any new text, or any tokens + // from the old tree that we decide we can't use for any reason. We will also continue + // scanning tokens from this source until we've decided that we're resynchronized and can + // read in subsequent data from the old tree. + // + // This parser source also keeps track of the absolute position in the text that we're in, + // and any token diagnostics produced. That way we dont' have to track that ourselves. + var _scannerParserSource: Scanner.IScannerParserSource; + + // The range of text in the *original* text that was changed, and the new length of it after + // the change. + var _changeRange: TextChangeRange; + + // Cached value of _changeRange.newSpan(). Cached for performance. + var _changeRangeNewSpan: TextSpan; + + // This number represents how our position in the old tree relates to the position we're + // pointing at in the new text. If it is 0 then our positions are in sync and we can read + // nodes or tokens from the old tree. If it is non-zero, then our positions are not in + // sync and we cannot use nodes or tokens from the old tree. + // + // Now, changeDelta could be negative or positive. Negative means 'the position we're at + // in the original tree is behind the position we're at in the text'. In this case we + // keep throwing out old nodes or tokens (and thus move forward in the original tree) until + // changeDelta becomes 0 again or positive. If it becomes 0 then we are resynched and can + // read nodes or tokesn from the tree. + // + // If changeDelta is positive, that means the current node or token we're pointing at in + // the old tree is at a further ahead position than the position we're pointing at in the + // new text. In this case we have no choice but to scan tokens from teh new text. We will + // continue to do so until, again, changeDelta becomes 0 and we've resynced, or change delta + // becomes negative and we need to skip nodes or tokes in the original tree. + var _changeDelta: number = 0; + + // The cursor we use to navigate through and retrieve nodes and tokens from the old tree. + var _oldSourceUnitCursor = getSyntaxCursor(); + var oldSourceUnit = oldSyntaxTree.sourceUnit(); + + var _outstandingRewindPointCount = 0; + + // Start the cursor pointing at the first element in the source unit (if it exists). + if (oldSourceUnit.moduleElements.length > 0) { + _oldSourceUnitCursor.pushElement(childAt(oldSourceUnit.moduleElements, 0), /*indexInParent:*/ 0); + } + + // In general supporting multiple individual edits is just not that important. So we + // just collapse this all down to a single range to make the code here easier. The only + // time this could be problematic would be if the user made a ton of discontinuous edits. + // For example, doing a column select on a *large* section of a code. If this is a + // problem, we can always update this code to handle multiple changes. + _changeRange = extendToAffectedRange(textChangeRange, oldSourceUnit); + _changeRangeNewSpan = _changeRange.newSpan(); + + // The old tree's length, plus whatever length change was caused by the edit + // Had better equal the new text's length! + if (Debug.shouldAssert(AssertionLevel.Aggressive)) { + Debug.assert((fullWidth(oldSourceUnit) - _changeRange.span().length() + _changeRange.newLength()) === text.length()); + } + + // Set up a scanner so that we can scan tokens out of the new text. + _scannerParserSource = Scanner.createParserSource(oldSyntaxTree.fileName(), text, oldSyntaxTree.languageVersion()); + + function release() { + _scannerParserSource.release(); + _scannerParserSource = null; + _oldSourceUnitCursor = null; + _outstandingRewindPointCount = 0; + } + + function extendToAffectedRange(changeRange: TextChangeRange, + sourceUnit: SourceUnitSyntax): TextChangeRange { + // Consider the following code: + // void foo() { /; } + // + // If the text changes with an insertion of / just before the semicolon then we end up with: + // void foo() { //; } + // + // If we were to just use the changeRange a is, then we would not rescan the { token + // (as it does not intersect the actual original change range). Because an edit may + // change the token touching it, we actually need to look back *at least* one token so + // that the prior token sees that change. + // + // Note: i believe (outside of regex tokens) max lookahead is just one token for + // TypeScript. However, if this turns out to be wrong, we may have to increase how much + // futher we look back. + // + // Note: lookahead handling for regex characters is handled specially in during + // incremental parsing, and does not need to be handled here. + + var maxLookahead = 1; + + var start = changeRange.span().start(); + + // the first iteration aligns us with the change start. subsequent iteration move us to + // the left by maxLookahead tokens. We only need to do this as long as we're not at the + // start of the tree. + for (var i = 0; start > 0 && i <= maxLookahead; i++) { + var token = findToken(sourceUnit, start); + + // Debug.assert(token.kind !== SyntaxKind.None); + // Debug.assert(token.kind() === SyntaxKind.EndOfFileToken || token.fullWidth() > 0); + + var position = token.fullStart(); + + start = Math.max(0, position - 1); + } + + var finalSpan = TextSpan.fromBounds(start, changeRange.span().end()); + var finalLength = changeRange.newLength() + (changeRange.span().start() - start); + + return new TextChangeRange(finalSpan, finalLength); + } + + function absolutePosition() { + return _scannerParserSource.absolutePosition(); + } + + function tokenDiagnostics(): Diagnostic[] { + return _scannerParserSource.tokenDiagnostics(); + } + + function getRewindPoint() { + // Get a rewind point for our new text reader and for our old source unit cursor. + var rewindPoint = _scannerParserSource.getRewindPoint(); + + // Clone our cursor. That way we can restore to that point if hte parser needs to rewind. + var oldSourceUnitCursorClone = cloneSyntaxCursor(_oldSourceUnitCursor); + + // Store where we were when the rewind point was created. + rewindPoint.changeDelta = _changeDelta; + rewindPoint.changeRange = _changeRange; + rewindPoint.oldSourceUnitCursor = _oldSourceUnitCursor; + + _oldSourceUnitCursor = oldSourceUnitCursorClone; + + // Debug.assert(rewindPoint.pinCount === _oldSourceUnitCursor.pinCount()); + + _outstandingRewindPointCount++; + return rewindPoint; + } + + function rewind(rewindPoint: IParserRewindPoint): void { + // Restore our state to the values when the rewind point was created. + _changeRange = rewindPoint.changeRange; + _changeDelta = rewindPoint.changeDelta; + + // Reset the cursor to what it was when we got the rewind point. Make sure to return + // our existing cursor to the pool so it can be reused. + returnSyntaxCursor(_oldSourceUnitCursor); + _oldSourceUnitCursor = rewindPoint.oldSourceUnitCursor; + + // Null out the cursor that the rewind point points to. This way we don't try + // to return it in 'releaseRewindPoint'. + rewindPoint.oldSourceUnitCursor = null; + + _scannerParserSource.rewind(rewindPoint); + } + + function releaseRewindPoint(rewindPoint: IParserRewindPoint): void { + if (rewindPoint.oldSourceUnitCursor !== null) { + returnSyntaxCursor(rewindPoint.oldSourceUnitCursor); + } + + _scannerParserSource.releaseRewindPoint(rewindPoint); + _outstandingRewindPointCount--; + Debug.assert(_outstandingRewindPointCount >= 0); + } + + function isPinned() { + return _outstandingRewindPointCount > 0; + } + + function canReadFromOldSourceUnit() { + // If we're currently pinned, then do not want to touch the cursor. Here's why. First, + // recall that we're 'pinned' when we're speculatively parsing. So say we were to allow + // returning old nodes/tokens while speculatively parsing. Then, the parser might start + // mutating the nodes and tokens we returned (i.e. by setting their parents). Then, + // when we rewound, those nodes and tokens would still have those updated parents. + // Parents which we just decided we did *not* want to parse (hence why we rewound). For + // Example, say we have something like: + // + // var v = fe; // note: this is not generic. + // + // When incrementally parsing, we will need to speculatively parse to determine if the + // above is generic. This will cause us to reuse the "a, b, c" tokens, and set their + // parent to a new type argument list. A type argument list we will then throw away once + // we decide that it isn't actually generic. We will have now 'broken' the original tree. + // + // As such, the rule is simple. We only return nodes/tokens from teh original tree if + // we know the parser will accept and consume them and never rewind back before them. + if (isPinned()) { + return false; + } + + // If our current absolute position is in the middle of the changed range in the new text + // then we definitely can't read from the old source unit right now. + if (_changeRange !== null && _changeRangeNewSpan.intersectsWithPosition(absolutePosition())) { + return false; + } + + // First, try to sync up with the new text if we're behind. + syncCursorToNewTextIfBehind(); + + // Now, if we're synced up *and* we're not currently pinned in the new text scanner, + // then we can read a node from the cursor. If we're pinned in the scanner then we + // can't read a node from the cursor because we will mess up the pinned scanner when + // we try to move it forward past this node. + return _changeDelta === 0 && + !_oldSourceUnitCursor.isFinished(); + } + + function updateTokens(nodeOrToken: ISyntaxNodeOrToken): void { + // If we got a node or token, and we're past the range of edited text, then walk its + // constituent tokens, making sure all their positions are correct. We don't need to + // do this for the tokens before the edited range (since their positions couldn't have + // been affected by the edit), and we don't need to do this for the tokens in the + // edited range, as their positions will be correct when the underlying parser source + // creates them. + + var position = absolutePosition(); + var tokenWasMoved = isPastChangeRange() && fullStart(nodeOrToken) !== position; + + if (tokenWasMoved) { + setTokenFullStartWalker.position = position; + + visitNodeOrToken(setTokenFullStartWalker, nodeOrToken); + } + } + + function currentNode(): ISyntaxNode { + if (canReadFromOldSourceUnit()) { + // Try to read a node. If we can't then our caller will call back in and just try + // to get a token. + var node = tryGetNodeFromOldSourceUnit(); + if (node !== null) { + // Make sure the positions for the tokens in this node are correct. + updateTokens(node); + return node; + } + } + + // Either we were ahead of the old text, or we were pinned. No node can be read here. + return null; + } + + function currentToken(): ISyntaxToken { + if (canReadFromOldSourceUnit()) { + var token = tryGetTokenFromOldSourceUnit(); + if (token !== null) { + // Make sure the token's position/text is correct. + updateTokens(token); + return token; + } + } + + // Either we couldn't read from the old source unit, or we weren't able to successfully + // get a token from it. In this case we need to read a token from the underlying text. + return _scannerParserSource.currentToken(); + } + + function currentContextualToken(): ISyntaxToken { + // Just delegate to the underlying source to handle + return _scannerParserSource.currentContextualToken(); + } + + function syncCursorToNewTextIfBehind() { + while (true) { + if (_oldSourceUnitCursor.isFinished()) { + // Can't sync up if the cursor is finished. + break; + } + + if (_changeDelta >= 0) { + // Nothing to do if we're synced up or ahead of the text. + break; + } + + // We're behind in the original tree. Throw out a node or token in an attempt to + // catch up to the position we're at in the new text. + + var currentNodeOrToken = _oldSourceUnitCursor.currentNodeOrToken(); + + // If we're pointing at a node, and that node's width is less than our delta, + // then we can just skip that node. Otherwise, if we're pointing at a node + // whose width is greater than the delta, then crumble it and try again. + // Otherwise, we must be pointing at a token. Just skip it and try again. + + if (isNode(currentNodeOrToken) && (fullWidth(currentNodeOrToken) > Math.abs(_changeDelta))) { + // We were pointing at a node whose width was more than changeDelta. Crumble the + // node and try again. Note: we haven't changed changeDelta. So the callers loop + // will just repeat this until we get to a node or token that we can skip over. + _oldSourceUnitCursor.moveToFirstChild(); + } + else { + _oldSourceUnitCursor.moveToNextSibling(); + + // Get our change delta closer to 0 as we skip past this item. + _changeDelta += fullWidth(currentNodeOrToken); + + // If this was a node, then our changeDelta is 0 or negative. If this was a + // token, then we could still be negative (and we have to read another token), + // we could be zero (we're done), or we could be positive (we've moved ahead + // of the new text). Only if we're negative will we continue looping. + } + } + + // At this point, we must be either: + // a) done with the cursor + // b) (ideally) caught up to the new text position. + // c) ahead of the new text position. + // In case 'b' we can try to reuse a node from teh old tree. + // Debug.assert(_oldSourceUnitCursor.isFinished() || _changeDelta >= 0); + } + + function intersectsWithChangeRangeSpanInOriginalText(start: number, length: number) { + return !isPastChangeRange() && _changeRange.span().intersectsWith(start, length); + } + + function tryGetNodeFromOldSourceUnit(): ISyntaxNode { + // Debug.assert(canReadFromOldSourceUnit()); + + // Keep moving the cursor down to the first node that is safe to return. A node is + // safe to return if: + // a) it does not intersect the changed text. + // b) it does not contain skipped text. + // c) it does not have any zero width tokens in it. + // d) it does not have a regex token in it. + // e) we are still in the same strict or non-strict state that the node was originally parsed in. + while (true) { + var node = _oldSourceUnitCursor.currentNode(); + if (node === null) { + // Couldn't even read a node, nothing to return. + return null; + } + + if (!intersectsWithChangeRangeSpanInOriginalText(absolutePosition(), fullWidth(node))) { + // Didn't intersect with the change range. + var isIncrementallyUnusuable = TypeScript.isIncrementallyUnusable(node); + if (!isIncrementallyUnusuable) { + + // Didn't contain anything that would make it unusable. Awesome. This is + // a node we can reuse. + return node; + } + } + + // We couldn't use currentNode. Try to move to its first child (in case that's a + // node). If it is we can try using that. Otherwise we'll just bail out in the + // next iteration of the loop. + _oldSourceUnitCursor.moveToFirstChild(); + } + } + + function canReuseTokenFromOldSourceUnit(position: number, token: ISyntaxToken): boolean { + // A token is safe to return if: + // a) it does not intersect the changed text. + // b) it does not contain skipped text. + // c) it is not zero width. + // d) it is not a contextual parser token. + // + // NOTE: It is safe to get a token regardless of what our strict context was/is. That's + // because the strict context doesn't change what tokens are scanned, only how the + // parser reacts to them. + // + // NOTE: we don't mark a keyword that was converted to an identifier as 'incrementally + // unusable. This is because we don't want to mark it's containing parent node as + // unusable. i.e. if i have this: "public Foo(string: Type) { }", then that *entire* node + // is reusuable even though "string" was converted to an identifier. However, we still + // need to make sure that if that the parser asks for a *token* we don't return it. + // Converted identifiers can't ever be created by the scanner, and as such, should not + // be returned by this source. + if (token !== null) { + if (!intersectsWithChangeRangeSpanInOriginalText(position, token.fullWidth())) { + // Didn't intersect with the change range. + if (!token.isIncrementallyUnusable() && !Scanner.isContextualToken(token)) { + + // Didn't contain anything that would make it unusable. Awesome. This is + // a token we can reuse. + return true; + } + } + } + + return false; + } + + function tryGetTokenFromOldSourceUnit(): ISyntaxToken { + // Debug.assert(canReadFromOldSourceUnit()); + + // get the current token that the cursor is pointing at. + var token = _oldSourceUnitCursor.currentToken(); + + return canReuseTokenFromOldSourceUnit(absolutePosition(), token) + ? token : null; + } + + function peekToken(n: number): ISyntaxToken { + if (canReadFromOldSourceUnit()) { + var token = tryPeekTokenFromOldSourceUnit(n); + if (token !== null) { + return token; + } + } + + // Couldn't peek this far in the old tree. Get the token from the new text. + return _scannerParserSource.peekToken(n); + } + + function tryPeekTokenFromOldSourceUnit(n: number): ISyntaxToken { + // Debug.assert(canReadFromOldSourceUnit()); + + // clone the existing cursor so we can move it forward and then restore ourselves back + // to where we started from. + + var cursorClone = cloneSyntaxCursor(_oldSourceUnitCursor); + + var token = tryPeekTokenFromOldSourceUnitWorker(n); + + returnSyntaxCursor(_oldSourceUnitCursor); + _oldSourceUnitCursor = cursorClone; + + return token; + } + + function tryPeekTokenFromOldSourceUnitWorker(n: number): ISyntaxToken { + // In order to peek the 'nth' token we need all the tokens up to that point. That way + // we know we know position that the nth token is at. The position is necessary so + // that we can test if this token (or any that precede it cross the change range). + var currentPosition = absolutePosition(); + + // First, make sure the cursor is pointing at a token. + _oldSourceUnitCursor.moveToFirstToken(); + + // Now, keep walking forward to successive tokens. + for (var i = 0; i < n; i++) { + var interimToken = _oldSourceUnitCursor.currentToken(); + + if (!canReuseTokenFromOldSourceUnit(currentPosition, interimToken)) { + return null; + } + + currentPosition += interimToken.fullWidth(); + _oldSourceUnitCursor.moveToNextSibling(); + } + + var token = _oldSourceUnitCursor.currentToken(); + return canReuseTokenFromOldSourceUnit(currentPosition, token) + ? token : null; + } + + function consumeNode(node: ISyntaxNode): void { + // A node could have only come from the old source unit cursor. Update it and our + // current state. + // Debug.assert(_changeDelta === 0); + // Debug.assert(currentNode() === node); + + _oldSourceUnitCursor.moveToNextSibling(); + + // Update the underlying source with where it should now be currently pointin. + var _absolutePosition = absolutePosition() + fullWidth(node); + _scannerParserSource.resetToPosition(_absolutePosition); + + // Debug.assert(previousToken !== null); + // Debug.assert(previousToken.width() > 0); + + //if (!isPastChangeRange()) { + // // If we still have a change range, then this node must have ended before the + // // change range starts. Thus, we don't need to call 'skipPastChanges'. + // Debug.assert(absolutePosition() < _changeRange.span().start()); + //} + } + + function consumeToken(currentToken: ISyntaxToken): void { + // This token may have come from the old source unit, or from the new text. Handle + // both accordingly. + + if (_oldSourceUnitCursor.currentToken() === currentToken) { + // The token came from the old source unit. So our tree and text must be in sync. + // Debug.assert(_changeDelta === 0); + + // Move the cursor past this token. + _oldSourceUnitCursor.moveToNextSibling(); + + // Debug.assert(!_normalParserSource.isPinned()); + + // Update the underlying source with where it should now be currently pointing. We + // don't need to do this when the token came from the new text as the source will + // automatically be placed in the right position. + var _absolutePosition = absolutePosition() + currentToken.fullWidth(); + _scannerParserSource.resetToPosition(_absolutePosition); + + // Debug.assert(previousToken !== null); + // Debug.assert(previousToken.width() > 0); + + //if (!isPastChangeRange()) { + // // If we still have a change range, then this token must have ended before the + // // change range starts. Thus, we don't need to call 'skipPastChanges'. + // Debug.assert(absolutePosition() < _changeRange.span().start()); + //} + } + else { + // the token came from the new text. That means the normal source moved forward, + // while the syntax cursor stayed in the same place. Thus our delta moves even + // further back. + _changeDelta -= currentToken.fullWidth(); + + // Move our underlying source forward. + _scannerParserSource.consumeToken(currentToken); + + // Because we read a token from the new text, we may have moved ourselves past the + // change range. If we did, then we may also have to update our change delta to + // compensate for the length change between the old and new text. + if (!isPastChangeRange()) { + // var changeEndInNewText = _changeRange.span().start() + _changeRange.newLength(); + if (absolutePosition() >= _changeRangeNewSpan.end()) { + _changeDelta += _changeRange.newLength() - _changeRange.span().length(); + + // Once we're past the change range, we no longer need it. Null it out. + // From now on we can check if we're past the change range just by seeing + // if this is null. + _changeRange = null; + } + } + } + } + + function isPastChangeRange(): boolean { + return _changeRange === null; + } + + return { + text: text, + fileName: fileName, + languageVersion: languageVersion, + currentNode: currentNode, + currentToken: currentToken, + currentContextualToken: currentContextualToken, + peekToken: peekToken, + consumeNode: consumeNode, + consumeToken: consumeToken, + getRewindPoint: getRewindPoint, + rewind: rewind, + releaseRewindPoint: releaseRewindPoint, + tokenDiagnostics: tokenDiagnostics, + release: release + }; + } + + interface SyntaxCursorPiece { + element: ISyntaxElement; + indexInParent: number + } + + function createSyntaxCursorPiece(element: ISyntaxElement, indexInParent: number) { + return { element: element, indexInParent: indexInParent }; + } + + // Pool syntax cursors so we don't churn too much memory when we need temporary cursors. + // i.e. when we're speculatively parsing, we can cheaply get a pooled cursor and then + // return it when we no longer need it. + var syntaxCursorPool: SyntaxCursor[] = []; + var syntaxCursorPoolCount: number = 0; + + function returnSyntaxCursor(cursor: SyntaxCursor): void { + // Make sure the cursor isn't holding onto any syntax elements. We don't want to leak + // them when we return the cursor to the pool. + cursor.clean(); + + syntaxCursorPool[syntaxCursorPoolCount] = cursor; + syntaxCursorPoolCount++; + } + + function getSyntaxCursor(): SyntaxCursor { + // Get an existing cursor from the pool if we have one. Or create a new one if we don't. + var cursor = syntaxCursorPoolCount > 0 + ? syntaxCursorPool[syntaxCursorPoolCount - 1] + : createSyntaxCursor(); + + if (syntaxCursorPoolCount > 0) { + // If we reused an existing cursor, take it out of the pool so no one else uses it. + syntaxCursorPoolCount--; + syntaxCursorPool[syntaxCursorPoolCount] = null; + } + + return cursor; + } + + function cloneSyntaxCursor(cursor: SyntaxCursor): SyntaxCursor { + var newCursor = getSyntaxCursor(); + + // Make the new cursor a *deep* copy of the cursor passed in. This ensures each cursor can + // be moved without affecting the other. + newCursor.deepCopyFrom(cursor); + + return newCursor; + } + + interface SyntaxCursor { + pieces: SyntaxCursorPiece[]; + + clean(): void; + isFinished(): boolean; + moveToFirstChild(): void; + moveToFirstToken(): void; + moveToNextSibling(): void; + currentNodeOrToken(): ISyntaxNodeOrToken; + currentNode(): ISyntaxNode; + currentToken(): ISyntaxToken; + pushElement(element: ISyntaxElement, indexInParent: number): void; + deepCopyFrom(other: SyntaxCursor): void; + } + + function createSyntaxCursor(): SyntaxCursor { + // Our list of path pieces. The piece pointed to by 'currentPieceIndex' must be a node or + // token. However, pieces earlier than that may point to list nodes. + // + // For perf we reuse pieces as much as possible. i.e. instead of popping items off the + // list, we just will change currentPieceIndex so we can reuse that piece later. + var pieces: SyntaxCursorPiece[] = []; + var currentPieceIndex: number = -1; + + // Cleans up this cursor so that it doesn't have any references to actual syntax nodes. + // This sould be done before returning the cursor to the pool so that the Parser module + // doesn't unnecessarily keep old syntax trees alive. + function clean(): void { + for (var i = 0, n = pieces.length; i < n; i++) { + var piece = pieces[i]; + + if (piece.element === null) { + break; + } + + piece.element = null; + piece.indexInParent = -1; + } + + currentPieceIndex = -1; + } + + // Makes this cursor into a deep copy of the cursor passed in. + function deepCopyFrom(other: SyntaxCursor): void { + // Debug.assert(currentPieceIndex === -1); + for (var i = 0, n = other.pieces.length; i < n; i++) { + var piece = other.pieces[i]; + + if (piece.element === null) { + break; + } + + pushElement(piece.element, piece.indexInParent); + } + + // Debug.assert(currentPieceIndex === other.currentPieceIndex); + } + + function isFinished(): boolean { + return currentPieceIndex < 0; + } + + function currentNodeOrToken(): ISyntaxNodeOrToken { + if (isFinished()) { + return null; + } + + var result = pieces[currentPieceIndex].element; + + // The current element must always be a node or a token. + // Debug.assert(result !== null); + // Debug.assert(result.isNode() || result.isToken()); + + return result; + } + + function currentNode(): ISyntaxNode { + var element = currentNodeOrToken(); + return isNode(element) ? element : null; + } + + function moveToFirstChild() { + var nodeOrToken = currentNodeOrToken(); + if (nodeOrToken === null) { + return; + } + + if (isToken(nodeOrToken)) { + // If we're already on a token, there's nothing to do. + return; + } + + // The last element must be a token or a node. + // Debug.assert(isNode(nodeOrToken)); + + // Either the node has some existent child, then move to it. if it doesn't, then it's + // an empty node. Conceptually the first child of an empty node is really just the + // next sibling of the empty node. + for (var i = 0, n = childCount(nodeOrToken); i < n; i++) { + var child = childAt(nodeOrToken, i); + if (child !== null && !isShared(child)) { + // Great, we found a real child. Push that. + pushElement(child, /*indexInParent:*/ i); + + // If it was a list, make sure we're pointing at its first element. We know we + // must have one because this is a non-shared list. + moveToFirstChildIfList(); + return; + } + } + + // This element must have been an empty node. Moving to its 'first child' is equivalent to just + // moving to the next sibling. + + // Debug.assert(fullWidth(nodeOrToken) === 0); + moveToNextSibling(); + } + + function moveToNextSibling(): void { + while (!isFinished()) { + // first look to our parent and see if it has a sibling of us that we can move to. + var currentPiece = pieces[currentPieceIndex]; + var parent = currentPiece.element.parent; + + // We start searching at the index one past our own index in the parent. + for (var i = currentPiece.indexInParent + 1, n = childCount(parent); i < n; i++) { + var sibling = childAt(parent, i); + + if (sibling !== null && !isShared(sibling)) { + // We found a good sibling that we can move to. Just reuse our existing piece + // so we don't have to push/pop. + currentPiece.element = sibling; + currentPiece.indexInParent = i; + + // The sibling might have been a list. Move to it's first child. it must have + // one since this was a non-shared element. + moveToFirstChildIfList(); + return; + } + } + + // Didn't have a sibling for this element. Go up to our parent and get its sibling. + + // Clear the data from the old piece. We don't want to keep any elements around + // unintentionally. + currentPiece.element = null; + currentPiece.indexInParent = -1; + + // Point at the parent. if we move past the top of the path, then we're finished. + currentPieceIndex--; + } + } + + function moveToFirstChildIfList(): void { + var element = pieces[currentPieceIndex].element; + + if (isList(element) || isSeparatedList(element)) { + // We cannot ever get an empty list in our piece path. Empty lists are 'shared' and + // we make sure to filter that out before pushing any children. + // Debug.assert(childCount(element) > 0); + + pushElement(childAt(element, 0), /*indexInParent:*/ 0); + } + } + + function pushElement(element: ISyntaxElement, indexInParent: number): void { + // Debug.assert(element !== null); + // Debug.assert(indexInParent >= 0); + currentPieceIndex++; + + // Reuse an existing piece if we have one. Otherwise, push a new piece to our list. + if (currentPieceIndex === pieces.length) { + pieces.push(createSyntaxCursorPiece(element, indexInParent)); + } + else { + var piece = pieces[currentPieceIndex]; + piece.element = element; + piece.indexInParent = indexInParent; + } + } + + function moveToFirstToken(): void { + while (!isFinished()) { + var element = pieces[currentPieceIndex].element; + if (isNode(element)) { + moveToFirstChild(); + continue; + } + + // Debug.assert(isToken(element)); + return; + } + } + + function currentToken(): ISyntaxToken { + moveToFirstToken(); + + var element = currentNodeOrToken(); + // Debug.assert(element === null || element.isToken()); + return element === null ? null : element; + } + + return { + pieces: pieces, + clean: clean, + isFinished: isFinished, + moveToFirstChild: moveToFirstChild, + moveToFirstToken: moveToFirstToken, + moveToNextSibling: moveToNextSibling, + currentNodeOrToken: currentNodeOrToken, + currentNode: currentNode, + currentToken: currentToken, + pushElement: pushElement, + deepCopyFrom: deepCopyFrom + }; + } + + // A simple walker we use to hit all the tokens of a node and update their positions when they + // are reused in a different location because of an incremental parse. + + class SetTokenFullStartWalker extends SyntaxWalker { + public position: number; + + public visitToken(token: ISyntaxToken): void { + var position = this.position; + token.setFullStart(position); + + this.position = position + token.fullWidth(); + } + } + + var setTokenFullStartWalker = new SetTokenFullStartWalker(); + + export function parse(oldSyntaxTree: SyntaxTree, textChangeRange: TextChangeRange, newText: ISimpleText): SyntaxTree { + Debug.assert(oldSyntaxTree.isConcrete(), "Can only incrementally parse a concrete syntax tree."); + if (textChangeRange.isUnchanged()) { + return oldSyntaxTree; + } + + return Parser.parseSource(createParserSource(oldSyntaxTree, textChangeRange, newText), oldSyntaxTree.isDeclaration()); + } +} \ No newline at end of file diff --git a/src/services/syntax/languageVersion.ts b/src/services/syntax/languageVersion.ts new file mode 100644 index 00000000000..0c662a0307c --- /dev/null +++ b/src/services/syntax/languageVersion.ts @@ -0,0 +1,3 @@ +module TypeScript { + +} \ No newline at end of file diff --git a/src/services/syntax/parser.ts b/src/services/syntax/parser.ts new file mode 100644 index 00000000000..0c886f129fc --- /dev/null +++ b/src/services/syntax/parser.ts @@ -0,0 +1,4385 @@ +/// + +module TypeScript.Parser { + // The factory used to produce parse tree nodes. Injected normally by the + // TypeScript.Syntax.Abstract or TypeScript.Syntax.Conrete modules. + export var syntaxFactory: Syntax.ISyntaxFactory; + + // Interface that represents the source that the parser pulls tokens from. Essentially, this + // is the interface that the parser needs an underlying scanner to provide. This allows us to + // separate out "what" the parser does with the tokens it retrieves versus "how" it obtains + // the tokens. i.e. all the logic for parsing language constructs sits in ParserImpl, while + // all the logic for retrieving tokens sits in individual IParserSources. + // + // By separating out this interface, we also make incremental parsing much easier. Instead of + // having the parser directly sit on top of the scanner, we sit it on this abstraction. Then + // in incremental scenarios, we can use the IncrementalParserSource to pull tokens (or even + // full nodes) from the previous tree when possible. Of course, we'll still end up using a + // scanner for new text. But that can all happen inside the source, with none of the logic in + // the parser having to be aware of it. + // + // In general terms, a parser source represents a position within a text. At that position, + // one can ask for the 'currentToken' that the source is pointing at. Then, once the parser + // consumes that token it can ask the source to 'moveToNextToken'. + // + // Additional special abilities include: + // 1) Being able to peek an arbitrary number of tokens ahead efficiently. + // 2) Being able to retrieve fully parsed nodes from the source, not just tokens. This happens + // in incremental scenarios when the source is certain that the node is completley safe to + // reuse. + // 3) Being able to get a 'rewind point' to the current location. This allows the parser to + // speculatively parse as much as it wants, and then reset itself back to that point, + // ensuring that no state changes that occurred after getting the 'rewing point' are + // observable. + // 4) Being able to reinterpret the current token being pointed at as a regular expression + // token. This is necessary as the scanner does not have enough information to correctly + // distinguish "/" or "/=" as divide tokens, versus "/..../" as a regex token. If the + // parser sees a "/" in a place where a divide is not allowed, but a regex would be, then + // it can call into the source and ask if a regex token could be returned instead. The + // sources are smart enough to do that and not be affected by any additional work they may + // have done when they originally scanned that token. + export interface IParserSource { + // The text we are parsing. + text: ISimpleText; + + // the name of the file we're parsing. + fileName: string; + + // The version of the language we're using while parsing. Does not affect the final tree, + // but can affect the diagnostics produced while parsing. + languageVersion: ts.ScriptTarget; + + // The current syntax node the source is pointing at. Only available in incremental settings. + // The source can point at a node if that node doesn't intersect any of the text changes in + // the file, and doesn't contain certain unacceptable constructs. For example, if the node + // contains skipped text, then it will not be reused. + currentNode(): ISyntaxNode; + + // The current token the source is pointing at. + currentToken(): ISyntaxToken; + + // The current token reinterpretted contextually based on where the parser is. If the + // source is on a / or /= token, then it can be reinterpretted as a regex token. If the + // source is on a > token, it may be reinterpretted to: >> >>> >= >>= >>>= + currentContextualToken(): ISyntaxToken; + + // Peek any number of tokens ahead from the current location in source. peekToken(0) is + // equivalent to 'currentToken', peekToken(1) is the next token, peekToken(2) the token + // after that, etc. If the caller peeks past the end of the text, then EndOfFile tokens + // will be returned. + peekToken(n: number): ISyntaxToken; + + // Called to move the source to the next node or token once the parser has consumed the + // current one. + consumeNode(node: ISyntaxNode): void; + consumeToken(token: ISyntaxToken): void; + + // Gets a rewind point that the parser can use to move back to after it speculatively + // parses something. The source guarantees that if the parser calls 'rewind' with that + // point that it will be mostly in the same state that it was in when 'getRewindPoint' + // was called. i.e. calling currentToken, peekToken, tokenDiagnostics, etc. will result + // in the same values. One allowed exemption to this is 'currentNode'. If a rewind point + // is requested and rewound, then getting the currentNode may not be possible. However, + // as this is purely a performance optimization, it will not affect correctness. + // + // Note: that rewind points are not free (but they should also not be too expensive). So + // they should be used judiciously. While a rewind point is held by the parser, the source + // is not free to do things that it would normally do. For example, it cannot throw away + // tokens that it has scanned on or after the rewind point as it must keep them alive for + // the parser to move back to. + // + // Rewind points also work in a stack fashion. The first rewind point given out must be + // the last rewind point released. Do not release them out of order, or bad things can + // happen. + // + // Do *NOT* forget to release a rewind point. Always put them in a finally block to ensure + // that they are released. If they are not released, things will still work, you will just + // consume far more memory than necessary. + getRewindPoint(): IRewindPoint; + + // Rewinds the source to the position and state it was at when this rewind point was created. + // This does not need to be called if the parser decides it does not need to rewind. For + // example, the parser may speculatively parse out a lambda expression when it sees something + // ambiguous like "(a = b, c = ...". If it succeeds parsing that as a lambda, then it will + // just return that result. However, if it fails *then* it will rewind and try it again as + // a parenthesized expression. + rewind(rewindPoint: IRewindPoint): void; + + // Called when the parser is done speculative parsing and no longer needs the rewind point. + // Must be called for every rewind point retrived. + releaseRewindPoint(rewindPoint: IRewindPoint): void; + + // Retrieves the diagnostics generated while the source was producing nodes or tokens. + // Should generally only be called after the document has been completely parsed. + tokenDiagnostics(): Diagnostic[]; + + release(): void; + } + + // Information the parser needs to effectively rewind. + export interface IRewindPoint { + } + + var arrayPool: any[][] = []; + var arrayPoolCount: number = 0; + + function getArray(): any[] { + if (arrayPoolCount === 0) { + return []; + } + + arrayPoolCount--; + var result = arrayPool[arrayPoolCount]; + arrayPool[arrayPoolCount] = null; + + return result; + } + + function returnZeroLengthArray(array: any[]) { + if (array.length === 0) { + returnArray(array); + } + } + + function returnArray(array: any[]) { + array.length = 0; + arrayPool[arrayPoolCount] = array; + arrayPoolCount++; + } + + interface IParserRewindPoint extends IRewindPoint { + // As we speculatively parse, we may build up diagnostics. When we rewind we want to + // 'forget' that information.In order to do that we store the count of diagnostics and + // when we start speculating, and we reset to that count when we're done. That way the + // speculative parse does not affect any further results. + diagnosticsCount: number; + + // isInStrictMode and listParsingState should not have to be tracked by a rewind point. + // Because they are naturally mutated and restored based on the normal stack movement of + // the parser, they should automatically return to whatever value they had to begin with + // if the parser decides to rewind or not. However, to ensure that this is true, we track + // these variables and check if they have the same value when we're rewinding/releasing. + isInStrictMode: boolean; + listParsingState: ListParsingState; + } + + // Contains the actual logic to parse typescript/javascript. This is the code that generally + // represents the logic necessary to handle all the language grammar constructs. When the + // language changes, this should generally only be the place necessary to fix up. + function createParseSyntaxTree(): (source: IParserSource, isDeclaration: boolean) => SyntaxTree { + // Name of the file we're parsing. + var fileName: string; + + // Underlying source where we pull nodes and tokens from. + var source: IParserSource; + + var languageVersion: ts.ScriptTarget; + + // TODO: do we need to store/restore this when speculative parsing? I don't think so. The + // parsing logic already handles storing/restoring this and should work properly even if we're + // speculative parsing. + var listParsingState: number = 0; + + // Whether or not we are in strict parsing mode. All that changes in strict parsing mode is + // that some tokens that would be considered identifiers may be considered keywords. When + // rewinding, we need to store and restore this as the mode may have changed. + // + // TODO: do we need to store/restore this when speculative parsing? I don't think so. The + // parsing logic already handles storing/restoring this and should work properly even if we're + // speculative parsing. + var isInStrictMode: boolean = false; + + // Current state of the parser. If we need to rewind we will store and reset these values as + // appropriate. + + // Diagnostics created when parsing invalid code. Any diagnosics created when speculative + // parsing need to removed when rewinding. To do this we store the count of diagnostics when + // we start speculative parsing. And if we rewind, we restore this to the same count that we + // started at. + var diagnostics: Diagnostic[] = []; + + var parseNodeData: number = 0; + + function parseSyntaxTree(_source: IParserSource, isDeclaration: boolean): SyntaxTree { + // First, set up our state. + fileName = _source.fileName; + source = _source; + languageVersion = source.languageVersion; + + // Now actually parse the tree. + var result = parseSyntaxTreeWorker(isDeclaration); + + // Now, clear out our state so that our singleton parser doesn't keep things alive. + diagnostics = []; + parseNodeData = SyntaxConstants.None; + fileName = null; + source.release(); + source = null; _source = null; + + return result; + } + + function parseSyntaxTreeWorker(isDeclaration: boolean): SyntaxTree { + var sourceUnit = parseSourceUnit(); + + var allDiagnostics = source.tokenDiagnostics().concat(diagnostics); + allDiagnostics.sort((a: Diagnostic, b: Diagnostic) => a.start() - b.start()); + + return new SyntaxTree(syntaxFactory.isConcrete, sourceUnit, isDeclaration, allDiagnostics, fileName, source.text, languageVersion); + } + + function getRewindPoint(): IParserRewindPoint { + var rewindPoint = source.getRewindPoint(); + + rewindPoint.diagnosticsCount = diagnostics.length; + + // Values we keep around for debug asserting purposes. + rewindPoint.isInStrictMode = isInStrictMode; + rewindPoint.listParsingState = listParsingState; + + return rewindPoint; + } + + function rewind(rewindPoint: IParserRewindPoint): void { + source.rewind(rewindPoint); + + diagnostics.length = rewindPoint.diagnosticsCount; + } + + function releaseRewindPoint(rewindPoint: IParserRewindPoint): void { + // Debug.assert(listParsingState === rewindPoint.listParsingState); + // Debug.assert(isInStrictMode === rewindPoint.isInStrictMode); + + source.releaseRewindPoint(rewindPoint); + } + + function currentNode(): ISyntaxNode { + var node = source.currentNode(); + + // We can only reuse a node if it was parsed under the same strict mode that we're + // currently in. i.e. if we originally parsed a node in non-strict mode, but then + // the user added 'using strict' at the top of the file, then we can't use that node + // again as the presense of strict mode may cause us to parse the tokens in the file + // differetly. + // + // Note: we *can* reuse tokens when the strict mode changes. That's because tokens + // are unaffected by strict mode. It's just the parser will decide what to do with it + // differently depending on what mode it is in. + if (node === null || parsedInStrictMode(node) !== isInStrictMode) { + return null; + } + + return node; + } + + function currentToken(): ISyntaxToken { + return source.currentToken(); + } + + function currentContextualToken(): ISyntaxToken { + // We're mutating the source here. We are potentially overwriting the original token we + // scanned with a regex token. So we have to clear our state. + return source.currentContextualToken(); + } + + function peekToken(n: number): ISyntaxToken { + return source.peekToken(n); + } + + function consumeToken(token: ISyntaxToken): ISyntaxToken { + source.consumeToken(token); + return token; + } + + function consumeNode(node: ISyntaxNode): void { + source.consumeNode(node); + } + + //this method is called very frequently + //we should keep it simple so that it can be inlined. + function eatToken(kind: SyntaxKind): ISyntaxToken { + var token = currentToken(); + if (token.kind() === kind) { + return consumeToken(token); + } + + //slow part of EatToken(SyntaxKind kind) + return createMissingToken(kind, token); + } + + // Eats the token if it is there. Otherwise does nothing. Will not report errors. + function tryEatToken(kind: SyntaxKind): ISyntaxToken { + var _currentToken = currentToken(); + if (_currentToken.kind() === kind) { + return consumeToken(_currentToken); + } + + return null; + } + + // An identifier is basically any word, unless it is a reserved keyword. so 'foo' is an + // identifier and 'return' is not. Note: a word may or may not be an identifier depending + // on the state of the parser. For example, 'yield' is an identifier *unless* the parser + // is in strict mode. + function isIdentifier(token: ISyntaxToken): boolean { + var tokenKind = token.kind(); + + if (tokenKind === SyntaxKind.IdentifierName) { + return true; + } + + // Keywords are only identifiers if they're FutureReservedStrictWords and we're in + // strict mode. *Or* if it's a typescript 'keyword'. + if (tokenKind >= SyntaxKind.FirstFutureReservedStrictKeyword) { + if (tokenKind <= SyntaxKind.LastFutureReservedStrictKeyword) { + // Could be a keyword or identifier. It's an identifier if we're not in strict + // mode. + return !isInStrictMode; + } + + // If it's typescript keyword, then it's actually a javascript identifier. + return tokenKind <= SyntaxKind.LastTypeScriptKeyword; + } + + // Anything else is not an identifier. + return false; + } + + // This method should be called when the grammar calls for an *IdentifierName* and not an + // *Identifier*. + function eatIdentifierNameToken(): ISyntaxToken { + var token = currentToken(); + + // If we have an identifier name, then consume and return it. + var tokenKind = token.kind(); + if (tokenKind === SyntaxKind.IdentifierName) { + return consumeToken(token); + } + + // If we have a keyword, then it can be used as an identifier name. However, we need + // to convert it to an identifier so that no later parts of the systems see it as a + // keyword. + if (SyntaxFacts.isAnyKeyword(tokenKind)) { + return TypeScript.Syntax.convertKeywordToIdentifier(consumeToken(token)); + } + + return createMissingToken(SyntaxKind.IdentifierName, token); + } + + function eatOptionalIdentifierToken(): ISyntaxToken { + return isIdentifier(currentToken()) ? eatIdentifierToken() : null; + } + + // This method should be called when the grammar calls for an *Identifier* and not an + // *IdentifierName*. + function eatIdentifierToken(diagnosticCode?: string): ISyntaxToken { + var token = currentToken(); + if (isIdentifier(token)) { + consumeToken(token); + + if (token.kind() === SyntaxKind.IdentifierName) { + return token; + } + + return TypeScript.Syntax.convertKeywordToIdentifier(token); + } + + return createMissingToken(SyntaxKind.IdentifierName, token, diagnosticCode); + } + + function previousTokenHasTrailingNewLine(token: ISyntaxToken): boolean { + var tokenFullStart = token.fullStart(); + if (tokenFullStart === 0) { + // First token in the document. Thus it has no 'previous' token, and there is + // no preceding newline. + return false; + } + + // If our previous token ended with a newline, then *by definition* we must have started + // at the beginning of a line. + var lineNumber = source.text.lineMap().getLineNumberFromPosition(tokenFullStart); + var lineStart = source.text.lineMap().getLineStartPosition(lineNumber); + + return lineStart == tokenFullStart; + } + + function canEatAutomaticSemicolon(allowWithoutNewLine: boolean): boolean { + var token = currentToken(); + + // An automatic semicolon is always allowed if we're at the end of the file. + var tokenKind = token.kind(); + if (tokenKind === SyntaxKind.EndOfFileToken) { + return true; + } + + // Or if the next token is a close brace (regardless of which line it is on). + if (tokenKind === SyntaxKind.CloseBraceToken) { + return true; + } + + if (allowWithoutNewLine) { + return true; + } + + // It is also allowed if there is a newline between the last token seen and the next one. + if (previousTokenHasTrailingNewLine(token)) { + return true; + } + + return false; + } + + function canEatExplicitOrAutomaticSemicolon(allowWithoutNewline: boolean): boolean { + var token = currentToken(); + + if (token.kind() === SyntaxKind.SemicolonToken) { + return true; + } + + return canEatAutomaticSemicolon(allowWithoutNewline); + } + + function eatExplicitOrAutomaticSemicolon(allowWithoutNewline: boolean): ISyntaxToken { + var token = currentToken(); + + // If we see a semicolon, then we can definitely eat it. + if (token.kind() === SyntaxKind.SemicolonToken) { + return consumeToken(token); + } + + // Check if an automatic semicolon could go here. If so, then there's no problem and + // we can proceed without error. Return 'null' as there's no actual token for this + // position. + if (canEatAutomaticSemicolon(allowWithoutNewline)) { + return null; + } + + // No semicolon could be consumed here at all. Just call the standard eating function + // so we get the token and the error for it. + return eatToken(SyntaxKind.SemicolonToken); + } + + function createMissingToken(expectedKind: SyntaxKind, actual: ISyntaxToken, diagnosticCode?: string): ISyntaxToken { + var diagnostic = getExpectedTokenDiagnostic(expectedKind, actual, diagnosticCode); + addDiagnostic(diagnostic); + + // The missing token will be at the full start of the current token. That way empty tokens + // will always be between real tokens and not inside an actual token. + return Syntax.emptyToken(expectedKind); + } + + function getExpectedTokenDiagnostic(expectedKind: SyntaxKind, actual: ISyntaxToken, diagnosticCode: string): Diagnostic { + var token = currentToken(); + + var args: any[] = null; + // If a specialized diagnostic message was provided, just use that. + if (!diagnosticCode) { + // They wanted something specific, just report that that token was missing. + if (SyntaxFacts.isAnyKeyword(expectedKind) || SyntaxFacts.isAnyPunctuation(expectedKind)) { + diagnosticCode = DiagnosticCode._0_expected; + args = [SyntaxFacts.getText(expectedKind)]; + } + else { + // They wanted an identifier. + + // If the user supplied a keyword, give them a specialized message. + if (actual !== null && SyntaxFacts.isAnyKeyword(actual.kind())) { + diagnosticCode = DiagnosticCode.Identifier_expected_0_is_a_keyword; + args = [SyntaxFacts.getText(actual.kind())]; + } + else { + // Otherwise just report that an identifier was expected. + diagnosticCode = DiagnosticCode.Identifier_expected; + } + } + } + + return new Diagnostic(fileName, source.text.lineMap(), start(token, source.text), width(token), diagnosticCode, args); + } + + function getBinaryExpressionPrecedence(tokenKind: SyntaxKind): BinaryExpressionPrecedence { + switch (tokenKind) { + case SyntaxKind.BarBarToken: return BinaryExpressionPrecedence.LogicalOrExpressionPrecedence; + case SyntaxKind.AmpersandAmpersandToken: return BinaryExpressionPrecedence.LogicalAndExpressionPrecedence; + case SyntaxKind.BarToken: return BinaryExpressionPrecedence.BitwiseOrExpressionPrecedence; + case SyntaxKind.CaretToken: return BinaryExpressionPrecedence.BitwiseExclusiveOrExpressionPrecedence; + case SyntaxKind.AmpersandToken: return BinaryExpressionPrecedence.BitwiseAndExpressionPrecedence; + case SyntaxKind.EqualsEqualsToken: + case SyntaxKind.ExclamationEqualsToken: + case SyntaxKind.EqualsEqualsEqualsToken: + case SyntaxKind.ExclamationEqualsEqualsToken: + return BinaryExpressionPrecedence.EqualityExpressionPrecedence; + case SyntaxKind.LessThanToken: + case SyntaxKind.GreaterThanToken: + case SyntaxKind.LessThanEqualsToken: + case SyntaxKind.GreaterThanEqualsToken: + case SyntaxKind.InstanceOfKeyword: + case SyntaxKind.InKeyword: + return BinaryExpressionPrecedence.RelationalExpressionPrecedence; + case SyntaxKind.LessThanLessThanToken: + case SyntaxKind.GreaterThanGreaterThanToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: + return BinaryExpressionPrecedence.ShiftExpressionPrecdence; + case SyntaxKind.PlusToken: + case SyntaxKind.MinusToken: + return BinaryExpressionPrecedence.AdditiveExpressionPrecedence; + case SyntaxKind.AsteriskToken: + case SyntaxKind.SlashToken: + case SyntaxKind.PercentToken: + return BinaryExpressionPrecedence.MultiplicativeExpressionPrecedence; + } + + throw Errors.invalidOperation(); + } + + function addSkippedTokenAfterNodeOrToken(nodeOrToken: ISyntaxNodeOrToken, skippedToken: ISyntaxToken): ISyntaxNodeOrToken { + if (isToken(nodeOrToken)) { + return addSkippedTokenAfterToken(nodeOrToken, skippedToken); + } + else if (isNode(nodeOrToken)) { + return addSkippedTokenAfterNode(nodeOrToken, skippedToken); + } + else { + throw Errors.invalidOperation(); + } + } + + function replaceTokenInParent(oldToken: ISyntaxToken, newToken: ISyntaxToken): void { + // oldToken may be parented by a node or a list. + replaceTokenInParentWorker(oldToken, newToken); + + var parent = oldToken.parent; + newToken.parent = parent; + + // Parent must be a list or a node. All of those have a 'data' element. + Debug.assert(isNode(parent) || isList(parent) || isSeparatedList(parent)); + var dataElement = <{ data: number }>parent; + if (dataElement.data) { + dataElement.data &= SyntaxConstants.NodeParsedInStrictModeMask + } + } + + function replaceTokenInParentWorker(oldToken: ISyntaxToken, newToken: ISyntaxToken): void { + var parent = oldToken.parent; + + if (isNode(parent)) { + var node = parent; + for (var key in node) { + if (node[key] === oldToken) { + node[key] = newToken; + return; + } + } + } + else if (isList(parent)) { + var list1 = parent; + for (var i = 0, n = list1.length; i < n; i++) { + if (list1[i] === oldToken) { + list1[i] = newToken; + return; + } + } + } + else if (isSeparatedList(parent)) { + var list2 = parent; + for (var i = 0, n = childCount(list2); i < n; i++) { + if (childAt(list2, i) === oldToken) { + if (i % 2 === 0) { + list2[i / 2] = newToken; + } + else { + list2.separators[(i - 1) / 2] = newToken; + } + return; + } + } + } + + throw Errors.invalidOperation(); + } + + function addSkippedTokenAfterNode(node: ISyntaxNode, skippedToken: ISyntaxToken): ISyntaxNode { + var oldToken = lastToken(node); + var newToken = addSkippedTokenAfterToken(oldToken, skippedToken); + + replaceTokenInParent(oldToken, newToken); + return node; + } + + function addSkippedTokensBeforeNode(node: ISyntaxNode, skippedTokens: ISyntaxToken[]): ISyntaxNode { + if (skippedTokens.length > 0) { + var oldToken = firstToken(node); + var newToken = addSkippedTokensBeforeToken(oldToken, skippedTokens); + + replaceTokenInParent(oldToken, newToken); + } + + return node; + } + + function addSkippedTokensBeforeToken(token: ISyntaxToken, skippedTokens: ISyntaxToken[]): ISyntaxToken { + // Debug.assert(token.fullWidth() > 0 || token.kind() === SyntaxKind.EndOfFileToken); + // Debug.assert(skippedTokens.length > 0); + + var leadingTrivia: ISyntaxTrivia[] = []; + for (var i = 0, n = skippedTokens.length; i < n; i++) { + var skippedToken = skippedTokens[i]; + addSkippedTokenToTriviaArray(leadingTrivia, skippedToken); + } + + addTriviaTo(token.leadingTrivia(source.text), leadingTrivia); + + var updatedToken = Syntax.withLeadingTrivia(token, Syntax.triviaList(leadingTrivia), source.text); + + // We've prepending this token with new leading trivia. This means the full start of + // the token is not where the scanner originally thought it was, but is instead at the + // start of the first skipped token. + updatedToken.setFullStart(skippedTokens[0].fullStart()); + + // Don't need this array anymore. Give it back so we can reuse it. + returnArray(skippedTokens); + + return updatedToken; + } + + function addSkippedTokensAfterToken(token: ISyntaxToken, skippedTokens: ISyntaxToken[]): ISyntaxToken { + // Debug.assert(token.fullWidth() > 0); + if (skippedTokens.length === 0) { + returnArray(skippedTokens); + return token; + } + + var trailingTrivia = token.trailingTrivia(source.text).toArray(); + + for (var i = 0, n = skippedTokens.length; i < n; i++) { + addSkippedTokenToTriviaArray(trailingTrivia, skippedTokens[i]); + } + + // Don't need this array anymore. Give it back so we can reuse it. + returnArray(skippedTokens); + return Syntax.withTrailingTrivia(token, Syntax.triviaList(trailingTrivia), source.text); + } + + function addSkippedTokenAfterToken(token: ISyntaxToken, skippedToken: ISyntaxToken): ISyntaxToken { + // Debug.assert(token.fullWidth() > 0); + var trailingTrivia = token.trailingTrivia(source.text).toArray(); + addSkippedTokenToTriviaArray(trailingTrivia, skippedToken); + + return Syntax.withTrailingTrivia(token, Syntax.triviaList(trailingTrivia), source.text); + } + + function addSkippedTokenToTriviaArray(array: ISyntaxTrivia[], skippedToken: ISyntaxToken): void { + // Debug.assert(skippedToken.text().length > 0); + + // first, add the leading trivia of the skipped token to the array + addTriviaTo(skippedToken.leadingTrivia(source.text), array); + + // now, add the text of the token as skipped text to the trivia array. + var trimmedToken = Syntax.withTrailingTrivia(Syntax.withLeadingTrivia(skippedToken, Syntax.emptyTriviaList, source.text), Syntax.emptyTriviaList, source.text); + + // Because we removed the leading trivia from the skipped token, the full start of the + // trimmed token is the start of the skipped token. + trimmedToken.setFullStart(start(skippedToken, source.text)); + + array.push(Syntax.skippedTokenTrivia(trimmedToken, source.text)); + + // Finally, add the trailing trivia of the skipped token to the trivia array. + addTriviaTo(skippedToken.trailingTrivia(source.text), array); + } + + function addTriviaTo(list: ISyntaxTriviaList, array: ISyntaxTrivia[]): void { + for (var i = 0, n = list.count(); i < n; i++) { + array.push(list.syntaxTriviaAt(i)); + } + } + + function setStrictMode(_isInStrictMode: boolean) { + isInStrictMode = _isInStrictMode; + parseNodeData = _isInStrictMode ? SyntaxConstants.NodeParsedInStrictModeMask : 0; + } + + function parseSourceUnit(): SourceUnitSyntax { + var savedIsInStrictMode = isInStrictMode + + var skippedTokens: ISyntaxToken[] = getArray(); + var moduleElements = parseSyntaxList(ListParsingState.SourceUnit_ModuleElements, skippedTokens, updateStrictModeState); + + setStrictMode(savedIsInStrictMode); + + var sourceUnit = new syntaxFactory.SourceUnitSyntax(parseNodeData, moduleElements, currentToken()); + + sourceUnit = addSkippedTokensBeforeNode(sourceUnit, skippedTokens); + + if (Debug.shouldAssert(AssertionLevel.Aggressive)) { + Debug.assert(fullWidth(sourceUnit) === source.text.length()); + + if (Debug.shouldAssert(AssertionLevel.VeryAggressive)) { + Debug.assert(fullText(sourceUnit) === source.text.substr(0, source.text.length())); + } + } + + return sourceUnit; + } + + function updateStrictModeState(items: any[]): void { + if (!isInStrictMode) { + // Check if all the items are directive prologue elements. + for (var i = 0; i < items.length; i++) { + var item = items[i]; + if (!SyntaxFacts.isDirectivePrologueElement(item)) { + return; + } + } + + setStrictMode(SyntaxFacts.isUseStrictDirective(items[items.length - 1])); + } + } + + function isModuleElement(inErrorRecovery: boolean): boolean { + if (SyntaxUtilities.isModuleElement(currentNode())) { + return true; + } + + var _modifierCount = modifierCount(); + return isInterfaceEnumClassModuleImportOrExport(_modifierCount) || + isStatement(_modifierCount, inErrorRecovery); + } + + function tryParseModuleElement(inErrorRecovery: boolean): IModuleElementSyntax { + var node = currentNode(); + if (SyntaxUtilities.isModuleElement(node)) { + consumeNode(node); + return node; + } + + var _currentToken = currentToken(); + var _modifierCount = modifierCount(); + + if (_modifierCount) { + // if we have modifiers, then these are definitely TS constructs and we can + // immediately start parsing them. + switch (peekToken(_modifierCount).kind()) { + case SyntaxKind.ImportKeyword: return parseImportDeclaration(); + case SyntaxKind.ModuleKeyword: return parseModuleDeclaration(); + case SyntaxKind.InterfaceKeyword: return parseInterfaceDeclaration(); + case SyntaxKind.ClassKeyword: return parseClassDeclaration(); + case SyntaxKind.EnumKeyword: return parseEnumDeclaration(); + } + } + + // No modifiers. If we see 'class, enum, import and export' we could technically + // aggressively consume them as they can't start another construct. However, it's + // not uncommon in error recovery to run into a situation where we see those keywords, + // but the code was using it as the name of an object property. To avoid overzealously + // consuming these, we only parse them out if we can see enough context to 'prove' that + // they really do start the module element + var nextToken = peekToken(1); + var currentTokenKind = _currentToken.kind(); + switch (currentTokenKind) { + case SyntaxKind.ModuleKeyword: + if (isIdentifier(nextToken) || nextToken.kind() === SyntaxKind.StringLiteral) { + return parseModuleDeclaration(); + } + break; + + case SyntaxKind.ImportKeyword: + if (isIdentifier(nextToken)) { + return parseImportDeclaration(); + } + break; + + case SyntaxKind.ClassKeyword: + if (isIdentifier(nextToken)) { + return parseClassDeclaration(); + } + break; + + case SyntaxKind.EnumKeyword: + if (isIdentifier(nextToken)) { + return parseEnumDeclaration(); + } + break; + + case SyntaxKind.InterfaceKeyword: + if (isIdentifier(nextToken)) { + return parseInterfaceDeclaration(); + } + break; + + case SyntaxKind.ExportKeyword: + // 'export' could be a modifier on a statement (like export var ...). So we + // only want to parse out an export assignment here if we actually see the equals. + if (nextToken.kind() === SyntaxKind.EqualsToken) { + return parseExportAssignment(); + } + break; + } + + return tryParseStatementWorker(_currentToken, currentTokenKind, _modifierCount, inErrorRecovery); + } + + function parseImportDeclaration(): ImportDeclarationSyntax { + return new syntaxFactory.ImportDeclarationSyntax(parseNodeData, + parseModifiers(), eatToken(SyntaxKind.ImportKeyword), eatIdentifierToken(), eatToken(SyntaxKind.EqualsToken), parseModuleReference(), eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false)); + } + + function parseExportAssignment(): ExportAssignmentSyntax { + return new syntaxFactory.ExportAssignmentSyntax(parseNodeData, + eatToken(SyntaxKind.ExportKeyword), eatToken(SyntaxKind.EqualsToken), eatIdentifierToken(), eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false)); + } + + function parseModuleReference(): IModuleReferenceSyntax { + return isExternalModuleReference() ? parseExternalModuleReference() : parseModuleNameModuleReference(); + } + + function isExternalModuleReference(): boolean { + return currentToken().kind() === SyntaxKind.RequireKeyword && + peekToken(1).kind() === SyntaxKind.OpenParenToken; + } + + function parseExternalModuleReference(): ExternalModuleReferenceSyntax { + return new syntaxFactory.ExternalModuleReferenceSyntax(parseNodeData, + eatToken(SyntaxKind.RequireKeyword), eatToken(SyntaxKind.OpenParenToken), eatToken(SyntaxKind.StringLiteral), eatToken(SyntaxKind.CloseParenToken)); + } + + function parseModuleNameModuleReference(): ModuleNameModuleReferenceSyntax { + return new syntaxFactory.ModuleNameModuleReferenceSyntax(parseNodeData, parseName(/*allowIdentifierNames:*/ false)); + } + + function tryParseTypeArgumentList(inExpression: boolean): TypeArgumentListSyntax { + var _currentToken = currentToken(); + if (_currentToken.kind() !== SyntaxKind.LessThanToken) { + return null; + } + + if (!inExpression) { + // if we're not in an expression, this must be a type argument list. Just parse + // it out as such. + var lessThanToken = consumeToken(_currentToken); + + var skippedTokens: ISyntaxToken[] = getArray(); + var typeArguments = parseSeparatedSyntaxList(ListParsingState.TypeArgumentList_Types, skippedTokens); + lessThanToken = addSkippedTokensAfterToken(lessThanToken, skippedTokens); + + return new syntaxFactory.TypeArgumentListSyntax(parseNodeData, lessThanToken, typeArguments, eatToken(SyntaxKind.GreaterThanToken)); + } + + // If we're in an expression, then we only want to consume this as a type argument list + // if we're sure that it's a type arg list and not an arithmetic expression. + + var rewindPoint = getRewindPoint(); + + // We've seen a '<'. Try to parse it out as a type argument list. + var lessThanToken = consumeToken(_currentToken); + + var skippedTokens: ISyntaxToken[] = getArray(); + var typeArguments = parseSeparatedSyntaxList(ListParsingState.TypeArgumentList_Types, skippedTokens); + var lessThanToken = addSkippedTokensAfterToken(lessThanToken, skippedTokens); + + var greaterThanToken = eatToken(SyntaxKind.GreaterThanToken); + + // We're in a context where '<' could be the start of a type argument list, or part + // of an arithmetic expression. We'll presume it's the latter unless we see the '>' + // and a following token that guarantees that it's supposed to be a type argument list. + if (greaterThanToken.fullWidth() === 0 || !canFollowTypeArgumentListInExpression(currentToken().kind())) { + rewind(rewindPoint); + releaseRewindPoint(rewindPoint); + return null; + } + else { + releaseRewindPoint(rewindPoint); + return new syntaxFactory.TypeArgumentListSyntax(parseNodeData, lessThanToken, typeArguments, greaterThanToken); + } + } + + function canFollowTypeArgumentListInExpression(kind: SyntaxKind): boolean { + switch (kind) { + case SyntaxKind.OpenParenToken: // foo( + case SyntaxKind.DotToken: // foo. + // These two cases are the only cases where this token can legally follow a + // type argument list. So we definitely want to treat this as a type arg list. + + case SyntaxKind.CloseParenToken: // foo) + case SyntaxKind.CloseBracketToken: // foo] + case SyntaxKind.ColonToken: // foo: + case SyntaxKind.SemicolonToken: // foo; + case SyntaxKind.CommaToken: // foo, + case SyntaxKind.QuestionToken: // foo? + case SyntaxKind.EqualsEqualsToken: // foo == + case SyntaxKind.EqualsEqualsEqualsToken: // foo === + case SyntaxKind.ExclamationEqualsToken: // foo != + case SyntaxKind.ExclamationEqualsEqualsToken: // foo !== + case SyntaxKind.AmpersandAmpersandToken: // foo && + case SyntaxKind.BarBarToken: // foo || + case SyntaxKind.CaretToken: // foo ^ + case SyntaxKind.AmpersandToken: // foo & + case SyntaxKind.BarToken: // foo | + case SyntaxKind.CloseBraceToken: // foo } + case SyntaxKind.EndOfFileToken: // foo + // these cases can't legally follow a type arg list. However, they're not legal + // expressions either. The user is probably in the middle of a generic type. So + // treat it as such. + return true; + + default: + // Anything else treat as an expression. + return false; + } + } + + function parseName(allowIdentifierName: boolean): INameSyntax { + return tryParseName(allowIdentifierName) || eatIdentifierToken(); + } + + function eatRightSideOfName(allowIdentifierNames: boolean): ISyntaxToken { + var _currentToken = currentToken(); + + // Technically a keyword is valid here as all keywords are identifier names. + // However, often we'll encounter this in error situations when the keyword + // is actually starting another valid construct. + + // So, we check for the following specific case: + + // name. + // keyword identifierNameOrKeyword + + // Note: the newlines are important here. For example, if that above code + // were rewritten into: + + // name.keyword + // identifierNameOrKeyword + + // Then we would consider it valid. That's because ASI would take effect and + // the code would be implicitly: "name.keyword; identifierNameOrKeyword". + // In the first case though, ASI will not take effect because there is not a + // line terminator after the keyword. + if (SyntaxFacts.isAnyKeyword(_currentToken.kind()) && + previousTokenHasTrailingNewLine(_currentToken)) { + + var token1 = peekToken(1); + if (!existsNewLineBetweenTokens(_currentToken, token1, source.text) && + SyntaxFacts.isIdentifierNameOrAnyKeyword(token1)) { + + return createMissingToken(SyntaxKind.IdentifierName, _currentToken); + } + } + + return allowIdentifierNames ? eatIdentifierNameToken() : eatIdentifierToken(); + } + + function tryParseName(allowIdentifierNames: boolean): INameSyntax { + var token0 = currentToken(); + var shouldContinue = isIdentifier(token0); + if (!shouldContinue) { + return null; + } + + // Call eatIdentifierName to convert the token to an identifier if it is as keyword. + var current: INameSyntax = eatIdentifierToken(); + + while (shouldContinue && currentToken().kind() === SyntaxKind.DotToken) { + var dotToken = consumeToken(currentToken()); + var identifierName = eatRightSideOfName(allowIdentifierNames); + + current = new syntaxFactory.QualifiedNameSyntax(parseNodeData, current, dotToken, identifierName); + shouldContinue = identifierName.fullWidth() > 0; + } + + return current; + } + + function parseEnumDeclaration(): EnumDeclarationSyntax { + var modifiers = parseModifiers(); + var enumKeyword = eatToken(SyntaxKind.EnumKeyword); + var identifier = eatIdentifierToken(); + + var openBraceToken = eatToken(SyntaxKind.OpenBraceToken); + var enumElements = Syntax.emptySeparatedList(); + + if (openBraceToken.fullWidth() > 0) { + var skippedTokens: ISyntaxToken[] = getArray(); + enumElements = parseSeparatedSyntaxList(ListParsingState.EnumDeclaration_EnumElements, skippedTokens); + openBraceToken = addSkippedTokensAfterToken(openBraceToken, skippedTokens); + } + + return new syntaxFactory.EnumDeclarationSyntax(parseNodeData, modifiers, enumKeyword, identifier, openBraceToken, enumElements, eatToken(SyntaxKind.CloseBraceToken)); + } + + function isEnumElement(inErrorRecovery: boolean): boolean { + var node = currentNode(); + if (node !== null && node.kind() === SyntaxKind.EnumElement) { + return true; + } + + return isPropertyName(currentToken(), inErrorRecovery); + } + + function tryParseEnumElementEqualsValueClause(): EqualsValueClauseSyntax { + return isEqualsValueClause(/*inParameter*/ false) ? parseEqualsValueClause(/*allowIn:*/ true) : null; + } + + function tryParseEnumElement(inErrorRecovery: boolean): EnumElementSyntax { + var node = currentNode(); + if (node !== null && node.kind() === SyntaxKind.EnumElement) { + consumeNode(node); + return node; + } + + if (!isPropertyName(currentToken(), inErrorRecovery)) { + return null; + } + + return new syntaxFactory.EnumElementSyntax(parseNodeData, eatPropertyName(), tryParseEnumElementEqualsValueClause()); + } + + function isModifierKind(kind: SyntaxKind): boolean { + switch (kind) { + case SyntaxKind.ExportKeyword: + case SyntaxKind.PublicKeyword: + case SyntaxKind.PrivateKeyword: + case SyntaxKind.StaticKeyword: + case SyntaxKind.DeclareKeyword: + return true; + } + + return false; + } + + function isModifier(token: ISyntaxToken, index: number): boolean { + if (isModifierKind(token.kind())) { + // These are modifiers only if we see an actual keyword, identifier, string literal + // or number following. + // Note: we also allow [ for error conditions. + // [ is for: static [a: number] + var nextToken = peekToken(index + 1); + var nextTokenKind = nextToken.kind(); + + switch (nextTokenKind) { + case SyntaxKind.IdentifierName: + case SyntaxKind.OpenBracketToken: + case SyntaxKind.NumericLiteral: + case SyntaxKind.StringLiteral: + return true; + default: + return SyntaxFacts.isAnyKeyword(nextTokenKind); + } + } + + return false; + } + + function modifierCount(): number { + var modifierCount = 0; + while (isModifier(peekToken(modifierCount), modifierCount)) { + modifierCount++; + } + + return modifierCount; + } + + function parseModifiers(): ISyntaxToken[] { + var tokens: ISyntaxToken[] = getArray(); + + while (true) { + var token = currentToken(); + if (isModifier(token, /*index:*/ 0)) { + tokens.push(consumeToken(token)); + continue; + } + + break; + } + + var result = Syntax.list(tokens); + + // If the tokens array is greater than one, then we can't return it. It will have been + // copied directly into the syntax list. + returnZeroLengthArray(tokens); + + return result; + } + + function parseHeritageClauses(): HeritageClauseSyntax[] { + var heritageClauses = Syntax.emptyList(); + + if (isHeritageClause()) { + // NOTE: we can pass "null" for the skipped tokens here as we know we can't get + // any leading skipped tokens. We have an 'extends' or 'implements' keyword, so + // any skipped tokeds will get attached to that instead. + heritageClauses= parseSyntaxList(ListParsingState.ClassOrInterfaceDeclaration_HeritageClauses, null); + } + + return heritageClauses; + } + + function tryParseHeritageClauseTypeName(): ITypeSyntax { + return isHeritageClauseTypeName() ? tryParseNameOrGenericType() : null; + } + + function parseClassDeclaration(): ClassDeclarationSyntax { + var modifiers = parseModifiers(); + var classKeyword = eatToken(SyntaxKind.ClassKeyword); + var identifier = eatIdentifierToken(); + var typeParameterList = tryParseTypeParameterList(/*requireCompleteTypeParameterList:*/ false); + var heritageClauses = parseHeritageClauses(); + var openBraceToken = eatToken(SyntaxKind.OpenBraceToken); + var classElements = Syntax.emptyList(); + + if (openBraceToken.fullWidth() > 0) { + var skippedTokens: ISyntaxToken[] = getArray(); + classElements = parseSyntaxList(ListParsingState.ClassDeclaration_ClassElements, skippedTokens); + openBraceToken = addSkippedTokensAfterToken(openBraceToken, skippedTokens); + }; + + return new syntaxFactory.ClassDeclarationSyntax(parseNodeData, + modifiers, classKeyword, identifier, typeParameterList, heritageClauses, openBraceToken, classElements, eatToken(SyntaxKind.CloseBraceToken)); + } + + function isAccessor(modifierCount: number, inErrorRecovery: boolean): boolean { + var tokenKind = peekToken(modifierCount).kind(); + if (tokenKind !== SyntaxKind.GetKeyword && + tokenKind !== SyntaxKind.SetKeyword) { + return false; + } + + return isPropertyName(peekToken(modifierCount + 1), inErrorRecovery); + } + + function parseAccessor(checkForStrictMode: boolean): ISyntaxNode { + var modifiers = parseModifiers(); + var _currenToken = currentToken(); + var tokenKind = _currenToken.kind(); + + if (tokenKind === SyntaxKind.GetKeyword) { + return parseGetMemberAccessorDeclaration(modifiers, _currenToken, checkForStrictMode); + } + else if (tokenKind === SyntaxKind.SetKeyword) { + return parseSetMemberAccessorDeclaration(modifiers, _currenToken, checkForStrictMode); + } + else { + throw Errors.invalidOperation(); + } + } + + function parseGetMemberAccessorDeclaration(modifiers: ISyntaxToken[], getKeyword: ISyntaxToken, checkForStrictMode: boolean): GetAccessorSyntax { + return new syntaxFactory.GetAccessorSyntax(parseNodeData, + modifiers, consumeToken(getKeyword), eatPropertyName(), + parseCallSignature(/*requireCompleteTypeParameterList:*/ false), + parseBlock(/*parseStatementsEvenWithNoOpenBrace:*/ false, checkForStrictMode)); + } + + function parseSetMemberAccessorDeclaration(modifiers: ISyntaxToken[], setKeyword: ISyntaxToken, checkForStrictMode: boolean): SetAccessorSyntax { + return new syntaxFactory.SetAccessorSyntax(parseNodeData, + modifiers, consumeToken(setKeyword), eatPropertyName(), + parseCallSignature(/*requireCompleteTypeParameterList:*/ false), + parseBlock(/*parseStatementsEvenWithNoOpenBrace:*/ false, checkForStrictMode)); + } + + function isClassElement(inErrorRecovery: boolean): boolean { + if (SyntaxUtilities.isClassElement(currentNode())) { + return true; + } + + // Note: the order of these calls is important. Specifically, isMemberVariableDeclaration + // checks for a subset of the conditions of the previous two calls. + var _modifierCount = modifierCount(); + return isConstructorDeclaration(_modifierCount) || + isMemberFunctionDeclaration(_modifierCount, inErrorRecovery) || + isAccessor(_modifierCount, inErrorRecovery) || + isMemberVariableDeclaration(_modifierCount, inErrorRecovery) || + isIndexMemberDeclaration(_modifierCount); + } + + function tryParseClassElement(inErrorRecovery: boolean): IClassElementSyntax { + var node = currentNode(); + if (SyntaxUtilities.isClassElement(node)) { + consumeNode(node); + return node; + } + + var _modifierCount = modifierCount(); + if (isConstructorDeclaration(_modifierCount)) { + return parseConstructorDeclaration(); + } + else if (isMemberFunctionDeclaration(_modifierCount, inErrorRecovery)) { + return parseMemberFunctionDeclaration(); + } + else if (isAccessor(_modifierCount, inErrorRecovery)) { + return parseAccessor(/*checkForStrictMode:*/ false); + } + else if (isMemberVariableDeclaration(_modifierCount, inErrorRecovery)) { + return parseMemberVariableDeclaration(); + } + else if (isIndexMemberDeclaration(_modifierCount)) { + return parseIndexMemberDeclaration(); + } + else { + return null; + } + } + + function isConstructorDeclaration(modifierCount: number): boolean { + // Note: we deviate slightly from the spec here. If we see 'constructor' then we + // assume this is a constructor. That means, if a user writes "public constructor;" + // it won't be viewed as a member. As a workaround, they can simply write: + // public 'constructor'; + return peekToken(modifierCount).kind() === SyntaxKind.ConstructorKeyword; + } + + function parseConstructorDeclaration(): ConstructorDeclarationSyntax { + var modifiers = parseModifiers(); + var constructorKeyword = eatToken(SyntaxKind.ConstructorKeyword); + var callSignature = parseCallSignature(/*requireCompleteTypeParameterList:*/ false); + + var semicolonToken: ISyntaxToken = null; + var block: BlockSyntax = null; + + if (isBlock()) { + block = parseBlock(/*parseStatementsEvenWithNoOpenBrace:*/ false, /*checkForStrictMode:*/ true); + } + else { + semicolonToken = eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false); + } + + return new syntaxFactory.ConstructorDeclarationSyntax(parseNodeData, modifiers, constructorKeyword, callSignature, block, semicolonToken); + } + + function isMemberFunctionDeclaration(modifierCount: number, inErrorRecovery: boolean): boolean { + return isPropertyName(peekToken(modifierCount), inErrorRecovery) && isCallSignature(modifierCount + 1); + } + + function parseMemberFunctionDeclaration(): MemberFunctionDeclarationSyntax { + var modifiers = parseModifiers(); + var propertyName = eatPropertyName(); + var callSignature = parseCallSignature(/*requireCompleteTypeParameterList:*/ false); + + // If we got an errant => then we want to parse what's coming up without requiring an + // open brace. + var parseBlockEvenWithNoOpenBrace = tryAddUnexpectedEqualsGreaterThanToken(callSignature); + + var block: BlockSyntax = null; + var semicolon: ISyntaxToken = null; + + if (parseBlockEvenWithNoOpenBrace || isBlock()) { + block = parseBlock(parseBlockEvenWithNoOpenBrace, /*checkForStrictMode:*/ true); + } + else { + semicolon = eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false); + } + + return new syntaxFactory.MemberFunctionDeclarationSyntax(parseNodeData, modifiers, propertyName, callSignature, block, semicolon); + } + + function isDefinitelyMemberVariablePropertyName(index: number): boolean { + // keywords are also property names. Only accept a keyword as a property + // name if is of the form: + // public; + // public= + // public: + // public } + // public + // public + if (SyntaxFacts.isAnyKeyword(peekToken(index).kind())) { + var nextToken = peekToken(index + 1); + switch (nextToken.kind()) { + case SyntaxKind.SemicolonToken: + case SyntaxKind.EqualsToken: + case SyntaxKind.ColonToken: + case SyntaxKind.CloseBraceToken: + case SyntaxKind.EndOfFileToken: + return true; + default: + return previousTokenHasTrailingNewLine(nextToken); + } + } + else { + // If was a property name and not a keyword, then we're good to go. + return true; + } + } + + function isMemberVariableDeclaration(modifierCount: number, inErrorRecover: boolean): boolean { + return isPropertyName(peekToken(modifierCount), inErrorRecover) && isDefinitelyMemberVariablePropertyName(modifierCount); + } + + function parseMemberVariableDeclaration(): MemberVariableDeclarationSyntax { + return new syntaxFactory.MemberVariableDeclarationSyntax(parseNodeData, + parseModifiers(), + tryParseVariableDeclarator(/*allowIn:*/ true, /*allowPropertyName:*/ true), eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false)); + } + + function isIndexMemberDeclaration(modifierCount: number): boolean { + return isIndexSignature(modifierCount); + } + + function parseIndexMemberDeclaration(): IndexMemberDeclarationSyntax { + return new syntaxFactory.IndexMemberDeclarationSyntax(parseNodeData, + parseModifiers(), parseIndexSignature(), eatExplicitOrAutomaticSemicolon(/*allowWithoutNewLine:*/ false)); + } + + function tryAddUnexpectedEqualsGreaterThanToken(callSignature: CallSignatureSyntax): boolean { + var token0 = currentToken(); + + var hasEqualsGreaterThanToken = token0.kind() === SyntaxKind.EqualsGreaterThanToken; + if (hasEqualsGreaterThanToken) { + // We can only do this if the call signature actually contains a final token that we + // could add the => to. + var _lastToken = lastToken(callSignature); + if (_lastToken && _lastToken.fullWidth() > 0) { + // Previously the language allowed "function f() => expr;" as a shorthand for + // "function f() { return expr; }. + // + // Detect if the user is typing this and attempt recovery. + var diagnostic = new Diagnostic(fileName, source.text.lineMap(), + start(token0, source.text), width(token0), DiagnosticCode.Unexpected_token_0_expected, [SyntaxFacts.getText(SyntaxKind.OpenBraceToken)]); + addDiagnostic(diagnostic); + + consumeToken(token0); + + // Note: we only do this if we're creating a concrete syntax tree (which contains + // everything, including skipped tokens, in it). + if (syntaxFactory.isConcrete) { + addSkippedTokenAfterNode(callSignature, token0); + } + return true; + } + } + + + return false; + } + + function isFunctionDeclaration(modifierCount: number): boolean { + return peekToken(modifierCount).kind() === SyntaxKind.FunctionKeyword; + } + + function parseFunctionDeclaration(): FunctionDeclarationSyntax { + var modifiers = parseModifiers(); + var functionKeyword = eatToken(SyntaxKind.FunctionKeyword); + var identifier = eatIdentifierToken(); + var callSignature = parseCallSignature(/*requireCompleteTypeParameterList:*/ false); + + // If we got an errant => then we want to parse what's coming up without requiring an + // open brace. + var parseBlockEvenWithNoOpenBrace = tryAddUnexpectedEqualsGreaterThanToken(callSignature); + + var semicolonToken: ISyntaxToken = null; + var block: BlockSyntax = null; + + // Parse a block if we're on a bock, or if we saw a '=>' + if (parseBlockEvenWithNoOpenBrace || isBlock()) { + block = parseBlock(parseBlockEvenWithNoOpenBrace, /*checkForStrictMode:*/ true); + } + else { + semicolonToken = eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false); + } + + return new syntaxFactory.FunctionDeclarationSyntax(parseNodeData, modifiers, functionKeyword, identifier, callSignature, block, semicolonToken); + } + + function parseModuleDeclaration(): ModuleDeclarationSyntax { + var modifiers = parseModifiers(); + var moduleKeyword = eatToken(SyntaxKind.ModuleKeyword); + + var moduleName: INameSyntax = null; + var stringLiteral: ISyntaxToken = null; + + if (currentToken().kind() === SyntaxKind.StringLiteral) { + stringLiteral = eatToken(SyntaxKind.StringLiteral); + } + else { + moduleName = parseName(/*allowIdentifierNames*/ false); + } + + var openBraceToken = eatToken(SyntaxKind.OpenBraceToken); + + var moduleElements = Syntax.emptyList(); + if (openBraceToken.fullWidth() > 0) { + var skippedTokens: ISyntaxToken[] = getArray(); + moduleElements = parseSyntaxList(ListParsingState.ModuleDeclaration_ModuleElements, skippedTokens); + openBraceToken = addSkippedTokensAfterToken(openBraceToken, skippedTokens); + } + + return new syntaxFactory.ModuleDeclarationSyntax(parseNodeData, + modifiers, moduleKeyword, moduleName, stringLiteral, openBraceToken, moduleElements, eatToken(SyntaxKind.CloseBraceToken)); + } + + function parseInterfaceDeclaration(): InterfaceDeclarationSyntax { + return new syntaxFactory.InterfaceDeclarationSyntax(parseNodeData, + parseModifiers(), eatToken(SyntaxKind.InterfaceKeyword), eatIdentifierToken(), + tryParseTypeParameterList(/*requireCompleteTypeParameterList:*/ false), parseHeritageClauses(), parseObjectType()); + } + + function parseObjectType(): ObjectTypeSyntax { + var openBraceToken = eatToken(SyntaxKind.OpenBraceToken); + + var typeMembers = Syntax.emptySeparatedList(); + if (openBraceToken.fullWidth() > 0) { + var skippedTokens: ISyntaxToken[] = getArray(); + typeMembers = parseSeparatedSyntaxList(ListParsingState.ObjectType_TypeMembers, skippedTokens); + openBraceToken = addSkippedTokensAfterToken(openBraceToken, skippedTokens); + } + + return new syntaxFactory.ObjectTypeSyntax(parseNodeData, openBraceToken, typeMembers, eatToken(SyntaxKind.CloseBraceToken)); + } + + function isTypeMember(inErrorRecovery: boolean): boolean { + if (SyntaxUtilities.isTypeMember(currentNode())) { + return true; + } + + return isCallSignature(/*tokenIndex:*/ 0) || + isConstructSignature() || + isIndexSignature(/*tokenIndex:*/ 0) || + isMethodSignature(inErrorRecovery) || + isPropertySignature(inErrorRecovery); + } + + function tryParseTypeMember(inErrorRecovery: boolean): ITypeMemberSyntax { + var node = currentNode(); + if (SyntaxUtilities.isTypeMember(node)) { + consumeNode(node); + return node; + } + + if (isCallSignature(/*tokenIndex:*/ 0)) { + return parseCallSignature(/*requireCompleteTypeParameterList:*/ false); + } + else if (isConstructSignature()) { + return parseConstructSignature(); + } + else if (isIndexSignature(/*tokenIndex:*/ 0)) { + return parseIndexSignature(); + } + else if (isMethodSignature(inErrorRecovery)) { + // Note: it is important that isFunctionSignature is called before isPropertySignature. + // isPropertySignature checks for a subset of isFunctionSignature. + return parseMethodSignature(); + } + else if (isPropertySignature(inErrorRecovery)) { + return parsePropertySignature(); + } + else { + return null; + } + } + + function parseConstructSignature(): ConstructSignatureSyntax { + return new syntaxFactory.ConstructSignatureSyntax(parseNodeData, eatToken(SyntaxKind.NewKeyword), parseCallSignature(/*requireCompleteTypeParameterList:*/ false)); + } + + function parseIndexSignature(): IndexSignatureSyntax { + var openBracketToken = eatToken(SyntaxKind.OpenBracketToken); + + var skippedTokens: ISyntaxToken[] = getArray(); + var parameters = parseSeparatedSyntaxList(ListParsingState.IndexSignature_Parameters, skippedTokens); + openBracketToken = addSkippedTokensAfterToken(openBracketToken, skippedTokens); + + return new syntaxFactory.IndexSignatureSyntax(parseNodeData, + openBracketToken, parameters, eatToken(SyntaxKind.CloseBracketToken), parseOptionalTypeAnnotation(/*allowStringLiteral:*/ false)); + } + + function parseMethodSignature(): MethodSignatureSyntax { + return new syntaxFactory.MethodSignatureSyntax(parseNodeData, + eatPropertyName(), tryEatToken(SyntaxKind.QuestionToken), parseCallSignature(/*requireCompleteTypeParameterList:*/ false)); + } + + function parsePropertySignature(): PropertySignatureSyntax { + return new syntaxFactory.PropertySignatureSyntax(parseNodeData, + eatPropertyName(), tryEatToken(SyntaxKind.QuestionToken), parseOptionalTypeAnnotation(/*allowStringLiteral:*/ false)); + } + + function isCallSignature(peekIndex: number): boolean { + var tokenKind = peekToken(peekIndex).kind(); + return tokenKind === SyntaxKind.OpenParenToken || tokenKind === SyntaxKind.LessThanToken; + } + + function isConstructSignature(): boolean { + if (currentToken().kind() !== SyntaxKind.NewKeyword) { + return false; + } + + return isCallSignature(/*peekIndex:*/1); + } + + function isIndexSignature(peekIndex: number): boolean { + return peekToken(peekIndex).kind() === SyntaxKind.OpenBracketToken; + } + + function isMethodSignature(inErrorRecovery: boolean): boolean { + if (isPropertyName(currentToken(), inErrorRecovery)) { + // id( + if (isCallSignature(1)) { + return true; + } + + // id?( + if (peekToken(1).kind() === SyntaxKind.QuestionToken && + isCallSignature(2)) { + return true; + } + } + + return false; + } + + function isPropertySignature(inErrorRecovery: boolean): boolean { + var _currentToken = currentToken(); + + // Keywords can start properties. However, they're often intended to start something + // else. If we see a modifier before something that can be a property, then don't + // try parse it out as a property. For example, if we have: + // + // public foo + // + // Then don't parse 'public' as a property name. Note: if you have: + // + // public + // foo + // + // Then we *should* parse it as a property name, as ASI takes effect here. + if (isModifier(_currentToken, /*index:*/ 0)) { + if (!existsNewLineBetweenTokens(_currentToken, peekToken(1), source.text) && + isPropertyName(peekToken(1), inErrorRecovery)) { + + return false; + } + } + + // Note: property names also start function signatures. So it's important that we call this + // after we calll isFunctionSignature. + return isPropertyName(_currentToken, inErrorRecovery); + } + + function isHeritageClause(): boolean { + var tokenKind = currentToken().kind(); + return tokenKind === SyntaxKind.ExtendsKeyword || tokenKind === SyntaxKind.ImplementsKeyword; + } + + function isNotHeritageClauseTypeName(): boolean { + var tokenKind = currentToken().kind(); + if (tokenKind === SyntaxKind.ImplementsKeyword || + tokenKind === SyntaxKind.ExtendsKeyword) { + + return isIdentifier(peekToken(1)); + } + + return false; + } + + function isHeritageClauseTypeName(): boolean { + if (isIdentifier(currentToken())) { + // We want to make sure that the "extends" in "extends foo" or the "implements" in + // "implements foo" is not considered a type name. + return !isNotHeritageClauseTypeName(); + } + + return false; + } + + function tryParseHeritageClause(): HeritageClauseSyntax { + var extendsOrImplementsKeyword = currentToken(); + var tokenKind = extendsOrImplementsKeyword.kind(); + if (tokenKind !== SyntaxKind.ExtendsKeyword && tokenKind !== SyntaxKind.ImplementsKeyword) { + return null; + } + + consumeToken(extendsOrImplementsKeyword); + + var skippedTokens: ISyntaxToken[] = getArray(); + var typeNames = parseSeparatedSyntaxList(ListParsingState.HeritageClause_TypeNameList, skippedTokens); + extendsOrImplementsKeyword = addSkippedTokensAfterToken(extendsOrImplementsKeyword, skippedTokens); + + return new syntaxFactory.HeritageClauseSyntax(parseNodeData, extendsOrImplementsKeyword, typeNames); + } + + function isInterfaceEnumClassModuleImportOrExport(modifierCount: number): boolean { + var _currentToken = currentToken(); + + if (modifierCount) { + // Any of these keywords following a modifier is definitely a TS construct. + switch (peekToken(modifierCount).kind()) { + case SyntaxKind.ImportKeyword: + case SyntaxKind.ModuleKeyword: + case SyntaxKind.InterfaceKeyword: + case SyntaxKind.ClassKeyword: + case SyntaxKind.EnumKeyword: + return true; + } + } + + // no modifiers. While certain of these keywords are javascript keywords as well, it + // is possible to run into them in some circumstances in error recovery where we don't + // want to consider them the start of the module element construct. For example, they + // might be hte name in an object literal. Because of that, we check the next token to + // make sure it really is the start of a module element. + var nextToken = peekToken(1); + + switch (_currentToken.kind()) { + case SyntaxKind.ModuleKeyword: + if (isIdentifier(nextToken) || nextToken.kind() === SyntaxKind.StringLiteral) { + return true; + } + break; + + case SyntaxKind.ImportKeyword: + case SyntaxKind.ClassKeyword: + case SyntaxKind.EnumKeyword: + case SyntaxKind.InterfaceKeyword: + if (isIdentifier(nextToken)) { + return true; + } + break; + + case SyntaxKind.ExportKeyword: + if (nextToken.kind() === SyntaxKind.EqualsToken) { + return true; + } + break; + } + + return false; + } + + function isStatement(modifierCount: number, inErrorRecovery: boolean): boolean { + if (SyntaxUtilities.isStatement(currentNode())) { + return true; + } + + var _currentToken = currentToken(); + var currentTokenKind = _currentToken.kind(); + switch (currentTokenKind) { + // ERROR RECOVERY + case SyntaxKind.PublicKeyword: + case SyntaxKind.PrivateKeyword: + case SyntaxKind.StaticKeyword: + // None of the above are actually keywords. And they might show up in a real + // statement (i.e. "public();"). However, if we see 'public ' then + // that can't possibly be a statement (and instead will be a class element), + // and we should not parse it out here. + var token1 = peekToken(1); + if (SyntaxFacts.isIdentifierNameOrAnyKeyword(token1)) { + // Definitely not a statement. + return false; + } + + // Handle this below in 'isExpressionStatement()' + break; + + // Common cases that we can immediately assume are statements. + case SyntaxKind.IfKeyword: + case SyntaxKind.OpenBraceToken: + case SyntaxKind.ReturnKeyword: + case SyntaxKind.SwitchKeyword: + case SyntaxKind.ThrowKeyword: + case SyntaxKind.BreakKeyword: + case SyntaxKind.ContinueKeyword: + case SyntaxKind.ForKeyword: + case SyntaxKind.WhileKeyword: + case SyntaxKind.WithKeyword: + case SyntaxKind.DoKeyword: + case SyntaxKind.TryKeyword: + case SyntaxKind.DebuggerKeyword: + return true; + } + + // Check for common things that might appear where we expect a statement, but which we + // do not want to consume. This can happen when the user does not terminate their + // existing block properly. We don't want to accidently consume these as expression + // below. + if (isInterfaceEnumClassModuleImportOrExport(modifierCount)) { + return false; + } + + // More complicated cases. + return isLabeledStatement(_currentToken) || + isVariableStatement(modifierCount) || + isFunctionDeclaration(modifierCount) || + isEmptyStatement(_currentToken, inErrorRecovery) || + isExpressionStatement(_currentToken); + } + + function parseStatement(inErrorRecovery: boolean): IStatementSyntax { + return tryParseStatement(inErrorRecovery) || parseExpressionStatement(); + } + + function tryParseStatement(inErrorRecovery: boolean): IStatementSyntax { + var node = currentNode(); + if (SyntaxUtilities.isStatement(node)) { + consumeNode(node); + return node; + } + + var _currentToken = currentToken(); + var currentTokenKind = _currentToken.kind(); + return tryParseStatementWorker(_currentToken, currentTokenKind, modifierCount(), inErrorRecovery); + } + + function tryParseStatementWorker(_currentToken: ISyntaxToken, currentTokenKind: SyntaxKind, modifierCount: number, inErrorRecovery: boolean): IStatementSyntax { + switch (currentTokenKind) { + // ERROR RECOVERY + case SyntaxKind.PublicKeyword: + case SyntaxKind.PrivateKeyword: + case SyntaxKind.StaticKeyword: + // None of the above are actually keywords. And they might show up in a real + // statement (i.e. "public();"). However, if we see 'public ' then + // that can't possibly be a statement (and instead will be a class element), + // and we should not parse it out here. + if (SyntaxFacts.isIdentifierNameOrAnyKeyword(peekToken(1))) { + // Definitely not a statement. + return null; + } + else { + break; + } + + case SyntaxKind.IfKeyword: return parseIfStatement(_currentToken); + case SyntaxKind.OpenBraceToken: return parseBlock(/*parseStatementsEvenWithNoOpenBrace:*/ false, /*checkForStrictMode:*/ false); + case SyntaxKind.ReturnKeyword: return parseReturnStatement(_currentToken); + case SyntaxKind.SwitchKeyword: return parseSwitchStatement(_currentToken); + case SyntaxKind.ThrowKeyword: return parseThrowStatement(_currentToken); + case SyntaxKind.BreakKeyword: return parseBreakStatement(_currentToken); + case SyntaxKind.ContinueKeyword: return parseContinueStatement(_currentToken); + case SyntaxKind.ForKeyword: return parseForOrForInStatement(_currentToken); + case SyntaxKind.WhileKeyword: return parseWhileStatement(_currentToken); + case SyntaxKind.WithKeyword: return parseWithStatement(_currentToken); + case SyntaxKind.DoKeyword: return parseDoStatement(_currentToken); + case SyntaxKind.TryKeyword: return parseTryStatement(_currentToken); + case SyntaxKind.DebuggerKeyword: return parseDebuggerStatement(_currentToken); + } + + // Check for common things that might appear where we expect a statement, but which we + // do not want to consume. This can happen when the user does not terminate their + // existing block properly. We don't want to accidently consume these as expression + // below. + if (isInterfaceEnumClassModuleImportOrExport(modifierCount)) { + return null; + } + else if (isVariableStatement(modifierCount)) { + return parseVariableStatement(); + } + else if (isLabeledStatement(_currentToken)) { + return parseLabeledStatement(_currentToken); + } + else if (isFunctionDeclaration(modifierCount)) { + return parseFunctionDeclaration(); + } + else if (isEmptyStatement(_currentToken, inErrorRecovery)) { + return parseEmptyStatement(_currentToken); + } + else if (isExpressionStatement(_currentToken)) { + return parseExpressionStatement(); + } + else { + return null; + } + } + + function parseDebuggerStatement(debuggerKeyword: ISyntaxToken): DebuggerStatementSyntax { + return new syntaxFactory.DebuggerStatementSyntax(parseNodeData, consumeToken(debuggerKeyword), eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false)); + } + + function parseDoStatement(doKeyword: ISyntaxToken): DoStatementSyntax { + // From: https://mail.mozilla.org/pipermail/es-discuss/2011-August/016188.html + // 157 min --- All allen at wirfs-brock.com CONF --- "do{;}while(false)false" prohibited in + // spec but allowed in consensus reality. Approved -- this is the de-facto standard whereby + // do;while(0)x will have a semicolon inserted before x. + return new syntaxFactory.DoStatementSyntax(parseNodeData, + consumeToken(doKeyword), parseStatement(/*inErrorRecovery:*/ false), eatToken(SyntaxKind.WhileKeyword), eatToken(SyntaxKind.OpenParenToken), + parseExpression(/*allowIn:*/ true), eatToken(SyntaxKind.CloseParenToken), eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ true)); + } + + function isLabeledStatement(currentToken: ISyntaxToken): boolean { + return isIdentifier(currentToken) && peekToken(1).kind() === SyntaxKind.ColonToken; + } + + function parseLabeledStatement(identifierToken: ISyntaxToken): LabeledStatementSyntax { + return new syntaxFactory.LabeledStatementSyntax(parseNodeData, + consumeToken(identifierToken), eatToken(SyntaxKind.ColonToken), parseStatement(/*inErrorRecovery:*/ false)); + } + + function parseTryStatement(tryKeyword: ISyntaxToken): TryStatementSyntax { + var tryKeyword = consumeToken(tryKeyword); + + var savedListParsingState = listParsingState; + listParsingState |= (1 << ListParsingState.TryBlock_Statements); + var block = parseBlock(/*parseStatementsEvenWithNoOpenBrace:*/ false, /*checkForStrictMode:*/ false); + listParsingState = savedListParsingState; + + var catchClause: CatchClauseSyntax = null; + if (currentToken().kind() === SyntaxKind.CatchKeyword) { + catchClause = parseCatchClause(); + } + + // If we don't have a catch clause, then we must have a finally clause. Try to parse + // one out no matter what. + var finallyClause: FinallyClauseSyntax = null; + if (catchClause === null || currentToken().kind() === SyntaxKind.FinallyKeyword) { + finallyClause = parseFinallyClause(); + } + + return new syntaxFactory.TryStatementSyntax(parseNodeData, tryKeyword, block, catchClause, finallyClause); + } + + function parseCatchClauseBlock(): BlockSyntax { + var savedListParsingState = listParsingState; + listParsingState |= (1 << ListParsingState.CatchBlock_Statements); + var block = parseBlock(/*parseStatementsEvenWithNoOpenBrace:*/ false, /*checkForStrictMode:*/ false); + listParsingState = savedListParsingState; + + return block; + } + + function parseCatchClause(): CatchClauseSyntax { + return new syntaxFactory.CatchClauseSyntax(parseNodeData, + eatToken(SyntaxKind.CatchKeyword), eatToken(SyntaxKind.OpenParenToken), eatIdentifierToken(), + parseOptionalTypeAnnotation(/*allowStringLiteral:*/ false), eatToken(SyntaxKind.CloseParenToken), parseCatchClauseBlock()); + } + + function parseFinallyClause(): FinallyClauseSyntax { + return new syntaxFactory.FinallyClauseSyntax(parseNodeData, + eatToken(SyntaxKind.FinallyKeyword), parseBlock(/*parseStatementsEvenWithNoOpenBrace:*/ false, /*checkForStrictMode:*/ false)); + } + + function parseWithStatement(withKeyword: ISyntaxToken): WithStatementSyntax { + return new syntaxFactory.WithStatementSyntax(parseNodeData, + consumeToken(withKeyword), eatToken(SyntaxKind.OpenParenToken), parseExpression(/*allowIn:*/ true), eatToken(SyntaxKind.CloseParenToken), parseStatement(/*inErrorRecovery:*/ false)); + } + + function parseWhileStatement(whileKeyword: ISyntaxToken): WhileStatementSyntax { + return new syntaxFactory.WhileStatementSyntax(parseNodeData, + consumeToken(whileKeyword), eatToken(SyntaxKind.OpenParenToken), parseExpression(/*allowIn:*/ true), eatToken(SyntaxKind.CloseParenToken), parseStatement(/*inErrorRecovery:*/ false)); + } + + function isEmptyStatement(currentToken: ISyntaxToken, inErrorRecovery: boolean): boolean { + // If we're in error recovery, then we don't want to treat ';' as an empty statement. + // The problem is that ';' can show up in far too many contexts, and if we see one + // and assume it's a statement, then we may bail out innapropriately from whatever + // we're parsing. For example, if we have a semicolon in the middle of a class, then + // we really don't want to assume the class is over and we're on a statement in the + // outer module. We just want to consume and move on. + if (inErrorRecovery) { + return false; + } + + return currentToken.kind() === SyntaxKind.SemicolonToken; + } + + function parseEmptyStatement(semicolonToken: ISyntaxToken): EmptyStatementSyntax { + return new syntaxFactory.EmptyStatementSyntax(parseNodeData, consumeToken(semicolonToken)); + } + + function parseForOrForInStatement(forKeyword: ISyntaxToken): IStatementSyntax { + // Debug.assert(isForOrForInStatement()); + + consumeToken(forKeyword); + var openParenToken = eatToken(SyntaxKind.OpenParenToken); + + var _currentToken = currentToken(); + var tokenKind = _currentToken.kind(); + if (tokenKind === SyntaxKind.VarKeyword) { + // for ( var VariableDeclarationListNoIn; Expressionopt ; Expressionopt ) Statement + // for ( var VariableDeclarationNoIn in Expression ) Statement + return parseForOrForInStatementWithVariableDeclaration(forKeyword, openParenToken); + } + else if (tokenKind === SyntaxKind.SemicolonToken) { + // for ( ; Expressionopt ; Expressionopt ) Statement + return parseForStatementWithNoVariableDeclarationOrInitializer(forKeyword, openParenToken); + } + else { + // for ( ExpressionNoInopt; Expressionopt ; Expressionopt ) Statement + // for ( LeftHandSideExpression in Expression ) Statement + return parseForOrForInStatementWithInitializer(forKeyword, openParenToken); + } + } + + function parseForOrForInStatementWithVariableDeclaration(forKeyword: ISyntaxToken, openParenToken: ISyntaxToken): IStatementSyntax { + // Debug.assert(forKeyword.kind === SyntaxKind.ForKeyword && openParenToken.kind() === SyntaxKind.OpenParenToken); + // Debug.assert(currentToken().kind() === SyntaxKind.VarKeyword); + + // for ( var VariableDeclarationListNoIn; Expressionopt ; Expressionopt ) Statement + // for ( var VariableDeclarationNoIn in Expression ) Statement + + var variableDeclaration = parseVariableDeclaration(/*allowIn:*/ false); + return currentToken().kind() === SyntaxKind.InKeyword + ? parseForInStatementWithVariableDeclarationOrInitializer(forKeyword, openParenToken, variableDeclaration, null) + : parseForStatementWithVariableDeclarationOrInitializer(forKeyword, openParenToken, variableDeclaration, null); + } + + function parseForInStatementWithVariableDeclarationOrInitializer(forKeyword: ISyntaxToken, openParenToken: ISyntaxToken, variableDeclaration: VariableDeclarationSyntax, initializer: IExpressionSyntax): ForInStatementSyntax { + // for ( var VariableDeclarationNoIn in Expression ) Statement + + return new syntaxFactory.ForInStatementSyntax(parseNodeData, + forKeyword, openParenToken, variableDeclaration, initializer, eatToken(SyntaxKind.InKeyword), + parseExpression(/*allowIn:*/ true), eatToken(SyntaxKind.CloseParenToken), parseStatement(/*inErrorRecovery:*/ false)); + } + + function parseForOrForInStatementWithInitializer(forKeyword: ISyntaxToken, openParenToken: ISyntaxToken): IStatementSyntax { + // Debug.assert(forKeyword.kind() === SyntaxKind.ForKeyword && openParenToken.kind() === SyntaxKind.OpenParenToken); + + // for ( ExpressionNoInopt; Expressionopt ; Expressionopt ) Statement + // for ( LeftHandSideExpression in Expression ) Statement + + var initializer = parseExpression(/*allowIn:*/ false); + return currentToken().kind() === SyntaxKind.InKeyword + ? parseForInStatementWithVariableDeclarationOrInitializer(forKeyword, openParenToken, null, initializer) + : parseForStatementWithVariableDeclarationOrInitializer(forKeyword, openParenToken, null, initializer); + } + + function parseForStatementWithNoVariableDeclarationOrInitializer(forKeyword: ISyntaxToken, openParenToken: ISyntaxToken): ForStatementSyntax { + // Debug.assert(forKeyword.kind() === SyntaxKind.ForKeyword && openParenToken.kind() === SyntaxKind.OpenParenToken); + // Debug.assert(currentToken().kind() === SyntaxKind.SemicolonToken); + // for ( ; Expressionopt ; Expressionopt ) Statement + + return parseForStatementWithVariableDeclarationOrInitializer(forKeyword, openParenToken, /*variableDeclaration:*/ null, /*initializer:*/ null); + } + + function tryParseForStatementCondition(): IExpressionSyntax { + var tokenKind = currentToken().kind(); + if (tokenKind !== SyntaxKind.SemicolonToken && + tokenKind !== SyntaxKind.CloseParenToken && + tokenKind !== SyntaxKind.EndOfFileToken) { + return parseExpression(/*allowIn:*/ true); + } + + return null; + } + + function tryParseForStatementIncrementor(): IExpressionSyntax { + var tokenKind = currentToken().kind(); + if (tokenKind !== SyntaxKind.CloseParenToken && + tokenKind !== SyntaxKind.EndOfFileToken) { + return parseExpression(/*allowIn:*/ true); + } + + return null; + } + + function parseForStatementWithVariableDeclarationOrInitializer(forKeyword: ISyntaxToken, openParenToken: ISyntaxToken, variableDeclaration: VariableDeclarationSyntax, initializer: IExpressionSyntax): ForStatementSyntax { + // NOTE: From the es5 section on Automatic Semicolon Insertion. + // a semicolon is never inserted automatically if the semicolon would then ... become + // one of the two semicolons in the header of a for statement + + return new syntaxFactory.ForStatementSyntax(parseNodeData, + forKeyword, openParenToken, variableDeclaration, initializer, + eatToken(SyntaxKind.SemicolonToken), tryParseForStatementCondition(), + eatToken(SyntaxKind.SemicolonToken), tryParseForStatementIncrementor(), + eatToken(SyntaxKind.CloseParenToken), parseStatement(/*inErrorRecovery:*/ false)); + } + + function tryEatBreakOrContinueLabel(): ISyntaxToken { + // If there is no newline after the break keyword, then we can consume an optional + // identifier. + var identifier: ISyntaxToken = null; + if (!canEatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false)) { + if (isIdentifier(currentToken())) { + return eatIdentifierToken(); + } + } + + return null; + } + + function parseBreakStatement(breakKeyword: ISyntaxToken): BreakStatementSyntax { + return new syntaxFactory.BreakStatementSyntax(parseNodeData, + consumeToken(breakKeyword), tryEatBreakOrContinueLabel(), eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false)); + } + + function parseContinueStatement(continueKeyword: ISyntaxToken): ContinueStatementSyntax { + return new syntaxFactory.ContinueStatementSyntax(parseNodeData, + consumeToken(continueKeyword), tryEatBreakOrContinueLabel(), eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false)); + } + + function parseSwitchStatement(switchKeyword: ISyntaxToken) { + // Debug.assert(isSwitchStatement()); + + consumeToken(switchKeyword); + var openParenToken = eatToken(SyntaxKind.OpenParenToken); + var expression = parseExpression(/*allowIn:*/ true); + var closeParenToken = eatToken(SyntaxKind.CloseParenToken); + var openBraceToken = eatToken(SyntaxKind.OpenBraceToken); + + var switchClauses = Syntax.emptyList(); + if (openBraceToken.fullWidth() > 0) { + var skippedTokens: ISyntaxToken[] = getArray(); + switchClauses = parseSyntaxList(ListParsingState.SwitchStatement_SwitchClauses, skippedTokens); + openBraceToken = addSkippedTokensAfterToken(openBraceToken, skippedTokens); + } + + return new syntaxFactory.SwitchStatementSyntax(parseNodeData, switchKeyword, openParenToken, expression, closeParenToken, openBraceToken, switchClauses, eatToken(SyntaxKind.CloseBraceToken)); + } + + function isSwitchClause(): boolean { + if (SyntaxUtilities.isSwitchClause(currentNode())) { + return true; + } + + var currentTokenKind = currentToken().kind(); + return currentTokenKind === SyntaxKind.CaseKeyword || currentTokenKind === SyntaxKind.DefaultKeyword; + } + + function tryParseSwitchClause(): ISwitchClauseSyntax { + // Debug.assert(isSwitchClause()); + var node = currentNode(); + if (SyntaxUtilities.isSwitchClause(node)) { + consumeNode(node); + return node; + } + + var _currentToken = currentToken(); + var kind = _currentToken.kind(); + if (kind === SyntaxKind.CaseKeyword) { + return parseCaseSwitchClause(_currentToken); + } + else if (kind === SyntaxKind.DefaultKeyword) { + return parseDefaultSwitchClause(_currentToken); + } + else { + return null; + } + } + + function parseCaseSwitchClause(caseKeyword: ISyntaxToken): CaseSwitchClauseSyntax { + // Debug.assert(isCaseSwitchClause()); + + consumeToken(caseKeyword); + var expression = parseExpression(/*allowIn:*/ true); + var colonToken = eatToken(SyntaxKind.ColonToken); + var statements = Syntax.emptyList(); + + // TODO: allow parsing of the list evne if there's no colon. However, we have to make + // sure we add any skipped tokens to the right previous node or token. + if (colonToken.fullWidth() > 0) { + var skippedTokens: ISyntaxToken[] = getArray(); + statements = parseSyntaxList(ListParsingState.SwitchClause_Statements, skippedTokens); + colonToken = addSkippedTokensAfterToken(colonToken, skippedTokens); + } + + return new syntaxFactory.CaseSwitchClauseSyntax(parseNodeData, caseKeyword, expression, colonToken, statements); + } + + function parseDefaultSwitchClause(defaultKeyword: ISyntaxToken): DefaultSwitchClauseSyntax { + // Debug.assert(isDefaultSwitchClause()); + + consumeToken(defaultKeyword); + var colonToken = eatToken(SyntaxKind.ColonToken); + var statements = Syntax.emptyList(); + + // TODO: Allow parsing without a colon here. However, ensure that we attach any skipped + // tokens to the defaultKeyword. + if (colonToken.fullWidth() > 0) { + var skippedTokens: ISyntaxToken[] = getArray(); + statements = parseSyntaxList(ListParsingState.SwitchClause_Statements, skippedTokens); + colonToken = addSkippedTokensAfterToken(colonToken, skippedTokens); + } + + return new syntaxFactory.DefaultSwitchClauseSyntax(parseNodeData, defaultKeyword, colonToken, statements); + } + + function parseThrowStatementExpression(): IExpressionSyntax { + // Because of automatic semicolon insertion, we need to report error if this + // throw could be terminated with a semicolon. Note: we can't call 'parseExpression' + // directly as that might consume an expression on the following line. + return canEatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false) + ? createMissingToken(SyntaxKind.IdentifierName, null) + : parseExpression(/*allowIn:*/ true); + } + + function parseThrowStatement(throwKeyword: ISyntaxToken): ThrowStatementSyntax { + return new syntaxFactory.ThrowStatementSyntax(parseNodeData, + consumeToken(throwKeyword), parseThrowStatementExpression(), eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false)); + } + + function tryParseReturnStatementExpression(): IExpressionSyntax { + return !canEatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false) ? parseExpression(/*allowIn:*/ true) : null; + } + + function parseReturnStatement(returnKeyword: ISyntaxToken): ReturnStatementSyntax { + return new syntaxFactory.ReturnStatementSyntax(parseNodeData, + consumeToken(returnKeyword), tryParseReturnStatementExpression(), eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false)); + } + + function isExpressionStatement(currentToken: ISyntaxToken): boolean { + // As per the gramar, neither { nor 'function' can start an expression statement. + var tokenKind = currentToken.kind(); + return tokenKind !== SyntaxKind.OpenBraceToken && tokenKind !== SyntaxKind.FunctionKeyword && isExpression(currentToken); + } + + function isAssignmentOrOmittedExpression(): boolean { + var _currentToken = currentToken(); + return _currentToken.kind() === SyntaxKind.CommaToken || isExpression(_currentToken); + } + + function tryParseAssignmentOrOmittedExpression(): IExpressionSyntax { + // Debug.assert(isAssignmentOrOmittedExpression()); + + if (currentToken().kind() === SyntaxKind.CommaToken) { + return new syntaxFactory.OmittedExpressionSyntax(parseNodeData); + } + + return tryParseAssignmentExpressionOrHigher(/*force:*/ false, /*allowIn:*/ true); + } + + function isExpression(currentToken: ISyntaxToken): boolean { + switch (currentToken.kind()) { + // Literals + case SyntaxKind.NumericLiteral: + case SyntaxKind.StringLiteral: + case SyntaxKind.RegularExpressionLiteral: + + // For array literals. + case SyntaxKind.OpenBracketToken: + + // For parenthesized expressions + case SyntaxKind.OpenParenToken: + + // For cast expressions. + case SyntaxKind.LessThanToken: + + // Prefix unary expressions. + case SyntaxKind.PlusPlusToken: + case SyntaxKind.MinusMinusToken: + case SyntaxKind.PlusToken: + case SyntaxKind.MinusToken: + case SyntaxKind.TildeToken: + case SyntaxKind.ExclamationToken: + + // For object type literal expressions. + case SyntaxKind.OpenBraceToken: + + // ERROR TOLERANCE: + // If we see a => then we know the user was probably trying to type in an arrow + // function. So allow this as the start of an expression, knowing that when we + // actually try to parse it we'll report the missing identifier. + case SyntaxKind.EqualsGreaterThanToken: + + case SyntaxKind.SlashToken: + case SyntaxKind.SlashEqualsToken: + // Note: if we see a / or /= token then we always consider this an expression. Why? + // Well, either that / or /= is actually a regular expression, in which case we're + // definitely an expression. Or, it's actually a divide. In which case, we *still* + // want to think of ourself as an expression. "But wait", you say. '/' doesn't + // start an expression. That's true. BUt like the above check for =>, for error + // tolerance, we will consider ourselves in an expression. We'll then parse out an + // missing identifier and then will consume the / token naturally as a binary + // expression. + + // Simple epxressions. + case SyntaxKind.SuperKeyword: + case SyntaxKind.ThisKeyword: + case SyntaxKind.TrueKeyword: + case SyntaxKind.FalseKeyword: + case SyntaxKind.NullKeyword: + + // For object creation expressions. + case SyntaxKind.NewKeyword: + + // Prefix unary expressions + case SyntaxKind.DeleteKeyword: + case SyntaxKind.VoidKeyword: + case SyntaxKind.TypeOfKeyword: + + // For function expressions. + case SyntaxKind.FunctionKeyword: + return true; + } + + return isIdentifier(currentToken); + } + + function parseExpressionStatement(): ExpressionStatementSyntax { + return new syntaxFactory.ExpressionStatementSyntax(parseNodeData, parseExpression(/*allowIn:*/ true), eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false)); + } + + function parseIfStatement(ifKeyword: ISyntaxToken): IfStatementSyntax { + return new syntaxFactory.IfStatementSyntax(parseNodeData, + consumeToken(ifKeyword), eatToken(SyntaxKind.OpenParenToken), parseExpression(/*allowIn:*/ true), + eatToken(SyntaxKind.CloseParenToken), parseStatement(/*inErrorRecovery:*/ false), parseOptionalElseClause()); + } + + function parseOptionalElseClause(): ElseClauseSyntax { + return currentToken().kind() === SyntaxKind.ElseKeyword ? parseElseClause() : null; + } + + function parseElseClause(): ElseClauseSyntax { + return new syntaxFactory.ElseClauseSyntax(parseNodeData, eatToken(SyntaxKind.ElseKeyword), parseStatement(/*inErrorRecovery:*/ false)); + } + + function isVariableStatement(modifierCount: number): boolean { + return peekToken(modifierCount).kind() === SyntaxKind.VarKeyword; + } + + function parseVariableStatement(): VariableStatementSyntax { + return new syntaxFactory.VariableStatementSyntax(parseNodeData, + parseModifiers(), parseVariableDeclaration(/*allowIn:*/ true), eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false)); + } + + function parseVariableDeclaration(allowIn: boolean): VariableDeclarationSyntax { + // Debug.assert(currentToken().kind() === SyntaxKind.VarKeyword); + + var varKeyword = eatToken(SyntaxKind.VarKeyword); + // Debug.assert(varKeyword.fullWidth() > 0); + + var listParsingState = allowIn + ? ListParsingState.VariableDeclaration_VariableDeclarators_AllowIn + : ListParsingState.VariableDeclaration_VariableDeclarators_DisallowIn; + + var skippedTokens: ISyntaxToken[] = getArray(); + var variableDeclarators = parseSeparatedSyntaxList(listParsingState, skippedTokens); + varKeyword = addSkippedTokensAfterToken(varKeyword, skippedTokens); + + return new syntaxFactory.VariableDeclarationSyntax(parseNodeData, varKeyword, variableDeclarators); + } + + function isVariableDeclarator(): boolean { + var node = currentNode(); + if (node !== null && node.kind() === SyntaxKind.VariableDeclarator) { + return true; + } + + return isIdentifier(currentToken()); + } + + function canReuseVariableDeclaratorNode(node: ISyntaxNode) { + if (node === null || node.kind() !== SyntaxKind.VariableDeclarator) { + return false; + } + + // Very subtle incremental parsing bug. Consider the following code: + // + // var v = new List < A, B + // + // This is actually legal code. It's a list of variable declarators "v = new List() + // + // then we have a problem. "v = new Listnode; + return variableDeclarator.equalsValueClause === null; + } + + function tryParseVariableDeclarator(allowIn: boolean, allowPropertyName: boolean): VariableDeclaratorSyntax { + // TODO(cyrusn): What if the 'allowIn' context has changed between when we last parsed + // and now? We could end up with an incorrect tree. For example, say we had in the old + // tree "var i = a in b". Then, in the new tree the declarator portion moved into: + // "for (var i = a in b". We would not want to reuse the declarator as the "in b" portion + // would need to be consumed by the for declaration instead. Need to see if it is possible + // to hit this case. + var node = currentNode(); + if (canReuseVariableDeclaratorNode(node)) { + consumeNode(node); + return node; + } + + if (allowPropertyName) { + // Debug.assert(isPropertyName(currentToken(), /*inErrorRecovery:*/ false)); + } + + if (!allowPropertyName && !isIdentifier(currentToken())) { + return null; + } + + var propertyName = allowPropertyName ? eatPropertyName() : eatIdentifierToken(); + var equalsValueClause: EqualsValueClauseSyntax = null; + var typeAnnotation: TypeAnnotationSyntax = null; + + if (propertyName.fullWidth() > 0) { + typeAnnotation = parseOptionalTypeAnnotation(/*allowStringLiteral:*/ false); + + if (isEqualsValueClause(/*inParameter*/ false)) { + equalsValueClause = parseEqualsValueClause(allowIn); + } + } + + return new syntaxFactory.VariableDeclaratorSyntax(parseNodeData, propertyName, typeAnnotation, equalsValueClause); + } + + function isEqualsValueClause(inParameter: boolean): boolean { + var token0 = currentToken(); + if (token0.kind() === SyntaxKind.EqualsToken) { + return true; + } + + // It's not uncommon during typing for the user to miss writing the '=' token. Check if + // there is no newline after the last token and if we're on an expression. If so, parse + // this as an equals-value clause with a missing equals. + if (!previousTokenHasTrailingNewLine(token0)) { + var tokenKind = token0.kind(); + + // The 'isExpression' call below returns true for "=>". That's because it smartly + // assumes that there is just a missing identifier and the user wanted a lambda. + // While this is sensible, we don't want to allow that here as that would mean we're + // glossing over multiple erorrs and we're probably making things worse. So don't + // treat this as an equals value clause and let higher up code handle things. + if (tokenKind === SyntaxKind.EqualsGreaterThanToken) { + return false; + } + + // There are two places where we allow equals-value clauses. The first is in a + // variable declarator. The second is with a parameter. For variable declarators + // it's more likely that a { would be a allowed (as an object literal). While this + // is also allowed for parameters, the risk is that we consume the { as an object + // literal when it really will be for the block following the parameter. + if (tokenKind === SyntaxKind.OpenBraceToken && + inParameter) { + return false; + } + + return isExpression(token0); + } + + return false; + } + + function parseEqualsValueClause(allowIn: boolean): EqualsValueClauseSyntax { + return new syntaxFactory.EqualsValueClauseSyntax(parseNodeData, + eatToken(SyntaxKind.EqualsToken), tryParseAssignmentExpressionOrHigher(/*force:*/ true, allowIn)); + } + + function parseExpression(allowIn: boolean): IExpressionSyntax { + // Expression[in]: + // AssignmentExpression[in] + // Expression[in] , AssignmentExpression[in] + + var leftOperand = tryParseAssignmentExpressionOrHigher(/*force:*/ true, allowIn); + while (true) { + var _currentToken = currentToken(); + if (_currentToken.kind() !== SyntaxKind.CommaToken) { + break; + } + + leftOperand = new syntaxFactory.BinaryExpressionSyntax(parseNodeData, leftOperand, consumeToken(_currentToken), + tryParseAssignmentExpressionOrHigher(/*force:*/ true, allowIn)); + } + + return leftOperand; + } + + // Called when you need to parse an expression, but you do not want to allow 'CommaExpressions'. + // i.e. if you have "var a = 1, b = 2" then when we parse '1' we want to parse with higher + // precedence than 'comma'. Otherwise we'll get: "var a = (1, (b = 2))", instead of + // "var a = (1), b = (2)"); + function tryParseAssignmentExpressionOrHigher(force: boolean, allowIn: boolean): IExpressionSyntax { + // Augmented by TypeScript: + // + // AssignmentExpression[in]: + // 1) ConditionalExpression[in] + // 2) LeftHandSideExpression = AssignmentExpression[in] + // 3) LeftHandSideExpression AssignmentOperator AssignmentExpression[in] + // 4) ArrowFunctionExpression <-- added by TypeScript + // + // Open spec question. Right now, there is no 'ArrowFunctionExpression[in]' variant. + // Thus, if the user has: + // + // for (var a = () => b in c) {} + // + // Then we will fail to parse (because the 'in' will be consumed as part of the body of + // the lambda, and not as part of the 'for' statement). This is likely not an issue + // whatsoever as there seems to be no good reason why anyone would ever write code like + // the above. + // + // Note: for ease of implementation we treat productions '2' and '3' as the same thing. + // (i.e. they're both BinaryExpressions with an assignment operator in it). + + // First, check if we have production '4' (an arrow function). Note that if we do, we + // must *not* recurse for productsion 1, 2 or 3. An ArrowFunction is not a + // LeftHandSideExpression, nor does it start a ConditionalExpression. So we are done + // with AssignmentExpression if we see one. + var _currentToken = currentToken(); + var arrowFunction = tryParseAnyArrowFunctionExpression(_currentToken); + if (arrowFunction !== null) { + return arrowFunction; + } + + // Now try to see if we're in production '1', '2' or '3'. A conditional expression can + // start with a LogicalOrExpression, while the assignment productions can only start with + // LeftHandSideExpressions. + // + // So, first, we try to just parse out a BinaryExpression. If we get something that is a + // LeftHandSide or higher, then we can try to parse out the assignment expression part. + // Otherwise, we try to parse out the conditional expression bit. We want to allow any + // binary expression here, so we pass in the 'lowest' precedence here so that it matches + // and consumes anything. + var leftOperand = tryParseBinaryExpressionOrHigher(_currentToken, force, BinaryExpressionPrecedence.Lowest, allowIn); + if (leftOperand === null) { + return null; + } + + if (SyntaxUtilities.isLeftHandSizeExpression(leftOperand)) { + // Note: we call currentOperatorToken so that we get an appropriately merged token + // for cases like > > = becoming >>= + var operatorToken = currentOperatorToken(); + + // Check for recursive assignment expressions. + if (SyntaxFacts.isAssignmentOperatorToken(operatorToken.kind())) { + return new syntaxFactory.BinaryExpressionSyntax(parseNodeData, leftOperand, consumeToken(operatorToken), + tryParseAssignmentExpressionOrHigher(/*force:*/ true, allowIn)); + } + } + + // It wasn't an assignment or a lambda. This is a conditional expression: + return parseConditionalExpressionRest(allowIn, leftOperand); + } + + function tryParseAnyArrowFunctionExpression(_currentToken: ISyntaxToken): IExpressionSyntax { + return isSimpleArrowFunctionExpression(_currentToken) + ? parseSimpleArrowFunctionExpression() + : tryParseParenthesizedArrowFunctionExpression(); + } + + function tryParseUnaryExpressionOrHigher(_currentToken: ISyntaxToken, force: boolean): IUnaryExpressionSyntax { + var currentTokenKind = _currentToken.kind(); + + switch (currentTokenKind) { + case SyntaxKind.PlusToken: + case SyntaxKind.MinusToken: + case SyntaxKind.TildeToken: + case SyntaxKind.ExclamationToken: + case SyntaxKind.PlusPlusToken: + case SyntaxKind.MinusMinusToken: + return new syntaxFactory.PrefixUnaryExpressionSyntax(parseNodeData, consumeToken(_currentToken), tryParseUnaryExpressionOrHigher(currentToken(), /*force:*/ true)); + case SyntaxKind.TypeOfKeyword: return parseTypeOfExpression(_currentToken); + case SyntaxKind.VoidKeyword: return parseVoidExpression(_currentToken); + case SyntaxKind.DeleteKeyword: return parseDeleteExpression(_currentToken); + case SyntaxKind.LessThanToken: return parseCastExpression(_currentToken); + default: + return tryParsePostfixExpressionOrHigher(_currentToken, force); + } + } + + function tryParseBinaryExpressionOrHigher(_currentToken: ISyntaxToken, force: boolean, precedence: BinaryExpressionPrecedence, allowIn: boolean): IExpressionSyntax { + // The binary expressions are incredibly left recursive in their definitions. We + // clearly can't implement that through recursion. So, instead, we first bottom out + // of all the recursion by jumping to this production and consuming a UnaryExpression + // first. + // + // MultiplicativeExpression: See 11.5 + // UnaryExpression + var leftOperand = tryParseUnaryExpressionOrHigher(_currentToken, force); + if (leftOperand === null) { + return null; + } + + // We then pop up the stack consuming the other side of the binary exprssion if it exists. + return parseBinaryExpressionRest(precedence, allowIn, leftOperand); + } + + function parseConditionalExpressionRest(allowIn: boolean, leftOperand: IExpressionSyntax): IExpressionSyntax { + // Note: we are passed in an expression which was produced from parseBinaryExpressionOrHigher. + + var _currentToken = currentToken(); + + // Now check for conditional expression. + if (_currentToken.kind() !== SyntaxKind.QuestionToken) { + return leftOperand; + } + + // Note: we explicitly do *not* pass 'allowIn' to the whenTrue part. An 'in' expression is always + // allowed in the 'true' part of a conditional expression. + + return new syntaxFactory.ConditionalExpressionSyntax(parseNodeData, + leftOperand, consumeToken(_currentToken), tryParseAssignmentExpressionOrHigher(/*force:*/ true, /*allowIn:*/ true), + eatToken(SyntaxKind.ColonToken), tryParseAssignmentExpressionOrHigher(/*force:*/ true, allowIn)); + } + + function parseBinaryExpressionRest(precedence: BinaryExpressionPrecedence, allowIn: boolean, leftOperand: IExpressionSyntax): IExpressionSyntax { + while (true) { + // We either have a binary operator here, or we're finished. We call + // currentOperatorToken versus currentToken here so that we merge token sequences + // like > and = into >= + var operatorToken = currentOperatorToken(); + var tokenKind = operatorToken.kind(); + + // Only proceed if we see binary expression token. However we don't parse + // assignment expressions or comma expressions here. Those are taken care of + // respectively in parseAssignmentExpression and parseExpression. + if (!SyntaxFacts.isBinaryExpressionOperatorToken(tokenKind) || + tokenKind === SyntaxKind.CommaToken || + SyntaxFacts.isAssignmentOperatorToken(tokenKind)) { + + break; + } + + // also, if it's the 'in' operator, only allow if our caller allows it. + if (tokenKind === SyntaxKind.InKeyword && !allowIn) { + break; + } + + var newPrecedence = getBinaryExpressionPrecedence(tokenKind); + + // All binary operators must have precedence > 0 + // Debug.assert(newPrecedence > 0); + + // Check the precedence to see if we should "take" this operator + if (newPrecedence <= precedence) { + break; + } + + // Precedence is okay, so we'll "take" this operator. + // Now skip the operator token we're on. + + leftOperand = new syntaxFactory.BinaryExpressionSyntax(parseNodeData, leftOperand, consumeToken(operatorToken), + tryParseBinaryExpressionOrHigher(currentToken(), /*force:*/ true, newPrecedence, allowIn)); + } + + return leftOperand; + } + + function currentOperatorToken(): ISyntaxToken { + var token0 = currentToken(); + + // If we see a > we need to see if we can actually merge this contextually into a + // >> >>> >= >>= >>>= token. + if (token0.kind() === SyntaxKind.GreaterThanToken) { + return currentContextualToken(); + // var kind = token0.kind; + //Debug.assert(kind() === SyntaxKind.GreaterThanToken || kind() === SyntaxKind.GreaterThanGreaterThanToken || + // kind() === SyntaxKind.GreaterThanGreaterThanGreaterThanToken || kind() === SyntaxKind.GreaterThanEqualsToken || + // kind() === SyntaxKind.GreaterThanGreaterThanEqualsToken || kind() === SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken); + } + + return token0; + } + + function tryParseMemberExpressionOrHigher(_currentToken: ISyntaxToken, force: boolean, inObjectCreation: boolean): IMemberExpressionSyntax { + // Note: to make our lives simpler, we decompose the the NewExpression productions and + // place ObjectCreationExpression and FunctionExpression into PrimaryExpression. + // like so: + // + // PrimaryExpression : See 11.1 + // this + // Identifier + // Literal + // ArrayLiteral + // ObjectLiteral + // (Expression) + // FunctionExpression + // new MemberExpression Arguments? + // + // MemberExpression : See 11.2 + // PrimaryExpression + // MemberExpression[Expression] + // MemberExpression.IdentifierName + // + // CallExpression : See 11.2 + // MemberExpression + // CallExpression Arguments + // CallExpression[Expression] + // CallExpression.IdentifierName + // + // Technically this is ambiguous. i.e. CallExpression defines: + // + // CallExpression: + // CallExpression Arguments + // + // If you see: "new Foo()" + // + // Then that could be treated as a single ObjectCreationExpression, or it could be + // treated as the invocation of "new Foo". We disambiguate that in code (to match + // the original grammar) by making sure that if we see an ObjectCreationExpression + // we always consume arguments if they are there. So we treat "new Foo()" as an + // object creation only, and not at all as an invocation) Another way to think + // about this is that for every "new" that we see, we will consume an argument list if + // it is there as part of the *associated* object creation node. Any additional + // argument lists we see, will become invocation expressions. + // + // Because there are no other places in the grammar now that refer to FunctionExpression + // or ObjectCreationExpression, it is safe to push down into the PrimaryExpression + // production. + // + // Because CallExpression and MemberExpression are left recursive, we need to bottom out + // of the recursion immediately. So we parse out a primary expression to start with. + var expression: IMemberExpressionSyntax = tryParsePrimaryExpression(_currentToken, force); + if (expression === null) { + return null; + } + + return parseMemberExpressionRest(expression, inObjectCreation); + } + + function parseCallExpressionRest(expression: ILeftHandSideExpressionSyntax): ILeftHandSideExpressionSyntax { + while (true) { + var _currentToken = currentToken(); + var currentTokenKind = _currentToken.kind(); + + switch (currentTokenKind) { + case SyntaxKind.OpenParenToken: + expression = new syntaxFactory.InvocationExpressionSyntax(parseNodeData, expression, parseArgumentList(/*typeArgumentList:*/ null)); + continue; + + case SyntaxKind.LessThanToken: + // See if this is the start of a generic invocation. If so, consume it and + // keep checking for postfix expressions. Otherwise, it's just a '<' that's + // part of an arithmetic expression. Break out so we consume it higher in the + // stack. + var argumentList = tryParseArgumentList(); + if (argumentList === null) { + break; + } + + expression = new syntaxFactory.InvocationExpressionSyntax(parseNodeData, expression, argumentList); + continue; + + case SyntaxKind.OpenBracketToken: + expression = parseElementAccessExpression(expression, _currentToken, /*inObjectCreation:*/ false); + continue; + + case SyntaxKind.DotToken: + expression = new syntaxFactory.MemberAccessExpressionSyntax(parseNodeData, expression, consumeToken(_currentToken), eatIdentifierNameToken()); + continue; + } + + return expression; + } + } + + function parseMemberExpressionRest(expression: IMemberExpressionSyntax, inObjectCreation: boolean): IMemberExpressionSyntax { + while (true) { + var _currentToken = currentToken(); + var currentTokenKind = _currentToken.kind(); + + switch (currentTokenKind) { + case SyntaxKind.OpenBracketToken: + expression = parseElementAccessExpression(expression, _currentToken, inObjectCreation); + continue; + + case SyntaxKind.DotToken: + expression = new syntaxFactory.MemberAccessExpressionSyntax(parseNodeData, expression, consumeToken(_currentToken), eatIdentifierNameToken()); + continue; + } + + return expression; + } + } + + function tryParseLeftHandSideExpressionOrHigher(_currentToken: ISyntaxToken, force: boolean): ILeftHandSideExpressionSyntax { + // Original Ecma: + // LeftHandSideExpression: See 11.2 + // NewExpression + // CallExpression + // + // Our simplification: + // + // LeftHandSideExpression: See 11.2 + // MemberExpression + // CallExpression + // + // See comment in parseMemberExpressionOrHigher on how we replaced NewExpression with + // MemberExpression to make our lives easier. + // + // to best understand the below code, it's important to see how CallExpression expands + // out into its own productions: + // + // CallExpression: + // MemberExpression Arguments + // CallExpression Arguments + // CallExpression[Expression] + // CallExpression.IdentifierName + // super ( ArgumentListopt ) + // super.IdentifierName + // + // Because of the recursion in these calls, we need to bottom out first. There are two + // bottom out states we can run into. Either we see 'super' which must start either of + // the last two CallExpression productions. Or we have a MemberExpression which either + // completes the LeftHandSideExpression, or starts the beginning of the first four + // CallExpression productions. + + var expression: ILeftHandSideExpressionSyntax = null; + if (_currentToken.kind() === SyntaxKind.SuperKeyword) { + expression = parseSuperExpression(_currentToken); + } + else { + expression = tryParseMemberExpressionOrHigher(_currentToken, force, /*inObjectCreation:*/ false); + if (expression === null) { + return null; + } + } + + // Now, we *may* be complete. However, we might have consumed the start of a + // CallExpression. As such, we need to consume the rest of it here to be complete. + return parseCallExpressionRest(expression); + } + + function parseSuperExpression(superToken: ISyntaxToken): ILeftHandSideExpressionSyntax { + var expression: ILeftHandSideExpressionSyntax = consumeToken(superToken); + + // If we have seen "super" it must be followed by '(' or '.'. + // If it wasn't then just try to parse out a '.' and report an error. + var currentTokenKind = currentToken().kind(); + return currentTokenKind === SyntaxKind.OpenParenToken || currentTokenKind === SyntaxKind.DotToken + ? expression + : new syntaxFactory.MemberAccessExpressionSyntax(parseNodeData, expression, eatToken(SyntaxKind.DotToken), eatIdentifierNameToken()); + } + + function tryParsePostfixExpressionOrHigher(_currentToken: ISyntaxToken, force: boolean): IPostfixExpressionSyntax { + var expression = tryParseLeftHandSideExpressionOrHigher(_currentToken, force); + if (expression === null) { + return null; + } + + var _currentToken = currentToken(); + var currentTokenKind = _currentToken.kind(); + + switch (currentTokenKind) { + case SyntaxKind.PlusPlusToken: + case SyntaxKind.MinusMinusToken: + // Because of automatic semicolon insertion, we should only consume the ++ or -- + // if it is on the same line as the previous token. + if (previousTokenHasTrailingNewLine(_currentToken)) { + break; + } + + return new syntaxFactory.PostfixUnaryExpressionSyntax(parseNodeData, expression, consumeToken(_currentToken)); + } + + return expression; + } + + function tryParseGenericArgumentList(): ArgumentListSyntax { + // Debug.assert(currentToken().kind() === SyntaxKind.LessThanToken); + // If we have a '<', then only parse this as a arugment list if the type arguments + // are complete and we have an open paren. if we don't, rewind and return nothing. + var rewindPoint = getRewindPoint(); + + var typeArgumentList = tryParseTypeArgumentList(/*inExpression:*/ true); + var token0 = currentToken(); + var tokenKind = token0.kind(); + + var isOpenParen = tokenKind === SyntaxKind.OpenParenToken; + var isDot = tokenKind === SyntaxKind.DotToken; + var isOpenParenOrDot = isOpenParen || isDot; + + var argumentList: ArgumentListSyntax = null; + if (typeArgumentList === null || !isOpenParenOrDot) { + // Wasn't generic. Rewind to where we started so this can be parsed as an + // arithmetic expression. + rewind(rewindPoint); + releaseRewindPoint(rewindPoint); + return null; + } + else { + releaseRewindPoint(rewindPoint); + // It's not uncommon for a user to type: "Foo." + // + // This is not legal in typescript (as an parameter list must follow the type + // arguments). We want to give a good error message for this as otherwise + // we'll bail out here and give a poor error message when we try to parse this + // as an arithmetic expression. + if (isDot) { + // A parameter list must follow a generic type argument list. + var diagnostic = new Diagnostic(fileName, source.text.lineMap(), start(token0, source.text), width(token0), + DiagnosticCode.A_parameter_list_must_follow_a_generic_type_argument_list_expected, null); + addDiagnostic(diagnostic); + + return new syntaxFactory.ArgumentListSyntax(parseNodeData, typeArgumentList, + Syntax.emptyToken(SyntaxKind.OpenParenToken), Syntax.emptySeparatedList(), Syntax.emptyToken(SyntaxKind.CloseParenToken)); + } + else { + return parseArgumentList(typeArgumentList); + } + } + } + + function tryParseArgumentList(): ArgumentListSyntax { + var tokenKind = currentToken().kind(); + if (tokenKind === SyntaxKind.LessThanToken) { + return tryParseGenericArgumentList(); + } + + if (tokenKind === SyntaxKind.OpenParenToken) { + return parseArgumentList(null); + } + + return null; + } + + function parseArgumentList(typeArgumentList: TypeArgumentListSyntax): ArgumentListSyntax { + var openParenToken = eatToken(SyntaxKind.OpenParenToken); + + // Don't use the name 'arguments' it prevents V8 from optimizing this method. + var _arguments = Syntax.emptySeparatedList(); + + if (openParenToken.fullWidth() > 0) { + var skippedTokens: ISyntaxToken[] = getArray(); + _arguments = parseSeparatedSyntaxList(ListParsingState.ArgumentList_AssignmentExpressions, skippedTokens); + openParenToken = addSkippedTokensAfterToken(openParenToken, skippedTokens); + } + + return new syntaxFactory.ArgumentListSyntax(parseNodeData, typeArgumentList, openParenToken, _arguments, eatToken(SyntaxKind.CloseParenToken)); + } + + function tryParseArgumentListExpression(): IExpressionSyntax { + // Generally while parsing lists, we don't want to 'force' the parser to parse + // the item. That way, if the expected item isn't htere, we can bail out and + // move to a higher stage of list parsing. However, it's extremely common to + // see something like "Foo(, a". in this case, even though there isn't an expression + // after the open paren, we still want to force parsing an expression (which will + // cause a missing identiifer to be created), so that we will then consume the + // comma and the following list items). + var force = currentToken().kind() === SyntaxKind.CommaToken; + return tryParseAssignmentExpressionOrHigher(force, /*allowIn:*/ true); + } + + function parseElementAccessArgumentExpression(openBracketToken: ISyntaxToken, inObjectCreation: boolean) { + // It's not uncommon for a user to write: "new Type[]". Check for that common pattern + // and report a better error message. + if (inObjectCreation && currentToken().kind() === SyntaxKind.CloseBracketToken) { + var errorStart = start(openBracketToken, source.text); + var errorEnd = end(currentToken(), source.text); + var diagnostic = new Diagnostic(fileName, source.text.lineMap(), errorStart, errorEnd - errorStart, + DiagnosticCode.new_T_cannot_be_used_to_create_an_array_Use_new_Array_T_instead, null); + addDiagnostic(diagnostic); + + return Syntax.emptyToken(SyntaxKind.IdentifierName); + } + else { + return parseExpression(/*allowIn:*/ true); + } + } + + function parseElementAccessExpression(expression: ILeftHandSideExpressionSyntax, openBracketToken: ISyntaxToken, inObjectCreation: boolean): ElementAccessExpressionSyntax { + // Debug.assert(currentToken().kind() === SyntaxKind.OpenBracketToken); + return new syntaxFactory.ElementAccessExpressionSyntax(parseNodeData, expression, consumeToken(openBracketToken), + parseElementAccessArgumentExpression(openBracketToken, inObjectCreation), eatToken(SyntaxKind.CloseBracketToken)); + } + + function tryParsePrimaryExpression(_currentToken: ISyntaxToken, force: boolean): IPrimaryExpressionSyntax { + if (isIdentifier(_currentToken)) { + return eatIdentifierToken(); + } + + var currentTokenKind = _currentToken.kind(); + switch (currentTokenKind) { + case SyntaxKind.ThisKeyword: + case SyntaxKind.TrueKeyword: + case SyntaxKind.FalseKeyword: + case SyntaxKind.NullKeyword: + case SyntaxKind.NumericLiteral: + case SyntaxKind.RegularExpressionLiteral: + case SyntaxKind.StringLiteral: + return consumeToken(_currentToken); + + case SyntaxKind.FunctionKeyword: return parseFunctionExpression(_currentToken); + case SyntaxKind.OpenBracketToken: return parseArrayLiteralExpression(_currentToken); + case SyntaxKind.OpenBraceToken: return parseObjectLiteralExpression(_currentToken); + case SyntaxKind.OpenParenToken: return parseParenthesizedExpression(_currentToken); + case SyntaxKind.NewKeyword: return parseObjectCreationExpression(_currentToken); + + case SyntaxKind.SlashToken: + case SyntaxKind.SlashEqualsToken: + // If we see a standalone / or /= and we're expecting a term, then try to reparse + // it as a regular expression. + var result = tryReparseDivideAsRegularExpression(); + + // If we get a result, then use it. Otherwise, create a missing identifier so + // that parsing can continue. Note: we do this even if 'force' is false. That's + // because we *do* want to consider a standalone / as an expression that should be + // returned from tryParseExpression even when 'force' is set to false. + return result || eatIdentifierToken(DiagnosticCode.Expression_expected); + } + + if (!force) { + return null; + } + + // Nothing else worked, report an error and produce a missing token. + return eatIdentifierToken(DiagnosticCode.Expression_expected); + } + + function tryReparseDivideAsRegularExpression(): IPrimaryExpressionSyntax { + // If we see a / or /= token, then that may actually be the start of a regex in certain + // contexts. + + // var currentToken = this.currentToken(); + // Debug.assert(SyntaxFacts.isAnyDivideToken(currentToken.kind())); + + // Ok, from our quick lexical check, this could be a place where a regular expression could + // go. Now we have to do a bunch of work. Ask the source to retrive the token at the + // current position again. But this time allow it to retrieve it as a regular expression. + var currentToken = currentContextualToken(); + + // Note: we *must* have gotten a /, /= or regular expression. Or else something went *very* + // wrong with our logic above. + // Debug.assert(SyntaxFacts.isAnyDivideOrRegularExpressionToken(currentToken.kind())); + + var tokenKind = currentToken.kind(); + if (tokenKind === SyntaxKind.SlashToken || tokenKind === SyntaxKind.SlashEqualsToken) { + // Still came back as a / or /=. This is not a regular expression literal. + return null; + } + else if (tokenKind === SyntaxKind.RegularExpressionLiteral) { + return consumeToken(currentToken); + } + else { + // Something *very* wrong happened. This is an internal parser fault that we need + // to figure out and fix. + throw Errors.invalidOperation(); + } + } + + function parseTypeOfExpression(typeOfKeyword: ISyntaxToken): TypeOfExpressionSyntax { + return new syntaxFactory.TypeOfExpressionSyntax(parseNodeData, consumeToken(typeOfKeyword), tryParseUnaryExpressionOrHigher(currentToken(), /*force:*/ true)); + } + + function parseDeleteExpression(deleteKeyword: ISyntaxToken): DeleteExpressionSyntax { + return new syntaxFactory.DeleteExpressionSyntax(parseNodeData, consumeToken(deleteKeyword), tryParseUnaryExpressionOrHigher(currentToken(), /*force:*/ true)); + } + + function parseVoidExpression(voidKeyword: ISyntaxToken): VoidExpressionSyntax { + return new syntaxFactory.VoidExpressionSyntax(parseNodeData, consumeToken(voidKeyword), tryParseUnaryExpressionOrHigher(currentToken(), /*force:*/ true)); + } + + function parseFunctionExpression(functionKeyword: ISyntaxToken): FunctionExpressionSyntax { + return new syntaxFactory.FunctionExpressionSyntax(parseNodeData, + consumeToken(functionKeyword), eatOptionalIdentifierToken(), + parseCallSignature(/*requireCompleteTypeParameterList:*/ false), + parseBlock(/*parseStatementsEvenWithNoOpenBrace:*/ false, /*checkForStrictMode:*/ true)); + } + + function parseObjectCreationExpression(newKeyword: ISyntaxToken): ObjectCreationExpressionSyntax { + // ObjectCreationExpression + // new MemberExpression Arguments? + // + // Note: if we see arguments we absolutely take them and attach them tightly to this + // object creation expression. + // + // See comment in tryParseMemberExpressionOrHigher for a more complete explanation of + // this decision. + + return new syntaxFactory.ObjectCreationExpressionSyntax(parseNodeData, + consumeToken(newKeyword), tryParseMemberExpressionOrHigher(currentToken(), /*force:*/ true, /*inObjectCreation:*/ true), tryParseArgumentList()); + } + + function parseCastExpression(lessThanToken: ISyntaxToken): CastExpressionSyntax { + return new syntaxFactory.CastExpressionSyntax(parseNodeData, + consumeToken(lessThanToken), parseType(), eatToken(SyntaxKind.GreaterThanToken), tryParseUnaryExpressionOrHigher(currentToken(), /*force:*/ true)); + } + + function parseParenthesizedExpression(openParenToken: ISyntaxToken): ParenthesizedExpressionSyntax { + return new syntaxFactory.ParenthesizedExpressionSyntax(parseNodeData, + consumeToken(openParenToken), parseExpression(/*allowIn:*/ true), eatToken(SyntaxKind.CloseParenToken)); + } + + function tryParseParenthesizedArrowFunctionExpression(): ParenthesizedArrowFunctionExpressionSyntax { + var tokenKind = currentToken().kind(); + if (tokenKind !== SyntaxKind.OpenParenToken && tokenKind !== SyntaxKind.LessThanToken) { + return null; + } + + // Because arrow functions and parenthesized expressions look similar, we have to check far + // enough ahead to be sure we've actually got an arrow function. For example, both nodes can + // start with: + // (a = b, c = d, ..., e = f). + //So we effectively need infinite lookahead to decide which node we're in. + // + // First, check for things that definitely have enough information to let us know it's an + // arrow function. + + if (isDefinitelyArrowFunctionExpression()) { + // We have something like "() =>" or "(a) =>". Definitely a lambda, so parse it + // unilaterally as such. + return tryParseParenthesizedArrowFunctionExpressionWorker(/*requiresArrow:*/ false); + } + + // Now, look for cases where we're sure it's not an arrow function. This will help save us + // a costly parse. + if (!isPossiblyArrowFunctionExpression()) { + return null; + } + + // Then, try to actually parse it as a arrow function, and only return if we see an => + var rewindPoint = getRewindPoint(); + + var arrowFunction = tryParseParenthesizedArrowFunctionExpressionWorker(/*requiresArrow:*/ true); + if (arrowFunction === null) { + rewind(rewindPoint); + } + + releaseRewindPoint(rewindPoint); + return arrowFunction; + } + + function tryParseParenthesizedArrowFunctionExpressionWorker(requireArrow: boolean): ParenthesizedArrowFunctionExpressionSyntax { + var _currentToken = currentToken(); + // Debug.assert(currentToken.kind() === SyntaxKind.OpenParenToken || currentToken.kind() === SyntaxKind.LessThanToken); + + var callSignature = parseCallSignature(/*requireCompleteTypeParameterList:*/ true); + + if (requireArrow && currentToken().kind() !== SyntaxKind.EqualsGreaterThanToken) { + return null; + } + + var equalsGreaterThanToken = eatToken(SyntaxKind.EqualsGreaterThanToken); + + var block = tryParseArrowFunctionBlock(); + var expression: IExpressionSyntax = null; + if (block === null) { + expression = tryParseAssignmentExpressionOrHigher(/*force:*/ true, /*allowIn:*/ true); + } + + return new syntaxFactory.ParenthesizedArrowFunctionExpressionSyntax(parseNodeData, callSignature, equalsGreaterThanToken, block, expression); + } + + function tryParseArrowFunctionBlock(): BlockSyntax { + if (isBlock()) { + return parseBlock(/*parseStatementsEvenWithNoOpenBrace:*/ false, /*checkForStrictMode:*/ false); + } + else { + // We didn't have a block. However, we may be in an error situation. For example, + // if the user wrote: + // + // a => + // var v = 0; + // } + // + // (i.e. they're missing the open brace). See if that's the case so we can try to + // recover better. If we don't do this, then the next close curly we see may end + // up preemptively closing the containing construct. + var _modifierCount = modifierCount(); + if (isStatement(_modifierCount, /*inErrorRecovery:*/ false) && + !isExpressionStatement(currentToken()) && + !isFunctionDeclaration(_modifierCount)) { + // We've seen a statement (and it isn't an expressionStatement like 'foo()'), + // so treat this like a block with a missing open brace. + return parseBlock(/*parseStatementsEvenWithNoOpenBrace:*/ true, /*checkForStrictMode:*/ false); + } + else { + return null; + } + } + } + + function isSimpleArrowFunctionExpression(_currentToken: ISyntaxToken): boolean { + // ERROR RECOVERY TWEAK: + // If we see a standalone => try to parse it as an arrow function as that's likely what + // the user intended to write. + if (_currentToken.kind() === SyntaxKind.EqualsGreaterThanToken) { + return true; + } + + return isIdentifier(_currentToken) && + peekToken(1).kind() === SyntaxKind.EqualsGreaterThanToken; + } + + function parseSimpleArrowFunctionExpression(): SimpleArrowFunctionExpressionSyntax { + // Debug.assert(isSimpleArrowFunctionExpression()); + + var parameter = eatSimpleParameter(); + var equalsGreaterThanToken = eatToken(SyntaxKind.EqualsGreaterThanToken); + + var block = tryParseArrowFunctionBlock(); + var expression: IExpressionSyntax = null; + if (block === null) { + expression = tryParseAssignmentExpressionOrHigher(/*force:*/ true, /*allowIn:*/ true); + } + + return new syntaxFactory.SimpleArrowFunctionExpressionSyntax(parseNodeData, parameter, equalsGreaterThanToken, block, expression); + } + + function isBlock(): boolean { + return currentToken().kind() === SyntaxKind.OpenBraceToken; + } + + function isDefinitelyArrowFunctionExpression(): boolean { + var token0 = currentToken(); + if (token0.kind() !== SyntaxKind.OpenParenToken) { + // If it didn't start with an (, then it could be generic. That's too complicated + // and we can't say it's 'definitely' an arrow function. + return false; + } + + var token1 = peekToken(1); + var token1Kind = token1.kind(); + + var token2: ISyntaxToken; + + if (token1Kind === SyntaxKind.CloseParenToken) { + // () + // Definitely an arrow function. Could never be a parenthesized expression. + // *However*, because of error situations, we could end up with things like "().foo". + // In this case, we don't want to think of this as the start of an arrow function. + // To prevent this, we are a little stricter, and we require that we at least see: + // "():" or "() =>" or "() {}". Note: the last one is illegal. However it + // most likely is a missing => and not a parenthesized expression. + token2 = peekToken(2); + var token2Kind = token2.kind(); + return token2Kind === SyntaxKind.ColonToken || + token2Kind === SyntaxKind.EqualsGreaterThanToken || + token2Kind === SyntaxKind.OpenBraceToken; + } + + if (token1Kind === SyntaxKind.DotDotDotToken) { + // (... + // Definitely an arrow function. Could never be a parenthesized expression. + return true; + } + + token2 = peekToken(2); + token2Kind = token2.kind(); + + if (token1Kind === SyntaxKind.PublicKeyword || token1Kind === SyntaxKind.PrivateKeyword) { + if (isIdentifier(token2)) { + // "(public id" or "(function id". Definitely an arrow function. Could never + // be a parenthesized expression. Note: this will be an *illegal* arrow + // function (as accessibility modifiers are not allowed in it). However, that + // will be reported by the grammar checker walker. + return true; + } + } + + if (!isIdentifier(token1)) { + // All other arrow functions must start with (id + // so this is definitely not an arrow function. + return false; + } + + // (id + // + // Lots of options here. Check for things that make us certain it's an + // arrow function. + if (token2Kind === SyntaxKind.ColonToken) { + // (id: + // Definitely an arrow function. Could never be a parenthesized expression. + return true; + } + + var token3 = peekToken(3); + var token3Kind = token3.kind(); + if (token2Kind === SyntaxKind.QuestionToken) { + // (id? + // Could be an arrow function, or a parenthesized conditional expression. + + // Check for the things that could only be arrow functions. + if (token3Kind === SyntaxKind.ColonToken || + token3Kind === SyntaxKind.CloseParenToken || + token3Kind === SyntaxKind.CommaToken) { + // (id?: + // (id?) + // (id?, + // These are the only cases where this could be an arrow function. + // And none of them can be parenthesized expression. + return true; + } + } + + if (token2Kind === SyntaxKind.CloseParenToken) { + // (id) + // Could be an arrow function, or a parenthesized conditional expression. + + if (token3Kind === SyntaxKind.EqualsGreaterThanToken) { + // (id) => + // Definitely an arrow function. Could not be a parenthesized expression. + return true; + } + + // Note: "(id):" *looks* like it could be an arrow function. However, it could + // show up in: "foo ? (id): + // So we can't return true here for that case. + } + + // TODO: Add more cases if you're sure that there is enough information to know to + // parse this as an arrow function. Note: be very careful here. + + // Anything else wasn't clear enough. Try to parse the expression as an arrow function and bail out + // if we fail. + return false; + } + + function isPossiblyArrowFunctionExpression(): boolean { + var token0 = currentToken(); + if (token0.kind() !== SyntaxKind.OpenParenToken) { + // If it didn't start with an (, then it could be generic. That's too complicated + // and we have to say it's possibly an arrow function. + return true; + } + + var token1 = peekToken(1); + + if (!isIdentifier(token1)) { + // All other arrow functions must start with (id + // so this is definitely not an arrow function. + return false; + } + + var token2 = peekToken(2); + var token2Kind = token2.kind(); + if (token2Kind === SyntaxKind.EqualsToken) { + // (id = + // + // This *could* be an arrow function. i.e. (id = 0) => { } + // Or it could be a parenthesized expression. So we'll have to actually + // try to parse it. + return true; + } + + if (token2Kind === SyntaxKind.CommaToken) { + // (id, + + // This *could* be an arrow function. i.e. (id, id2) => { } + // Or it could be a parenthesized expression (as javascript supports + // the comma operator). So we'll have to actually try to parse it. + return true; + } + + if (token2Kind === SyntaxKind.CloseParenToken) { + // (id) + + var token3 = peekToken(3); + if (token3.kind() === SyntaxKind.ColonToken) { + // (id): + // + // This could be an arrow function. i.e. (id): number => { } + // Or it could be parenthesized exprssion: foo ? (id) : + // So we'll have to actually try to parse it. + return true; + } + } + + // Nothing else could be an arrow function. + return false; + } + + function parseObjectLiteralExpression(openBraceToken: ISyntaxToken): ObjectLiteralExpressionSyntax { + // Debug.assert(currentToken().kind() === SyntaxKind.OpenBraceToken); + + consumeToken(openBraceToken); + // Debug.assert(openBraceToken.fullWidth() > 0); + + var skippedTokens: ISyntaxToken[] = getArray(); + var propertyAssignments = parseSeparatedSyntaxList(ListParsingState.ObjectLiteralExpression_PropertyAssignments, skippedTokens); + openBraceToken = addSkippedTokensAfterToken(openBraceToken, skippedTokens); + + return new syntaxFactory.ObjectLiteralExpressionSyntax(parseNodeData, openBraceToken, propertyAssignments, eatToken(SyntaxKind.CloseBraceToken)); + } + + function tryParsePropertyAssignment(inErrorRecovery: boolean): IPropertyAssignmentSyntax { + // Debug.assert(isPropertyAssignment(/*inErrorRecovery:*/ false)); + + if (isAccessor(modifierCount(), inErrorRecovery)) { + return parseAccessor(/*checkForStrictMode:*/ true); + } + else if (isFunctionPropertyAssignment(inErrorRecovery)) { + return parseFunctionPropertyAssignment(); + } + else if (isSimplePropertyAssignment(inErrorRecovery)) { + return parseSimplePropertyAssignment(); + } + else { + return null; + } + } + + function isPropertyAssignment(inErrorRecovery: boolean): boolean { + return isAccessor(modifierCount(), inErrorRecovery) || + isFunctionPropertyAssignment(inErrorRecovery) || + isSimplePropertyAssignment(inErrorRecovery); + } + + function eatPropertyName(): ISyntaxToken { + var _currentToken = currentToken(); + return SyntaxFacts.isIdentifierNameOrAnyKeyword(_currentToken) + ? eatIdentifierNameToken() + : consumeToken(_currentToken); + } + + function isFunctionPropertyAssignment(inErrorRecovery: boolean): boolean { + return isPropertyName(currentToken(), inErrorRecovery) && + isCallSignature(/*peekIndex:*/ 1); + } + + function parseFunctionPropertyAssignment(): FunctionPropertyAssignmentSyntax { + return new syntaxFactory.FunctionPropertyAssignmentSyntax(parseNodeData, + eatPropertyName(), parseCallSignature(/*requireCompleteTypeParameterList:*/ false), + parseBlock(/*parseBlockEvenWithNoOpenBrace:*/ false, /*checkForStrictMode:*/ true)); + } + + function isSimplePropertyAssignment(inErrorRecovery: boolean): boolean { + return isPropertyName(currentToken(), inErrorRecovery); + } + + function parseSimplePropertyAssignment(): SimplePropertyAssignmentSyntax { + return new syntaxFactory.SimplePropertyAssignmentSyntax(parseNodeData, + eatPropertyName(), eatToken(SyntaxKind.ColonToken), tryParseAssignmentExpressionOrHigher(/*force:*/ true, /*allowIn:*/ true)); + } + + function isPropertyName(token: ISyntaxToken, inErrorRecovery: boolean): boolean { + // NOTE: we do *not* want to check "isIdentifier" here. Any IdentifierName is + // allowed here, even reserved words like keywords. + if (SyntaxFacts.isIdentifierNameOrAnyKeyword(token)) { + // Except: if we're in error recovery, then we don't want to consider keywords. + // After all, if we have: + // + // { a: 1 + // return + // + // we don't want consider 'return' to be the next property in the object literal. + if (inErrorRecovery) { + return isIdentifier(token); + } + else { + return true; + } + } + + var kind = token.kind(); + return kind === SyntaxKind.StringLiteral || kind === SyntaxKind.NumericLiteral; + } + + function parseArrayLiteralExpression(openBracketToken: ISyntaxToken): ArrayLiteralExpressionSyntax { + // Debug.assert(currentToken().kind() === SyntaxKind.OpenBracketToken); + consumeToken(openBracketToken); + // Debug.assert(openBracketToken.fullWidth() > 0); + + var skippedTokens: ISyntaxToken[] = getArray(); + var expressions = parseSeparatedSyntaxList(ListParsingState.ArrayLiteralExpression_AssignmentExpressions, skippedTokens); + openBracketToken = addSkippedTokensAfterToken(openBracketToken, skippedTokens); + + return new syntaxFactory.ArrayLiteralExpressionSyntax(parseNodeData, openBracketToken, expressions, eatToken(SyntaxKind.CloseBracketToken)); + } + + function parseBlock(parseBlockEvenWithNoOpenBrace: boolean, checkForStrictMode: boolean): BlockSyntax { + var openBraceToken = eatToken(SyntaxKind.OpenBraceToken); + var statements = Syntax.emptyList(); + + if (parseBlockEvenWithNoOpenBrace || openBraceToken.fullWidth() > 0) { + var savedIsInStrictMode = isInStrictMode; + + var processItems = checkForStrictMode ? updateStrictModeState : null; + var skippedTokens: ISyntaxToken[] = getArray(); + var statements = parseSyntaxList(ListParsingState.Block_Statements, skippedTokens, processItems); + openBraceToken = addSkippedTokensAfterToken(openBraceToken, skippedTokens); + + setStrictMode(savedIsInStrictMode); + } + + return new syntaxFactory.BlockSyntax(parseNodeData, openBraceToken, statements, eatToken(SyntaxKind.CloseBraceToken)); + } + + function parseCallSignature(requireCompleteTypeParameterList: boolean): CallSignatureSyntax { + return new syntaxFactory.CallSignatureSyntax(parseNodeData, + tryParseTypeParameterList(requireCompleteTypeParameterList), parseParameterList(), parseOptionalTypeAnnotation(/*allowStringLiteral:*/ false)); + } + + function tryParseTypeParameterList(requireCompleteTypeParameterList: boolean): TypeParameterListSyntax { + var _currentToken = currentToken(); + if (_currentToken.kind() !== SyntaxKind.LessThanToken) { + return null; + } + + var rewindPoint = getRewindPoint(); + + var lessThanToken = consumeToken(_currentToken); + + var skippedTokens: ISyntaxToken[] = getArray(); + var typeParameters = parseSeparatedSyntaxList(ListParsingState.TypeParameterList_TypeParameters, skippedTokens); + lessThanToken = addSkippedTokensAfterToken(lessThanToken, skippedTokens); + + var greaterThanToken = eatToken(SyntaxKind.GreaterThanToken); + + // return null if we were required to have a '>' token and we did not have one. + if (requireCompleteTypeParameterList && greaterThanToken.fullWidth() === 0) { + rewind(rewindPoint); + releaseRewindPoint(rewindPoint); + return null; + } + else { + releaseRewindPoint(rewindPoint); + return new syntaxFactory.TypeParameterListSyntax(parseNodeData, lessThanToken, typeParameters, greaterThanToken); + } + } + + function isTypeParameter(): boolean { + return isIdentifier(currentToken()); + } + + function tryParseTypeParameter(): TypeParameterSyntax { + // Debug.assert(isTypeParameter()); + if (!isIdentifier(currentToken())) { + return null; + } + + return new syntaxFactory.TypeParameterSyntax(parseNodeData, eatIdentifierToken(), tryParseConstraint()); + } + + function tryParseConstraint(): ConstraintSyntax { + if (currentToken().kind() !== SyntaxKind.ExtendsKeyword) { + return null; + } + + return new syntaxFactory.ConstraintSyntax(parseNodeData, eatToken(SyntaxKind.ExtendsKeyword), parseTypeOrExpression()); + } + + function tryParseParameterList(): ParameterListSyntax { + if (currentToken().kind() === SyntaxKind.OpenParenToken) { + var token1 = peekToken(1); + + if (token1.kind() === SyntaxKind.CloseParenToken || isParameterHelper(token1)) { + return parseParameterList(); + } + } + + return null; + } + + function parseParameterList(): ParameterListSyntax { + var openParenToken = eatToken(SyntaxKind.OpenParenToken); + var parameters = Syntax.emptySeparatedList(); + + if (openParenToken.fullWidth() > 0) { + var skippedTokens: ISyntaxToken[] = getArray(); + parameters = parseSeparatedSyntaxList(ListParsingState.ParameterList_Parameters, skippedTokens); + openParenToken = addSkippedTokensAfterToken(openParenToken, skippedTokens); + } + + return new syntaxFactory.ParameterListSyntax(parseNodeData, openParenToken, parameters, eatToken(SyntaxKind.CloseParenToken)); + } + + function parseOptionalTypeAnnotation(allowStringLiteral: boolean): TypeAnnotationSyntax { + return currentToken().kind() === SyntaxKind.ColonToken ? parseTypeAnnotation(allowStringLiteral) : null; + } + + function parseTypeAnnotationType(allowStringLiteral: boolean): ITypeSyntax { + if (allowStringLiteral) { + var _currentToken = currentToken(); + if (_currentToken.kind() === SyntaxKind.StringLiteral) { + return consumeToken(_currentToken); + } + } + + return parseType(); + } + + function parseTypeAnnotation(allowStringLiteral: boolean): TypeAnnotationSyntax { + return new syntaxFactory.TypeAnnotationSyntax(parseNodeData, consumeToken(currentToken()), parseTypeAnnotationType(allowStringLiteral)); + } + + function isType(): boolean { + var _currentToken = currentToken(); + + switch (_currentToken.kind()) { + case SyntaxKind.TypeOfKeyword: + case SyntaxKind.AnyKeyword: + case SyntaxKind.NumberKeyword: + case SyntaxKind.BooleanKeyword: + case SyntaxKind.StringKeyword: + case SyntaxKind.VoidKeyword: + case SyntaxKind.OpenBraceToken: + case SyntaxKind.OpenParenToken: + case SyntaxKind.LessThanToken: + case SyntaxKind.NewKeyword: + return true; + default: + return isIdentifier(_currentToken); + } + } + + function parseTypeOrExpression(): ISyntaxNodeOrToken { + var result: ISyntaxNodeOrToken = tryParseType(); + if (result) { + return result; + } + + var _currentToken = currentToken(); + if (isExpression(_currentToken)) { + // We parse out an expression here, but we very specifically ask for a unary + // expression, and not just any expression. That's because if we have: + // + // + // + // We do not want the > to be consumed as part of the "" expression. By starting + // at 'unary' expression and not 'binary' expression, we ensure that we don't accidently + // consume the >. + return tryParseUnaryExpressionOrHigher(_currentToken, /*force:*/ true); + } + + return eatIdentifierToken(DiagnosticCode.Type_expected); + } + + function parseType(): ITypeSyntax { + return tryParseType() || eatIdentifierToken(DiagnosticCode.Type_expected); + } + + function tryParseType(): ITypeSyntax { + // First consume any underlying element type. + var type = tryParseNonArrayType(); + + // ArrayType: + // ElementType [no LineTerminator here] [ ] + + // Now, we want to keep consuming pairs of brackets, as long as the opening bracket + // is on the same line as the last token. + while (type) { + var _currentToken = currentToken(); + + if (previousTokenHasTrailingNewLine(_currentToken) || + _currentToken.kind() !== SyntaxKind.OpenBracketToken) { + break; + } + + type = new syntaxFactory.ArrayTypeSyntax(parseNodeData, type, consumeToken(_currentToken), eatToken(SyntaxKind.CloseBracketToken)); + } + + return type; + } + + function parseTypeQuery(typeOfKeyword: ISyntaxToken): TypeQuerySyntax { + return new syntaxFactory.TypeQuerySyntax(parseNodeData, consumeToken(typeOfKeyword), parseName(/*allowIdentifierNames:*/ true)); + } + + function tryParseNonArrayType(): ITypeSyntax { + var _currentToken = currentToken(); + switch (_currentToken.kind()) { + case SyntaxKind.AnyKeyword: + case SyntaxKind.NumberKeyword: + case SyntaxKind.BooleanKeyword: + case SyntaxKind.StringKeyword: + // if any of these are followed by '.', then this is actually a module name, + // and these keywords will be reinterpreted as an identifier. + if (peekToken(1).kind() === SyntaxKind.DotToken) { + break; + } + + return consumeToken(_currentToken); + case SyntaxKind.OpenParenToken: + case SyntaxKind.LessThanToken: return tryParseFunctionType(); + case SyntaxKind.VoidKeyword: return consumeToken(_currentToken); + case SyntaxKind.OpenBraceToken: return parseObjectType(); + case SyntaxKind.NewKeyword: return parseConstructorType(); + case SyntaxKind.TypeOfKeyword: return parseTypeQuery(_currentToken); + } + + return tryParseNameOrGenericType(); + } + + function tryParseNameOrGenericType(): ITypeSyntax { + var name = tryParseName(/*allowIdentifierNames*/ false); + if (name === null) { + return null; + } + + // TypeReference: + // TypeName [no LineTerminator here] TypeArgumentsopt + // + // Only consume type arguments if they appear on the same line. + if (previousTokenHasTrailingNewLine(currentToken())) { + return name; + } + + var typeArgumentList = tryParseTypeArgumentList(/*inExpression:*/ false); + return typeArgumentList === null + ? name + : new syntaxFactory.GenericTypeSyntax(parseNodeData, name, typeArgumentList); + } + + function tryParseFunctionType(): FunctionTypeSyntax { + var typeParameterList = tryParseTypeParameterList(/*requireCompleteTypeParameterList:*/ false); + var parameterList: ParameterListSyntax = null; + if (typeParameterList === null) { + parameterList = tryParseParameterList(); + if (parameterList === null) { + return null; + } + } + else { + parameterList = parseParameterList(); + } + + return new syntaxFactory.FunctionTypeSyntax(parseNodeData, + typeParameterList, parameterList, eatToken(SyntaxKind.EqualsGreaterThanToken), parseType()); + } + + function parseConstructorType(): ConstructorTypeSyntax { + return new syntaxFactory.ConstructorTypeSyntax(parseNodeData, + eatToken(SyntaxKind.NewKeyword), tryParseTypeParameterList(/*requireCompleteTypeParameterList:*/ false), + parseParameterList(), eatToken(SyntaxKind.EqualsGreaterThanToken), parseType()); + } + + function isParameter(): boolean { + if (currentNode() !== null && currentNode().kind() === SyntaxKind.Parameter) { + return true; + } + + return isParameterHelper(currentToken()); + } + + function isParameterHelper(token: ISyntaxToken): boolean { + var tokenKind = token.kind(); + return tokenKind === SyntaxKind.DotDotDotToken || + isModifierKind(tokenKind) || + isIdentifier(token); + } + + function eatSimpleParameter() { + return new syntaxFactory.ParameterSyntax(parseNodeData, + /*dotDotDotToken:*/ null, /*modifiers:*/ Syntax.emptyList(), eatIdentifierToken(), + /*questionToken:*/ null, /*typeAnnotation:*/ null, /*equalsValueClause:*/ null); + } + + function tryParseParameter(): ParameterSyntax { + var node = currentNode(); + if (node !== null && node.kind() === SyntaxKind.Parameter) { + consumeNode(node); + return node; + } + + var dotDotDotToken = tryEatToken(SyntaxKind.DotDotDotToken); + var modifiers = parseModifiers(); + + // If we're not forcing, and we don't see anything to indicate this is a parameter, then + // bail out. + var _currentToken = currentToken(); + if (!isIdentifier(_currentToken) && dotDotDotToken === null && modifiers.length === 0) { + // ERROR RECOVERY: + // If we see a modifier alone in a parameter list, like: foo(static) + // + // then treat it like modifier, and continue parsing the parameter. + if (isModifierKind(_currentToken.kind())) { + modifiers = Syntax.list([consumeToken(_currentToken)]); + } + else { + return null; + } + } + + var identifier = eatIdentifierToken(); + var questionToken = tryEatToken(SyntaxKind.QuestionToken); + var typeAnnotation = parseOptionalTypeAnnotation(/*allowStringLiteral:*/ true); + + var equalsValueClause: EqualsValueClauseSyntax = null; + if (isEqualsValueClause(/*inParameter*/ true)) { + equalsValueClause = parseEqualsValueClause(/*allowIn:*/ true); + } + + return new syntaxFactory.ParameterSyntax(parseNodeData, dotDotDotToken, modifiers, identifier, questionToken, typeAnnotation, equalsValueClause); + } + + function parseSyntaxList( + currentListType: ListParsingState, skippedTokens: ISyntaxToken[], processItems: (items: any[]) => void = null): T[] { + var savedListParsingState = listParsingState; + listParsingState |= (1 << currentListType); + + var result = parseSyntaxListWorker(currentListType, skippedTokens, processItems); + + listParsingState = savedListParsingState; + + return result; + } + + function parseSeparatedSyntaxList(currentListType: ListParsingState, skippedTokens: ISyntaxToken[]): T[] { + var savedListParsingState = listParsingState; + listParsingState |= (1 << currentListType); + + var result = parseSeparatedSyntaxListWorker(currentListType, skippedTokens); + + listParsingState = savedListParsingState; + + return result; + } + + // Returns true if we should abort parsing. + function abortParsingListOrMoveToNextToken( + currentListType: ListParsingState, nodes: T[], separators: ISyntaxToken[], skippedTokens: ISyntaxToken[]): boolean { + // Ok. We're at a token that is not a terminator for the list and wasn't the start of + // an item in the list. Definitely report an error for this token. + reportUnexpectedTokenDiagnostic(currentListType); + + // Now, check if the token is a terminator for one our parent lists, or the start of an + // item in one of our parent lists. If so, we won't want to consume the token. We've + // already reported the error, so just return to our caller so that a higher up + // production can consume it. + for (var state = ListParsingState.LastListParsingState; state >= ListParsingState.FirstListParsingState; state--) { + if ((listParsingState & (1 << state)) !== 0) { + if (isExpectedListTerminator(state) || isExpectedListItem(state, /*inErrorRecovery:*/ true)) { + // Abort parsing this list. + return true; + } + } + } + + // Otherwise, if none of the lists we're in can capture this token, then we need to + // unilaterally skip it. Note: we've already reported an error above. + addSkippedTokenToList(nodes, separators, skippedTokens, consumeToken(currentToken())); + + // Continue parsing this list. Attach this token to whatever we've seen already. + return false; + } + + function addSkippedTokenToList( + nodes: T[], separators: ISyntaxToken[], skippedTokens: ISyntaxToken[], skippedToken: ISyntaxToken): void { + // Now, add this skipped token to the last item we successfully parsed in the list. Or + // add it to the list of skipped tokens if we haven't parsed anything. Our caller will + // have to deal with them. + // + // Note: we only bother doing this if we're creating a concrete syntax tree. + if (syntaxFactory.isConcrete) { + var length = nodes.length + (separators ? separators.length : 0); + + for (var i = length - 1; i >= 0; i--) { + var array: ISyntaxNodeOrToken[] = separators && (i % 2 === 1) ? separators : nodes; + var arrayIndex = separators ? IntegerUtilities.integerDivide(i, 2) : i; + + var item = array[arrayIndex]; + var _lastToken = lastToken(item); + if (_lastToken && _lastToken.fullWidth() > 0) { + array[arrayIndex] = addSkippedTokenAfterNodeOrToken(item, skippedToken); + return; + } + } + + // Didn't have anything in the list we could add to. Add to the skipped items array + // for our caller to handle. + skippedTokens.push(skippedToken); + } + } + + function tryParseExpectedListItem( + currentListType: ListParsingState, inErrorRecovery: boolean, items: ISyntaxElement[], processItems: (items: any[]) => void): boolean { + var item = tryParseExpectedListItemWorker(currentListType, inErrorRecovery); + + if (item === null) { + return false; + } + // Debug.assert(item !== null); + + items.push(item); + + if (processItems !== null) { + processItems(items); + } + + return true; + } + + function listIsTerminated(currentListType: ListParsingState): boolean { + return isExpectedListTerminator(currentListType) || + currentToken().kind() === SyntaxKind.EndOfFileToken; + } + + function parseSyntaxListWorker(currentListType: ListParsingState, skippedTokens: ISyntaxToken[], processItems: (items: any[]) => void ): T[] { + var items: T[] = getArray(); + + while (true) { + // Try to parse an item of the list. If we fail then decide if we need to abort or + // continue parsing. + var succeeded = tryParseExpectedListItem(currentListType, /*inErrorRecovery:*/ false, items, processItems); + + if (!succeeded) { + // We weren't able to parse out a list element. + + // That may have been because the list is complete. In that case, break out + // and return the items we were able parse. + if (listIsTerminated(currentListType)) { + break; + } + + // List wasn't complete and we didn't get an item. Figure out if we should bail out + // or skip a token and continue. + var abort = abortParsingListOrMoveToNextToken(currentListType, items, null, skippedTokens); + if (abort) { + break; + } + } + + // We either parsed an element. Or we failed to, but weren't at the end of the list + // and didn't want to abort. Continue parsing elements. + } + + var result = Syntax.list(items); + + // Can't return if it has more then 1 element. In that case, the list will have been + // copied into the SyntaxList. + returnZeroLengthArray(items); + + return result; + } + + function parseSeparatedSyntaxListWorker(currentListType: ListParsingState, skippedTokens: ISyntaxToken[]): T[] { + var nodes: T[] = getArray(); + var separators: ISyntaxToken[] = getArray(); + + // Debug.assert(nodes.length === 0); + // Debug.assert(separators.length === 0); + // Debug.assert(skippedTokens.length === 0); + // Debug.assert(skippedTokens !== nodes); + // Debug.assert(skippedTokens !== separators); + // Debug.assert(nodes !== separators); + + var _separatorKind = currentListType === ListParsingState.ObjectType_TypeMembers ? SyntaxKind.SemicolonToken : SyntaxKind.CommaToken; + var allowAutomaticSemicolonInsertion = _separatorKind === SyntaxKind.SemicolonToken; + + var inErrorRecovery = false; + while (true) { + // Try to parse an item of the list. If we fail then decide if we need to abort or + // continue parsing. + + // Debug.assert(oldItemsCount % 2 === 0); + var succeeded = tryParseExpectedListItem(currentListType, inErrorRecovery, nodes, null); + + if (!succeeded) { + // We weren't able to parse out a list element. + // Debug.assert(items === null || items.length % 2 === 0); + + // That may have been because the list is complete. In that case, break out + // and return the items we were able parse. + if (listIsTerminated(currentListType)) { + break; + } + + // List wasn't complete and we didn't get an item. Figure out if we should bail out + // or skip a token and continue. + var abort = abortParsingListOrMoveToNextToken(currentListType, nodes, separators, skippedTokens); + if (abort) { + break; + } + else { + // We just skipped a token. We're now in error recovery mode. + inErrorRecovery = true; + continue; + } + } + + // Debug.assert(newItemsCount % 2 === 1); + + // We were able to successfully parse out a list item. So we're no longer in error + // recovery. + inErrorRecovery = false; + + // Now, we have to see if we have a separator or not. If we do have a separator + // we've got to consume it and continue trying to parse list items. Note: we always + // allow 'comma' as a separator (for error tolerance). We will later do a post pass + // to report when a comma was used improperly in a list that needed semicolons. + var _currentToken = currentToken(); + var tokenKind = _currentToken.kind(); + if (tokenKind === _separatorKind || tokenKind === SyntaxKind.CommaToken) { + // Consume the last separator and continue parsing list elements. + separators.push(consumeToken(_currentToken)); + continue; + } + + // We didn't see the expected separator. There are two reasons this might happen. + // First, we may actually be at the end of the list. If we are, then we're done + // parsing list elements. + if (listIsTerminated(currentListType)) { + break; + } + + // Otherwise, it might be a case where we can parse out an implicit semicolon. + + // Note: it's important that we check this *after* the check above for + // 'listIsTerminated'. Consider the following case: + // + // { + // a // <-- just finished parsing 'a' + // } + // + // Automatic semicolon insertion rules state: "When, as the program is parsed from + // left to right, a token (called the offending token) is encountered that is not + // allowed by any production of the grammar". So we should only ever insert a + // semicolon if we couldn't consume something normally. in the above case, we can + // consume the '}' just fine. So ASI doesn't apply. + + if (allowAutomaticSemicolonInsertion && canEatAutomaticSemicolon(/*allowWithoutNewline:*/ false)) { + var semicolonToken = eatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false) || Syntax.emptyToken(SyntaxKind.SemicolonToken); + separators.push(semicolonToken); + // Debug.assert(items.length % 2 === 0); + continue; + } + + // We weren't at the end of the list. And thre was no separator we could parse out. + // Try parse the separator we expected, and continue parsing more list elements. + // This time mark that we're in error recovery mode though. + // + // Note: trying to eat this token will emit the appropriate diagnostic. + separators.push(eatToken(_separatorKind)); + + // Now that we're in 'error recovery' mode we cantweak some parsing rules as + // appropriate. For example, if we have: + // + // var v = { a + // return + // + // Then we'll be missing the comma. As such, we want to parse 'return' in a less + // tolerant manner. Normally 'return' could be a property in an object literal. + // However, in error recovery mode, we do *not* want it to be. + // + // Continue trying to parse out list elements. + inErrorRecovery = true; + } + + var result = Syntax.separatedList(nodes, separators); + + // Can't return if it has more then 0 elements. In that case, the list will have been + // copied into the SyntaxList. + returnZeroLengthArray(nodes); + returnZeroLengthArray(separators); + + return result; + } + + function reportUnexpectedTokenDiagnostic(listType: ListParsingState): void { + var token = currentToken(); + + var diagnostic = new Diagnostic(fileName, source.text.lineMap(), + start(token, source.text), width(token), DiagnosticCode.Unexpected_token_0_expected, [getExpectedListElementType(listType)]); + addDiagnostic(diagnostic); + } + + function addDiagnostic(diagnostic: Diagnostic): void { + // Except: if we already have a diagnostic for this position, don't report another one. + if (diagnostics.length > 0 && + diagnostics[diagnostics.length - 1].start() === diagnostic.start()) { + return; + } + + diagnostics.push(diagnostic); + } + + function isExpectedListTerminator(currentListType: ListParsingState): boolean { + switch (currentListType) { + case ListParsingState.SourceUnit_ModuleElements: return isExpectedSourceUnit_ModuleElementsTerminator(); + case ListParsingState.ClassDeclaration_ClassElements: return isExpectedClassDeclaration_ClassElementsTerminator(); + case ListParsingState.ModuleDeclaration_ModuleElements: return isExpectedModuleDeclaration_ModuleElementsTerminator(); + case ListParsingState.SwitchStatement_SwitchClauses: return isExpectedSwitchStatement_SwitchClausesTerminator(); + case ListParsingState.SwitchClause_Statements: return isExpectedSwitchClause_StatementsTerminator(); + case ListParsingState.Block_Statements: return isExpectedBlock_StatementsTerminator(); + case ListParsingState.TryBlock_Statements: return isExpectedTryBlock_StatementsTerminator(); + case ListParsingState.CatchBlock_Statements: return isExpectedCatchBlock_StatementsTerminator(); + case ListParsingState.EnumDeclaration_EnumElements: return isExpectedEnumDeclaration_EnumElementsTerminator(); + case ListParsingState.ObjectType_TypeMembers: return isExpectedObjectType_TypeMembersTerminator(); + case ListParsingState.ClassOrInterfaceDeclaration_HeritageClauses: return isExpectedClassOrInterfaceDeclaration_HeritageClausesTerminator(); + case ListParsingState.HeritageClause_TypeNameList: return isExpectedHeritageClause_TypeNameListTerminator(); + case ListParsingState.VariableDeclaration_VariableDeclarators_AllowIn: return isExpectedVariableDeclaration_VariableDeclarators_AllowInTerminator(); + case ListParsingState.VariableDeclaration_VariableDeclarators_DisallowIn: return isExpectedVariableDeclaration_VariableDeclarators_DisallowInTerminator(); + case ListParsingState.ArgumentList_AssignmentExpressions: return isExpectedArgumentList_AssignmentExpressionsTerminator(); + case ListParsingState.ObjectLiteralExpression_PropertyAssignments: return isExpectedObjectLiteralExpression_PropertyAssignmentsTerminator(); + case ListParsingState.ArrayLiteralExpression_AssignmentExpressions: return isExpectedLiteralExpression_AssignmentExpressionsTerminator(); + case ListParsingState.ParameterList_Parameters: return isExpectedParameterList_ParametersTerminator(); + case ListParsingState.IndexSignature_Parameters: return isExpectedIndexSignature_ParametersTerminator(); + case ListParsingState.TypeArgumentList_Types: return isExpectedTypeArgumentList_TypesTerminator(); + case ListParsingState.TypeParameterList_TypeParameters: return isExpectedTypeParameterList_TypeParametersTerminator(); + default: + throw Errors.invalidOperation(); + } + } + + function isExpectedSourceUnit_ModuleElementsTerminator(): boolean { + return currentToken().kind() === SyntaxKind.EndOfFileToken; + } + + function isExpectedEnumDeclaration_EnumElementsTerminator(): boolean { + return currentToken().kind() === SyntaxKind.CloseBraceToken; + } + + function isExpectedModuleDeclaration_ModuleElementsTerminator(): boolean { + return currentToken().kind() === SyntaxKind.CloseBraceToken; + } + + function isExpectedObjectType_TypeMembersTerminator(): boolean { + return currentToken().kind() === SyntaxKind.CloseBraceToken; + } + + function isExpectedObjectLiteralExpression_PropertyAssignmentsTerminator(): boolean { + return currentToken().kind() === SyntaxKind.CloseBraceToken; + } + + function isExpectedLiteralExpression_AssignmentExpressionsTerminator(): boolean { + return currentToken().kind() === SyntaxKind.CloseBracketToken; + } + + function isExpectedTypeArgumentList_TypesTerminator(): boolean { + var token = currentToken(); + var tokenKind = token.kind(); + if (tokenKind === SyntaxKind.GreaterThanToken) { + return true; + } + + // If we're at a token that can follow the type argument list, then we'll also consider + // the list terminated. + if (canFollowTypeArgumentListInExpression(tokenKind)) { + return true; + } + + // TODO: add more cases as necessary for error tolerance. + return false; + } + + function isExpectedTypeParameterList_TypeParametersTerminator(): boolean { + var tokenKind = currentToken().kind(); + if (tokenKind === SyntaxKind.GreaterThanToken) { + return true; + } + + // These commonly follow type parameter lists. + if (tokenKind === SyntaxKind.OpenParenToken || + tokenKind === SyntaxKind.OpenBraceToken || + tokenKind === SyntaxKind.ExtendsKeyword || + tokenKind === SyntaxKind.ImplementsKeyword) { + return true; + } + + // TODO: add more cases as necessary for error tolerance. + return false; + } + + function isExpectedParameterList_ParametersTerminator(): boolean { + var tokenKind = currentToken().kind(); + if (tokenKind === SyntaxKind.CloseParenToken) { + return true; + } + + // We may also see a { in an error case. i.e.: + // function (a, b, c { + if (tokenKind === SyntaxKind.OpenBraceToken) { + return true; + } + + // We may also see a => in an error case. i.e.: + // (f: number => { ... } + if (tokenKind === SyntaxKind.EqualsGreaterThanToken) { + return true; + } + + return false; + } + + function isExpectedIndexSignature_ParametersTerminator() { + var tokenKind = currentToken().kind(); + if (tokenKind === SyntaxKind.CloseBracketToken) { + return true; + } + + // We may also see a { in an error case. i.e.: + // function (a, b, c { + if (tokenKind === SyntaxKind.OpenBraceToken) { + return true; + } + + return false; + } + + function isExpectedVariableDeclaration_VariableDeclarators_DisallowInTerminator(): boolean { + // This is the case when we're parsing variable declarations in a for/for-in statement. + var tokenKind = currentToken().kind(); + + if (tokenKind === SyntaxKind.SemicolonToken || + tokenKind === SyntaxKind.CloseParenToken) { + return true; + } + + if (tokenKind === SyntaxKind.InKeyword) { + return true; + } + + return false; + } + + function isExpectedVariableDeclaration_VariableDeclarators_AllowInTerminator(): boolean { + //// This is the case when we're parsing variable declarations in a variable statement. + + // ERROR RECOVERY TWEAK: + // For better error recovery, if we see a => then we just stop immediately. We've got an + // arrow function here and it's going to be very unlikely that we'll resynchronize and get + // another variable declaration. + if (currentToken().kind() === SyntaxKind.EqualsGreaterThanToken) { + return true; + } + + // We're done when we can eat a semicolon. + return canEatExplicitOrAutomaticSemicolon(/*allowWithoutNewline:*/ false); + } + + function isExpectedClassOrInterfaceDeclaration_HeritageClausesTerminator(): boolean { + var tokenKind = currentToken().kind(); + if (tokenKind === SyntaxKind.OpenBraceToken || tokenKind === SyntaxKind.CloseBraceToken) { + return true; + } + + return false; + } + + function isExpectedHeritageClause_TypeNameListTerminator(): boolean { + var tokenKind = currentToken().kind(); + if (tokenKind === SyntaxKind.ExtendsKeyword || tokenKind === SyntaxKind.ImplementsKeyword) { + return true; + } + + if (isExpectedClassOrInterfaceDeclaration_HeritageClausesTerminator()) { + return true; + } + + return false; + } + + function isExpectedArgumentList_AssignmentExpressionsTerminator(): boolean { + var token0 = currentToken(); + var tokenKind = token0.kind(); + return tokenKind === SyntaxKind.CloseParenToken || + tokenKind === SyntaxKind.SemicolonToken; + } + + function isExpectedClassDeclaration_ClassElementsTerminator(): boolean { + return currentToken().kind() === SyntaxKind.CloseBraceToken; + } + + function isExpectedSwitchStatement_SwitchClausesTerminator(): boolean { + return currentToken().kind() === SyntaxKind.CloseBraceToken; + } + + function isExpectedSwitchClause_StatementsTerminator(): boolean { + return currentToken().kind() === SyntaxKind.CloseBraceToken || + isSwitchClause(); + } + + function isExpectedBlock_StatementsTerminator(): boolean { + return currentToken().kind() === SyntaxKind.CloseBraceToken; + } + + function isExpectedTryBlock_StatementsTerminator(): boolean { + var tokenKind = currentToken().kind(); + return tokenKind === SyntaxKind.CatchKeyword || + tokenKind === SyntaxKind.FinallyKeyword; + } + + function isExpectedCatchBlock_StatementsTerminator(): boolean { + return currentToken().kind() === SyntaxKind.FinallyKeyword; + } + + function isExpectedListItem(currentListType: ListParsingState, inErrorRecovery: boolean): any { + switch (currentListType) { + case ListParsingState.SourceUnit_ModuleElements: return isModuleElement(inErrorRecovery); + case ListParsingState.ClassDeclaration_ClassElements: return isClassElement(inErrorRecovery); + case ListParsingState.ModuleDeclaration_ModuleElements: return isModuleElement(inErrorRecovery); + case ListParsingState.SwitchStatement_SwitchClauses: return isSwitchClause(); + case ListParsingState.SwitchClause_Statements: return isStatement(modifierCount(), inErrorRecovery); + case ListParsingState.Block_Statements: return isStatement(modifierCount(), inErrorRecovery); + // These two are special. They're just augmentations of "Block_Statements" + // used so we can abort out of the try block if we see a 'catch' or 'finally' + // keyword. There are no additional list items that they add, so we just + // return 'false' here. + case ListParsingState.TryBlock_Statements: return false; + case ListParsingState.CatchBlock_Statements: return false; + case ListParsingState.EnumDeclaration_EnumElements: return isEnumElement(inErrorRecovery); + case ListParsingState.ObjectType_TypeMembers: return isTypeMember(inErrorRecovery); + case ListParsingState.ClassOrInterfaceDeclaration_HeritageClauses: return isHeritageClause(); + case ListParsingState.HeritageClause_TypeNameList: return isHeritageClauseTypeName(); + case ListParsingState.VariableDeclaration_VariableDeclarators_AllowIn: return isVariableDeclarator(); + case ListParsingState.VariableDeclaration_VariableDeclarators_DisallowIn: return isVariableDeclarator(); + case ListParsingState.ArgumentList_AssignmentExpressions: return isExpectedArgumentList_AssignmentExpression(); + case ListParsingState.ObjectLiteralExpression_PropertyAssignments: return isPropertyAssignment(inErrorRecovery); + case ListParsingState.ArrayLiteralExpression_AssignmentExpressions: return isAssignmentOrOmittedExpression(); + case ListParsingState.ParameterList_Parameters: return isParameter(); + case ListParsingState.IndexSignature_Parameters: return isParameter(); + case ListParsingState.TypeArgumentList_Types: return isType(); + case ListParsingState.TypeParameterList_TypeParameters: return isTypeParameter(); + default: throw Errors.invalidOperation(); + } + } + + function isExpectedArgumentList_AssignmentExpression(): boolean { + var _currentToken = currentToken(); + if (isExpression(_currentToken)) { + return true; + } + + // If we're on a comma then the user has written something like "Foo(a,," or "Foo(,". + // Instead of skipping the comma, create an empty expression to go before the comma + // so that the tree is more well formed and doesn't have skipped tokens. + if (_currentToken.kind() === SyntaxKind.CommaToken) { + return true; + } + + return false; + } + + function tryParseExpectedListItemWorker(currentListType: ListParsingState, inErrorRecovery: boolean): ISyntaxNodeOrToken { + switch (currentListType) { + case ListParsingState.SourceUnit_ModuleElements: return tryParseModuleElement(inErrorRecovery); + case ListParsingState.ClassDeclaration_ClassElements: return tryParseClassElement(inErrorRecovery); + case ListParsingState.ModuleDeclaration_ModuleElements: return tryParseModuleElement(inErrorRecovery); + case ListParsingState.SwitchStatement_SwitchClauses: return tryParseSwitchClause(); + case ListParsingState.SwitchClause_Statements: return tryParseStatement(inErrorRecovery); + case ListParsingState.Block_Statements: return tryParseStatement(inErrorRecovery); + case ListParsingState.TryBlock_Statements: return tryParseStatement(inErrorRecovery); + case ListParsingState.CatchBlock_Statements: return tryParseStatement(inErrorRecovery); + case ListParsingState.EnumDeclaration_EnumElements: return tryParseEnumElement(inErrorRecovery); + case ListParsingState.ObjectType_TypeMembers: return tryParseTypeMember(inErrorRecovery); + case ListParsingState.ClassOrInterfaceDeclaration_HeritageClauses: return tryParseHeritageClause(); + case ListParsingState.HeritageClause_TypeNameList: return tryParseHeritageClauseTypeName(); + case ListParsingState.VariableDeclaration_VariableDeclarators_AllowIn: return tryParseVariableDeclarator(/*allowIn:*/ true, /*allowIdentifierName:*/ false); + case ListParsingState.VariableDeclaration_VariableDeclarators_DisallowIn: return tryParseVariableDeclarator(/*allowIn:*/ false, /*allowIdentifierName:*/ false); + case ListParsingState.ArgumentList_AssignmentExpressions: return tryParseArgumentListExpression(); + case ListParsingState.ObjectLiteralExpression_PropertyAssignments: return tryParsePropertyAssignment(inErrorRecovery); + case ListParsingState.ArrayLiteralExpression_AssignmentExpressions: return tryParseAssignmentOrOmittedExpression(); + case ListParsingState.ParameterList_Parameters: return tryParseParameter(); + case ListParsingState.IndexSignature_Parameters: return tryParseParameter(); + case ListParsingState.TypeArgumentList_Types: return tryParseType(); + case ListParsingState.TypeParameterList_TypeParameters: return tryParseTypeParameter(); + default: throw Errors.invalidOperation(); + } + } + + function getExpectedListElementType(currentListType: ListParsingState): string { + switch (currentListType) { + case ListParsingState.SourceUnit_ModuleElements: return getLocalizedText(DiagnosticCode.module_class_interface_enum_import_or_statement, null); + case ListParsingState.ClassOrInterfaceDeclaration_HeritageClauses: return '{'; + case ListParsingState.ClassDeclaration_ClassElements: return getLocalizedText(DiagnosticCode.constructor_function_accessor_or_variable, null); + case ListParsingState.ModuleDeclaration_ModuleElements: return getLocalizedText(DiagnosticCode.module_class_interface_enum_import_or_statement, null); + case ListParsingState.SwitchStatement_SwitchClauses: return getLocalizedText(DiagnosticCode.case_or_default_clause, null); + case ListParsingState.SwitchClause_Statements: return getLocalizedText(DiagnosticCode.statement, null); + case ListParsingState.Block_Statements: return getLocalizedText(DiagnosticCode.statement, null); + case ListParsingState.VariableDeclaration_VariableDeclarators_AllowIn: return getLocalizedText(DiagnosticCode.identifier, null); + case ListParsingState.VariableDeclaration_VariableDeclarators_DisallowIn: return getLocalizedText(DiagnosticCode.identifier, null); + case ListParsingState.EnumDeclaration_EnumElements: return getLocalizedText(DiagnosticCode.identifier, null); + case ListParsingState.ObjectType_TypeMembers: return getLocalizedText(DiagnosticCode.call_construct_index_property_or_function_signature, null); + case ListParsingState.ArgumentList_AssignmentExpressions: return getLocalizedText(DiagnosticCode.expression, null); + case ListParsingState.HeritageClause_TypeNameList: return getLocalizedText(DiagnosticCode.type_name, null); + case ListParsingState.ObjectLiteralExpression_PropertyAssignments: return getLocalizedText(DiagnosticCode.property_or_accessor, null); + case ListParsingState.ParameterList_Parameters: return getLocalizedText(DiagnosticCode.parameter, null); + case ListParsingState.IndexSignature_Parameters: return getLocalizedText(DiagnosticCode.parameter, null); + case ListParsingState.TypeArgumentList_Types: return getLocalizedText(DiagnosticCode.type, null); + case ListParsingState.TypeParameterList_TypeParameters: return getLocalizedText(DiagnosticCode.type_parameter, null); + case ListParsingState.ArrayLiteralExpression_AssignmentExpressions: return getLocalizedText(DiagnosticCode.expression, null); + default: throw Errors.invalidOperation(); + } + } + + return parseSyntaxTree; + } + + // The precedence of expressions in typescript. While we're parsing an expression, we will + // continue to consume and form new trees if the precedence is *strictly* greater than our current + // precedence. For example, if we have: a + b * c, we will first parse 'a' with precedence 1 (Lowest). + // We will then see the + with precedence 10. 10 is greater than 1 so we will decide to create + // a binary expression with the result of parsing the sub expression "b * c". We'll then parse + // the term 'b' (passing in precedence 10). We will then see the * with precedence 11. 11 is + // greater than 10, so we will create a binary expression from "b" and "c", return that, and + // join it with "a" producing: + // + // + + // / \ + // a * + // / \ + // b c + // + // If we instead had: "a * b + c", we would first parser 'a' with precedence 1 (lowest). We would then see + // the * with precedence 11. 11 is greater than 1 so we will decide to create a binary expression + // with the result of parsing the sub expression "b + c". We'll then parse the term 'b' (passing in + // precedence 11). We will then see the + with precedence 10. 10 is less than 11, so we won't + // continue parsing subexpressions and will just return the expression 'b'. The caller will join + // that into "a * b" (and will be back at precedence 1). It will then see the + with precedence 10. + // 10 is greater than 1 so it will parse the sub expression and make a binary expression out of it + // producing: + // + // + + // / \ + // * c + // / \ + // a b + // + // Note: because all these binary expressions have left-to-right precedence, if we see a * b * c + // then we parse it as: + // + // * + // / \ + // * c + // / \ + // a b + // + // The code to do this uses the above logic. It will see an operator with the same precedence, + // and so it won't consume it. + enum BinaryExpressionPrecedence { + Lowest = 1, + + // Intuitively, logical || have the lowest precedence. "a || b && c" is "a || (b && c)", not + // "(a || b) && c" + LogicalOrExpressionPrecedence = 2, + LogicalAndExpressionPrecedence = 3, + BitwiseOrExpressionPrecedence = 4, + BitwiseExclusiveOrExpressionPrecedence = 5, + BitwiseAndExpressionPrecedence = 6, + EqualityExpressionPrecedence = 7, + RelationalExpressionPrecedence = 8, + ShiftExpressionPrecdence = 9, + AdditiveExpressionPrecedence = 10, + + // Intuitively, multiplicative expressions have the highest precedence. After all, if you have: + // a + b * c + // + // Then you have "a + (b * c)" not "(a + b) * c" + MultiplicativeExpressionPrecedence = 11, + } + + // The current state of the parser wrt to list parsing. The way to read these is as: + // CurrentProduction_SubList. i.e. "Block_Statements" means "we're parsing a Block, and we're + // currently parsing list of statements within it". This is used by the list parsing mechanism + // to parse the elements of the lists, and recover from errors we encounter when we run into + // unexpected code. + // + // For example, when we are in ArgumentList_Arguments, we will continue trying to consume code + // as long as "isArgument" is true. If we run into a token for which "isArgument" is not true + // we will do the following: + // + // If the token is a StopToken for ArgumentList_Arguments (like ")" ) then we will stop parsing + // the list of arguments with no error. + // + // Otherwise, we *do* report an error for this unexpected token, and then enter error recovery + // mode to decide how to try to recover from this unexpected token. + // + // Error recovery will walk up the list of states we're in seeing if the token is a stop token + // for that construct *or* could start another element within what construct. For example, if + // the unexpected token was '}' then that would be a stop token for Block_Statements. + // Alternatively, if the unexpected token was 'return', then that would be a start token for + // the next statment in Block_Statements. + // + // If either of those cases are true, We will then return *without* consuming that token. + // (Remember, we've already reported an error). Now we're just letting the higher up parse + // constructs eventually try to consume that token. + // + // If none of the higher up states consider this a stop or start token, then we will simply + // consume the token and add it to our list of 'skipped tokens'. We will then repeat the + // above algorithm until we resynchronize at some point. + enum ListParsingState { + SourceUnit_ModuleElements = 0, + ClassDeclaration_ClassElements = 1, + ModuleDeclaration_ModuleElements = 2, + SwitchStatement_SwitchClauses = 3, + SwitchClause_Statements = 4, + Block_Statements = 5, + TryBlock_Statements = 6, + CatchBlock_Statements = 7, + EnumDeclaration_EnumElements = 8, + ObjectType_TypeMembers = 9, + ClassOrInterfaceDeclaration_HeritageClauses = 10, + HeritageClause_TypeNameList = 11, + VariableDeclaration_VariableDeclarators_AllowIn = 12, + VariableDeclaration_VariableDeclarators_DisallowIn = 13, + ArgumentList_AssignmentExpressions = 14, + ObjectLiteralExpression_PropertyAssignments = 15, + ArrayLiteralExpression_AssignmentExpressions = 16, + ParameterList_Parameters = 17, + IndexSignature_Parameters = 18, + TypeArgumentList_Types = 19, + TypeParameterList_TypeParameters = 20, + + FirstListParsingState = SourceUnit_ModuleElements, + LastListParsingState = TypeParameterList_TypeParameters, + } + + // We keep the parser around as a singleton. This is because calling createParser is actually + // expensive in V8 currently. We then clear it after a parse so that it doesn't keep state + // alive unintentionally. + var parseSyntaxTree = createParseSyntaxTree(); + + export function parse(fileName: string, text: ISimpleText, languageVersion: ts.ScriptTarget, isDeclaration: boolean): SyntaxTree { + return parseSource(Scanner.createParserSource(fileName, text, languageVersion), isDeclaration); + } + + export function parseSource(source: IParserSource, isDeclaration: boolean): SyntaxTree { + return parseSyntaxTree(source, isDeclaration); + } +} \ No newline at end of file diff --git a/src/services/syntax/prettyPrinter.ts b/src/services/syntax/prettyPrinter.ts new file mode 100644 index 00000000000..f19b9224f7e --- /dev/null +++ b/src/services/syntax/prettyPrinter.ts @@ -0,0 +1,1007 @@ +/// + +module TypeScript.PrettyPrinter { + export function prettyPrint(node: ISyntaxNode, indentWhitespace: string = " "): string { + var impl = new PrettyPrinterImpl(indentWhitespace); + visitNodeOrToken(impl, node); + return impl.result.join(""); + } + + class PrettyPrinterImpl implements ISyntaxVisitor { + public result: string[] = []; + private indentations: string[] = []; + private indentation: number = 0; + + constructor(private indentWhitespace: string) { + } + + private newLineCountBetweenModuleElements(element1: IModuleElementSyntax, element2: IModuleElementSyntax): number { + if (element1 === null || element2 === null) { + return 0; + } + + if (lastToken(element1).kind() === SyntaxKind.CloseBraceToken) { + return 2; + } + + return 1; + } + + private newLineCountBetweenClassElements(element1: IClassElementSyntax, element2: IClassElementSyntax): number { + if (element1 === null || element2 === null) { + return 0; + } + + return 1; + } + + private newLineCountBetweenStatements(element1: IClassElementSyntax, element2: IClassElementSyntax): number { + if (element1 === null || element2 === null) { + return 0; + } + + if (lastToken(element1).kind() === SyntaxKind.CloseBraceToken) { + return 2; + } + + return 1; + } + + private newLineCountBetweenSwitchClauses(element1: ISwitchClauseSyntax, element2: ISwitchClauseSyntax): number { + if (element1 === null || element2 === null) { + return 0; + } + + if (childCount(element1.statements) === 0) { + return 1; + } + + return 2; + } + + private ensureSpace(): void { + if (this.result.length > 0) { + var last = ArrayUtilities.last(this.result); + if (last !== " " && last !== "\r\n") { + this.appendText(" "); + } + } + } + + private ensureNewLine(): void { + if (this.result.length > 0) { + var last = ArrayUtilities.last(this.result); + if (last !== "\r\n") { + this.appendText("\r\n"); + } + } + } + + private appendNewLines(count: number): void { + for (var i = 0; i < count; i++) { + this.appendText("\r\n"); + } + } + + private getIndentation(count: number): string { + for (var i = this.indentations.length; i <= count; i++) { + var text = i === 0 + ? "" + : this.indentations[i - 1] + this.indentWhitespace; + this.indentations[i] = text; + } + + return this.indentations[count]; + } + + private appendIndentationIfAfterNewLine(): void { + if (this.result.length > 0) { + if (ArrayUtilities.last(this.result) === "\r\n") { + this.result.push(this.getIndentation(this.indentation)); + } + } + } + + private appendText(text: string): void { + this.result.push(text); + } + + private appendElement(element: ISyntaxElement): void { + if (isToken(element)) { + this.appendToken(element); + } + else if (isNode(element)) { + this.appendNode(element); + } + } + + private appendNode(node: ISyntaxNode): void { + visitNodeOrToken(this, node); + } + + private appendToken(token: ISyntaxToken): void { + if (token !== null && token.fullWidth() > 0) { + this.appendIndentationIfAfterNewLine(); + this.appendText(token.text()); + } + } + + public visitToken(token: ISyntaxToken): void { + this.appendToken(token); + } + + private appendSpaceList(list: ISyntaxNodeOrToken[]): void { + for (var i = 0, n = childCount(list); i < n; i++) { + if (isNode(childAt(list, i))) { + this.appendNode(childAt(list, i)); + } + else { + this.appendToken(childAt(list, i)); + } + + this.ensureSpace(); + } + } + + private appendSeparatorSpaceList(list: ISyntaxNodeOrToken[]): void { + for (var i = 0, n = childCount(list); i < n; i++) { + if (i % 2 === 0) { + if (i > 0) { + this.ensureSpace(); + } + + visitNodeOrToken(this, childAt(list, i)); + } + else { + this.appendToken(childAt(list, i)); + } + } + } + + private appendSeparatorNewLineList(list: ISyntaxNodeOrToken[]): void { + for (var i = 0, n = childCount(list); i < n; i++) { + if (i % 2 === 0) { + if (i > 0) { + this.ensureNewLine(); + } + + visitNodeOrToken(this, childAt(list, i)); + } + else { + this.appendToken(childAt(list, i)); + } + } + } + + private appendModuleElements(list: IModuleElementSyntax[]): void { + var lastModuleElement: IModuleElementSyntax = null; + for (var i = 0, n = list.length; i < n; i++) { + var moduleElement = list[i]; + var newLineCount = this.newLineCountBetweenModuleElements(lastModuleElement, moduleElement); + + this.appendNewLines(newLineCount); + visitNodeOrToken(this, moduleElement); + + lastModuleElement = moduleElement; + } + } + + public visitSourceUnit(node: SourceUnitSyntax): void { + this.appendModuleElements(node.moduleElements); + } + + public visitExternalModuleReference(node: ExternalModuleReferenceSyntax): void { + this.appendToken(node.requireKeyword); + this.appendToken(node.openParenToken); + this.appendToken(node.stringLiteral); + this.appendToken(node.closeParenToken); + } + + public visitModuleNameModuleReference(node: ModuleNameModuleReferenceSyntax): void { + visitNodeOrToken(this, node.moduleName); + } + + public visitImportDeclaration(node: ImportDeclarationSyntax): void { + this.appendToken(node.importKeyword); + this.ensureSpace(); + this.appendToken(node.identifier); + this.ensureSpace(); + this.appendToken(node.equalsToken); + this.ensureSpace(); + visitNodeOrToken(this, node.moduleReference); + this.appendToken(node.semicolonToken); + } + + public visitExportAssignment(node: ExportAssignmentSyntax): void { + this.appendToken(node.exportKeyword); + this.ensureSpace(); + this.appendToken(node.equalsToken); + this.ensureSpace(); + this.appendToken(node.identifier); + this.appendToken(node.semicolonToken); + } + + public visitClassDeclaration(node: ClassDeclarationSyntax): void { + this.appendSpaceList(node.modifiers); + this.ensureSpace(); + this.appendToken(node.classKeyword); + this.ensureSpace(); + this.appendToken(node.identifier); + this.appendNode(node.typeParameterList); + this.ensureSpace(); + this.appendSpaceList(node.heritageClauses); + this.ensureSpace(); + this.appendToken(node.openBraceToken); + this.ensureNewLine(); + + this.indentation++; + + var lastClassElement: IClassElementSyntax = null; + for (var i = 0, n = node.classElements.length; i < n; i++) { + var classElement = node.classElements[i]; + var newLineCount = this.newLineCountBetweenClassElements(lastClassElement, classElement); + + this.appendNewLines(newLineCount); + visitNodeOrToken(this, classElement); + + lastClassElement = classElement; + } + + this.indentation--; + + this.ensureNewLine(); + this.appendToken(node.closeBraceToken); + } + + public visitInterfaceDeclaration(node: InterfaceDeclarationSyntax): void { + this.appendSpaceList(node.modifiers); + this.ensureSpace(); + this.appendToken(node.interfaceKeyword); + this.ensureSpace(); + this.appendToken(node.identifier); + this.appendNode(node.typeParameterList); + this.ensureSpace(); + this.appendSpaceList(node.heritageClauses); + this.ensureSpace(); + this.appendObjectType(node.body, /*appendNewLines:*/ true); + } + + private appendObjectType(node: ObjectTypeSyntax, appendNewLines: boolean): void { + this.appendToken(node.openBraceToken); + + if (appendNewLines) { + this.ensureNewLine(); + this.indentation++; + } + else { + this.ensureSpace(); + } + + for (var i = 0, n = childCount(node.typeMembers); i < n; i++) { + visitNodeOrToken(this, childAt(node.typeMembers, i)); + + if (appendNewLines) { + this.ensureNewLine(); + } + else { + this.ensureSpace(); + } + } + + this.indentation--; + this.appendToken(node.closeBraceToken); + } + + public visitHeritageClause(node: HeritageClauseSyntax): void { + this.appendToken(node.extendsOrImplementsKeyword); + this.ensureSpace(); + this.appendSeparatorSpaceList(node.typeNames); + } + + public visitModuleDeclaration(node: ModuleDeclarationSyntax): void { + this.appendSpaceList(node.modifiers); + this.ensureSpace(); + this.appendToken(node.moduleKeyword); + this.ensureSpace(); + this.appendElement(node.name); + this.ensureSpace(); + this.appendToken(node.stringLiteral); + this.ensureSpace(); + + this.appendToken(node.openBraceToken); + this.ensureNewLine(); + + this.indentation++; + + this.appendModuleElements(node.moduleElements); + + this.indentation--; + this.appendToken(node.closeBraceToken); + } + + private appendBlockOrSemicolon(block: BlockSyntax, semicolonToken: ISyntaxToken) { + if (block) { + this.ensureSpace(); + visitNodeOrToken(this, block); + } + else { + this.appendToken(semicolonToken); + } + } + + public visitFunctionDeclaration(node: FunctionDeclarationSyntax): void { + this.appendSpaceList(node.modifiers); + this.ensureSpace(); + this.appendToken(node.functionKeyword); + this.ensureSpace(); + this.appendToken(node.identifier); + this.appendNode(node.callSignature); + this.appendBlockOrSemicolon(node.block, node.semicolonToken); + } + + public visitVariableStatement(node: VariableStatementSyntax): void { + this.appendSpaceList(node.modifiers); + this.ensureSpace(); + visitNodeOrToken(this, node.variableDeclaration); + this.appendToken(node.semicolonToken); + } + + public visitVariableDeclaration(node: VariableDeclarationSyntax): void { + this.appendToken(node.varKeyword); + this.ensureSpace(); + this.appendSeparatorSpaceList(node.variableDeclarators); + } + + public visitVariableDeclarator(node: VariableDeclaratorSyntax): void { + this.appendToken(node.propertyName); + this.appendNode(node.equalsValueClause); + } + + public visitEqualsValueClause(node: EqualsValueClauseSyntax): void { + this.ensureSpace(); + this.appendToken(node.equalsToken); + this.ensureSpace(); + visitNodeOrToken(this, node.value); + } + + public visitPrefixUnaryExpression(node: PrefixUnaryExpressionSyntax): void { + this.appendToken(node.operatorToken); + visitNodeOrToken(this, node.operand); + } + + public visitArrayLiteralExpression(node: ArrayLiteralExpressionSyntax): void { + this.appendToken(node.openBracketToken); + this.appendSeparatorSpaceList(node.expressions); + this.appendToken(node.closeBracketToken); + } + + public visitOmittedExpression(node: OmittedExpressionSyntax): void { + // Nothing to do. + } + + public visitParenthesizedExpression(node: ParenthesizedExpressionSyntax): void { + this.appendToken(node.openParenToken); + visitNodeOrToken(this, node.expression); + this.appendToken(node.closeParenToken); + } + + public visitSimpleArrowFunctionExpression(node: SimpleArrowFunctionExpressionSyntax): void { + this.appendNode(node.parameter); + this.ensureSpace(); + this.appendToken(node.equalsGreaterThanToken); + this.ensureSpace(); + this.appendNode(node.block); + this.appendElement(node.expression); + } + + public visitParenthesizedArrowFunctionExpression(node: ParenthesizedArrowFunctionExpressionSyntax): void { + visitNodeOrToken(this, node.callSignature); + this.ensureSpace(); + this.appendToken(node.equalsGreaterThanToken); + this.ensureSpace(); + this.appendNode(node.block); + this.appendElement(node.expression); + } + + public visitQualifiedName(node: QualifiedNameSyntax): void { + visitNodeOrToken(this, node.left); + this.appendToken(node.dotToken); + this.appendToken(node.right); + } + + public visitTypeQuery(node: TypeQuerySyntax): void { + this.appendToken(node.typeOfKeyword); + this.ensureSpace(); + visitNodeOrToken(this, node.name); + } + + public visitTypeArgumentList(node: TypeArgumentListSyntax): void { + this.appendToken(node.lessThanToken); + this.appendSeparatorSpaceList(node.typeArguments); + this.appendToken(node.greaterThanToken); + } + + public visitConstructorType(node: ConstructorTypeSyntax): void { + this.appendToken(node.newKeyword); + this.ensureSpace(); + this.appendNode(node.typeParameterList); + visitNodeOrToken(this, node.parameterList); + this.ensureSpace(); + this.appendToken(node.equalsGreaterThanToken); + this.ensureSpace(); + visitNodeOrToken(this, node.type); + } + + public visitFunctionType(node: FunctionTypeSyntax): void { + this.appendNode(node.typeParameterList); + visitNodeOrToken(this, node.parameterList); + this.ensureSpace(); + this.appendToken(node.equalsGreaterThanToken); + this.ensureSpace(); + visitNodeOrToken(this, node.type); + } + + public visitObjectType(node: ObjectTypeSyntax): void { + this.appendToken(node.openBraceToken); + this.ensureSpace(); + this.appendSeparatorSpaceList(node.typeMembers); + this.appendToken(node.closeBraceToken); + } + + public visitArrayType(node: ArrayTypeSyntax): void { + visitNodeOrToken(this, node.type); + this.appendToken(node.openBracketToken); + this.appendToken(node.closeBracketToken); + } + + public visitGenericType(node: GenericTypeSyntax): void { + visitNodeOrToken(this, node.name); + visitNodeOrToken(this, node.typeArgumentList); + } + + public visitTypeAnnotation(node: TypeAnnotationSyntax): void { + this.appendToken(node.colonToken); + this.ensureSpace(); + visitNodeOrToken(this, node.type); + } + + private appendStatements(statements: IStatementSyntax[]): void { + var lastStatement: IStatementSyntax = null; + for (var i = 0, n = statements.length; i < n; i++) { + var statement = statements[i]; + + var newLineCount = this.newLineCountBetweenStatements(lastStatement, statement); + + this.appendNewLines(newLineCount); + visitNodeOrToken(this, statement); + + lastStatement = statement; + } + } + + public visitBlock(node: BlockSyntax): void { + this.appendToken(node.openBraceToken); + this.ensureNewLine(); + this.indentation++; + + this.appendStatements(node.statements); + + this.indentation--; + this.ensureNewLine(); + this.appendToken(node.closeBraceToken); + } + + public visitParameter(node: ParameterSyntax): void { + this.appendToken(node.dotDotDotToken); + this.appendSpaceList(node.modifiers); + this.appendToken(node.identifier); + this.appendToken(node.questionToken); + this.appendNode(node.typeAnnotation); + this.appendNode(node.equalsValueClause); + } + + public visitMemberAccessExpression(node: MemberAccessExpressionSyntax): void { + visitNodeOrToken(this, node.expression); + this.appendToken(node.dotToken); + this.appendToken(node.name); + } + + public visitPostfixUnaryExpression(node: PostfixUnaryExpressionSyntax): void { + visitNodeOrToken(this, node.operand); + this.appendToken(node.operatorToken); + } + + public visitElementAccessExpression(node: ElementAccessExpressionSyntax): void { + visitNodeOrToken(this, node.expression); + this.appendToken(node.openBracketToken); + visitNodeOrToken(this, node.argumentExpression); + this.appendToken(node.closeBracketToken); + } + + public visitInvocationExpression(node: InvocationExpressionSyntax): void { + visitNodeOrToken(this, node.expression); + visitNodeOrToken(this, node.argumentList); + } + + public visitArgumentList(node: ArgumentListSyntax): void { + this.appendToken(node.openParenToken); + this.appendSeparatorSpaceList(node.arguments); + this.appendToken(node.closeParenToken); + } + + public visitBinaryExpression(node: BinaryExpressionSyntax): void { + visitNodeOrToken(this, node.left); + + if (node.kind() !== SyntaxKind.CommaExpression) { + this.ensureSpace(); + } + + this.appendToken(node.operatorToken); + this.ensureSpace(); + visitNodeOrToken(this, node.right); + } + + public visitConditionalExpression(node: ConditionalExpressionSyntax): void { + visitNodeOrToken(this, node.condition); + this.ensureSpace(); + this.appendToken(node.questionToken); + this.ensureSpace(); + visitNodeOrToken(this, node.whenTrue); + this.ensureSpace(); + this.appendToken(node.colonToken); + this.ensureSpace(); + visitNodeOrToken(this, node.whenFalse); + } + + public visitConstructSignature(node: ConstructSignatureSyntax): void { + this.appendToken(node.newKeyword); + visitNodeOrToken(this, node.callSignature); + } + + public visitMethodSignature(node: MethodSignatureSyntax): void { + this.appendToken(node.propertyName); + this.appendToken(node.questionToken); + visitNodeOrToken(this, node.callSignature); + } + + public visitIndexSignature(node: IndexSignatureSyntax): void { + this.appendToken(node.openBracketToken); + this.appendSeparatorSpaceList(node.parameters) + this.appendToken(node.closeBracketToken); + this.appendNode(node.typeAnnotation); + } + + public visitPropertySignature(node: PropertySignatureSyntax): void { + this.appendToken(node.propertyName); + this.appendToken(node.questionToken); + this.appendNode(node.typeAnnotation); + } + + public visitParameterList(node: ParameterListSyntax): void { + this.appendToken(node.openParenToken); + this.appendSeparatorSpaceList(node.parameters); + this.appendToken(node.closeParenToken); + } + + public visitCallSignature(node: CallSignatureSyntax): void { + this.appendNode(node.typeParameterList); + visitNodeOrToken(this, node.parameterList); + this.appendNode(node.typeAnnotation); + } + + public visitTypeParameterList(node: TypeParameterListSyntax): void { + this.appendToken(node.lessThanToken); + this.appendSeparatorSpaceList(node.typeParameters); + this.appendToken(node.greaterThanToken); + } + + public visitTypeParameter(node: TypeParameterSyntax): void { + this.appendToken(node.identifier); + this.appendNode(node.constraint); + } + + public visitConstraint(node: ConstraintSyntax): void { + this.ensureSpace(); + this.appendToken(node.extendsKeyword); + this.ensureSpace(); + visitNodeOrToken(this, node.typeOrExpression); + } + + private appendBlockOrStatement(node: IStatementSyntax): void { + if (node.kind() === SyntaxKind.Block) { + this.ensureSpace(); + visitNodeOrToken(this, node); + } + else { + this.ensureNewLine(); + this.indentation++; + visitNodeOrToken(this, node); + this.indentation--; + } + } + + public visitIfStatement(node: IfStatementSyntax): void { + this.appendToken(node.ifKeyword); + this.ensureSpace(); + this.appendToken(node.openParenToken); + visitNodeOrToken(this, node.condition); + this.appendToken(node.closeParenToken); + this.appendBlockOrStatement(node.statement); + this.appendNode(node.elseClause); + } + + public visitElseClause(node: ElseClauseSyntax): void { + this.ensureNewLine(); + this.appendToken(node.elseKeyword); + + if (node.statement.kind() === SyntaxKind.IfStatement) { + this.ensureSpace(); + visitNodeOrToken(this, node.statement); + } + else { + this.appendBlockOrStatement(node.statement); + } + } + + public visitExpressionStatement(node: ExpressionStatementSyntax): void { + visitNodeOrToken(this, node.expression); + this.appendToken(node.semicolonToken); + } + + public visitConstructorDeclaration(node: ConstructorDeclarationSyntax): void { + this.appendToken(node.constructorKeyword); + visitNodeOrToken(this, node.callSignature); + this.appendBlockOrSemicolon(node.block, node.semicolonToken); + } + + public visitIndexMemberDeclaration(node: IndexMemberDeclarationSyntax): void { + this.appendSpaceList(node.modifiers); + this.ensureSpace(); + visitNodeOrToken(this, node.indexSignature); + this.appendToken(node.semicolonToken); + } + + public visitMemberFunctionDeclaration(node: MemberFunctionDeclarationSyntax): void { + this.appendSpaceList(node.modifiers); + this.ensureSpace(); + this.appendToken(node.propertyName); + visitNodeOrToken(this, node.callSignature); + this.appendBlockOrSemicolon(node.block, node.semicolonToken); + } + + public visitGetAccessor(node: GetAccessorSyntax): void { + this.appendSpaceList(node.modifiers); + this.ensureSpace(); + this.appendToken(node.getKeyword); + this.ensureSpace(); + this.appendToken(node.propertyName); + visitNodeOrToken(this, node.callSignature); + this.ensureSpace(); + visitNodeOrToken(this, node.block); + } + + public visitSetAccessor(node: SetAccessorSyntax): void { + this.appendSpaceList(node.modifiers); + this.ensureSpace(); + this.appendToken(node.setKeyword); + this.ensureSpace(); + this.appendToken(node.propertyName); + visitNodeOrToken(this, node.callSignature) + this.ensureSpace(); + visitNodeOrToken(this, node.block); + } + + public visitMemberVariableDeclaration(node: MemberVariableDeclarationSyntax): void { + this.appendSpaceList(node.modifiers); + this.ensureSpace(); + visitNodeOrToken(this, node.variableDeclarator); + this.appendToken(node.semicolonToken); + } + + public visitThrowStatement(node: ThrowStatementSyntax): void { + this.appendToken(node.throwKeyword); + + if (node.expression) { + this.ensureSpace(); + visitNodeOrToken(this, node.expression); + } + + this.appendToken(node.semicolonToken); + } + + public visitReturnStatement(node: ReturnStatementSyntax): void { + this.appendToken(node.returnKeyword); + + if (node.expression) { + this.ensureSpace(); + visitNodeOrToken(this, node.expression); + } + + this.appendToken(node.semicolonToken); + } + + public visitObjectCreationExpression(node: ObjectCreationExpressionSyntax): void { + this.appendToken(node.newKeyword); + this.ensureSpace(); + visitNodeOrToken(this, node.expression); + this.appendNode(node.argumentList); + } + + public visitSwitchStatement(node: SwitchStatementSyntax): void { + this.appendToken(node.switchKeyword); + this.ensureSpace(); + this.appendToken(node.openParenToken); + visitNodeOrToken(this, node.expression); + this.appendToken(node.closeParenToken); + this.ensureSpace(); + this.appendToken(node.openBraceToken); + this.ensureNewLine(); + + var lastSwitchClause: ISwitchClauseSyntax = null; + for (var i = 0, n = node.switchClauses.length; i < n; i++) { + var switchClause = node.switchClauses[i]; + + var newLineCount = this.newLineCountBetweenSwitchClauses(lastSwitchClause, switchClause); + + this.appendNewLines(newLineCount); + visitNodeOrToken(this, switchClause); + + lastSwitchClause = switchClause; + } + + this.ensureNewLine(); + this.appendToken(node.closeBraceToken); + } + + private appendSwitchClauseStatements(node: ISwitchClauseSyntax): void { + if (childCount(node.statements) === 1 && childAt(node.statements, 0).kind() === SyntaxKind.Block) { + this.ensureSpace(); + visitNodeOrToken(this, childAt(node.statements, 0)); + } + else if (childCount(node.statements) > 0) { + this.ensureNewLine(); + + this.indentation++; + this.appendStatements(node.statements); + this.indentation--; + } + } + + public visitCaseSwitchClause(node: CaseSwitchClauseSyntax): void { + this.appendToken(node.caseKeyword); + this.ensureSpace(); + visitNodeOrToken(this, node.expression); + this.appendToken(node.colonToken); + this.appendSwitchClauseStatements(node); + } + + public visitDefaultSwitchClause(node: DefaultSwitchClauseSyntax): void { + this.appendToken(node.defaultKeyword); + this.appendToken(node.colonToken); + this.appendSwitchClauseStatements(node); + } + + public visitBreakStatement(node: BreakStatementSyntax): void { + this.appendToken(node.breakKeyword); + if (node.identifier) { + this.ensureSpace(); + this.appendToken(node.identifier); + } + + this.appendToken(node.semicolonToken); + } + + public visitContinueStatement(node: ContinueStatementSyntax): void { + this.appendToken(node.continueKeyword); + if (node.identifier) { + this.ensureSpace(); + this.appendToken(node.identifier); + } + + this.appendToken(node.semicolonToken); + } + + public visitForStatement(node: ForStatementSyntax): void { + this.appendToken(node.forKeyword); + this.ensureSpace(); + this.appendToken(node.openParenToken); + this.appendNode(node.variableDeclaration); + this.appendElement(node.initializer); + this.appendToken(node.firstSemicolonToken); + + if (node.condition) { + this.ensureSpace(); + visitNodeOrToken(this, node.condition); + } + + this.appendToken(node.secondSemicolonToken); + + if (node.incrementor) { + this.ensureSpace(); + visitNodeOrToken(this, node.incrementor); + } + + this.appendToken(node.closeParenToken); + this.appendBlockOrStatement(node.statement); + } + + public visitForInStatement(node: ForInStatementSyntax): void { + this.appendToken(node.forKeyword); + this.ensureSpace(); + this.appendToken(node.openParenToken); + this.appendNode(node.variableDeclaration); + this.appendElement(node.left); + this.ensureSpace(); + this.appendToken(node.inKeyword); + this.ensureSpace(); + this.appendElement(node.expression); + this.appendToken(node.closeParenToken); + this.appendBlockOrStatement(node.statement); + } + + public visitWhileStatement(node: WhileStatementSyntax): void { + this.appendToken(node.whileKeyword); + this.ensureSpace(); + this.appendToken(node.openParenToken); + visitNodeOrToken(this, node.condition); + this.appendToken(node.closeParenToken); + this.appendBlockOrStatement(node.statement); + } + + public visitWithStatement(node: WithStatementSyntax): void { + this.appendToken(node.withKeyword); + this.ensureSpace(); + this.appendToken(node.openParenToken); + visitNodeOrToken(this, node.condition); + this.appendToken(node.closeParenToken); + this.appendBlockOrStatement(node.statement); + } + + public visitEnumDeclaration(node: EnumDeclarationSyntax): void { + this.appendSpaceList(node.modifiers); + this.ensureSpace(); + this.appendToken(node.enumKeyword); + this.ensureSpace(); + this.appendToken(node.identifier); + this.ensureSpace(); + this.appendToken(node.openBraceToken); + this.ensureNewLine(); + + this.indentation++; + this.appendSeparatorNewLineList(node.enumElements); + this.indentation--; + + this.appendToken(node.closeBraceToken); + } + + public visitEnumElement(node: EnumElementSyntax): void { + this.appendToken(node.propertyName); + this.ensureSpace(); + this.appendNode(node.equalsValueClause); + } + + public visitCastExpression(node: CastExpressionSyntax): void { + this.appendToken(node.lessThanToken); + visitNodeOrToken(this, node.type); + this.appendToken(node.greaterThanToken); + visitNodeOrToken(this, node.expression); + } + + public visitObjectLiteralExpression(node: ObjectLiteralExpressionSyntax): void { + this.appendToken(node.openBraceToken); + + if (childCount(node.propertyAssignments) === 1) { + this.ensureSpace(); + visitNodeOrToken(this, childAt(node.propertyAssignments, 0)); + this.ensureSpace(); + } + else if (childCount(node.propertyAssignments) > 0) { + this.indentation++; + this.ensureNewLine(); + this.appendSeparatorNewLineList(node.propertyAssignments); + this.ensureNewLine(); + this.indentation--; + } + + this.appendToken(node.closeBraceToken); + } + + public visitSimplePropertyAssignment(node: SimplePropertyAssignmentSyntax): void { + this.appendToken(node.propertyName); + this.appendToken(node.colonToken); + this.ensureSpace(); + visitNodeOrToken(this, node.expression); + } + + public visitFunctionPropertyAssignment(node: FunctionPropertyAssignmentSyntax): void { + this.appendToken(node.propertyName); + visitNodeOrToken(this, node.callSignature); + this.ensureSpace(); + visitNodeOrToken(this, node.block); + } + + public visitFunctionExpression(node: FunctionExpressionSyntax): void { + this.appendToken(node.functionKeyword); + + if (node.identifier) { + this.ensureSpace(); + this.appendToken(node.identifier); + } + + visitNodeOrToken(this, node.callSignature); + this.ensureSpace(); + visitNodeOrToken(this, node.block); + } + + public visitEmptyStatement(node: EmptyStatementSyntax): void { + this.appendToken(node.semicolonToken); + } + + public visitTryStatement(node: TryStatementSyntax): void { + this.appendToken(node.tryKeyword); + this.ensureSpace(); + visitNodeOrToken(this, node.block); + this.appendNode(node.catchClause); + this.appendNode(node.finallyClause); + } + + public visitCatchClause(node: CatchClauseSyntax): void { + this.ensureNewLine(); + this.appendToken(node.catchKeyword); + this.ensureSpace(); + this.appendToken(node.openParenToken); + this.appendToken(node.identifier); + this.appendToken(node.closeParenToken); + this.ensureSpace(); + visitNodeOrToken(this, node.block); + } + + public visitFinallyClause(node: FinallyClauseSyntax): void { + this.ensureNewLine(); + this.appendToken(node.finallyKeyword); + this.ensureNewLine(); + visitNodeOrToken(this, node.block); + } + + public visitLabeledStatement(node: LabeledStatementSyntax): void { + this.appendToken(node.identifier); + this.appendToken(node.colonToken); + this.appendBlockOrStatement(node.statement); + } + + public visitDoStatement(node: DoStatementSyntax): void { + this.appendToken(node.doKeyword); + this.appendBlockOrStatement(node.statement); + this.ensureNewLine(); + this.appendToken(node.whileKeyword); + this.ensureSpace(); + this.appendToken(node.openParenToken); + visitNodeOrToken(this, node.condition); + this.appendToken(node.closeParenToken); + this.appendToken(node.semicolonToken); + } + + public visitTypeOfExpression(node: TypeOfExpressionSyntax): void { + this.appendToken(node.typeOfKeyword); + this.ensureSpace(); + visitNodeOrToken(this, node.expression); + } + + public visitDeleteExpression(node: DeleteExpressionSyntax): void { + this.appendToken(node.deleteKeyword); + this.ensureSpace(); + visitNodeOrToken(this, node.expression); + } + + public visitVoidExpression(node: VoidExpressionSyntax): void { + this.appendToken(node.voidKeyword); + this.ensureSpace(); + visitNodeOrToken(this, node.expression); + } + + public visitDebuggerStatement(node: DebuggerStatementSyntax): void { + this.appendToken(node.debuggerKeyword); + this.appendToken(node.semicolonToken); + } + } +} \ No newline at end of file diff --git a/src/services/syntax/references.ts b/src/services/syntax/references.ts new file mode 100644 index 00000000000..a4eb9efc595 --- /dev/null +++ b/src/services/syntax/references.ts @@ -0,0 +1,49 @@ +/// + +/// +/// +/// +// /// +/// + +// Scanner depends on SyntaxKind and SyntaxFacts +/// +/// +/// + +/// +/// +/// +/// +/// +/// +/// +/// +/// + +// SyntaxDedenter depends on SyntaxRewriter +// /// +// SyntaxIndenter depends on SyntaxRewriter +// /// + +/// +/// +/// +/// +/// +/// + +// SyntaxInformationMap depends on SyntaxWalker +// /// + +// DepthLimitedWalker depends on PositionTrackingWalker +/// +/// + +// Concrete nodes depend on the parser. +/// + +// SyntaxTree depends on PositionTrackingWalker +/// + +/// diff --git a/src/services/syntax/scanner.ts b/src/services/syntax/scanner.ts new file mode 100644 index 00000000000..8f937fa540c --- /dev/null +++ b/src/services/syntax/scanner.ts @@ -0,0 +1,1678 @@ +/// + +module TypeScript.Scanner { + // Make sure we can encode a token's kind in 7 bits. + Debug.assert(SyntaxKind.LastToken <= 127); + + // Fixed width tokens (keywords and punctuation) that have no trivia generally make up 30% of + // all the tokens in a program. We heavily optimize for that case with a token instance that + // just needs a parent pointer and a single 30bit int like so: + // + // 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0xxx xxxx <-- kind + // 0000 0000 0000 0000 0000 0000 0000 0000 00xx xxxx xxxx xxxx xxxx xxxx x000 0000 <-- full start + // ^ ^ ^ + // | | | + // Bit 64 Bit 30 Bit 1 + // + // This gives us 23 bits for the start of the token. We don't need to store the width as it + // can be inferred from the 'kind' for a fixed width token. + // + // For small tokens, we encode the data in one 30bit int like so: + // + // 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0xxx xxxx <-- kind + // 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 xxxx x000 0000 <-- full width + // 0000 0000 0000 0000 0000 0000 0000 0000 00xx xxxx xxxx xxxx xxxx 0000 0000 0000 <-- full start + // ^ ^ ^ + // | | | + // Bit 64 Bit 30 Bit 1 + // + // This allows for 5bits for teh width. i.e. tokens up to 31 chars in width. And 18 bits for + // the full start. This allows for tokens starting up to and including position 262,143. + // + // In practice, for codebases we have measured, these values are sufficient to cover ~85% of + // all tokens. If a token won't fit within those limits, we make a large token for it. + // + // + // For large tokens, we encode data with two 30 bit ints like so: + // + // _packedFullStartAndInfo: + // + // 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 000x <-- has leading trivia + // 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 00x0 <-- has trailing trivia + // 0000 0000 0000 0000 0000 0000 0000 0000 00xx xxxx xxxx xxxx xxxx xxxx xxxx xx00 <-- full start + // ^ ^ ^ + // | | | + // Bit 64 Bit 30 Bit 1 + // + // This gives us 28 bits for the start of the token. At 256MB That's more than enough for + // any codebase. + // + // _packedFullWidthAndKind: + // + // 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0xxx xxxx <-- kind + // 0000 0000 0000 0000 0000 0000 0000 0000 00xx xxxx xxxx xxxx xxxx xxxx x000 0000 <-- full width + // ^ ^ ^ + // | | | + // Bit 64 Bit 30 Bit 1 + // + // This gives us 23bit for width (or 8MB of width which should be enough for any codebase). + + enum ScannerConstants { + LargeTokenFullStartShift = 2, + LargeTokenFullWidthShift = 7, + + FixedWidthTokenFullStartShift = 7, + + SmallTokenFullWidthShift = 7, + SmallTokenFullStartShift = 12, + + KindMask = 0x7F, // 01111111 + IsVariableWidthMask = 0x80, // 10000000 + + LargeTokenLeadingTriviaBitMask = 0x01, // 00000001 + LargeTokenTrailingTriviaBitMask = 0x02, // 00000010 + + SmallTokenFullWidthMask = 0x1F, // 00011111 + + FixedWidthTokenMaxFullStart = 0x7FFFFF, // 23 ones. + SmallTokenMaxFullStart = 0x3FFFF, // 18 ones. + SmallTokenMaxFullWidth = 0x1F, // 5 ones + } + + // Make sure our math works for packing/unpacking large fullStarts. + Debug.assert(largeTokenUnpackFullStart(largeTokenPackFullStartAndInfo(1 << 28, 1, 1)) === (1 << 28)); + Debug.assert(largeTokenUnpackFullStart(largeTokenPackFullStartAndInfo(3 << 27, 0, 1)) === (3 << 27)); + Debug.assert(largeTokenUnpackFullStart(largeTokenPackFullStartAndInfo(10 << 25, 1, 0)) === (10 << 25)); + + function fixedWidthTokenPackData(fullStart: number, kind: SyntaxKind) { + return (fullStart << ScannerConstants.FixedWidthTokenFullStartShift) | kind; + } + + function fixedWidthTokenUnpackFullStart(packedData: number) { + return packedData >> ScannerConstants.FixedWidthTokenFullStartShift; + } + + function smallTokenPackData(fullStart: number, fullWidth: number, kind: SyntaxKind) { + return (fullStart << ScannerConstants.SmallTokenFullStartShift) | + (fullWidth << ScannerConstants.SmallTokenFullWidthShift) | + kind; + } + + function smallTokenUnpackFullWidth(packedData: number): SyntaxKind { + return (packedData >> ScannerConstants.SmallTokenFullWidthShift) & ScannerConstants.SmallTokenFullWidthMask; + } + + function smallTokenUnpackFullStart(packedData: number): number { + return packedData >> ScannerConstants.SmallTokenFullStartShift; + } + + function largeTokenPackFullStartAndInfo(fullStart: number, hasLeadingTriviaInfo: number, hasTrailingTriviaInfo: number): number { + return (fullStart << ScannerConstants.LargeTokenFullStartShift) | hasLeadingTriviaInfo | hasTrailingTriviaInfo; + } + + function largeTokenUnpackFullWidth(packedFullWidthAndKind: number) { + return packedFullWidthAndKind >> ScannerConstants.LargeTokenFullWidthShift; + } + + function largeTokenUnpackFullStart(packedFullStartAndInfo: number): number { + return packedFullStartAndInfo >> ScannerConstants.LargeTokenFullStartShift; + } + + function largeTokenUnpackHasLeadingTriviaInfo(packed: number): number { + return packed & ScannerConstants.LargeTokenLeadingTriviaBitMask; + } + + function largeTokenUnpackHasTrailingTriviaInfo(packed: number): number { + return packed & ScannerConstants.LargeTokenTrailingTriviaBitMask; + } + + var isKeywordStartCharacter: number[] = ArrayUtilities.createArray(CharacterCodes.maxAsciiCharacter, 0); + var isIdentifierStartCharacter: boolean[] = ArrayUtilities.createArray(CharacterCodes.maxAsciiCharacter, false); + var isIdentifierPartCharacter: boolean[] = ArrayUtilities.createArray(CharacterCodes.maxAsciiCharacter, false); + + for (var character = 0; character < CharacterCodes.maxAsciiCharacter; character++) { + if ((character >= CharacterCodes.a && character <= CharacterCodes.z) || + (character >= CharacterCodes.A && character <= CharacterCodes.Z) || + character === CharacterCodes._ || character === CharacterCodes.$) { + + isIdentifierStartCharacter[character] = true; + isIdentifierPartCharacter[character] = true; + } + else if (character >= CharacterCodes._0 && character <= CharacterCodes._9) { + isIdentifierPartCharacter[character] = true; + } + } + + for (var keywordKind = SyntaxKind.FirstKeyword; keywordKind <= SyntaxKind.LastKeyword; keywordKind++) { + var keyword = SyntaxFacts.getText(keywordKind); + isKeywordStartCharacter[keyword.charCodeAt(0)] = 1; + } + + export function isContextualToken(token: ISyntaxToken): boolean { + // These tokens are contextually created based on parsing decisions. We can't reuse + // them in incremental scenarios as we may be in a context where the parser would not + // create them. + switch (token.kind()) { + // Created by the parser when it sees / or /= in a location where it needs an expression. + case SyntaxKind.RegularExpressionLiteral: + + // Created by the parser when it sees > in a binary expression operator context. + case SyntaxKind.GreaterThanGreaterThanToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: + case SyntaxKind.GreaterThanEqualsToken: + case SyntaxKind.GreaterThanGreaterThanEqualsToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: + return true; + + default: + return token.isKeywordConvertedToIdentifier(); + } + } + + var lastTokenInfo = { leadingTriviaWidth: -1, width: -1 }; + var lastTokenInfoTokenID: number = -1; + + var triviaScanner = createScannerInternal(ts.ScriptTarget.ES5, SimpleText.fromString(""), () => { }); + + interface IScannerToken extends ISyntaxToken { + } + + function fillSizeInfo(token: IScannerToken, text: ISimpleText): void { + if (lastTokenInfoTokenID !== syntaxID(token)) { + triviaScanner.fillTokenInfo(token, text, lastTokenInfo); + lastTokenInfoTokenID = syntaxID(token); + } + } + + function fullText(token: IScannerToken, text: ISimpleText): string { + return text.substr(token.fullStart(), token.fullWidth()); + } + + function leadingTrivia(token: IScannerToken, text: ISimpleText): ISyntaxTriviaList { + if (!token.hasLeadingTrivia()) { + return Syntax.emptyTriviaList; + } + + return triviaScanner.scanTrivia(token, text, /*isTrailing:*/ false); + } + + function trailingTrivia(token: IScannerToken, text: ISimpleText): ISyntaxTriviaList { + if (!token.hasTrailingTrivia()) { + return Syntax.emptyTriviaList; + } + + return triviaScanner.scanTrivia(token, text, /*isTrailing:*/ true); + } + + function leadingTriviaWidth(token: IScannerToken, text: ISimpleText): number { + if (!token.hasLeadingTrivia()) { + return 0; + } + + fillSizeInfo(token, text); + return lastTokenInfo.leadingTriviaWidth; + } + + function trailingTriviaWidth(token: IScannerToken, text: ISimpleText): number { + if (!token.hasTrailingTrivia()) { + return 0; + } + + fillSizeInfo(token, text); + return token.fullWidth() - lastTokenInfo.leadingTriviaWidth - lastTokenInfo.width; + } + + function tokenIsIncrementallyUnusable(token: IScannerToken): boolean { + // No scanner tokens make their *containing node* incrementally unusable. + // Note: several scanner tokens may themselves be unusable. i.e. if the parser asks + // for a full node, then that ndoe can be returned even if it contains parser generated + // tokens (like regexs and merged operator tokens). However, if the parser asks for a + // for a token, then those contextual tokens will not be reusable. + return false; + } + + class FixedWidthTokenWithNoTrivia implements ISyntaxToken { + public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; public _typeBrand: any; + + constructor(private _packedData: number) { + } + + public setFullStart(fullStart: number): void { + this._packedData = fixedWidthTokenPackData(fullStart, this.kind()); + } + + public isIncrementallyUnusable(): boolean { return false; } + public isKeywordConvertedToIdentifier(): boolean { return false; } + public hasSkippedToken(): boolean { return false; } + public fullText(): string { return SyntaxFacts.getText(this.kind()); } + public text(): string { return this.fullText(); } + public leadingTrivia(): ISyntaxTriviaList { return Syntax.emptyTriviaList; } + public trailingTrivia(): ISyntaxTriviaList { return Syntax.emptyTriviaList; } + public leadingTriviaWidth(): number { return 0; } + public trailingTriviaWidth(): number { return 0; } + + public kind(): SyntaxKind { return this._packedData & ScannerConstants.KindMask; } + public fullWidth(): number { return this.fullText().length; } + public fullStart(): number { return fixedWidthTokenUnpackFullStart(this._packedData); } + public hasLeadingTrivia(): boolean { return false; } + public hasTrailingTrivia(): boolean { return false; } + public clone(): ISyntaxToken { return new FixedWidthTokenWithNoTrivia(this._packedData); } + } + + class LargeScannerToken implements ISyntaxToken { + public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; public _typeBrand: any; + + private cachedText: string; + constructor(private _packedFullStartAndInfo: number, private _packedFullWidthAndKind: number, cachedText: string) { + if (cachedText !== undefined) { + this.cachedText = cachedText; + } + } + + public setFullStart(fullStart: number): void { + this._packedFullStartAndInfo = largeTokenPackFullStartAndInfo(fullStart, + largeTokenUnpackHasLeadingTriviaInfo(this._packedFullStartAndInfo), + largeTokenUnpackHasTrailingTriviaInfo(this._packedFullStartAndInfo)); + } + + private syntaxTreeText(text: ISimpleText) { + var result = text || syntaxTree(this).text; + Debug.assert(result); + return result; + } + + public isIncrementallyUnusable(): boolean { return tokenIsIncrementallyUnusable(this); } + public isKeywordConvertedToIdentifier(): boolean { return false; } + public hasSkippedToken(): boolean { return false; } + + public fullText(text?: ISimpleText): string { + return fullText(this, this.syntaxTreeText(text)); + } + + public text(): string { + var cachedText = this.cachedText; + return cachedText !== undefined ? cachedText : SyntaxFacts.getText(this.kind()); + } + + public leadingTrivia(text?: ISimpleText): ISyntaxTriviaList { return leadingTrivia(this, this.syntaxTreeText(text)); } + public trailingTrivia(text?: ISimpleText): ISyntaxTriviaList { return trailingTrivia(this, this.syntaxTreeText(text)); } + + public leadingTriviaWidth(text?: ISimpleText): number { + return leadingTriviaWidth(this, this.syntaxTreeText(text)); + } + + public trailingTriviaWidth(text?: ISimpleText): number { + return trailingTriviaWidth(this, this.syntaxTreeText(text)); + } + + public kind(): SyntaxKind { return this._packedFullWidthAndKind & ScannerConstants.KindMask; } + public fullWidth(): number { return largeTokenUnpackFullWidth(this._packedFullWidthAndKind); } + public fullStart(): number { return largeTokenUnpackFullStart(this._packedFullStartAndInfo); } + public hasLeadingTrivia(): boolean { return largeTokenUnpackHasLeadingTriviaInfo(this._packedFullStartAndInfo) !== 0; } + public hasTrailingTrivia(): boolean { return largeTokenUnpackHasTrailingTriviaInfo(this._packedFullStartAndInfo) !== 0; } + public clone(): ISyntaxToken { return new LargeScannerToken(this._packedFullStartAndInfo, this._packedFullWidthAndKind, this.cachedText); } + } + + export interface DiagnosticCallback { + (position: number, width: number, key: string, arguments: any[]): void; + } + + interface TokenInfo { + leadingTriviaWidth: number; + width: number; + } + + interface IScannerInternal extends IScanner { + fillTokenInfo(token: IScannerToken, text: ISimpleText, tokenInfo: TokenInfo): void; + scanTrivia(token: IScannerToken, text: ISimpleText, isTrailing: boolean): ISyntaxTriviaList; + } + + export interface IScanner { + setIndex(index: number): void; + scan(allowContextualToken: boolean): ISyntaxToken; + } + + export function createScanner(languageVersion: ts.ScriptTarget, text: ISimpleText, reportDiagnostic: DiagnosticCallback): IScanner { + var scanner = createScannerInternal(languageVersion, text, reportDiagnostic); + return { + setIndex: scanner.setIndex, + scan: scanner.scan, + }; + } + + function createScannerInternal(languageVersion: ts.ScriptTarget, text: ISimpleText, reportDiagnostic: DiagnosticCallback): IScannerInternal { + var str: string; + var index: number; + var start: number; + var end: number; + + function setIndex(_index: number) { + index = _index; + } + + function reset(_text: ISimpleText, _start: number, _end: number) { + Debug.assert(_start <= _text.length()); + Debug.assert(_end <= _text.length()); + + if (!str || text !== _text) { + text = _text; + str = _text.substr(0, _text.length()); + } + + start = _start; + end = _end; + index = _start; + } + + function scan(allowContextualToken: boolean): ISyntaxToken { + var fullStart = index; + var leadingTriviaInfo = scanTriviaInfo(/*isTrailing: */ false); + + var start = index; + var kindAndIsVariableWidth = scanSyntaxKind(allowContextualToken); + + var end = index; + var trailingTriviaInfo = scanTriviaInfo(/*isTrailing: */true); + + var fullWidth = index - fullStart; + + // If we have no trivia, and we are a fixed width token kind, and our size isn't too + // large, and we're a real fixed width token (and not something like "\u0076ar"). + var kind = kindAndIsVariableWidth & ScannerConstants.KindMask; + var isFixedWidth = kind >= SyntaxKind.FirstFixedWidth && kind <= SyntaxKind.LastFixedWidth && + ((kindAndIsVariableWidth & ScannerConstants.IsVariableWidthMask) === 0); + + if (isFixedWidth && + leadingTriviaInfo === 0 && trailingTriviaInfo === 0 && + fullStart <= ScannerConstants.FixedWidthTokenMaxFullStart && + (kindAndIsVariableWidth & ScannerConstants.IsVariableWidthMask) === 0) { + + return new FixedWidthTokenWithNoTrivia((fullStart << ScannerConstants.FixedWidthTokenFullStartShift) | kind); + } + else { + // inline the packing logic for perf. + var packedFullStartAndTriviaInfo = (fullStart << ScannerConstants.LargeTokenFullStartShift) | + leadingTriviaInfo | (trailingTriviaInfo << 1); + + var packedFullWidthAndKind = (fullWidth << ScannerConstants.LargeTokenFullWidthShift) | kind; + var cachedText = isFixedWidth ? undefined : text.substr(start, end - start); + return new LargeScannerToken(packedFullStartAndTriviaInfo, packedFullWidthAndKind, cachedText); + } + } + + function scanTrivia(parent: IScannerToken, text: ISimpleText, isTrailing: boolean): ISyntaxTriviaList { + var tokenFullStart = parent.fullStart(); + var tokenStart = tokenFullStart + leadingTriviaWidth(parent, text) + + if (isTrailing) { + reset(text, tokenStart + parent.text().length, tokenFullStart + parent.fullWidth()); + } + else { + reset(text, tokenFullStart, tokenStart); + } + // Debug.assert(length > 0); + + // Keep this exactly in sync with scanTriviaInfo + var trivia: ISyntaxTrivia[] = []; + + while (true) { + if (index < end) { + var ch = str.charCodeAt(index); + switch (ch) { + // Unicode 3.0 space characters + case CharacterCodes.space: + case CharacterCodes.nonBreakingSpace: + case CharacterCodes.enQuad: + case CharacterCodes.emQuad: + case CharacterCodes.enSpace: + case CharacterCodes.emSpace: + case CharacterCodes.threePerEmSpace: + case CharacterCodes.fourPerEmSpace: + case CharacterCodes.sixPerEmSpace: + case CharacterCodes.figureSpace: + case CharacterCodes.punctuationSpace: + case CharacterCodes.thinSpace: + case CharacterCodes.hairSpace: + case CharacterCodes.zeroWidthSpace: + case CharacterCodes.narrowNoBreakSpace: + case CharacterCodes.ideographicSpace: + + case CharacterCodes.tab: + case CharacterCodes.verticalTab: + case CharacterCodes.formFeed: + case CharacterCodes.byteOrderMark: + // Normal whitespace. Consume and continue. + trivia.push(scanWhitespaceTrivia()); + continue; + + case CharacterCodes.slash: + // Potential comment. Consume if so. Otherwise, break out and return. + var ch2 = str.charCodeAt(index + 1); + if (ch2 === CharacterCodes.slash) { + trivia.push(scanSingleLineCommentTrivia()); + continue; + } + + if (ch2 === CharacterCodes.asterisk) { + trivia.push(scanMultiLineCommentTrivia()); + continue; + } + + // Not a comment. Don't consume. + throw Errors.invalidOperation(); + + case CharacterCodes.carriageReturn: + case CharacterCodes.lineFeed: + case CharacterCodes.paragraphSeparator: + case CharacterCodes.lineSeparator: + trivia.push(scanLineTerminatorSequenceTrivia(ch)); + + // If we're consuming leading trivia, then we will continue consuming more + // trivia (including newlines) up to the first token we see. If we're + // consuming trailing trivia, then we break after the first newline we see. + if (!isTrailing) { + continue; + } + + break; + + default: + throw Errors.invalidOperation(); + } + } + + // Debug.assert(trivia.length > 0); + var triviaList = Syntax.triviaList(trivia); + triviaList.parent = parent; + + return triviaList; + } + } + + // Returns 0 if there was no trivia, or 1 if there was trivia. Returned as an int instead + // of a boolean because we'll need a numerical value later on to store in our tokens. + function scanTriviaInfo(isTrailing: boolean): number { + // Keep this exactly in sync with scanTrivia + var result = 0; + var _end = end; + + while (index < _end) { + var ch = str.charCodeAt(index); + + switch (ch) { + case CharacterCodes.tab: + case CharacterCodes.space: + case CharacterCodes.verticalTab: + case CharacterCodes.formFeed: + index++; + result = 1; + continue; + + case CharacterCodes.carriageReturn: + if ((index + 1) < end && str.charCodeAt(index + 1) === CharacterCodes.lineFeed) { + index++; + } + // fall through. + case CharacterCodes.lineFeed: + index++; + + // If we're consuming leading trivia, then we will continue consuming more + // trivia (including newlines) up to the first token we see. If we're + // consuming trailing trivia, then we break after the first newline we see. + if (isTrailing) { + return 1; + } + + result = 1; + continue; + + case CharacterCodes.slash: + if ((index + 1) < _end) { + var ch2 = str.charCodeAt(index + 1); + if (ch2 === CharacterCodes.slash) { + result = 1; + skipSingleLineCommentTrivia(); + continue; + } + + if (ch2 === CharacterCodes.asterisk) { + result = 1; + skipMultiLineCommentTrivia(); + continue; + } + } + + // Not a comment. Don't consume. + return result; + + default: + if (ch > CharacterCodes.maxAsciiCharacter && slowScanTriviaInfo(ch)) { + result = 1; + continue; + } + + return result; + } + } + + return result; + } + + function slowScanTriviaInfo(ch: number): boolean { + switch (ch) { + case CharacterCodes.nonBreakingSpace: + case CharacterCodes.enQuad: + case CharacterCodes.emQuad: + case CharacterCodes.enSpace: + case CharacterCodes.emSpace: + case CharacterCodes.threePerEmSpace: + case CharacterCodes.fourPerEmSpace: + case CharacterCodes.sixPerEmSpace: + case CharacterCodes.figureSpace: + case CharacterCodes.punctuationSpace: + case CharacterCodes.thinSpace: + case CharacterCodes.hairSpace: + case CharacterCodes.zeroWidthSpace: + case CharacterCodes.narrowNoBreakSpace: + case CharacterCodes.ideographicSpace: + case CharacterCodes.byteOrderMark: + case CharacterCodes.paragraphSeparator: + case CharacterCodes.lineSeparator: + index++; + return true; + + default: + return false; + } + } + + function isNewLineCharacter(ch: number): boolean { + switch (ch) { + case CharacterCodes.carriageReturn: + case CharacterCodes.lineFeed: + case CharacterCodes.paragraphSeparator: + case CharacterCodes.lineSeparator: + return true; + default: + return false; + } + } + + function scanWhitespaceTrivia(): ISyntaxTrivia { + // We're going to be extracting text out of sliding window. Make sure it can't move past + // this point. + var absoluteStartIndex = index; + + while (true) { + var ch = str.charCodeAt(index); + + switch (ch) { + // Unicode 3.0 space characters + case CharacterCodes.space: + case CharacterCodes.nonBreakingSpace: + case CharacterCodes.enQuad: + case CharacterCodes.emQuad: + case CharacterCodes.enSpace: + case CharacterCodes.emSpace: + case CharacterCodes.threePerEmSpace: + case CharacterCodes.fourPerEmSpace: + case CharacterCodes.sixPerEmSpace: + case CharacterCodes.figureSpace: + case CharacterCodes.punctuationSpace: + case CharacterCodes.thinSpace: + case CharacterCodes.hairSpace: + case CharacterCodes.zeroWidthSpace: + case CharacterCodes.narrowNoBreakSpace: + case CharacterCodes.ideographicSpace: + + case CharacterCodes.tab: + case CharacterCodes.verticalTab: + case CharacterCodes.formFeed: + case CharacterCodes.byteOrderMark: + // Normal whitespace. Consume and continue. + index++; + continue; + } + + break; + } + + return createTrivia(SyntaxKind.WhitespaceTrivia, absoluteStartIndex); + } + + function createTrivia(kind: SyntaxKind, absoluteStartIndex: number): ISyntaxTrivia { + var fullWidth = index - absoluteStartIndex; + return Syntax.deferredTrivia(kind, text, absoluteStartIndex, fullWidth); + } + + function scanSingleLineCommentTrivia(): ISyntaxTrivia { + var absoluteStartIndex = index; + skipSingleLineCommentTrivia(); + + return createTrivia(SyntaxKind.SingleLineCommentTrivia, absoluteStartIndex); + } + + function skipSingleLineCommentTrivia(): void { + index += 2; + + // The '2' is for the "//" we consumed. + while (index < end) { + if (isNewLineCharacter(str.charCodeAt(index))) { + return; + } + + index++; + } + } + + function scanMultiLineCommentTrivia(): ISyntaxTrivia { + var absoluteStartIndex = index; + skipMultiLineCommentTrivia(); + + return createTrivia(SyntaxKind.MultiLineCommentTrivia, absoluteStartIndex); + } + + function skipMultiLineCommentTrivia(): number { + // The '2' is for the "/*" we consumed. + index += 2; + + while (true) { + if (index === end) { + reportDiagnostic(end, 0, DiagnosticCode.AsteriskSlash_expected, null); + return; + } + + if ((index + 1) < end && + str.charCodeAt(index) === CharacterCodes.asterisk && + str.charCodeAt(index + 1) === CharacterCodes.slash) { + + index += 2; + return; + } + + index++; + } + } + + function scanLineTerminatorSequenceTrivia(ch: number): ISyntaxTrivia { + var absoluteStartIndex = index; + skipLineTerminatorSequence(ch); + + return createTrivia(SyntaxKind.NewLineTrivia, absoluteStartIndex); + } + + function skipLineTerminatorSequence(ch: number): void { + // Consume the first of the line terminator we saw. + index++; + + // If it happened to be a \r and there's a following \n, then consume both. + if (ch === CharacterCodes.carriageReturn && str.charCodeAt(index) === CharacterCodes.lineFeed) { + index++; + } + } + + function scanSyntaxKind(allowContextualToken: boolean): SyntaxKind { + if (index >= end) { + return SyntaxKind.EndOfFileToken; + } + + var character = str.charCodeAt(index); + index++; + + switch (character) { + case CharacterCodes.exclamation /*33*/: return scanExclamationToken(); + case CharacterCodes.doubleQuote/*34*/: return scanStringLiteral(character); + case CharacterCodes.percent /*37*/: return scanPercentToken(); + case CharacterCodes.ampersand /*38*/: return scanAmpersandToken(); + case CharacterCodes.singleQuote/*39*/: return scanStringLiteral(character); + case CharacterCodes.openParen/*40*/: return SyntaxKind.OpenParenToken; + case CharacterCodes.closeParen/*41*/: return SyntaxKind.CloseParenToken; + case CharacterCodes.asterisk/*42*/: return scanAsteriskToken(); + case CharacterCodes.plus/*43*/: return scanPlusToken(); + case CharacterCodes.comma/*44*/: return SyntaxKind.CommaToken; + case CharacterCodes.minus/*45*/: return scanMinusToken(); + case CharacterCodes.dot/*46*/: return scanDotToken(); + case CharacterCodes.slash/*47*/: return scanSlashToken(allowContextualToken); + + case CharacterCodes._0/*48*/: case CharacterCodes._1: case CharacterCodes._2: case CharacterCodes._3: + case CharacterCodes._4: case CharacterCodes._5: case CharacterCodes._6: case CharacterCodes._7: + case CharacterCodes._8: case CharacterCodes._9/*57*/: + return scanNumericLiteral(character); + + case CharacterCodes.colon/*58*/: return SyntaxKind.ColonToken; + case CharacterCodes.semicolon/*59*/: return SyntaxKind.SemicolonToken; + case CharacterCodes.lessThan/*60*/: return scanLessThanToken(); + case CharacterCodes.equals/*61*/: return scanEqualsToken(); + case CharacterCodes.greaterThan/*62*/: return scanGreaterThanToken(allowContextualToken); + case CharacterCodes.question/*63*/: return SyntaxKind.QuestionToken; + + case CharacterCodes.openBracket/*91*/: return SyntaxKind.OpenBracketToken; + case CharacterCodes.closeBracket/*93*/: return SyntaxKind.CloseBracketToken; + case CharacterCodes.caret/*94*/: return scanCaretToken(); + + case CharacterCodes.openBrace/*123*/: return SyntaxKind.OpenBraceToken; + case CharacterCodes.bar/*124*/: return scanBarToken(); + case CharacterCodes.closeBrace/*125*/: return SyntaxKind.CloseBraceToken; + case CharacterCodes.tilde/*126*/: return SyntaxKind.TildeToken; + } + + // We run into so many identifiers (and keywords) when scanning, that we want the code to + // be as fast as possible. To that end, we have an extremely fast path for scanning that + // handles the 99.9% case of no-unicode characters and no unicode escapes. + if (isIdentifierStartCharacter[character]) { + var result = tryFastScanIdentifierOrKeyword(character); + if (result !== SyntaxKind.None) { + return result; + } + } + + // Move the index back one and try the slow path. + index--; + if (isIdentifierStart(peekCharOrUnicodeEscape())) { + return slowScanIdentifierOrKeyword(); + } + + // Was nothing that we could understand. Report the issue and keep moving on. + var text = String.fromCharCode(character); + var messageText = getErrorMessageText(text); + reportDiagnostic(index, 1, DiagnosticCode.Unexpected_character_0, [messageText]); + + index++; + + return SyntaxKind.ErrorToken; + } + + function isIdentifierStart(interpretedChar: number): boolean { + if (isIdentifierStartCharacter[interpretedChar]) { + return true; + } + + return interpretedChar > CharacterCodes.maxAsciiCharacter && Unicode.isIdentifierStart(interpretedChar, languageVersion); + } + + function isIdentifierPart(interpretedChar: number): boolean { + if (isIdentifierPartCharacter[interpretedChar]) { + return true; + } + + return interpretedChar > CharacterCodes.maxAsciiCharacter && Unicode.isIdentifierPart(interpretedChar, languageVersion); + } + + function tryFastScanIdentifierOrKeyword(firstCharacter: number): SyntaxKind { + var startIndex = index; + var character = firstCharacter; + + // Note that we go up to the windowCount-1 so that we can read the character at the end + // of the window and check if it's *not* an identifier part character. + while (index < end) { + character = str.charCodeAt(index); + if (!isIdentifierPartCharacter[character]) { + break; + } + + index++; + } + + if (index < end && (character === CharacterCodes.backslash || character > CharacterCodes.maxAsciiCharacter)) { + // We saw a \ (which could start a unicode escape), or we saw a unicode character. + // This can't be scanned quickly. Don't update the window position and just bail out + // to the slow path. + index = startIndex; + return SyntaxKind.None; + } + else { + // Saw an ascii character that wasn't a backslash and wasn't an identifier + // character. Or we hit the end of the file This identifier is done. + + // Also check if it a keyword if it started with a keyword start char. + if (isKeywordStartCharacter[firstCharacter]) { + return ScannerUtilities.identifierKind(str, startIndex - 1, index - startIndex + 1); + } + else { + return SyntaxKind.IdentifierName; + } + } + } + + // A slow path for scanning identifiers. Called when we run into a unicode character or + // escape sequence while processing the fast path. + function slowScanIdentifierOrKeyword(): SyntaxKind { + var startIndex = index; + + do { + scanCharOrUnicodeEscape(); + } + while (isIdentifierPart(peekCharOrUnicodeEscape())); + + // From ES6 specification. + // The ReservedWord definitions are specified as literal sequences of Unicode + // characters.However, any Unicode character in a ReservedWord can also be + // expressed by a \ UnicodeEscapeSequence that expresses that same Unicode + // character's code point.Use of such escape sequences does not change the meaning + // of the ReservedWord. + // + // i.e. "\u0076ar" is the keyword 'var'. Check for that here. + var length = index - startIndex; + var text = str.substr(startIndex, length); + var valueText = massageEscapes(text); + + var keywordKind = SyntaxFacts.getTokenKind(valueText); + if (keywordKind >= SyntaxKind.FirstKeyword && keywordKind <= SyntaxKind.LastKeyword) { + // We have a keyword, but it is also variable width. We can't put represent this + // width a fixed width token. + return keywordKind | ScannerConstants.IsVariableWidthMask; + } + + return SyntaxKind.IdentifierName; + } + + function scanNumericLiteral(ch: number): SyntaxKind { + if (isHexNumericLiteral(ch)) { + scanHexNumericLiteral(); + } + else if (isOctalNumericLiteral(ch)) { + scanOctalNumericLiteral(); + } + else { + scanDecimalNumericLiteral(); + } + + return SyntaxKind.NumericLiteral; + } + + function isOctalNumericLiteral(ch: number): boolean { + return ch === CharacterCodes._0 && + CharacterInfo.isOctalDigit(str.charCodeAt(index)); + } + + function scanOctalNumericLiteral(): void { + var start = index - 1; + + while (CharacterInfo.isOctalDigit(str.charCodeAt(index))) { + index++; + } + + if (languageVersion >= ts.ScriptTarget.ES5) { + reportDiagnostic( + start, index - start, DiagnosticCode.Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher, null); + } + } + + function scanDecimalDigits(): void { + while (CharacterInfo.isDecimalDigit(str.charCodeAt(index))) { + index++; + } + } + + function scanDecimalNumericLiteral(): void { + scanDecimalDigits(); + + if (str.charCodeAt(index) === CharacterCodes.dot) { + index++; + } + + scanDecimalNumericLiteralAfterDot(); + } + + function scanDecimalNumericLiteralAfterDot() { + scanDecimalDigits(); + + // If we see an 'e' or 'E' we should only consume it if its of the form: + // e or E + // e+ E+ + // e- E- + var ch = str.charCodeAt(index); + if (ch === CharacterCodes.e || ch === CharacterCodes.E) { + // Ok, we've got 'e' or 'E'. Make sure it's followed correctly. + var nextChar1 = str.charCodeAt(index + 1); + + if (CharacterInfo.isDecimalDigit(nextChar1)) { + // e or E + // Consume 'e' or 'E' and the number portion. + index++; + scanDecimalDigits(); + } + else if (nextChar1 === CharacterCodes.minus || nextChar1 === CharacterCodes.plus) { + // e+ or E+ or e- or E- + var nextChar2 = str.charCodeAt(index + 2); + if (CharacterInfo.isDecimalDigit(nextChar2)) { + // e+ or E+ or e- or E- + // Consume first two characters and the number portion. + index += 2; + scanDecimalDigits(); + } + } + } + } + + function scanHexNumericLiteral(): void { + // Move past the x. + index++; + + while (CharacterInfo.isHexDigit(str.charCodeAt(index))) { + index++; + } + } + + function isHexNumericLiteral(ch: number): boolean { + if (ch === CharacterCodes._0) { + var ch = str.charCodeAt(index); + + if (ch === CharacterCodes.x || ch === CharacterCodes.X) { + return CharacterInfo.isHexDigit(str.charCodeAt(index + 1)); + } + } + + return false; + } + + function scanLessThanToken(): SyntaxKind { + var ch0 = str.charCodeAt(index); + if (ch0 === CharacterCodes.equals) { + index++; + return SyntaxKind.LessThanEqualsToken; + } + else if (ch0 === CharacterCodes.lessThan) { + index++; + if (str.charCodeAt(index) === CharacterCodes.equals) { + index++; + return SyntaxKind.LessThanLessThanEqualsToken; + } + else { + return SyntaxKind.LessThanLessThanToken; + } + } + else { + return SyntaxKind.LessThanToken; + } + } + + function scanGreaterThanToken(allowContextualToken: boolean): SyntaxKind { + if (allowContextualToken) { + var ch0 = str.charCodeAt(index); + if (ch0 === CharacterCodes.greaterThan) { + // >> + index++; + var ch1 = str.charCodeAt(index); + if (ch1 === CharacterCodes.greaterThan) { + // >>> + index++; + var ch2 = str.charCodeAt(index); + if (ch2 === CharacterCodes.equals) { + // >>>= + index++; + return SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken; + } + else { + return SyntaxKind.GreaterThanGreaterThanGreaterThanToken; + } + } + else if (ch1 === CharacterCodes.equals) { + // >>= + index++; + return SyntaxKind.GreaterThanGreaterThanEqualsToken; + } + else { + return SyntaxKind.GreaterThanGreaterThanToken; + } + } + else if (ch0 === CharacterCodes.equals) { + // >= + index++; + return SyntaxKind.GreaterThanEqualsToken; + } + } + + return SyntaxKind.GreaterThanToken; + } + + function scanBarToken(): SyntaxKind { + var ch = str.charCodeAt(index); + if (ch === CharacterCodes.equals) { + index++; + return SyntaxKind.BarEqualsToken; + } + else if (ch === CharacterCodes.bar) { + index++; + return SyntaxKind.BarBarToken; + } + else { + return SyntaxKind.BarToken; + } + } + + function scanCaretToken(): SyntaxKind { + if (str.charCodeAt(index) === CharacterCodes.equals) { + index++; + return SyntaxKind.CaretEqualsToken; + } + else { + return SyntaxKind.CaretToken; + } + } + + function scanAmpersandToken(): SyntaxKind { + var character = str.charCodeAt(index); + if (character === CharacterCodes.equals) { + index++; + return SyntaxKind.AmpersandEqualsToken; + } + else if (character === CharacterCodes.ampersand) { + index++; + return SyntaxKind.AmpersandAmpersandToken; + } + else { + return SyntaxKind.AmpersandToken; + } + } + + function scanPercentToken(): SyntaxKind { + if (str.charCodeAt(index) === CharacterCodes.equals) { + index++; + return SyntaxKind.PercentEqualsToken; + } + else { + return SyntaxKind.PercentToken; + } + } + + function scanMinusToken(): SyntaxKind { + var character = str.charCodeAt(index); + + if (character === CharacterCodes.equals) { + index++; + return SyntaxKind.MinusEqualsToken; + } + else if (character === CharacterCodes.minus) { + index++; + return SyntaxKind.MinusMinusToken; + } + else { + return SyntaxKind.MinusToken; + } + } + + function scanPlusToken(): SyntaxKind { + var character = str.charCodeAt(index); + if (character === CharacterCodes.equals) { + index++; + return SyntaxKind.PlusEqualsToken; + } + else if (character === CharacterCodes.plus) { + index++; + return SyntaxKind.PlusPlusToken; + } + else { + return SyntaxKind.PlusToken; + } + } + + function scanAsteriskToken(): SyntaxKind { + if (str.charCodeAt(index) === CharacterCodes.equals) { + index++; + return SyntaxKind.AsteriskEqualsToken; + } + else { + return SyntaxKind.AsteriskToken; + } + } + + function scanEqualsToken(): SyntaxKind { + var character = str.charCodeAt(index); + if (character === CharacterCodes.equals) { + index++; + + if (str.charCodeAt(index) === CharacterCodes.equals) { + index++; + + return SyntaxKind.EqualsEqualsEqualsToken; + } + else { + return SyntaxKind.EqualsEqualsToken; + } + } + else if (character === CharacterCodes.greaterThan) { + index++; + return SyntaxKind.EqualsGreaterThanToken; + } + else { + return SyntaxKind.EqualsToken; + } + } + + function scanDotToken(): SyntaxKind { + var nextChar = str.charCodeAt(index); + if (CharacterInfo.isDecimalDigit(nextChar)) { + scanDecimalNumericLiteralAfterDot(); + return SyntaxKind.NumericLiteral; + } + + if (nextChar === CharacterCodes.dot && + str.charCodeAt(index + 1) === CharacterCodes.dot) { + + index += 2; + return SyntaxKind.DotDotDotToken; + } + else { + return SyntaxKind.DotToken; + } + } + + function scanSlashToken(allowContextualToken: boolean): SyntaxKind { + // NOTE: By default, we do not try scanning a / as a regexp here. We instead consider it a + // div or div-assign. Later on, if the parser runs into a situation where it would like a + // term, and it sees one of these then it may restart us asking specifically if we could + // scan out a regex. + if (allowContextualToken) { + var result = tryScanRegularExpressionToken(); + if (result !== SyntaxKind.None) { + return result; + } + } + + if (str.charCodeAt(index) === CharacterCodes.equals) { + index++; + return SyntaxKind.SlashEqualsToken; + } + else { + return SyntaxKind.SlashToken; + } + } + + function tryScanRegularExpressionToken(): SyntaxKind { + var startIndex = index; + + var inEscape = false; + var inCharacterClass = false; + while (true) { + var ch = str.charCodeAt(index); + + if (isNaN(ch) || isNewLineCharacter(ch)) { + index = startIndex; + return SyntaxKind.None; + } + + index++; + if (inEscape) { + inEscape = false; + continue; + } + + switch (ch) { + case CharacterCodes.backslash: + // We're now in an escape. Consume the next character we see (unless it's + // a newline or null. + inEscape = true; + continue; + + case CharacterCodes.openBracket: + // If we see a [ then we're starting an character class. Note: it's ok if + // we then hit another [ inside a character class. We'll just set the value + // to true again and that's ok. + inCharacterClass = true; + continue; + + case CharacterCodes.closeBracket: + // If we ever hit a cloe bracket then we're now no longer in a character + // class. If we weren't in a character class to begin with, then this has + // no effect. + inCharacterClass = false; + continue; + + case CharacterCodes.slash: + // If we see a slash, and we're in a character class, then ignore it. + if (inCharacterClass) { + continue; + } + + // We're done with the regex. Break out of the switch (which will break + // out of hte loop. + break; + + default: + // Just consume any other characters. + continue; + } + + break; + } + + // TODO: The grammar says any identifier part is allowed here. Do we need to support + // \u identifiers here? The existing typescript parser does not. + while (isIdentifierPartCharacter[str.charCodeAt(index)]) { + index++; + } + + return SyntaxKind.RegularExpressionLiteral; + } + + function scanExclamationToken(): SyntaxKind { + if (str.charCodeAt(index) === CharacterCodes.equals) { + index++; + + if (str.charCodeAt(index) === CharacterCodes.equals) { + index++; + + return SyntaxKind.ExclamationEqualsEqualsToken; + } + else { + return SyntaxKind.ExclamationEqualsToken; + } + } + else { + return SyntaxKind.ExclamationToken; + } + } + + // Convert text into a printable form usable for an error message. This will both quote the + // string, and ensure all characters printable (i.e. by using unicode escapes when they're not). + function getErrorMessageText(text: string): string { + // For just a simple backslash, we return it as is. The default behavior of JSON.stringify + // is not what we want here. + if (text === "\\") { + return '"\\"'; + } + + return JSON.stringify(text); + } + + function skipEscapeSequence(): void { + var rewindPoint = index; + + // Consume the backslash. + index++; + + // Get the char after the backslash + var ch = str.charCodeAt(index); + if (isNaN(ch)) { + // if we're at teh end of the file, just return, the string scanning code will + // report an appropriate error. + return; + } + + index++; + switch (ch) { + case CharacterCodes.x: + case CharacterCodes.u: + index = rewindPoint; + var value = scanUnicodeOrHexEscape(/*report:*/ true); + break; + + case CharacterCodes.carriageReturn: + // If it's \r\n then consume both characters. + if (str.charCodeAt(index) === CharacterCodes.lineFeed) { + index++; + } + break; + + // We don't have to do anything special about these characters. I'm including them + // Just so it's clear that we intentially process them in the exact same way: + //case CharacterCodes.singleQuote: + //case CharacterCodes.doubleQuote: + //case CharacterCodes.backslash: + //case CharacterCodes._0: + //case CharacterCodes.b: + //case CharacterCodes.f: + //case CharacterCodes.n: + //case CharacterCodes.r: + //case CharacterCodes.t: + //case CharacterCodes.v: + //case CharacterCodes.lineFeed: + //case CharacterCodes.paragraphSeparator: + //case CharacterCodes.lineSeparator: + default: + // Any other character is ok as well. As per rule: + // EscapeSequence :: CharacterEscapeSequence + // CharacterEscapeSequence :: NonEscapeCharacter + // NonEscapeCharacter :: SourceCharacter but notEscapeCharacter or LineTerminator + break; + } + } + + function scanStringLiteral(quoteCharacter: number): SyntaxKind { + // Debug.assert(quoteCharacter === CharacterCodes.singleQuote || quoteCharacter === CharacterCodes.doubleQuote); + + while (true) { + var ch = str.charCodeAt(index); + if (ch === CharacterCodes.backslash) { + skipEscapeSequence(); + } + else if (ch === quoteCharacter) { + index++; + break; + } + else if (isNaN(ch) || isNewLineCharacter(ch)) { + reportDiagnostic(Math.min(index, end), 1, DiagnosticCode.Missing_close_quote_character, null); + break; + } + else { + index++; + } + } + + return SyntaxKind.StringLiteral; + } + + function isUnicodeEscape(character: number): boolean { + return character === CharacterCodes.backslash && + str.charCodeAt(index + 1) === CharacterCodes.u; + } + + function peekCharOrUnicodeEscape(): number { + var character = str.charCodeAt(index); + if (isUnicodeEscape(character)) { + return peekUnicodeOrHexEscape(); + } + else { + return character; + } + } + + function peekUnicodeOrHexEscape(): number { + var startIndex = index; + + // if we're peeking, then we don't want to change the position + var ch = scanUnicodeOrHexEscape(/*report:*/ false); + + index = startIndex; + + return ch; + } + + // Returns true if this was a unicode escape. + function scanCharOrUnicodeEscape(): void { + if (str.charCodeAt(index) === CharacterCodes.backslash && + str.charCodeAt(index + 1) === CharacterCodes.u) { + + scanUnicodeOrHexEscape(/*report:*/ true); + } + else { + index++; + } + } + + function scanUnicodeOrHexEscape(report: boolean): number { + var start = index; + var character = str.charCodeAt(index); + // Debug.assert(character === CharacterCodes.backslash); + index++; + + character = str.charCodeAt(index); + // Debug.assert(character === CharacterCodes.u || character === CharacterCodes.x); + + var intChar = 0; + index++; + + var count = character === CharacterCodes.u ? 4 : 2; + + for (var i = 0; i < count; i++) { + var ch2 = str.charCodeAt(index); + if (!CharacterInfo.isHexDigit(ch2)) { + if (report) { + reportDiagnostic(start, index - start, DiagnosticCode.Unrecognized_escape_sequence, null) + } + + break; + } + + intChar = (intChar << 4) + CharacterInfo.hexValue(ch2); + index++; + } + + return intChar; + } + + function fillTokenInfo(token: IScannerToken, text: ISimpleText, tokenInfo: TokenInfo): void { + var fullStart = token.fullStart(); + var fullEnd = fullStart + token.fullWidth(); + reset(text, fullStart, fullEnd); + + var leadingTriviaInfo = scanTriviaInfo(/*isTrailing: */ false); + + var start = index; + scanSyntaxKind(isContextualToken(token)); + var end = index; + + tokenInfo.leadingTriviaWidth = start - fullStart; + tokenInfo.width = end - start; + } + + reset(text, 0, text.length()); + + return { + setIndex: setIndex, + scan: scan, + fillTokenInfo: fillTokenInfo, + scanTrivia: scanTrivia, + }; + } + + export function isValidIdentifier(text: ISimpleText, languageVersion: ts.ScriptTarget): boolean { + var hadError = false; + var scanner = createScanner(languageVersion, text, () => hadError = true); + + var token = scanner.scan(/*allowContextualToken:*/ false); + + return !hadError && SyntaxFacts.isIdentifierNameOrAnyKeyword(token) && width(token) === text.length(); + } + + // A parser source that gets its data from an underlying scanner. + export interface IScannerParserSource extends Parser.IParserSource { + // The position that the scanner is currently at. + absolutePosition(): number; + + // Resets the source to this position. Any diagnostics produced after this point will be + // removed. + resetToPosition(absolutePosition: number): void; + } + + interface IScannerRewindPoint extends Parser.IRewindPoint { + // Information used by normal parser source. + absolutePosition: number; + slidingWindowIndex: number; + } + + // Parser source used in batch scenarios. Directly calls into an underlying text scanner and + // supports none of the functionality to reuse nodes. Good for when you just want want to do + // a single parse of a file. + export function createParserSource(fileName: string, text: ISimpleText, languageVersion: ts.ScriptTarget): IScannerParserSource { + // The absolute position we're at in the text we're reading from. + var _absolutePosition: number = 0; + + // The diagnostics we get while scanning. Note: this never gets rewound when we do a normal + // rewind. That's because rewinding doesn't affect the tokens created. It only affects where + // in the token stream we're pointing at. However, it will get modified if we we decide to + // reparse a / or /= as a regular expression. + var _tokenDiagnostics: Diagnostic[] = []; + + // Pool of rewind points we give out if the parser needs one. + var rewindPointPool: IScannerRewindPoint[] = []; + var rewindPointPoolCount = 0; + + var lastDiagnostic: Diagnostic = null; + var reportDiagnostic = (position: number, fullWidth: number, diagnosticKey: string, args: any[]) => { + lastDiagnostic = new Diagnostic(fileName, text.lineMap(), position, fullWidth, diagnosticKey, args); + }; + + // The sliding window that we store tokens in. + var slidingWindow = new SlidingWindow(fetchNextItem, ArrayUtilities.createArray(/*defaultWindowSize:*/ 1024, null), null); + + // The scanner we're pulling tokens from. + var scanner = createScanner(languageVersion, text, reportDiagnostic); + + function release() { + slidingWindow = null; + scanner = null; + _tokenDiagnostics = []; + rewindPointPool = []; + lastDiagnostic = null; + reportDiagnostic = null; + } + + function currentNode(): ISyntaxNode { + // The normal parser source never returns nodes. They're only returned by the + // incremental parser source. + return null; + } + + function consumeNode(node: ISyntaxNode): void { + // Should never get called. + throw Errors.invalidOperation(); + } + + function absolutePosition() { + return _absolutePosition; + } + + function tokenDiagnostics(): Diagnostic[] { + return _tokenDiagnostics; + } + + function getOrCreateRewindPoint(): IScannerRewindPoint { + if (rewindPointPoolCount === 0) { + return {}; + } + + rewindPointPoolCount--; + var result = rewindPointPool[rewindPointPoolCount]; + rewindPointPool[rewindPointPoolCount] = null; + return result; + } + + function getRewindPoint(): IScannerRewindPoint { + var slidingWindowIndex = slidingWindow.getAndPinAbsoluteIndex(); + + var rewindPoint = getOrCreateRewindPoint(); + + rewindPoint.slidingWindowIndex = slidingWindowIndex; + rewindPoint.absolutePosition = _absolutePosition; + + // rewindPoint.pinCount = slidingWindow.pinCount(); + + return rewindPoint; + } + + function rewind(rewindPoint: IScannerRewindPoint): void { + slidingWindow.rewindToPinnedIndex(rewindPoint.slidingWindowIndex); + + _absolutePosition = rewindPoint.absolutePosition; + } + + function releaseRewindPoint(rewindPoint: IScannerRewindPoint): void { + // Debug.assert(slidingWindow.pinCount() === rewindPoint.pinCount); + slidingWindow.releaseAndUnpinAbsoluteIndex((rewindPoint).absoluteIndex); + + rewindPointPool[rewindPointPoolCount] = rewindPoint; + rewindPointPoolCount++; + } + + function fetchNextItem(allowContextualToken: boolean): ISyntaxToken { + // Assert disabled because it is actually expensive enugh to affect perf. + // Debug.assert(spaceAvailable > 0); + var token = scanner.scan(allowContextualToken); + + if (lastDiagnostic === null) { + return token; + } + + // If we produced any diagnostics while creating this token, then realize the token so + // it won't be reused in incremental scenarios. + + _tokenDiagnostics.push(lastDiagnostic); + lastDiagnostic = null; + return Syntax.realizeToken(token, text); + } + + function peekToken(n: number): ISyntaxToken { + return slidingWindow.peekItemN(n); + } + + function consumeToken(token: ISyntaxToken): void { + // Debug.assert(currentToken() === token); + _absolutePosition += token.fullWidth(); + + slidingWindow.moveToNextItem(); + } + + function currentToken(): ISyntaxToken { + return slidingWindow.currentItem(/*allowContextualToken:*/ false); + } + + function removeDiagnosticsOnOrAfterPosition(position: number): void { + // walk backwards, removing any diagnostics that came after the the current token's + // full start position. + var tokenDiagnosticsLength = _tokenDiagnostics.length; + while (tokenDiagnosticsLength > 0) { + var diagnostic = _tokenDiagnostics[tokenDiagnosticsLength - 1]; + if (diagnostic.start() >= position) { + tokenDiagnosticsLength--; + } + else { + break; + } + } + + _tokenDiagnostics.length = tokenDiagnosticsLength; + } + + function resetToPosition(absolutePosition: number): void { + _absolutePosition = absolutePosition; + + // First, remove any diagnostics that came after this position. + removeDiagnosticsOnOrAfterPosition(absolutePosition); + + // Now, tell our sliding window to throw away all tokens after this position as well. + slidingWindow.disgardAllItemsFromCurrentIndexOnwards(); + + // Now tell the scanner to reset its position to this position as well. That way + // when we try to scan the next item, we'll be at the right location. + scanner.setIndex(absolutePosition); + } + + function currentContextualToken(): ISyntaxToken { + // We better be on a / or > token right now. + // Debug.assert(SyntaxFacts.isAnyDivideToken(currentToken().kind())); + + // First, we're going to rewind all our data to the point where this / or /= token started. + // That's because if it does turn out to be a regular expression, then any tokens or token + // diagnostics we produced after the original / may no longer be valid. This would actually + // be a fairly expected case. For example, if you had: / ... gibberish ... /, we may have + // produced several diagnostics in the process of scanning the tokens after the first / as + // they may not have been legal javascript okens. + // + // We also need to remove all the tokens we've gotten from the slash and onwards. They may + // not have been what the scanner would have produced if it decides that this is actually + // a regular expresion. + resetToPosition(_absolutePosition); + + // Now actually fetch the token again from the scanner. This time let it know that it + // can scan it as a regex token if it wants to. + var token = slidingWindow.currentItem(/*allowContextualToken:*/ true); + + // We have better gotten some sort of regex token. Otherwise, something *very* wrong has + // occurred. + // Debug.assert(SyntaxFacts.isAnyDivideOrRegularExpressionToken(token.kind())); + + return token; + } + + return { + text: text, + fileName: fileName, + languageVersion: languageVersion, + currentNode: currentNode, + currentToken: currentToken, + currentContextualToken: currentContextualToken, + peekToken: peekToken, + consumeNode: consumeNode, + consumeToken: consumeToken, + getRewindPoint: getRewindPoint, + rewind: rewind, + releaseRewindPoint: releaseRewindPoint, + tokenDiagnostics: tokenDiagnostics, + release: release, + absolutePosition: absolutePosition, + resetToPosition: resetToPosition, + }; + } +} \ No newline at end of file diff --git a/src/services/syntax/scannerUtilities.generated.ts b/src/services/syntax/scannerUtilities.generated.ts new file mode 100644 index 00000000000..fbf1b1cb952 --- /dev/null +++ b/src/services/syntax/scannerUtilities.generated.ts @@ -0,0 +1,142 @@ +/// + +module TypeScript { + export class ScannerUtilities { + public static identifierKind(str: string, start: number, length: number): SyntaxKind { + switch (length) { + case 2: // do, if, in + switch(str.charCodeAt(start)) { + case CharacterCodes.d: return (str.charCodeAt(start + 1) === CharacterCodes.o) ? SyntaxKind.DoKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.i: // if, in + switch(str.charCodeAt(start + 1)) { + case CharacterCodes.f: return SyntaxKind.IfKeyword; + case CharacterCodes.n: return SyntaxKind.InKeyword; + default: return SyntaxKind.IdentifierName; + } + default: return SyntaxKind.IdentifierName; + } + case 3: // any, for, get, let, new, set, try, var + switch(str.charCodeAt(start)) { + case CharacterCodes.a: return (str.charCodeAt(start + 1) === CharacterCodes.n && str.charCodeAt(start + 2) === CharacterCodes.y) ? SyntaxKind.AnyKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.f: return (str.charCodeAt(start + 1) === CharacterCodes.o && str.charCodeAt(start + 2) === CharacterCodes.r) ? SyntaxKind.ForKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.g: return (str.charCodeAt(start + 1) === CharacterCodes.e && str.charCodeAt(start + 2) === CharacterCodes.t) ? SyntaxKind.GetKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.l: return (str.charCodeAt(start + 1) === CharacterCodes.e && str.charCodeAt(start + 2) === CharacterCodes.t) ? SyntaxKind.LetKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.n: return (str.charCodeAt(start + 1) === CharacterCodes.e && str.charCodeAt(start + 2) === CharacterCodes.w) ? SyntaxKind.NewKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.s: return (str.charCodeAt(start + 1) === CharacterCodes.e && str.charCodeAt(start + 2) === CharacterCodes.t) ? SyntaxKind.SetKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.t: return (str.charCodeAt(start + 1) === CharacterCodes.r && str.charCodeAt(start + 2) === CharacterCodes.y) ? SyntaxKind.TryKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.v: return (str.charCodeAt(start + 1) === CharacterCodes.a && str.charCodeAt(start + 2) === CharacterCodes.r) ? SyntaxKind.VarKeyword : SyntaxKind.IdentifierName; + default: return SyntaxKind.IdentifierName; + } + case 4: // case, else, enum, null, this, true, void, with + switch(str.charCodeAt(start)) { + case CharacterCodes.c: return (str.charCodeAt(start + 1) === CharacterCodes.a && str.charCodeAt(start + 2) === CharacterCodes.s && str.charCodeAt(start + 3) === CharacterCodes.e) ? SyntaxKind.CaseKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.e: // else, enum + switch(str.charCodeAt(start + 1)) { + case CharacterCodes.l: return (str.charCodeAt(start + 2) === CharacterCodes.s && str.charCodeAt(start + 3) === CharacterCodes.e) ? SyntaxKind.ElseKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.n: return (str.charCodeAt(start + 2) === CharacterCodes.u && str.charCodeAt(start + 3) === CharacterCodes.m) ? SyntaxKind.EnumKeyword : SyntaxKind.IdentifierName; + default: return SyntaxKind.IdentifierName; + } + case CharacterCodes.n: return (str.charCodeAt(start + 1) === CharacterCodes.u && str.charCodeAt(start + 2) === CharacterCodes.l && str.charCodeAt(start + 3) === CharacterCodes.l) ? SyntaxKind.NullKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.t: // this, true + switch(str.charCodeAt(start + 1)) { + case CharacterCodes.h: return (str.charCodeAt(start + 2) === CharacterCodes.i && str.charCodeAt(start + 3) === CharacterCodes.s) ? SyntaxKind.ThisKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.r: return (str.charCodeAt(start + 2) === CharacterCodes.u && str.charCodeAt(start + 3) === CharacterCodes.e) ? SyntaxKind.TrueKeyword : SyntaxKind.IdentifierName; + default: return SyntaxKind.IdentifierName; + } + case CharacterCodes.v: return (str.charCodeAt(start + 1) === CharacterCodes.o && str.charCodeAt(start + 2) === CharacterCodes.i && str.charCodeAt(start + 3) === CharacterCodes.d) ? SyntaxKind.VoidKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.w: return (str.charCodeAt(start + 1) === CharacterCodes.i && str.charCodeAt(start + 2) === CharacterCodes.t && str.charCodeAt(start + 3) === CharacterCodes.h) ? SyntaxKind.WithKeyword : SyntaxKind.IdentifierName; + default: return SyntaxKind.IdentifierName; + } + case 5: // break, catch, class, const, false, super, throw, while, yield + switch(str.charCodeAt(start)) { + case CharacterCodes.b: return (str.charCodeAt(start + 1) === CharacterCodes.r && str.charCodeAt(start + 2) === CharacterCodes.e && str.charCodeAt(start + 3) === CharacterCodes.a && str.charCodeAt(start + 4) === CharacterCodes.k) ? SyntaxKind.BreakKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.c: // catch, class, const + switch(str.charCodeAt(start + 1)) { + case CharacterCodes.a: return (str.charCodeAt(start + 2) === CharacterCodes.t && str.charCodeAt(start + 3) === CharacterCodes.c && str.charCodeAt(start + 4) === CharacterCodes.h) ? SyntaxKind.CatchKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.l: return (str.charCodeAt(start + 2) === CharacterCodes.a && str.charCodeAt(start + 3) === CharacterCodes.s && str.charCodeAt(start + 4) === CharacterCodes.s) ? SyntaxKind.ClassKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.o: return (str.charCodeAt(start + 2) === CharacterCodes.n && str.charCodeAt(start + 3) === CharacterCodes.s && str.charCodeAt(start + 4) === CharacterCodes.t) ? SyntaxKind.ConstKeyword : SyntaxKind.IdentifierName; + default: return SyntaxKind.IdentifierName; + } + case CharacterCodes.f: return (str.charCodeAt(start + 1) === CharacterCodes.a && str.charCodeAt(start + 2) === CharacterCodes.l && str.charCodeAt(start + 3) === CharacterCodes.s && str.charCodeAt(start + 4) === CharacterCodes.e) ? SyntaxKind.FalseKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.s: return (str.charCodeAt(start + 1) === CharacterCodes.u && str.charCodeAt(start + 2) === CharacterCodes.p && str.charCodeAt(start + 3) === CharacterCodes.e && str.charCodeAt(start + 4) === CharacterCodes.r) ? SyntaxKind.SuperKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.t: return (str.charCodeAt(start + 1) === CharacterCodes.h && str.charCodeAt(start + 2) === CharacterCodes.r && str.charCodeAt(start + 3) === CharacterCodes.o && str.charCodeAt(start + 4) === CharacterCodes.w) ? SyntaxKind.ThrowKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.w: return (str.charCodeAt(start + 1) === CharacterCodes.h && str.charCodeAt(start + 2) === CharacterCodes.i && str.charCodeAt(start + 3) === CharacterCodes.l && str.charCodeAt(start + 4) === CharacterCodes.e) ? SyntaxKind.WhileKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.y: return (str.charCodeAt(start + 1) === CharacterCodes.i && str.charCodeAt(start + 2) === CharacterCodes.e && str.charCodeAt(start + 3) === CharacterCodes.l && str.charCodeAt(start + 4) === CharacterCodes.d) ? SyntaxKind.YieldKeyword : SyntaxKind.IdentifierName; + default: return SyntaxKind.IdentifierName; + } + case 6: // delete, export, import, module, number, public, return, static, string, switch, typeof + switch(str.charCodeAt(start)) { + case CharacterCodes.d: return (str.charCodeAt(start + 1) === CharacterCodes.e && str.charCodeAt(start + 2) === CharacterCodes.l && str.charCodeAt(start + 3) === CharacterCodes.e && str.charCodeAt(start + 4) === CharacterCodes.t && str.charCodeAt(start + 5) === CharacterCodes.e) ? SyntaxKind.DeleteKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.e: return (str.charCodeAt(start + 1) === CharacterCodes.x && str.charCodeAt(start + 2) === CharacterCodes.p && str.charCodeAt(start + 3) === CharacterCodes.o && str.charCodeAt(start + 4) === CharacterCodes.r && str.charCodeAt(start + 5) === CharacterCodes.t) ? SyntaxKind.ExportKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.i: return (str.charCodeAt(start + 1) === CharacterCodes.m && str.charCodeAt(start + 2) === CharacterCodes.p && str.charCodeAt(start + 3) === CharacterCodes.o && str.charCodeAt(start + 4) === CharacterCodes.r && str.charCodeAt(start + 5) === CharacterCodes.t) ? SyntaxKind.ImportKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.m: return (str.charCodeAt(start + 1) === CharacterCodes.o && str.charCodeAt(start + 2) === CharacterCodes.d && str.charCodeAt(start + 3) === CharacterCodes.u && str.charCodeAt(start + 4) === CharacterCodes.l && str.charCodeAt(start + 5) === CharacterCodes.e) ? SyntaxKind.ModuleKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.n: return (str.charCodeAt(start + 1) === CharacterCodes.u && str.charCodeAt(start + 2) === CharacterCodes.m && str.charCodeAt(start + 3) === CharacterCodes.b && str.charCodeAt(start + 4) === CharacterCodes.e && str.charCodeAt(start + 5) === CharacterCodes.r) ? SyntaxKind.NumberKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.p: return (str.charCodeAt(start + 1) === CharacterCodes.u && str.charCodeAt(start + 2) === CharacterCodes.b && str.charCodeAt(start + 3) === CharacterCodes.l && str.charCodeAt(start + 4) === CharacterCodes.i && str.charCodeAt(start + 5) === CharacterCodes.c) ? SyntaxKind.PublicKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.r: return (str.charCodeAt(start + 1) === CharacterCodes.e && str.charCodeAt(start + 2) === CharacterCodes.t && str.charCodeAt(start + 3) === CharacterCodes.u && str.charCodeAt(start + 4) === CharacterCodes.r && str.charCodeAt(start + 5) === CharacterCodes.n) ? SyntaxKind.ReturnKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.s: // static, string, switch + switch(str.charCodeAt(start + 1)) { + case CharacterCodes.t: // static, string + switch(str.charCodeAt(start + 2)) { + case CharacterCodes.a: return (str.charCodeAt(start + 3) === CharacterCodes.t && str.charCodeAt(start + 4) === CharacterCodes.i && str.charCodeAt(start + 5) === CharacterCodes.c) ? SyntaxKind.StaticKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.r: return (str.charCodeAt(start + 3) === CharacterCodes.i && str.charCodeAt(start + 4) === CharacterCodes.n && str.charCodeAt(start + 5) === CharacterCodes.g) ? SyntaxKind.StringKeyword : SyntaxKind.IdentifierName; + default: return SyntaxKind.IdentifierName; + } + case CharacterCodes.w: return (str.charCodeAt(start + 2) === CharacterCodes.i && str.charCodeAt(start + 3) === CharacterCodes.t && str.charCodeAt(start + 4) === CharacterCodes.c && str.charCodeAt(start + 5) === CharacterCodes.h) ? SyntaxKind.SwitchKeyword : SyntaxKind.IdentifierName; + default: return SyntaxKind.IdentifierName; + } + case CharacterCodes.t: return (str.charCodeAt(start + 1) === CharacterCodes.y && str.charCodeAt(start + 2) === CharacterCodes.p && str.charCodeAt(start + 3) === CharacterCodes.e && str.charCodeAt(start + 4) === CharacterCodes.o && str.charCodeAt(start + 5) === CharacterCodes.f) ? SyntaxKind.TypeOfKeyword : SyntaxKind.IdentifierName; + default: return SyntaxKind.IdentifierName; + } + case 7: // boolean, declare, default, extends, finally, package, private, require + switch(str.charCodeAt(start)) { + case CharacterCodes.b: return (str.charCodeAt(start + 1) === CharacterCodes.o && str.charCodeAt(start + 2) === CharacterCodes.o && str.charCodeAt(start + 3) === CharacterCodes.l && str.charCodeAt(start + 4) === CharacterCodes.e && str.charCodeAt(start + 5) === CharacterCodes.a && str.charCodeAt(start + 6) === CharacterCodes.n) ? SyntaxKind.BooleanKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.d: // declare, default + switch(str.charCodeAt(start + 1)) { + case CharacterCodes.e: // declare, default + switch(str.charCodeAt(start + 2)) { + case CharacterCodes.c: return (str.charCodeAt(start + 3) === CharacterCodes.l && str.charCodeAt(start + 4) === CharacterCodes.a && str.charCodeAt(start + 5) === CharacterCodes.r && str.charCodeAt(start + 6) === CharacterCodes.e) ? SyntaxKind.DeclareKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.f: return (str.charCodeAt(start + 3) === CharacterCodes.a && str.charCodeAt(start + 4) === CharacterCodes.u && str.charCodeAt(start + 5) === CharacterCodes.l && str.charCodeAt(start + 6) === CharacterCodes.t) ? SyntaxKind.DefaultKeyword : SyntaxKind.IdentifierName; + default: return SyntaxKind.IdentifierName; + } + default: return SyntaxKind.IdentifierName; + } + case CharacterCodes.e: return (str.charCodeAt(start + 1) === CharacterCodes.x && str.charCodeAt(start + 2) === CharacterCodes.t && str.charCodeAt(start + 3) === CharacterCodes.e && str.charCodeAt(start + 4) === CharacterCodes.n && str.charCodeAt(start + 5) === CharacterCodes.d && str.charCodeAt(start + 6) === CharacterCodes.s) ? SyntaxKind.ExtendsKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.f: return (str.charCodeAt(start + 1) === CharacterCodes.i && str.charCodeAt(start + 2) === CharacterCodes.n && str.charCodeAt(start + 3) === CharacterCodes.a && str.charCodeAt(start + 4) === CharacterCodes.l && str.charCodeAt(start + 5) === CharacterCodes.l && str.charCodeAt(start + 6) === CharacterCodes.y) ? SyntaxKind.FinallyKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.p: // package, private + switch(str.charCodeAt(start + 1)) { + case CharacterCodes.a: return (str.charCodeAt(start + 2) === CharacterCodes.c && str.charCodeAt(start + 3) === CharacterCodes.k && str.charCodeAt(start + 4) === CharacterCodes.a && str.charCodeAt(start + 5) === CharacterCodes.g && str.charCodeAt(start + 6) === CharacterCodes.e) ? SyntaxKind.PackageKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.r: return (str.charCodeAt(start + 2) === CharacterCodes.i && str.charCodeAt(start + 3) === CharacterCodes.v && str.charCodeAt(start + 4) === CharacterCodes.a && str.charCodeAt(start + 5) === CharacterCodes.t && str.charCodeAt(start + 6) === CharacterCodes.e) ? SyntaxKind.PrivateKeyword : SyntaxKind.IdentifierName; + default: return SyntaxKind.IdentifierName; + } + case CharacterCodes.r: return (str.charCodeAt(start + 1) === CharacterCodes.e && str.charCodeAt(start + 2) === CharacterCodes.q && str.charCodeAt(start + 3) === CharacterCodes.u && str.charCodeAt(start + 4) === CharacterCodes.i && str.charCodeAt(start + 5) === CharacterCodes.r && str.charCodeAt(start + 6) === CharacterCodes.e) ? SyntaxKind.RequireKeyword : SyntaxKind.IdentifierName; + default: return SyntaxKind.IdentifierName; + } + case 8: // continue, debugger, function + switch(str.charCodeAt(start)) { + case CharacterCodes.c: return (str.charCodeAt(start + 1) === CharacterCodes.o && str.charCodeAt(start + 2) === CharacterCodes.n && str.charCodeAt(start + 3) === CharacterCodes.t && str.charCodeAt(start + 4) === CharacterCodes.i && str.charCodeAt(start + 5) === CharacterCodes.n && str.charCodeAt(start + 6) === CharacterCodes.u && str.charCodeAt(start + 7) === CharacterCodes.e) ? SyntaxKind.ContinueKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.d: return (str.charCodeAt(start + 1) === CharacterCodes.e && str.charCodeAt(start + 2) === CharacterCodes.b && str.charCodeAt(start + 3) === CharacterCodes.u && str.charCodeAt(start + 4) === CharacterCodes.g && str.charCodeAt(start + 5) === CharacterCodes.g && str.charCodeAt(start + 6) === CharacterCodes.e && str.charCodeAt(start + 7) === CharacterCodes.r) ? SyntaxKind.DebuggerKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.f: return (str.charCodeAt(start + 1) === CharacterCodes.u && str.charCodeAt(start + 2) === CharacterCodes.n && str.charCodeAt(start + 3) === CharacterCodes.c && str.charCodeAt(start + 4) === CharacterCodes.t && str.charCodeAt(start + 5) === CharacterCodes.i && str.charCodeAt(start + 6) === CharacterCodes.o && str.charCodeAt(start + 7) === CharacterCodes.n) ? SyntaxKind.FunctionKeyword : SyntaxKind.IdentifierName; + default: return SyntaxKind.IdentifierName; + } + case 9: // interface, protected + switch(str.charCodeAt(start)) { + case CharacterCodes.i: return (str.charCodeAt(start + 1) === CharacterCodes.n && str.charCodeAt(start + 2) === CharacterCodes.t && str.charCodeAt(start + 3) === CharacterCodes.e && str.charCodeAt(start + 4) === CharacterCodes.r && str.charCodeAt(start + 5) === CharacterCodes.f && str.charCodeAt(start + 6) === CharacterCodes.a && str.charCodeAt(start + 7) === CharacterCodes.c && str.charCodeAt(start + 8) === CharacterCodes.e) ? SyntaxKind.InterfaceKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.p: return (str.charCodeAt(start + 1) === CharacterCodes.r && str.charCodeAt(start + 2) === CharacterCodes.o && str.charCodeAt(start + 3) === CharacterCodes.t && str.charCodeAt(start + 4) === CharacterCodes.e && str.charCodeAt(start + 5) === CharacterCodes.c && str.charCodeAt(start + 6) === CharacterCodes.t && str.charCodeAt(start + 7) === CharacterCodes.e && str.charCodeAt(start + 8) === CharacterCodes.d) ? SyntaxKind.ProtectedKeyword : SyntaxKind.IdentifierName; + default: return SyntaxKind.IdentifierName; + } + case 10: // implements, instanceof + switch(str.charCodeAt(start)) { + case CharacterCodes.i: // implements, instanceof + switch(str.charCodeAt(start + 1)) { + case CharacterCodes.m: return (str.charCodeAt(start + 2) === CharacterCodes.p && str.charCodeAt(start + 3) === CharacterCodes.l && str.charCodeAt(start + 4) === CharacterCodes.e && str.charCodeAt(start + 5) === CharacterCodes.m && str.charCodeAt(start + 6) === CharacterCodes.e && str.charCodeAt(start + 7) === CharacterCodes.n && str.charCodeAt(start + 8) === CharacterCodes.t && str.charCodeAt(start + 9) === CharacterCodes.s) ? SyntaxKind.ImplementsKeyword : SyntaxKind.IdentifierName; + case CharacterCodes.n: return (str.charCodeAt(start + 2) === CharacterCodes.s && str.charCodeAt(start + 3) === CharacterCodes.t && str.charCodeAt(start + 4) === CharacterCodes.a && str.charCodeAt(start + 5) === CharacterCodes.n && str.charCodeAt(start + 6) === CharacterCodes.c && str.charCodeAt(start + 7) === CharacterCodes.e && str.charCodeAt(start + 8) === CharacterCodes.o && str.charCodeAt(start + 9) === CharacterCodes.f) ? SyntaxKind.InstanceOfKeyword : SyntaxKind.IdentifierName; + default: return SyntaxKind.IdentifierName; + } + default: return SyntaxKind.IdentifierName; + } + case 11: return (str.charCodeAt(start) === CharacterCodes.c && str.charCodeAt(start + 1) === CharacterCodes.o && str.charCodeAt(start + 2) === CharacterCodes.n && str.charCodeAt(start + 3) === CharacterCodes.s && str.charCodeAt(start + 4) === CharacterCodes.t && str.charCodeAt(start + 5) === CharacterCodes.r && str.charCodeAt(start + 6) === CharacterCodes.u && str.charCodeAt(start + 7) === CharacterCodes.c && str.charCodeAt(start + 8) === CharacterCodes.t && str.charCodeAt(start + 9) === CharacterCodes.o && str.charCodeAt(start + 10) === CharacterCodes.r) ? SyntaxKind.ConstructorKeyword : SyntaxKind.IdentifierName; + default: return SyntaxKind.IdentifierName; + } + } + } +} \ No newline at end of file diff --git a/src/services/syntax/slidingWindow.ts b/src/services/syntax/slidingWindow.ts new file mode 100644 index 00000000000..d90fa4892c9 --- /dev/null +++ b/src/services/syntax/slidingWindow.ts @@ -0,0 +1,189 @@ +/// + +module TypeScript { + export interface ISlidingWindowSource { + // Asks the source to copy items starting at sourceIndex into the window at 'destinationIndex' + // with up to 'spaceAvailable' items. The actual number of items fetched should be given as + // the return value. + (argument: any): any; + } + + export class SlidingWindow { + + // The number of valid items in window. + public windowCount: number = 0; + + // The *absolute* index in the *full* array of items the *window* array starts at. i.e. + // if there were 100 items, and window contains tokens [70, 80), then this value would be + // 70. + public windowAbsoluteStartIndex: number = 0; + + // The index in the window array that we're at. i.e. if there 100 items and + // window contains tokens [70, 80), and we're on item 75, then this value would be '5'. + // Note: it is not absolute. It is relative to the start of the window. + public currentRelativeItemIndex: number = 0; + + // The number of pinned points there are. As long as there is at least one pinned point, we + // will not advance the start of the window array past the item marked by that pin point. + private _pinCount: number = 0; + + // If there are any outstanding rewind points, this is index in the full array of items + // that the first rewind point points to. If this is not -1, then we will not shift the + // start of the items array past this point. + private firstPinnedAbsoluteIndex: number = -1; + + constructor(// Underlying source that we retrieve items from. + private fetchNextItem: ISlidingWindowSource, + // A window of items that has been read in from the underlying source. + public window: any[], + // The default value to return when there are no more items left in the window. + private defaultValue: any, + // The length of the source we're reading from if we know it up front. -1 if we do not. + private sourceLength = -1) { + } + + private addMoreItemsToWindow(argument: any): boolean { + var sourceLength = this.sourceLength; + if (sourceLength >= 0 && this.absoluteIndex() >= sourceLength) { + return false; + } + + // First, make room for the new items if we're out of room. + if (this.windowCount >= this.window.length) { + this.tryShiftOrGrowWindow(); + } + + var item = this.fetchNextItem(argument); + + this.window[this.windowCount] = item; + + // Assert disabled because it is actually expensive enugh to affect perf. + + this.windowCount++; + return true; + } + + private tryShiftOrGrowWindow(): void { + // We want to shift if our current item is past the halfway point of the current item window. + var currentIndexIsPastWindowHalfwayPoint = this.currentRelativeItemIndex > (this.window.length >>> 1); + + // However, we can only shift if we have no outstanding rewind points. Or, if we have an + // outstanding rewind point, that it points to some point after the start of the window. + var isAllowedToShift = + this.firstPinnedAbsoluteIndex === -1 || + this.firstPinnedAbsoluteIndex > this.windowAbsoluteStartIndex; + + if (currentIndexIsPastWindowHalfwayPoint && isAllowedToShift) { + // Figure out where we're going to start shifting from. If we have no oustanding rewind + // points, then we'll start shifting over all the items starting from the current + // token we're point out. Otherwise, we'll shift starting from the first item that + // the rewind point is pointing at. + // + // We'll call that point 'N' from now on. + var shiftStartIndex = this.firstPinnedAbsoluteIndex === -1 + ? this.currentRelativeItemIndex + : this.firstPinnedAbsoluteIndex - this.windowAbsoluteStartIndex; + + // We have to shift the number of elements between the start index and the number of + // items in the window. + var shiftCount = this.windowCount - shiftStartIndex; + + // Debug.assert(shiftStartIndex > 0); + if (shiftCount > 0) { + ArrayUtilities.copy(this.window, shiftStartIndex, this.window, 0, shiftCount); + } + + // The window has now moved over to the right by N. + this.windowAbsoluteStartIndex += shiftStartIndex; + + // The number of valid items in the window has now decreased by N. + this.windowCount -= shiftStartIndex; + + // The current item now starts further to the left in the window. + this.currentRelativeItemIndex -= shiftStartIndex; + } + else { + // Grow the exisitng array. + // this.window[this.window.length * 2 - 1] = this.defaultValue; + ArrayUtilities.grow(this.window, this.window.length * 2, this.defaultValue); + } + } + + public absoluteIndex(): number { + return this.windowAbsoluteStartIndex + this.currentRelativeItemIndex; + } + + public isAtEndOfSource(): boolean { + return this.absoluteIndex() >= this.sourceLength; + } + + public getAndPinAbsoluteIndex(): number { + // Find the absolute index of this pin point. i.e. it's the index as if we had an + // array containing *all* tokens. + var absoluteIndex = this.absoluteIndex(); + var pinCount = this._pinCount++; + if (pinCount === 0) { + // If this is the first pinned point, then store off this index. We will ensure that + // we never shift the window past this point. + this.firstPinnedAbsoluteIndex = absoluteIndex; + } + + return absoluteIndex; + } + + public releaseAndUnpinAbsoluteIndex(absoluteIndex: number) { + this._pinCount--; + if (this._pinCount === 0) { + // If we just released the last outstanding pin, then we no longer need to 'fix' the + // token window so it can't move forward. Set the index to -1 so that we can shift + // things over the next time we read past the end of the array. + this.firstPinnedAbsoluteIndex = -1; + } + } + + public rewindToPinnedIndex(absoluteIndex: number): void { + // The rewind point shows which absolute item we want to rewind to. Get the relative + // index in the actual array that we want to point to. + var relativeIndex = absoluteIndex - this.windowAbsoluteStartIndex; + + // Make sure we haven't screwed anything up. + // Debug.assert(relativeIndex >= 0 && relativeIndex < this.windowCount); + + // Set ourselves back to that point. + this.currentRelativeItemIndex = relativeIndex; + } + + public currentItem(argument: any): any { + if (this.currentRelativeItemIndex >= this.windowCount) { + if (!this.addMoreItemsToWindow(argument)) { + return this.defaultValue; + } + } + + return this.window[this.currentRelativeItemIndex]; + } + + public peekItemN(n: number): any { + // Assert disabled because it is actually expensive enugh to affect perf. + // Debug.assert(n >= 0); + while (this.currentRelativeItemIndex + n >= this.windowCount) { + if (!this.addMoreItemsToWindow(/*argument:*/ null)) { + return this.defaultValue; + } + } + + return this.window[this.currentRelativeItemIndex + n]; + } + + public moveToNextItem(): void { + this.currentRelativeItemIndex++; + } + + public disgardAllItemsFromCurrentIndexOnwards(): void { + // By setting the window count to the current relative offset, we are effectively making + // any items we added to the window from the current offset onwards unusable. When we + // try to get the next item, we'll be forced to refetch them from the underlying source. + this.windowCount = this.currentRelativeItemIndex; + } + } +} \ No newline at end of file diff --git a/src/services/syntax/syntax.ts b/src/services/syntax/syntax.ts new file mode 100644 index 00000000000..2cc55ba0620 --- /dev/null +++ b/src/services/syntax/syntax.ts @@ -0,0 +1,283 @@ +/// + +module TypeScript.Syntax { + export var _nextSyntaxID: number = 1; + + export function childIndex(parent: ISyntaxElement, child: ISyntaxElement) { + for (var i = 0, n = childCount(parent); i < n; i++) { + var current = childAt(parent, i); + if (current === child) { + return i; + } + } + + throw Errors.invalidOperation(); + } + + export function nodeHasSkippedOrMissingTokens(node: ISyntaxNode): boolean { + for (var i = 0; i < childCount(node); i++) { + var child = childAt(node, i); + if (isToken(child)) { + var token = child; + // If a token is skipped, return true. Or if it is a missing token. The only empty token that is not missing is EOF + if (token.hasSkippedToken() || (width(token) === 0 && token.kind() !== SyntaxKind.EndOfFileToken)) { + return true; + } + } + } + + return false; + } + + export function isUnterminatedStringLiteral(token: ISyntaxToken): boolean { + if (token && token.kind() === SyntaxKind.StringLiteral) { + var text = token.text(); + return text.length < 2 || text.charCodeAt(text.length - 1) !== text.charCodeAt(0); + } + + return false; + } + + export function isUnterminatedMultilineCommentTrivia(trivia: ISyntaxTrivia): boolean { + if (trivia && trivia.kind() === SyntaxKind.MultiLineCommentTrivia) { + var text = trivia.fullText(); + return text.length < 4 || text.substring(text.length - 2) !== "*/"; + } + return false; + } + + export function isEntirelyInsideCommentTrivia(trivia: ISyntaxTrivia, fullStart: number, position: number): boolean { + if (trivia && trivia.isComment() && position > fullStart) { + var end = fullStart + trivia.fullWidth(); + if (position < end) { + return true; + } + else if (position === end) { + return trivia.kind() === SyntaxKind.SingleLineCommentTrivia || isUnterminatedMultilineCommentTrivia(trivia); + } + } + + return false; + } + + export function isEntirelyInsideComment(sourceUnit: SourceUnitSyntax, position: number): boolean { + var positionedToken = findToken(sourceUnit, position); + var fullStart = positionedToken.fullStart(); + var triviaList: ISyntaxTriviaList = null; + var lastTriviaBeforeToken: ISyntaxTrivia = null; + + if (positionedToken.kind() === SyntaxKind.EndOfFileToken) { + // Check if the trivia is leading on the EndOfFile token + if (positionedToken.hasLeadingTrivia()) { + triviaList = positionedToken.leadingTrivia(); + } + // Or trailing on the previous token + else { + positionedToken = previousToken(positionedToken); + if (positionedToken) { + if (positionedToken && positionedToken.hasTrailingTrivia()) { + triviaList = positionedToken.trailingTrivia(); + fullStart = end(positionedToken); + } + } + } + } + else { + if (position <= (fullStart + positionedToken.leadingTriviaWidth())) { + triviaList = positionedToken.leadingTrivia(); + } + else if (position >= (fullStart + width(positionedToken))) { + triviaList = positionedToken.trailingTrivia(); + fullStart = end(positionedToken); + } + } + + if (triviaList) { + // Try to find the trivia matching the position + for (var i = 0, n = triviaList.count(); i < n; i++) { + var trivia = triviaList.syntaxTriviaAt(i); + if (position <= fullStart) { + // Moved passed the trivia we need + break; + } + else if (position <= fullStart + trivia.fullWidth() && trivia.isComment()) { + // Found the comment trivia we were looking for + lastTriviaBeforeToken = trivia; + break; + } + + fullStart += trivia.fullWidth(); + } + } + + return lastTriviaBeforeToken && isEntirelyInsideCommentTrivia(lastTriviaBeforeToken, fullStart, position); + } + + export function isEntirelyInStringOrRegularExpressionLiteral(sourceUnit: SourceUnitSyntax, position: number): boolean { + var positionedToken = findToken(sourceUnit, position); + + if (positionedToken) { + if (positionedToken.kind() === SyntaxKind.EndOfFileToken) { + // EndOfFile token, enusre it did not follow an unterminated string literal + positionedToken = previousToken(positionedToken); + return positionedToken && positionedToken.trailingTriviaWidth() === 0 && isUnterminatedStringLiteral(positionedToken); + } + else if (position > start(positionedToken)) { + // Ensure position falls enterily within the literal if it is terminated, or the line if it is not + return (position < end(positionedToken) && (positionedToken.kind() === TypeScript.SyntaxKind.StringLiteral || positionedToken.kind() === TypeScript.SyntaxKind.RegularExpressionLiteral)) || + (position <= end(positionedToken) && isUnterminatedStringLiteral(positionedToken)); + } + } + + return false; + } + + function findSkippedTokenOnLeftInTriviaList(positionedToken: ISyntaxToken, position: number, lookInLeadingTriviaList: boolean): ISyntaxToken { + var triviaList: TypeScript.ISyntaxTriviaList = null; + var fullEnd: number; + + if (lookInLeadingTriviaList) { + triviaList = positionedToken.leadingTrivia(); + fullEnd = positionedToken.fullStart() + triviaList.fullWidth(); + } + else { + triviaList = positionedToken.trailingTrivia(); + fullEnd = TypeScript.fullEnd(positionedToken); + } + + if (triviaList && triviaList.hasSkippedToken()) { + for (var i = triviaList.count() - 1; i >= 0; i--) { + var trivia = triviaList.syntaxTriviaAt(i); + var triviaWidth = trivia.fullWidth(); + + if (trivia.isSkippedToken() && position >= fullEnd) { + return trivia.skippedToken(); + } + + fullEnd -= triviaWidth; + } + } + + return null; + } + + export function findSkippedTokenOnLeft(positionedToken: ISyntaxToken, position: number): ISyntaxToken { + var positionInLeadingTriviaList = (position < start(positionedToken)); + return findSkippedTokenOnLeftInTriviaList(positionedToken, position, /*lookInLeadingTriviaList*/ positionInLeadingTriviaList); + } + + export function getAncestorOfKind(positionedToken: ISyntaxElement, kind: SyntaxKind): ISyntaxElement { + while (positionedToken && positionedToken.parent) { + if (positionedToken.parent.kind() === kind) { + return positionedToken.parent; + } + + positionedToken = positionedToken.parent; + } + + return null; + } + + export function hasAncestorOfKind(positionedToken: ISyntaxElement, kind: SyntaxKind): boolean { + return getAncestorOfKind(positionedToken, kind) !== null; + } + + export function isIntegerLiteral(expression: IExpressionSyntax): boolean { + if (expression) { + switch (expression.kind()) { + case SyntaxKind.PlusExpression: + case SyntaxKind.NegateExpression: + // Note: if there is a + or - sign, we can only allow a normal integer following + // (and not a hex integer). i.e. -0xA is a legal expression, but it is not a + // *literal*. + expression = (expression).operand; + return isToken(expression) && IntegerUtilities.isInteger((expression).text()); + + case SyntaxKind.NumericLiteral: + // If it doesn't have a + or -, then either an integer literal or a hex literal + // is acceptable. + var text = ( expression).text(); + return IntegerUtilities.isInteger(text) || IntegerUtilities.isHexInteger(text); + } + } + + return false; + } + + export function containingNode(element: ISyntaxElement): ISyntaxNode { + var current = element.parent; + + while (current !== null && !isNode(current)) { + current = current.parent; + } + + return current; + } + + export function findTokenOnLeft(element: ISyntaxElement, position: number, includeSkippedTokens: boolean = false): ISyntaxToken { + var positionedToken = findToken(element, position, /*includeSkippedTokens*/ false); + var _start = start(positionedToken); + + // Position better fall within this token. + // Debug.assert(position >= positionedToken.fullStart()); + // Debug.assert(position < positionedToken.fullEnd() || positionedToken.token().tokenKind === SyntaxKind.EndOfFileToken); + + if (includeSkippedTokens) { + positionedToken = findSkippedTokenOnLeft(positionedToken, position) || positionedToken; + } + + // if position is after the start of the token, then this token is the token on the left. + if (position > _start) { + return positionedToken; + } + + // we're in the trivia before the start of the token. Need to return the previous token. + if (positionedToken.fullStart() === 0) { + // Already on the first token. Nothing before us. + return null; + } + + return previousToken(positionedToken, includeSkippedTokens); + } + + export function findCompleteTokenOnLeft(element: ISyntaxElement, position: number, includeSkippedTokens: boolean = false): ISyntaxToken { + var positionedToken = findToken(element, position, /*includeSkippedTokens*/ false); + + // Position better fall within this token. + // Debug.assert(position >= positionedToken.fullStart()); + // Debug.assert(position < positionedToken.fullEnd() || positionedToken.token().tokenKind === SyntaxKind.EndOfFileToken); + + if (includeSkippedTokens) { + positionedToken = findSkippedTokenOnLeft(positionedToken, position) || positionedToken; + } + + // if position is after the end of the token, then this token is the token on the left. + if (width(positionedToken) > 0 && position >= end(positionedToken)) { + return positionedToken; + } + + return previousToken(positionedToken, includeSkippedTokens); + } + + export function firstTokenInLineContainingPosition(syntaxTree: SyntaxTree, position: number): ISyntaxToken { + var current = findToken(syntaxTree.sourceUnit(), position); + while (true) { + if (isFirstTokenInLine(current, syntaxTree.lineMap())) { + break; + } + + current = previousToken(current); + } + + return current; + } + + function isFirstTokenInLine(token: ISyntaxToken, lineMap: LineMap): boolean { + var _previousToken = previousToken(token); + if (_previousToken === null) { + return true; + } + + return lineMap.getLineNumberFromPosition(end(_previousToken)) !== lineMap.getLineNumberFromPosition(start(token)); + } +} \ No newline at end of file diff --git a/src/services/syntax/syntaxDedenter.ts b/src/services/syntax/syntaxDedenter.ts new file mode 100644 index 00000000000..3c3cdb7b25f --- /dev/null +++ b/src/services/syntax/syntaxDedenter.ts @@ -0,0 +1,193 @@ +/// + +module TypeScript { + export class SyntaxDedenter extends SyntaxRewriter { + private lastTriviaWasNewLine: boolean; + + constructor(dedentFirstToken: boolean, + private dedentationAmount: number, + private minimumIndent: number, + private options: FormattingOptions) { + super(); + this.lastTriviaWasNewLine = dedentFirstToken; + } + + private abort(): void { + this.lastTriviaWasNewLine = false; + this.dedentationAmount = 0; + } + + private isAborted(): boolean { + return this.dedentationAmount === 0; + } + + public visitToken(token: ISyntaxToken): ISyntaxToken { + if (token.width() === 0) { + return token; + } + + var result = token; + if (this.lastTriviaWasNewLine) { + // have to add our indentation to every line that this token hits. + result = token.withLeadingTrivia(this.dedentTriviaList(token.leadingTrivia())); + } + + if (this.isAborted()) { + // If we've decided to stop dedenting. Then just return immediately. + return token; + } + + this.lastTriviaWasNewLine = token.hasTrailingNewLine(); + return result; + } + + private dedentTriviaList(triviaList: ISyntaxTriviaList): ISyntaxTriviaList { + var result: ISyntaxTrivia[] = []; + var dedentNextWhitespace = true; + + // Keep walking through all our trivia (as long as we haven't decided to stop dedenting). + // Adjust the indentation on any whitespace trivia at the start of a line, or any multi-line + // trivia that span multiple lines. + for (var i = 0, n = triviaList.count(); i < n && !this.isAborted(); i++) { + var trivia = triviaList.syntaxTriviaAt(i); + + var dedentThisTrivia = dedentNextWhitespace; + dedentNextWhitespace = false; + + if (dedentThisTrivia) { + if (trivia.kind() === SyntaxKind.WhitespaceTrivia) { + // We pass in if there was a following newline after this whitespace. If there + // is, then it's fine if we dedent this newline all the way to 0. Otherwise, + // if the whitespace is followed by something, then we need to determine how + // much of the whitespace we can remove. If we can't remove all that we want, + // we'll need to adjust the dedentAmount. And, if we can't remove at all, then + // we need to stop dedenting entirely. + var hasFollowingNewLine = (i < triviaList.count() - 1) && + triviaList.syntaxTriviaAt(i + 1).kind() === SyntaxKind.NewLineTrivia; + result.push(this.dedentWhitespace(trivia, hasFollowingNewLine)); + continue; + } + else if (trivia.kind() !== SyntaxKind.NewLineTrivia) { + // We wanted to dedent, but the trivia we're on isn't whitespace and wasn't a + // newline. That means that we have something like a comment at the beginning + // of the line that we can't dedent. And, if we can't dedent it, then we + // shouldn't dedent this token or any more tokens. + this.abort(); + break; + } + } + + if (trivia.kind() === SyntaxKind.MultiLineCommentTrivia) { + // This trivia may span multiple lines. If it does, we need to dedent each + // successive line of it until it terminates. + result.push(this.dedentMultiLineComment(trivia)); + continue; + } + + // All other trivia we just append to the list. + result.push(trivia); + if (trivia.kind() === SyntaxKind.NewLineTrivia) { + // We hit a newline processing the trivia. We need to add the indentation to the + // next line as well. + dedentNextWhitespace = true; + } + } + + if (dedentNextWhitespace) { + // We hit a new line as the last trivia (or there was no trivia). We want to dedent + // the next trivia, but we can't (because the token starts at the start of the line). + // If we can't dedent this, then we shouldn't dedent anymore. + this.abort(); + } + + if (this.isAborted()) { + return triviaList; + } + + return Syntax.triviaList(result); + } + + private dedentSegment(segment: string, hasFollowingNewLineTrivia: boolean): string { + // Find the position of the first non whitespace character in the segment. + var firstNonWhitespacePosition = Indentation.firstNonWhitespacePosition(segment); + + if (firstNonWhitespacePosition === segment.length) { + if (hasFollowingNewLineTrivia) { + // It was entirely whitespace trivia, with a newline after it. Just trim this down + // to an empty string. + return ""; + } + } + else if (CharacterInfo.isLineTerminator(segment.charCodeAt(firstNonWhitespacePosition))) { + // It was entirely whitespace, with a newline after it. Just trim this down to + // the newline + return segment.substring(firstNonWhitespacePosition); + } + + // It was whitespace without a newline following it. We need to try to dedent this a bit. + + // Convert that position to a column. + var firstNonWhitespaceColumn = Indentation.columnForPositionInString(segment, firstNonWhitespacePosition, this.options); + + // Find the new column we want the nonwhitespace text to start at. Ideally it would be + // whatever column it was minus the dedentation amount. However, we won't go below a + // specified minimum indent (hence, max(initial - dedentAmount, minIndent). *But* if + // the initial column was less than that minimum indent, then we'll keep it at that column. + // (hence min(initial, desired)). + var newFirstNonWhitespaceColumn = + MathPrototype.min(firstNonWhitespaceColumn, + MathPrototype.max(firstNonWhitespaceColumn - this.dedentationAmount, this.minimumIndent)); + + if (newFirstNonWhitespaceColumn === firstNonWhitespaceColumn) { + // We aren't able to detent this token. Abort what we're doing + this.abort(); + return segment; + } + + // Update the dedentation amount for all subsequent tokens we run into. + this.dedentationAmount = firstNonWhitespaceColumn - newFirstNonWhitespaceColumn; + Debug.assert(this.dedentationAmount >= 0); + + // Compute an indentation string for that. + var indentationString = Indentation.indentationString(newFirstNonWhitespaceColumn, this.options); + + // Join the new indentation and the original string without its indentation. + return indentationString + segment.substring(firstNonWhitespacePosition); + } + + private dedentWhitespace(trivia: ISyntaxTrivia, hasFollowingNewLineTrivia: boolean): ISyntaxTrivia { + var newIndentation = this.dedentSegment(trivia.fullText(), hasFollowingNewLineTrivia); + return Syntax.whitespace(newIndentation); + } + + private dedentMultiLineComment(trivia: ISyntaxTrivia): ISyntaxTrivia { + var segments = Syntax.splitMultiLineCommentTriviaIntoMultipleLines(trivia); + if (segments.length === 1) { + // If there was only one segment, then this wasn't multiline. + return trivia; + } + + for (var i = 1; i < segments.length; i++) { + var segment = segments[i]; + segments[i] = this.dedentSegment(segment, /*hasFollowingNewLineTrivia*/ false); + } + + var result = segments.join(""); + + // Create a new trivia token out of the indented lines. + return Syntax.multiLineComment(result); + } + + public static dedentNode(node: T, dedentFirstToken: boolean, dedentAmount: number, minimumIndent: number, options: FormattingOptions): T { + var dedenter = new SyntaxDedenter(dedentFirstToken, dedentAmount, minimumIndent, options); + var result = node.accept(dedenter); + + if (dedenter.isAborted()) { + // We failed to dedent a token in this node. Return the original node as is. + return node; + } + + return result; + } + } +} \ No newline at end of file diff --git a/src/services/syntax/syntaxElement.ts b/src/services/syntax/syntaxElement.ts new file mode 100644 index 00000000000..211e8b1dd86 --- /dev/null +++ b/src/services/syntax/syntaxElement.ts @@ -0,0 +1,557 @@ +/// + +module TypeScript { + // True if there is only a single instance of this element (and thus can be reused in many + // places in a syntax tree). Examples of this include our empty lists. Because empty + // lists can be found all over the tree, we want to save on memory by using this single + // instance instead of creating new objects for each case. Note: because of this, shared + // nodes don't have positions or parents. + export function isShared(element: ISyntaxElement): boolean { + var kind = element.kind(); + return (kind === SyntaxKind.List || kind === SyntaxKind.SeparatedList) && (element).length === 0; + } + + export function childCount(element: ISyntaxElement): number { + var kind = element.kind(); + if (kind === SyntaxKind.List) { + return (element).length; + } + else if (kind === SyntaxKind.SeparatedList) { + return (element).length + (element).separators.length; + } + else if (kind >= SyntaxKind.FirstToken && kind <= SyntaxKind.LastToken) { + return 0; + } + else { + return nodeMetadata[kind].length; + } + } + + export function childAt(element: ISyntaxElement, index: number): ISyntaxElement { + var kind = element.kind(); + if (kind === SyntaxKind.List) { + return (element)[index]; + } + else if (kind === SyntaxKind.SeparatedList) { + return (index % 2 === 0) ? (element)[index / 2] : (element).separators[(index - 1) / 2]; + } + else { + // Debug.assert(isNode(element)); + return (element)[nodeMetadata[element.kind()][index]]; + } + } + + export function syntaxTree(element: ISyntaxElement): SyntaxTree { + if (element) { + Debug.assert(!isShared(element)); + + while (element) { + if (element.kind() === SyntaxKind.SourceUnit) { + return (element).syntaxTree; + } + + element = element.parent; + } + } + + return null; + } + + export function parsedInStrictMode(node: ISyntaxNode): boolean { + var info = node.data; + if (info === undefined) { + return false; + } + + return (info & SyntaxConstants.NodeParsedInStrictModeMask) !== 0; + } + + export function previousToken(token: ISyntaxToken, includeSkippedTokens: boolean = false): ISyntaxToken { + if (includeSkippedTokens) { + var triviaList = token.leadingTrivia(); + if (triviaList && triviaList.hasSkippedToken()) { + var currentTriviaEndPosition = TypeScript.start(token); + for (var i = triviaList.count() - 1; i >= 0; i--) { + var trivia = triviaList.syntaxTriviaAt(i); + if (trivia.isSkippedToken()) { + return trivia.skippedToken(); + } + + currentTriviaEndPosition -= trivia.fullWidth(); + } + } + } + + var start = token.fullStart(); + if (start === 0) { + return null; + } + + return findToken(syntaxTree(token).sourceUnit(), start - 1, includeSkippedTokens); + } + + /** + * Finds a token according to the following rules: + * 1) If position matches the End of the node/s FullSpan and the node is SourceUnitSyntax, + * then the EOF token is returned. + * + * 2) If node.FullSpan.Contains(position) then the token that contains given position is + * returned. + * + * 3) Otherwise an ArgumentOutOfRangeException is thrown + * + * Note: findToken will always return a non-missing token with width greater than or equal to + * 1 (except for EOF). Empty tokens synthesized by the parser are never returned. + */ + export function findToken(element: ISyntaxElement, position: number, includeSkippedTokens: boolean = false): ISyntaxToken { + var endOfFileToken = tryGetEndOfFileAt(element, position); + if (endOfFileToken !== null) { + return endOfFileToken; + } + + if (position < 0 || position >= fullWidth(element)) { + throw Errors.argumentOutOfRange("position"); + } + + var positionedToken = findTokenWorker(element, position); + + if (includeSkippedTokens) { + return findSkippedTokenInPositionedToken(positionedToken, position) || positionedToken; + } + + // Could not find a better match + return positionedToken; + } + + export function findSkippedTokenInPositionedToken(positionedToken: ISyntaxToken, position: number): ISyntaxToken { + var positionInLeadingTriviaList = (position < start(positionedToken)); + return findSkippedTokenInTriviaList(positionedToken, position, /*lookInLeadingTriviaList*/ positionInLeadingTriviaList); + } + + export function findSkippedTokenInLeadingTriviaList(positionedToken: ISyntaxToken, position: number): ISyntaxToken { + return findSkippedTokenInTriviaList(positionedToken, position, /*lookInLeadingTriviaList*/ true); + } + + export function findSkippedTokenInTrailingTriviaList(positionedToken: ISyntaxToken, position: number): ISyntaxToken { + return findSkippedTokenInTriviaList(positionedToken, position, /*lookInLeadingTriviaList*/ false); + } + + function findSkippedTokenInTriviaList(positionedToken: ISyntaxToken, position: number, lookInLeadingTriviaList: boolean): ISyntaxToken { + var triviaList: TypeScript.ISyntaxTriviaList = null; + var fullStart: number; + + if (lookInLeadingTriviaList) { + triviaList = positionedToken.leadingTrivia(); + fullStart = positionedToken.fullStart(); + } + else { + triviaList = positionedToken.trailingTrivia(); + fullStart = end(positionedToken); + } + + if (triviaList && triviaList.hasSkippedToken()) { + for (var i = 0, n = triviaList.count(); i < n; i++) { + var trivia = triviaList.syntaxTriviaAt(i); + var triviaWidth = trivia.fullWidth(); + + if (trivia.isSkippedToken() && position >= fullStart && position <= fullStart + triviaWidth) { + return trivia.skippedToken(); + } + + fullStart += triviaWidth; + } + } + + return null; + } + + function findTokenWorker(element: ISyntaxElement, position: number): ISyntaxToken { + // Debug.assert(position >= 0 && position < this.fullWidth()); + if (isToken(element)) { + Debug.assert(fullWidth(element) > 0); + return element; + } + + if (isShared(element)) { + // This should never have been called on this element. It has a 0 width, so the client + // should have skipped over this. + throw Errors.invalidOperation(); + } + + // Consider: we could use a binary search here to find the child more quickly. + for (var i = 0, n = childCount(element); i < n; i++) { + var child = childAt(element, i); + + if (child !== null) { + var childFullWidth = fullWidth(child); + if (childFullWidth > 0) { + var childFullStart = fullStart(child); + + if (position >= childFullStart) { + var childFullEnd = childFullStart + childFullWidth; + + if (position < childFullEnd) { + return findTokenWorker(child, position); + } + } + } + } + } + + throw Errors.invalidOperation(); + } + + function tryGetEndOfFileAt(element: ISyntaxElement, position: number): ISyntaxToken { + if (element.kind() === SyntaxKind.SourceUnit && position === fullWidth(element)) { + var sourceUnit = element; + return sourceUnit.endOfFileToken; + } + + return null; + } + + export function nextToken(token: ISyntaxToken, text?: ISimpleText, includeSkippedTokens: boolean = false): ISyntaxToken { + if (token.kind() === SyntaxKind.EndOfFileToken) { + return null; + } + + if (includeSkippedTokens) { + var triviaList = token.trailingTrivia(text); + if (triviaList && triviaList.hasSkippedToken()) { + for (var i = 0, n = triviaList.count(); i < n; i++) { + var trivia = triviaList.syntaxTriviaAt(i); + if (trivia.isSkippedToken()) { + return trivia.skippedToken(); + } + } + } + } + + return findToken(syntaxTree(token).sourceUnit(), fullEnd(token), includeSkippedTokens); + } + + export function isNode(element: ISyntaxElement): boolean { + if (element !== null) { + var kind = element.kind(); + return kind >= SyntaxKind.FirstNode && kind <= SyntaxKind.LastNode; + } + + return false; + } + + function isTokenKind(kind: SyntaxKind) { + return kind >= SyntaxKind.FirstToken && kind <= SyntaxKind.LastToken + } + + export function isToken(element: ISyntaxElement): boolean { + if (element !== null) { + return isTokenKind(element.kind()); + } + + return false; + } + + export function isList(element: ISyntaxElement): boolean { + return element !== null && element.kind() === SyntaxKind.List; + } + + export function isSeparatedList(element: ISyntaxElement): boolean { + return element !== null && element.kind() === SyntaxKind.SeparatedList; + } + + export function syntaxID(element: ISyntaxElement): number { + if (isShared(element)) { + throw Errors.invalidOperation("Should not use shared syntax element as a key."); + } + + var obj = element; + if (obj._syntaxID === undefined) { + obj._syntaxID = TypeScript.Syntax._nextSyntaxID++; + } + + return obj._syntaxID; + } + + function collectTextElements(element: ISyntaxElement, elements: string[], text: ISimpleText): void { + if (element) { + if (isToken(element)) { + elements.push((element).fullText(text)); + } + else { + for (var i = 0, n = childCount(element); i < n; i++) { + collectTextElements(childAt(element, i), elements, text); + } + } + } + } + + export function fullText(element: ISyntaxElement, text?: ISimpleText): string { + if (isToken(element)) { + return (element).fullText(text); + } + + var elements: string[] = []; + collectTextElements(element, elements, text); + + return elements.join(""); + } + + export function leadingTriviaWidth(element: ISyntaxElement, text?: ISimpleText): number { + var token = firstToken(element); + return token ? token.leadingTriviaWidth(text) : 0; + } + + export function trailingTriviaWidth(element: ISyntaxElement, text?: ISimpleText): number { + var token = lastToken(element); + return token ? token.trailingTriviaWidth(text) : 0; + } + + export function firstToken(element: ISyntaxElement): ISyntaxToken { + if (element) { + var kind = element.kind(); + + if (isTokenKind(kind)) { + return fullWidth(element) > 0 || element.kind() === SyntaxKind.EndOfFileToken ? element : null; + } + + if (kind === SyntaxKind.List) { + var array = element; + for (var i = 0, n = array.length; i < n; i++) { + var token = firstToken(array[i]); + if (token) { + return token; + } + } + } + else if (kind === SyntaxKind.SeparatedList) { + var array = element; + var separators = array.separators; + for (var i = 0, n = array.length + separators.length; i < n; i++) { + var token = firstToken(i % 2 === 0 ? array[i / 2] : separators[(i - 1) / 2]); + if (token) { + return token; + } + } + } + else { + var metadata = nodeMetadata[kind]; + for (var i = 0, n = metadata.length; i < n; i++) { + var child = (element)[metadata[i]]; + var token = firstToken(child); + if (token) { + return token; + } + } + + if (element.kind() === SyntaxKind.SourceUnit) { + return (element).endOfFileToken; + } + } + } + + return null; + } + + export function lastToken(element: ISyntaxElement): ISyntaxToken { + if (isToken(element)) { + return fullWidth(element) > 0 || element.kind() === SyntaxKind.EndOfFileToken ? element : null; + } + + if (element.kind() === SyntaxKind.SourceUnit) { + return (element).endOfFileToken; + } + + for (var i = childCount(element) - 1; i >= 0; i--) { + var child = childAt(element, i); + if (child !== null) { + var token = lastToken(child); + if (token) { + return token; + } + } + } + + return null; + } + + export function fullStart(element: ISyntaxElement): number { + Debug.assert(!isShared(element)); + var token = isToken(element) ? element : firstToken(element); + return token ? token.fullStart() : -1; + } + + export function fullWidth(element: ISyntaxElement): number { + if (isToken(element)) { + return (element).fullWidth(); + } + + if (isShared(element)) { + return 0; + } + + var info = data(element); + return info >>> SyntaxConstants.NodeFullWidthShift; + } + + export function isIncrementallyUnusable(element: ISyntaxElement): boolean { + if (isToken(element)) { + return (element).isIncrementallyUnusable(); + } + + if (isShared(element)) { + // All shared lists are reusable. + return false; + } + + return (data(element) & SyntaxConstants.NodeIncrementallyUnusableMask) !== 0; + } + + function data(element: ISyntaxElement): number { + Debug.assert(isNode(element) || isList(element) || isSeparatedList(element)); + + // Lists and nodes all have a 'data' element. + var dataElement = <{ data: number }>element; + + var info = dataElement.data; + if (info === undefined) { + info = 0; + } + + if ((info & SyntaxConstants.NodeDataComputed) === 0) { + info |= computeData(element); + dataElement.data = info; + } + + return info; + } + + function computeData(element: ISyntaxElement): number { + var slotCount = childCount(element); + + var fullWidth = 0; + + // If we have no children (like an OmmittedExpressionSyntax), we're automatically not reusable. + var isIncrementallyUnusable = slotCount === 0; + + for (var i = 0, n = slotCount; i < n; i++) { + var child = childAt(element, i); + + if (child) { + fullWidth += TypeScript.fullWidth(child); + + isIncrementallyUnusable = isIncrementallyUnusable || TypeScript.isIncrementallyUnusable(child); + } + } + + return (fullWidth << SyntaxConstants.NodeFullWidthShift) + | (isIncrementallyUnusable ? SyntaxConstants.NodeIncrementallyUnusableMask : 0) + | SyntaxConstants.NodeDataComputed; + } + + export function start(element: ISyntaxElement, text?: ISimpleText): number { + var token = isToken(element) ? element : firstToken(element); + return token ? token.fullStart() + token.leadingTriviaWidth(text) : -1; + } + + export function end(element: ISyntaxElement, text?: ISimpleText): number { + var token = isToken(element) ? element : lastToken(element); + return token ? fullEnd(token) - token.trailingTriviaWidth(text) : -1; + } + + export function width(element: ISyntaxElement, text?: ISimpleText): number { + if (isToken(element)) { + return (element).text().length; + } + return fullWidth(element) - leadingTriviaWidth(element, text) - trailingTriviaWidth(element, text); + } + + export function fullEnd(element: ISyntaxElement): number { + return fullStart(element) + fullWidth(element); + } + + export function existsNewLineBetweenTokens(token1: ISyntaxToken, token2: ISyntaxToken, text: ISimpleText) { + if (token1 === token2) { + return false; + } + + if (token1 === null || token2 === null) { + return true; + } + + var lineMap = text.lineMap(); + return lineMap.getLineNumberFromPosition(end(token1, text)) !== lineMap.getLineNumberFromPosition(start(token2, text)); + } + + export interface ISyntaxElement { + kind(): SyntaxKind; + parent?: ISyntaxElement; + } + + export interface ISyntaxNode extends ISyntaxNodeOrToken { + data: number; + } + + export interface IModuleReferenceSyntax extends ISyntaxNode { + _moduleReferenceBrand: any; + } + + export interface IModuleElementSyntax extends ISyntaxNode { + } + + export interface IStatementSyntax extends IModuleElementSyntax { + _statementBrand: any; + } + + export interface ITypeMemberSyntax extends ISyntaxNode { + } + + export interface IClassElementSyntax extends ISyntaxNode { + } + + export interface IMemberDeclarationSyntax extends IClassElementSyntax { + } + + export interface IPropertyAssignmentSyntax extends IClassElementSyntax { + } + + export interface ISwitchClauseSyntax extends ISyntaxNode { + _switchClauseBrand: any; + statements: IStatementSyntax[]; + } + + export interface IExpressionSyntax extends ISyntaxNodeOrToken { + _expressionBrand: any; + } + + export interface IUnaryExpressionSyntax extends IExpressionSyntax { + _unaryExpressionBrand: any; + } + + export interface IPostfixExpressionSyntax extends IUnaryExpressionSyntax { + _postfixExpressionBrand: any; + } + + export interface ILeftHandSideExpressionSyntax extends IPostfixExpressionSyntax { + _leftHandSideExpressionBrand: any; + } + + export interface IMemberExpressionSyntax extends ILeftHandSideExpressionSyntax { + _memberExpressionBrand: any; + } + + export interface ICallExpressionSyntax extends ILeftHandSideExpressionSyntax { + _callExpressionBrand: any; + expression: IExpressionSyntax; + } + + export interface IPrimaryExpressionSyntax extends IMemberExpressionSyntax { + _primaryExpressionBrand: any; + } + + export interface ITypeSyntax extends ISyntaxNodeOrToken { + _typeBrand: any; + } + + export interface INameSyntax extends ITypeSyntax { + } +} \ No newline at end of file diff --git a/src/services/syntax/syntaxFacts.ts b/src/services/syntax/syntaxFacts.ts new file mode 100644 index 00000000000..3b8d877429c --- /dev/null +++ b/src/services/syntax/syntaxFacts.ts @@ -0,0 +1,301 @@ +/// + +module TypeScript.SyntaxFacts { + var textToKeywordKind: any = { + "any": SyntaxKind.AnyKeyword, + "boolean": SyntaxKind.BooleanKeyword, + "break": SyntaxKind.BreakKeyword, + "case": SyntaxKind.CaseKeyword, + "catch": SyntaxKind.CatchKeyword, + "class": SyntaxKind.ClassKeyword, + "continue": SyntaxKind.ContinueKeyword, + "const": SyntaxKind.ConstKeyword, + "constructor": SyntaxKind.ConstructorKeyword, + "debugger": SyntaxKind.DebuggerKeyword, + "declare": SyntaxKind.DeclareKeyword, + "default": SyntaxKind.DefaultKeyword, + "delete": SyntaxKind.DeleteKeyword, + "do": SyntaxKind.DoKeyword, + "else": SyntaxKind.ElseKeyword, + "enum": SyntaxKind.EnumKeyword, + "export": SyntaxKind.ExportKeyword, + "extends": SyntaxKind.ExtendsKeyword, + "false": SyntaxKind.FalseKeyword, + "finally": SyntaxKind.FinallyKeyword, + "for": SyntaxKind.ForKeyword, + "function": SyntaxKind.FunctionKeyword, + "get": SyntaxKind.GetKeyword, + "if": SyntaxKind.IfKeyword, + "implements": SyntaxKind.ImplementsKeyword, + "import": SyntaxKind.ImportKeyword, + "in": SyntaxKind.InKeyword, + "instanceof": SyntaxKind.InstanceOfKeyword, + "interface": SyntaxKind.InterfaceKeyword, + "let": SyntaxKind.LetKeyword, + "module": SyntaxKind.ModuleKeyword, + "new": SyntaxKind.NewKeyword, + "null": SyntaxKind.NullKeyword, + "number":SyntaxKind.NumberKeyword, + "package": SyntaxKind.PackageKeyword, + "private": SyntaxKind.PrivateKeyword, + "protected": SyntaxKind.ProtectedKeyword, + "public": SyntaxKind.PublicKeyword, + "require": SyntaxKind.RequireKeyword, + "return": SyntaxKind.ReturnKeyword, + "set": SyntaxKind.SetKeyword, + "static": SyntaxKind.StaticKeyword, + "string": SyntaxKind.StringKeyword, + "super": SyntaxKind.SuperKeyword, + "switch": SyntaxKind.SwitchKeyword, + "this": SyntaxKind.ThisKeyword, + "throw": SyntaxKind.ThrowKeyword, + "true": SyntaxKind.TrueKeyword, + "try": SyntaxKind.TryKeyword, + "typeof": SyntaxKind.TypeOfKeyword, + "var": SyntaxKind.VarKeyword, + "void": SyntaxKind.VoidKeyword, + "while": SyntaxKind.WhileKeyword, + "with": SyntaxKind.WithKeyword, + "yield": SyntaxKind.YieldKeyword, + + "{": SyntaxKind.OpenBraceToken, + "}": SyntaxKind.CloseBraceToken, + "(": SyntaxKind.OpenParenToken, + ")": SyntaxKind.CloseParenToken, + "[": SyntaxKind.OpenBracketToken, + "]": SyntaxKind.CloseBracketToken, + ".": SyntaxKind.DotToken, + "...": SyntaxKind.DotDotDotToken, + ";": SyntaxKind.SemicolonToken, + ",": SyntaxKind.CommaToken, + "<": SyntaxKind.LessThanToken, + ">": SyntaxKind.GreaterThanToken, + "<=": SyntaxKind.LessThanEqualsToken, + ">=": SyntaxKind.GreaterThanEqualsToken, + "==": SyntaxKind.EqualsEqualsToken, + "=>": SyntaxKind.EqualsGreaterThanToken, + "!=": SyntaxKind.ExclamationEqualsToken, + "===": SyntaxKind.EqualsEqualsEqualsToken, + "!==": SyntaxKind.ExclamationEqualsEqualsToken, + "+": SyntaxKind.PlusToken, + "-": SyntaxKind.MinusToken, + "*": SyntaxKind.AsteriskToken, + "%": SyntaxKind.PercentToken, + "++": SyntaxKind.PlusPlusToken, + "--": SyntaxKind.MinusMinusToken, + "<<": SyntaxKind.LessThanLessThanToken, + ">>": SyntaxKind.GreaterThanGreaterThanToken, + ">>>": SyntaxKind.GreaterThanGreaterThanGreaterThanToken, + "&": SyntaxKind.AmpersandToken, + "|": SyntaxKind.BarToken, + "^": SyntaxKind.CaretToken, + "!": SyntaxKind.ExclamationToken, + "~": SyntaxKind.TildeToken, + "&&": SyntaxKind.AmpersandAmpersandToken, + "||": SyntaxKind.BarBarToken, + "?": SyntaxKind.QuestionToken, + ":": SyntaxKind.ColonToken, + "=": SyntaxKind.EqualsToken, + "+=": SyntaxKind.PlusEqualsToken, + "-=": SyntaxKind.MinusEqualsToken, + "*=": SyntaxKind.AsteriskEqualsToken, + "%=": SyntaxKind.PercentEqualsToken, + "<<=": SyntaxKind.LessThanLessThanEqualsToken, + ">>=": SyntaxKind.GreaterThanGreaterThanEqualsToken, + ">>>=": SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken, + "&=": SyntaxKind.AmpersandEqualsToken, + "|=": SyntaxKind.BarEqualsToken, + "^=": SyntaxKind.CaretEqualsToken, + "/": SyntaxKind.SlashToken, + "/=": SyntaxKind.SlashEqualsToken, + }; + + var kindToText = new Array(); + + for (var name in textToKeywordKind) { + if (textToKeywordKind.hasOwnProperty(name)) { + // Debug.assert(kindToText[textToKeywordKind[name]] === undefined); + kindToText[textToKeywordKind[name]] = name; + } + } + + // Manually work around a bug in the CScript 5.8 runtime where 'constructor' is not + // listed when SyntaxFacts.textToKeywordKind is enumerated because it is the name of + // the constructor function. + kindToText[SyntaxKind.ConstructorKeyword] = "constructor"; + + export function getTokenKind(text: string): SyntaxKind { + if (textToKeywordKind.hasOwnProperty(text)) { + return textToKeywordKind[text]; + } + + return SyntaxKind.None; + } + + export function getText(kind: SyntaxKind): string { + var result = kindToText[kind]; + return result !== undefined ? result : null; + } + + export function isAnyKeyword(kind: SyntaxKind): boolean { + return kind >= SyntaxKind.FirstKeyword && kind <= SyntaxKind.LastKeyword; + } + + export function isAnyPunctuation(kind: SyntaxKind): boolean { + return kind >= SyntaxKind.FirstPunctuation && kind <= SyntaxKind.LastPunctuation; + } + + export function isPrefixUnaryExpressionOperatorToken(tokenKind: SyntaxKind): boolean { + return getPrefixUnaryExpressionFromOperatorToken(tokenKind) !== SyntaxKind.None; + } + + export function isBinaryExpressionOperatorToken(tokenKind: SyntaxKind): boolean { + return getBinaryExpressionFromOperatorToken(tokenKind) !== SyntaxKind.None; + } + + export function getPrefixUnaryExpressionFromOperatorToken(tokenKind: SyntaxKind): SyntaxKind { + switch (tokenKind) { + case SyntaxKind.PlusToken: return SyntaxKind.PlusExpression; + case SyntaxKind.MinusToken: return SyntaxKind.NegateExpression; + case SyntaxKind.TildeToken: return SyntaxKind.BitwiseNotExpression; + case SyntaxKind.ExclamationToken: return SyntaxKind.LogicalNotExpression; + case SyntaxKind.PlusPlusToken: return SyntaxKind.PreIncrementExpression; + case SyntaxKind.MinusMinusToken: return SyntaxKind.PreDecrementExpression; + default: return SyntaxKind.None; + } + } + + export function getPostfixUnaryExpressionFromOperatorToken(tokenKind: SyntaxKind): SyntaxKind { + switch (tokenKind) { + case SyntaxKind.PlusPlusToken: return SyntaxKind.PostIncrementExpression; + case SyntaxKind.MinusMinusToken: return SyntaxKind.PostDecrementExpression; + default: return SyntaxKind.None; + } + } + + export function getBinaryExpressionFromOperatorToken(tokenKind: SyntaxKind): SyntaxKind { + switch (tokenKind) { + case SyntaxKind.AsteriskToken: return SyntaxKind.MultiplyExpression; + case SyntaxKind.SlashToken: return SyntaxKind.DivideExpression; + case SyntaxKind.PercentToken: return SyntaxKind.ModuloExpression; + case SyntaxKind.PlusToken: return SyntaxKind.AddExpression; + case SyntaxKind.MinusToken: return SyntaxKind.SubtractExpression; + case SyntaxKind.LessThanLessThanToken: return SyntaxKind.LeftShiftExpression; + case SyntaxKind.GreaterThanGreaterThanToken: return SyntaxKind.SignedRightShiftExpression; + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: return SyntaxKind.UnsignedRightShiftExpression; + case SyntaxKind.LessThanToken: return SyntaxKind.LessThanExpression; + case SyntaxKind.GreaterThanToken: return SyntaxKind.GreaterThanExpression; + case SyntaxKind.LessThanEqualsToken: return SyntaxKind.LessThanOrEqualExpression; + case SyntaxKind.GreaterThanEqualsToken: return SyntaxKind.GreaterThanOrEqualExpression; + case SyntaxKind.InstanceOfKeyword: return SyntaxKind.InstanceOfExpression; + case SyntaxKind.InKeyword: return SyntaxKind.InExpression; + case SyntaxKind.EqualsEqualsToken: return SyntaxKind.EqualsWithTypeConversionExpression; + case SyntaxKind.ExclamationEqualsToken: return SyntaxKind.NotEqualsWithTypeConversionExpression; + case SyntaxKind.EqualsEqualsEqualsToken: return SyntaxKind.EqualsExpression; + case SyntaxKind.ExclamationEqualsEqualsToken: return SyntaxKind.NotEqualsExpression; + case SyntaxKind.AmpersandToken: return SyntaxKind.BitwiseAndExpression; + case SyntaxKind.CaretToken: return SyntaxKind.BitwiseExclusiveOrExpression; + case SyntaxKind.BarToken: return SyntaxKind.BitwiseOrExpression; + case SyntaxKind.AmpersandAmpersandToken: return SyntaxKind.LogicalAndExpression; + case SyntaxKind.BarBarToken: return SyntaxKind.LogicalOrExpression; + case SyntaxKind.BarEqualsToken: return SyntaxKind.OrAssignmentExpression; + case SyntaxKind.AmpersandEqualsToken: return SyntaxKind.AndAssignmentExpression; + case SyntaxKind.CaretEqualsToken: return SyntaxKind.ExclusiveOrAssignmentExpression; + case SyntaxKind.LessThanLessThanEqualsToken: return SyntaxKind.LeftShiftAssignmentExpression; + case SyntaxKind.GreaterThanGreaterThanEqualsToken: return SyntaxKind.SignedRightShiftAssignmentExpression; + case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: return SyntaxKind.UnsignedRightShiftAssignmentExpression; + case SyntaxKind.PlusEqualsToken: return SyntaxKind.AddAssignmentExpression; + case SyntaxKind.MinusEqualsToken: return SyntaxKind.SubtractAssignmentExpression; + case SyntaxKind.AsteriskEqualsToken: return SyntaxKind.MultiplyAssignmentExpression; + case SyntaxKind.SlashEqualsToken: return SyntaxKind.DivideAssignmentExpression; + case SyntaxKind.PercentEqualsToken: return SyntaxKind.ModuloAssignmentExpression; + case SyntaxKind.EqualsToken: return SyntaxKind.AssignmentExpression; + case SyntaxKind.CommaToken: return SyntaxKind.CommaExpression; + default: return SyntaxKind.None; + } + } + + export function getOperatorTokenFromBinaryExpression(tokenKind: SyntaxKind): SyntaxKind { + switch (tokenKind) { + case SyntaxKind.MultiplyExpression: return SyntaxKind.AsteriskToken; + case SyntaxKind.DivideExpression: return SyntaxKind.SlashToken; + case SyntaxKind.ModuloExpression: return SyntaxKind.PercentToken; + case SyntaxKind.AddExpression: return SyntaxKind.PlusToken; + case SyntaxKind.SubtractExpression: return SyntaxKind.MinusToken; + case SyntaxKind.LeftShiftExpression: return SyntaxKind.LessThanLessThanToken; + case SyntaxKind.SignedRightShiftExpression: return SyntaxKind.GreaterThanGreaterThanToken; + case SyntaxKind.UnsignedRightShiftExpression: return SyntaxKind.GreaterThanGreaterThanGreaterThanToken; + case SyntaxKind.LessThanExpression: return SyntaxKind.LessThanToken; + case SyntaxKind.GreaterThanExpression: return SyntaxKind.GreaterThanToken; + case SyntaxKind.LessThanOrEqualExpression: return SyntaxKind.LessThanEqualsToken; + case SyntaxKind.GreaterThanOrEqualExpression: return SyntaxKind.GreaterThanEqualsToken; + case SyntaxKind.InstanceOfExpression: return SyntaxKind.InstanceOfKeyword; + case SyntaxKind.InExpression: return SyntaxKind.InKeyword; + case SyntaxKind.EqualsWithTypeConversionExpression: return SyntaxKind.EqualsEqualsToken; + case SyntaxKind.NotEqualsWithTypeConversionExpression: return SyntaxKind.ExclamationEqualsToken; + case SyntaxKind.EqualsExpression: return SyntaxKind.EqualsEqualsEqualsToken; + case SyntaxKind.NotEqualsExpression: return SyntaxKind.ExclamationEqualsEqualsToken; + case SyntaxKind.BitwiseAndExpression: return SyntaxKind.AmpersandToken; + case SyntaxKind.BitwiseExclusiveOrExpression: return SyntaxKind.CaretToken; + case SyntaxKind.BitwiseOrExpression: return SyntaxKind.BarToken; + case SyntaxKind.LogicalAndExpression: return SyntaxKind.AmpersandAmpersandToken; + case SyntaxKind.LogicalOrExpression: return SyntaxKind.BarBarToken; + case SyntaxKind.OrAssignmentExpression: return SyntaxKind.BarEqualsToken; + case SyntaxKind.AndAssignmentExpression: return SyntaxKind.AmpersandEqualsToken; + case SyntaxKind.ExclusiveOrAssignmentExpression: return SyntaxKind.CaretEqualsToken; + case SyntaxKind.LeftShiftAssignmentExpression: return SyntaxKind.LessThanLessThanEqualsToken; + case SyntaxKind.SignedRightShiftAssignmentExpression: return SyntaxKind.GreaterThanGreaterThanEqualsToken; + case SyntaxKind.UnsignedRightShiftAssignmentExpression: return SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken; + case SyntaxKind.AddAssignmentExpression: return SyntaxKind.PlusEqualsToken; + case SyntaxKind.SubtractAssignmentExpression: return SyntaxKind.MinusEqualsToken; + case SyntaxKind.MultiplyAssignmentExpression: return SyntaxKind.AsteriskEqualsToken; + case SyntaxKind.DivideAssignmentExpression: return SyntaxKind.SlashEqualsToken; + case SyntaxKind.ModuloAssignmentExpression: return SyntaxKind.PercentEqualsToken; + case SyntaxKind.AssignmentExpression: return SyntaxKind.EqualsToken; + case SyntaxKind.CommaExpression: return SyntaxKind.CommaToken; + default: return SyntaxKind.None; + } + } + + export function isAssignmentOperatorToken(tokenKind: SyntaxKind): boolean { + switch (tokenKind) { + case SyntaxKind.BarEqualsToken: + case SyntaxKind.AmpersandEqualsToken: + case SyntaxKind.CaretEqualsToken: + case SyntaxKind.LessThanLessThanEqualsToken: + case SyntaxKind.GreaterThanGreaterThanEqualsToken: + case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: + case SyntaxKind.PlusEqualsToken: + case SyntaxKind.MinusEqualsToken: + case SyntaxKind.AsteriskEqualsToken: + case SyntaxKind.SlashEqualsToken: + case SyntaxKind.PercentEqualsToken: + case SyntaxKind.EqualsToken: + return true; + + default: + return false; + } + } + + export function isType(kind: SyntaxKind): boolean { + switch (kind) { + case SyntaxKind.ArrayType: + case SyntaxKind.AnyKeyword: + case SyntaxKind.NumberKeyword: + case SyntaxKind.BooleanKeyword: + case SyntaxKind.StringKeyword: + case SyntaxKind.VoidKeyword: + case SyntaxKind.FunctionType: + case SyntaxKind.ObjectType: + case SyntaxKind.ConstructorType: + case SyntaxKind.TypeQuery: + case SyntaxKind.GenericType: + case SyntaxKind.QualifiedName: + case SyntaxKind.IdentifierName: + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/src/services/syntax/syntaxFacts2.ts b/src/services/syntax/syntaxFacts2.ts new file mode 100644 index 00000000000..ec59a583e05 --- /dev/null +++ b/src/services/syntax/syntaxFacts2.ts @@ -0,0 +1,29 @@ +/// + +module TypeScript.SyntaxFacts { + export function isDirectivePrologueElement(node: ISyntaxNodeOrToken): boolean { + if (node.kind() === SyntaxKind.ExpressionStatement) { + var expressionStatement = node; + var expression = expressionStatement.expression; + + if (expression.kind() === SyntaxKind.StringLiteral) { + return true; + } + } + + return false; + } + + export function isUseStrictDirective(node: ISyntaxNodeOrToken): boolean { + var expressionStatement = node; + var stringLiteral = expressionStatement.expression; + + var text = stringLiteral.text(); + return text === '"use strict"' || text === "'use strict'"; + } + + export function isIdentifierNameOrAnyKeyword(token: ISyntaxToken): boolean { + var tokenKind = token.kind(); + return tokenKind === SyntaxKind.IdentifierName || SyntaxFacts.isAnyKeyword(tokenKind); + } +} \ No newline at end of file diff --git a/src/services/syntax/syntaxGenerator.ts b/src/services/syntax/syntaxGenerator.ts new file mode 100644 index 00000000000..21f65bb79e3 --- /dev/null +++ b/src/services/syntax/syntaxGenerator.ts @@ -0,0 +1,2883 @@ +/// +/// +/// +/// + +// Adds argument checking to the generated nodes. Argument checking appears to slow things down +// parsing about 7%. If we want to get that perf back, we can always remove this. +var argumentChecks = false; +var forPrettyPrinter = false; + +interface ITypeDefinition { + name: string; + baseType: string; + interfaces?: string[]; + children: IMemberDefinition[]; + syntaxKinds?: string[]; + isTypeScriptSpecific: boolean; +} + +interface IMemberDefinition { + name: string; + type?: string; + isToken?: boolean; + isList?: boolean; + isSeparatedList?: boolean; + requiresAtLeastOneItem?: boolean; + isOptional?: boolean; + tokenKinds?: string[]; + isTypeScriptSpecific: boolean; + elementType?: string; + excludeFromAST?: boolean; +} + +var interfaces: TypeScript.IIndexable = { + IMemberDeclarationSyntax: 'IClassElementSyntax', + IStatementSyntax: 'IModuleElementSyntax', + INameSyntax: 'ITypeSyntax', + IUnaryExpressionSyntax: 'IExpressionSyntax', + IPostfixExpressionSyntax: 'IUnaryExpressionSyntax', + ILeftHandSideExpressionSyntax: 'IPostfixExpressionSyntax', + // Note: for simplicity's sake, we merge CallExpression, NewExpression and MemberExpression + // into IMemberExpression. + IMemberExpressionSyntax: 'ILeftHandSideExpressionSyntax', + ICallExpressionSyntax: 'ILeftHandSideExpressionSyntax', + IPrimaryExpressionSyntax: 'IMemberExpressionSyntax', +}; + +var definitions:ITypeDefinition[] = [ + { + name: 'SourceUnitSyntax', + baseType: 'ISyntaxNode', + children: [ + { name: 'moduleElements', isList: true, elementType: 'IModuleElementSyntax' }, + { name: 'endOfFileToken', isToken: true } + ] + }, + { + name: 'ExternalModuleReferenceSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IModuleReferenceSyntax'], + children: [ + { name: 'requireKeyword', isToken: true, tokenKinds: ['RequireKeyword'], excludeFromAST: true }, + { name: 'openParenToken', isToken: true, excludeFromAST: true }, + { name: 'stringLiteral', isToken: true, tokenKinds: ['StringLiteral'] }, + { name: 'closeParenToken', isToken: true, excludeFromAST: true } + ], + isTypeScriptSpecific: true + }, + { + name: 'ModuleNameModuleReferenceSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IModuleReferenceSyntax'], + children: [ + { name: 'moduleName', type: 'INameSyntax' } + ], + isTypeScriptSpecific: true + }, + { + name: 'ImportDeclarationSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IModuleElementSyntax'], + children: [ + { name: 'modifiers', isList: true, elementType: 'ISyntaxToken' }, + { name: 'importKeyword', isToken: true, excludeFromAST: true }, + { name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] }, + { name: 'equalsToken', isToken: true, excludeFromAST: true }, + { name: 'moduleReference', type: 'IModuleReferenceSyntax' }, + { name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true } + ], + isTypeScriptSpecific: true + }, + { + name: 'ExportAssignmentSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IModuleElementSyntax'], + children: [ + { name: 'exportKeyword', isToken: true, excludeFromAST: true }, + { name: 'equalsToken', isToken: true, excludeFromAST: true }, + { name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] }, + { name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true } + ], + isTypeScriptSpecific: true + }, + { + name: 'ClassDeclarationSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IModuleElementSyntax'], + children: [ + { name: 'modifiers', isList: true, elementType: 'ISyntaxToken' }, + { name: 'classKeyword', isToken: true, excludeFromAST: true }, + { name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] }, + { name: 'typeParameterList', type: 'TypeParameterListSyntax', isOptional: true }, + { name: 'heritageClauses', isList: true, elementType: 'HeritageClauseSyntax' }, + { name: 'openBraceToken', isToken: true, excludeFromAST: true }, + { name: 'classElements', isList: true, elementType: 'IClassElementSyntax' }, + { name: 'closeBraceToken', isToken: true, excludeFromAST: true } + ], + isTypeScriptSpecific: true + }, + { + name: 'InterfaceDeclarationSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IModuleElementSyntax'], + children: [ + { name: 'modifiers', isList: true, elementType: 'ISyntaxToken' }, + { name: 'interfaceKeyword', isToken: true, excludeFromAST: true }, + { name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] }, + { name: 'typeParameterList', type: 'TypeParameterListSyntax', isOptional: true }, + { name: 'heritageClauses', isList: true, elementType: 'HeritageClauseSyntax' }, + { name: 'body', type: 'ObjectTypeSyntax' } + ], + isTypeScriptSpecific: true + }, + { + name: 'HeritageClauseSyntax', + baseType: 'ISyntaxNode', + children: [ + { name: 'extendsOrImplementsKeyword', isToken: true, tokenKinds: ['ExtendsKeyword', 'ImplementsKeyword'] }, + { name: 'typeNames', isSeparatedList: true, requiresAtLeastOneItem: true, elementType: 'INameSyntax' } + ], + syntaxKinds: ["ExtendsHeritageClause", "ImplementsHeritageClause"], + isTypeScriptSpecific: true + }, + { + name: 'ModuleDeclarationSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IModuleElementSyntax'], + children: [ + { name: 'modifiers', isList: true, elementType: 'ISyntaxToken' }, + { name: 'moduleKeyword', isToken: true, excludeFromAST: true }, + { name: 'name', type: 'INameSyntax', isOptional: true }, + { name: 'stringLiteral', isToken: true, isOptional: true, tokenKinds: ['StringLiteral'] }, + { name: 'openBraceToken', isToken: true, excludeFromAST: true }, + { name: 'moduleElements', isList: true, elementType: 'IModuleElementSyntax' }, + { name: 'closeBraceToken', isToken: true, excludeFromAST: true } + ], + isTypeScriptSpecific: true + }, + { + name: 'FunctionDeclarationSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IStatementSyntax'], + children: [ + { name: 'modifiers', isList: true, elementType: 'ISyntaxToken', isTypeScriptSpecific: true }, + { name: 'functionKeyword', isToken: true, excludeFromAST: true }, + { name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] }, + { name: 'callSignature', type: 'CallSignatureSyntax' }, + { name: 'block', type: 'BlockSyntax', isOptional: true }, + { name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true } + ] + }, + { + name: 'VariableStatementSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IStatementSyntax'], + children: [ + { name: 'modifiers', isList: true, elementType: 'ISyntaxToken', isTypeScriptSpecific: true }, + { name: 'variableDeclaration', type: 'VariableDeclarationSyntax' }, + { name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true } + ] + }, + { + name: 'VariableDeclarationSyntax', + baseType: 'ISyntaxNode', + children: [ + { name: 'varKeyword', isToken: true }, + { name: 'variableDeclarators', isSeparatedList: true, requiresAtLeastOneItem: true, elementType: 'VariableDeclaratorSyntax' } + ] + }, + { + name: 'VariableDeclaratorSyntax', + baseType: 'ISyntaxNode', + children: [ + { name: 'propertyName', isToken: true, tokenKinds: ['IdentifierName', 'StringLiteral', 'NumericLiteral'] }, + { name: 'typeAnnotation', type: 'TypeAnnotationSyntax', isOptional: true, isTypeScriptSpecific: true }, + { name: 'equalsValueClause', type: 'EqualsValueClauseSyntax', isOptional: true } + ] + }, + { + name: 'EqualsValueClauseSyntax', + baseType: 'ISyntaxNode', + children: [ + { name: 'equalsToken', isToken: true, excludeFromAST: true }, + { name: 'value', type: 'IExpressionSyntax' } + ] + }, + { + name: 'PrefixUnaryExpressionSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IUnaryExpressionSyntax'], + children: [ + { name: 'operatorToken', isToken: true, tokenKinds: ['PlusPlusToken', 'MinusMinusToken', 'PlusToken', 'MinusToken', 'TildeToken', 'ExclamationToken'] }, + { name: 'operand', type: 'IUnaryExpressionSyntax' } + ], + syntaxKinds: ["PreIncrementExpression", "PreDecrementExpression", "PlusExpression", "NegateExpression", "BitwiseNotExpression", "LogicalNotExpression"], + }, + { + name: 'ArrayLiteralExpressionSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IPrimaryExpressionSyntax'], + children: [ + { name: 'openBracketToken', isToken: true, excludeFromAST: true }, + { name: 'expressions', isSeparatedList: true, elementType: 'IExpressionSyntax' }, + { name: 'closeBracketToken', isToken: true, excludeFromAST: true } + ] + }, + { + name: 'OmittedExpressionSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IExpressionSyntax'], + children: [] + }, + { + name: 'ParenthesizedExpressionSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IPrimaryExpressionSyntax'], + children: [ + { name: 'openParenToken', isToken: true, excludeFromAST: true }, + { name: 'expression', type: 'IExpressionSyntax' }, + { name: 'closeParenToken', isToken: true, excludeFromAST: true } + ] + }, + { + name: 'SimpleArrowFunctionExpressionSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IUnaryExpressionSyntax'], + children: [ + { name: 'parameter', type: 'ParameterSyntax' }, + { name: 'equalsGreaterThanToken', isToken: true, excludeFromAST: true }, + { name: 'block', type: 'BlockSyntax', isOptional: true }, + { name: 'expression', type: 'IExpressionSyntax', isOptional: true } + ], + isTypeScriptSpecific: true + }, + { + name: 'ParenthesizedArrowFunctionExpressionSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IUnaryExpressionSyntax'], + children: [ + { name: 'callSignature', type: 'CallSignatureSyntax' }, + { name: 'equalsGreaterThanToken', isToken: true, excludeFromAST: true }, + { name: 'block', type: 'BlockSyntax', isOptional: true }, + { name: 'expression', type: 'IExpressionSyntax', isOptional: true } + ], + isTypeScriptSpecific: true + }, + { + name: 'QualifiedNameSyntax', + baseType: 'ISyntaxNode', + interfaces: ['INameSyntax'], + children: [ + { name: 'left', type: 'INameSyntax' }, + { name: 'dotToken', isToken: true, excludeFromAST: true }, + { name: 'right', isToken: true, tokenKinds:['IdentifierName'] } + ], + // Qualified names only show up in Types, which are TypeScript specific. Note that a dotted + // expression (like A.B.Foo()) is a MemberAccessExpression, not a QualifiedName. + isTypeScriptSpecific: true + }, + { + name: 'TypeArgumentListSyntax', + baseType: 'ISyntaxNode', + children: [ + { name: 'lessThanToken', isToken: true }, + { name: 'typeArguments', isSeparatedList: true, elementType: 'ITypeSyntax' }, + { name: 'greaterThanToken', isToken: true, excludeFromAST: true } + ], + isTypeScriptSpecific: true + }, + { + name: 'ConstructorTypeSyntax', + baseType: 'ISyntaxNode', + interfaces: ['ITypeSyntax'], + children: [ + { name: 'newKeyword', isToken: true, excludeFromAST: true }, + { name: 'typeParameterList', type: 'TypeParameterListSyntax', isOptional: true }, + { name: 'parameterList', type: 'ParameterListSyntax' }, + { name: 'equalsGreaterThanToken', isToken: true, excludeFromAST: true }, + { name: 'type', type: 'ITypeSyntax' } + ], + isTypeScriptSpecific: true + }, + { + name: 'FunctionTypeSyntax', + baseType: 'ISyntaxNode', + interfaces: ['ITypeSyntax'], + children: [ + { name: 'typeParameterList', type: 'TypeParameterListSyntax', isOptional: true }, + { name: 'parameterList', type: 'ParameterListSyntax' }, + { name: 'equalsGreaterThanToken', isToken: true, excludeFromAST: true }, + { name: 'type', type: 'ITypeSyntax' } + ], + isTypeScriptSpecific: true + }, + { + name: 'ObjectTypeSyntax', + baseType: 'ISyntaxNode', + interfaces: ['ITypeSyntax'], + children: [ + { name: 'openBraceToken', isToken: true, excludeFromAST: true }, + { name: 'typeMembers', isSeparatedList: true, elementType: 'ITypeMemberSyntax' }, + { name: 'closeBraceToken', isToken: true, excludeFromAST: true } + ], + isTypeScriptSpecific: true + }, + { + name: 'ArrayTypeSyntax', + baseType: 'ISyntaxNode', + interfaces: ['ITypeSyntax'], + children: [ + { name: 'type', type: 'ITypeSyntax' }, + { name: 'openBracketToken', isToken: true, excludeFromAST: true }, + { name: 'closeBracketToken', isToken: true, excludeFromAST: true } + ], + isTypeScriptSpecific: true + }, + { + name: 'GenericTypeSyntax', + baseType: 'ISyntaxNode', + interfaces: ['ITypeSyntax'], + children: [ + { name: 'name', type: 'INameSyntax' }, + { name: 'typeArgumentList', type: 'TypeArgumentListSyntax' } + ], + isTypeScriptSpecific: true + }, + { + name: 'TypeQuerySyntax', + baseType: 'ISyntaxNode', + interfaces: ['ITypeSyntax'], + children: [ + { name: 'typeOfKeyword', isToken: true, excludeFromAST: true }, + { name: 'name', type: 'INameSyntax' } + ], + isTypeScriptSpecific: true + }, + { + name: 'TypeAnnotationSyntax', + baseType: 'ISyntaxNode', + children: [ + { name: 'colonToken', isToken: true, excludeFromAST: true }, + { name: 'type', type: 'ITypeSyntax' } + ], + isTypeScriptSpecific: true + }, + { + name: 'BlockSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IStatementSyntax'], + children: [ + { name: 'openBraceToken', isToken: true }, + { name: 'statements', isList: true, elementType: 'IStatementSyntax' }, + { name: 'closeBraceToken', isToken: true, excludeFromAST: true } + ] + }, + { + name: 'ParameterSyntax', + baseType: 'ISyntaxNode', + children: [ + { name: 'dotDotDotToken', isToken: true, isOptional: true, isTypeScriptSpecific: true }, + { name: 'modifiers', isList: true, elementType: 'ISyntaxToken' }, + { name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] }, + { name: 'questionToken', isToken: true, isOptional: true, isTypeScriptSpecific: true }, + { name: 'typeAnnotation', type: 'TypeAnnotationSyntax', isOptional: true, isTypeScriptSpecific: true }, + { name: 'equalsValueClause', type: 'EqualsValueClauseSyntax', isOptional: true, isTypeScriptSpecific: true } + ] + }, + { + name: 'MemberAccessExpressionSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IMemberExpressionSyntax', 'ICallExpressionSyntax'], + children: [ + { name: 'expression', type: 'ILeftHandSideExpressionSyntax' }, + { name: 'dotToken', isToken: true, excludeFromAST: true }, + { name: 'name', isToken: true, tokenKinds: ['IdentifierName'] } + ] + }, + { + name: 'PostfixUnaryExpressionSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IPostfixExpressionSyntax'], + children: [ + { name: 'operand', type: 'ILeftHandSideExpressionSyntax' }, + { name: 'operatorToken', isToken: true, tokenKinds:['PlusPlusToken', 'MinusMinusToken'] } + ], + syntaxKinds: ["PostIncrementExpression", "PostDecrementExpression"], + }, + { + name: 'ElementAccessExpressionSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IMemberExpressionSyntax', 'ICallExpressionSyntax'], + children: [ + { name: 'expression', type: 'ILeftHandSideExpressionSyntax' }, + { name: 'openBracketToken', isToken: true, excludeFromAST: true }, + { name: 'argumentExpression', type: 'IExpressionSyntax' }, + { name: 'closeBracketToken', isToken: true, excludeFromAST: true } + ] + }, + { + name: 'InvocationExpressionSyntax', + baseType: 'ISyntaxNode', + interfaces: ['ICallExpressionSyntax'], + children: [ + { name: 'expression', type: 'ILeftHandSideExpressionSyntax' }, + { name: 'argumentList', type: 'ArgumentListSyntax' } + ] + }, + { + name: 'ArgumentListSyntax', + baseType: 'ISyntaxNode', + children: [ + { name: 'typeArgumentList', type: 'TypeArgumentListSyntax', isOptional: true }, + { name: 'openParenToken', isToken: true, excludeFromAST: true }, + { name: 'arguments', isSeparatedList: true, elementType: 'IExpressionSyntax' }, + { name: 'closeParenToken', isToken: true, excludeFromAST: true } + ] + }, + { + name: 'BinaryExpressionSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IExpressionSyntax'], + children: [ + { name: 'left', type: 'IExpressionSyntax' }, + { name: 'operatorToken', isToken: true, + tokenKinds:['AsteriskToken', 'SlashToken', 'PercentToken', 'PlusToken', 'MinusToken', 'LessThanLessThanToken', + 'GreaterThanGreaterThanToken', 'GreaterThanGreaterThanGreaterThanToken', 'LessThanToken', + 'GreaterThanToken', 'LessThanEqualsToken', 'GreaterThanEqualsToken', 'InstanceOfKeyword', + 'InKeyword', 'EqualsEqualsToken', 'ExclamationEqualsToken', 'EqualsEqualsEqualsToken', + 'ExclamationEqualsEqualsToken', 'AmpersandToken', 'CaretToken', 'BarToken', 'AmpersandAmpersandToken', + 'BarBarToken', 'BarEqualsToken', 'AmpersandEqualsToken', 'CaretEqualsToken', 'LessThanLessThanEqualsToken', + 'GreaterThanGreaterThanEqualsToken', 'GreaterThanGreaterThanGreaterThanEqualsToken', 'PlusEqualsToken', + 'MinusEqualsToken', 'AsteriskEqualsToken', 'SlashEqualsToken', 'PercentEqualsToken', 'EqualsToken', + 'CommaToken'] }, + { name: 'right', type: 'IExpressionSyntax' } + ], + syntaxKinds: ["MultiplyExpression", "DivideExpression", "ModuloExpression", "AddExpression", "SubtractExpression", "LeftShiftExpression", + "SignedRightShiftExpression", "UnsignedRightShiftExpression", "LessThanExpression", + "GreaterThanExpression", "LessThanOrEqualExpression", "GreaterThanOrEqualExpression", "InstanceOfExpression", + "InExpression", "EqualsWithTypeConversionExpression", "NotEqualsWithTypeConversionExpression", "EqualsExpression", + "NotEqualsExpression", "BitwiseAndExpression", "BitwiseExclusiveOrExpression", "BitwiseOrExpression", "LogicalAndExpression", + "LogicalOrExpression", "OrAssignmentExpression", "AndAssignmentExpression", "ExclusiveOrAssignmentExpression", "LeftShiftAssignmentExpression", + "SignedRightShiftAssignmentExpression", "UnsignedRightShiftAssignmentExpression", "AddAssignmentExpression", + "SubtractAssignmentExpression", "MultiplyAssignmentExpression", "DivideAssignmentExpression", "ModuloAssignmentExpression", "AssignmentExpression", + "CommaExpression"] + }, + { + name: 'ConditionalExpressionSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IExpressionSyntax'], + children: [ + { name: 'condition', type: 'IExpressionSyntax' }, + { name: 'questionToken', isToken: true, excludeFromAST: true }, + { name: 'whenTrue', type: 'IExpressionSyntax' }, + { name: 'colonToken', isToken: true, excludeFromAST: true }, + { name: 'whenFalse', type: 'IExpressionSyntax' } + ] + }, + { + name: 'ConstructSignatureSyntax', + baseType: 'ISyntaxNode', + interfaces: ['ITypeMemberSyntax'], + children: [ + { name: 'newKeyword', isToken: true, excludeFromAST: true }, + { name: 'callSignature', type: 'CallSignatureSyntax' } + ], + isTypeScriptSpecific: true + }, + { + name: 'MethodSignatureSyntax', + baseType: 'ISyntaxNode', + interfaces: ['ITypeMemberSyntax'], + children: [ + { name: 'propertyName', isToken: true, tokenKinds: ['IdentifierName', 'StringLiteral', 'NumericLiteral'] }, + { name: 'questionToken', isToken: true, isOptional: true, itTypeScriptSpecific: true }, + { name: 'callSignature', type: 'CallSignatureSyntax' } + ] + }, + { + name: 'IndexSignatureSyntax', + baseType: 'ISyntaxNode', + interfaces: ['ITypeMemberSyntax'], + children: [ + { name: 'openBracketToken', isToken: true }, + { name: 'parameters', isSeparatedList: true, elementType: 'ParameterSyntax' }, + { name: 'closeBracketToken', isToken: true }, + { name: 'typeAnnotation', type: 'TypeAnnotationSyntax', isOptional: true } + ], + isTypeScriptSpecific: true + }, + { + name: 'PropertySignatureSyntax', + baseType: 'ISyntaxNode', + interfaces: ['ITypeMemberSyntax'], + children: [ + { name: 'propertyName', isToken: true, tokenKinds: ['IdentifierName', 'StringLiteral', 'NumericLiteral'] }, + { name: 'questionToken', isToken: true, isOptional: true }, + { name: 'typeAnnotation', type: 'TypeAnnotationSyntax', isOptional: true } + ], + isTypeScriptSpecific: true + }, + { + name: 'CallSignatureSyntax', + baseType: 'ISyntaxNode', + interfaces: ['ITypeMemberSyntax'], + children: [ + { name: 'typeParameterList', type: 'TypeParameterListSyntax', isOptional: true, isTypeScriptSpecific: true }, + { name: 'parameterList', type: 'ParameterListSyntax' }, + { name: 'typeAnnotation', type: 'TypeAnnotationSyntax', isOptional: true, isTypeScriptSpecific: true } + ] + }, + { + name: 'ParameterListSyntax', + baseType: 'ISyntaxNode', + children: [ + { name: 'openParenToken', isToken: true, excludeFromAST: true }, + { name: 'parameters', isSeparatedList: true, elementType: 'ParameterSyntax' }, + { name: 'closeParenToken', isToken: true, excludeFromAST: true } + ] + }, + { + name: 'TypeParameterListSyntax', + baseType: 'ISyntaxNode', + children: [ + { name: 'lessThanToken', isToken: true }, + { name: 'typeParameters', isSeparatedList: true, elementType: 'TypeParameterSyntax' }, + { name: 'greaterThanToken', isToken: true, excludeFromAST: true } + ], + isTypeScriptSpecific: true + }, + { + name: 'TypeParameterSyntax', + baseType: 'ISyntaxNode', + children: [ + { name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] }, + { name: 'constraint', type: 'ConstraintSyntax', isOptional: true } + ], + isTypeScriptSpecific: true + }, + { + name: 'ConstraintSyntax', + baseType: 'ISyntaxNode', + children: [ + { name: 'extendsKeyword', isToken: true, excludeFromAST: true }, + // Expression only in error cases. + { name: 'typeOrExpression', type: 'ISyntaxNodeOrToken' } + ], + isTypeScriptSpecific: true + }, + { + name: 'ElseClauseSyntax', + baseType: 'ISyntaxNode', + children: [ + { name: 'elseKeyword', isToken: true, excludeFromAST: true }, + { name: 'statement', type: 'IStatementSyntax' } + ] + }, + { + name: 'IfStatementSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IStatementSyntax'], + children: [ + { name: 'ifKeyword', isToken: true, excludeFromAST: true }, + { name: 'openParenToken', isToken: true, excludeFromAST: true }, + { name: 'condition', type: 'IExpressionSyntax' }, + { name: 'closeParenToken', isToken: true, excludeFromAST: true }, + { name: 'statement', type: 'IStatementSyntax' }, + { name: 'elseClause', type: 'ElseClauseSyntax', isOptional: true } + ] + }, + { + name: 'ExpressionStatementSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IStatementSyntax'], + children: [ + { name: 'expression', type: 'IExpressionSyntax' }, + { name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true } + ] + }, + { + name: 'ConstructorDeclarationSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IClassElementSyntax'], + children: [ + { name: 'modifiers', isList: true, elementType: 'ISyntaxToken' }, + { name: 'constructorKeyword', isToken: true }, + { name: 'callSignature', type: 'CallSignatureSyntax' }, + { name: 'block', type: 'BlockSyntax', isOptional: true }, + { name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true } + ], + isTypeScriptSpecific: true + }, + { + name: 'MemberFunctionDeclarationSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IMemberDeclarationSyntax'], + children: [ + { name: 'modifiers', isList: true, elementType: 'ISyntaxToken' }, + { name: 'propertyName', isToken: true, tokenKinds: ['IdentifierName', 'StringLiteral', 'NumericLiteral'] }, + { name: 'callSignature', type: 'CallSignatureSyntax' }, + { name: 'block', type: 'BlockSyntax', isOptional: true }, + { name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true } + ], + isTypeScriptSpecific: true + }, + { + name: 'GetAccessorSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IMemberDeclarationSyntax', 'IPropertyAssignmentSyntax' ], + children: [ + { name: 'modifiers', isList: true, elementType: 'ISyntaxToken', isTypeScriptSpecific: true }, + { name: 'getKeyword', isToken: true, excludeFromAST: true }, + { name: 'propertyName', isToken: true, tokenKinds: ['IdentifierName', 'StringLiteral', 'NumericLiteral'] }, + { name: 'callSignature', type: 'CallSignatureSyntax' }, + { name: 'block', type: 'BlockSyntax' } + ] + }, + { + name: 'SetAccessorSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IMemberDeclarationSyntax', 'IPropertyAssignmentSyntax'], + children: [ + { name: 'modifiers', isList: true, elementType: 'ISyntaxToken', isTypeScriptSpecific: true }, + { name: 'setKeyword', isToken: true, excludeFromAST: true }, + { name: 'propertyName', isToken: true, tokenKinds: ['IdentifierName', 'StringLiteral', 'NumericLiteral'] }, + { name: 'callSignature', type: 'CallSignatureSyntax' }, + { name: 'block', type: 'BlockSyntax' } + ], + isTypeScriptSpecific: true + }, + { + name: 'MemberVariableDeclarationSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IMemberDeclarationSyntax'], + children: [ + { name: 'modifiers', isList: true, elementType: 'ISyntaxToken' }, + { name: 'variableDeclarator', type: 'VariableDeclaratorSyntax' }, + { name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true } + ], + isTypeScriptSpecific: true + }, + { + name: 'IndexMemberDeclarationSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IClassElementSyntax'], + children: [ + { name: 'modifiers', isList: true, elementType: 'ISyntaxToken' }, + { name: 'indexSignature', type: 'IndexSignatureSyntax' }, + { name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true } + ], + isTypeScriptSpecific: true + }, + { + name: 'ThrowStatementSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IStatementSyntax'], + children: [ + { name: 'throwKeyword', isToken: true, excludeFromAST: true }, + { name: 'expression', type: 'IExpressionSyntax' }, + { name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true } + ] + }, + { + name: 'ReturnStatementSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IStatementSyntax'], + children: [ + { name: 'returnKeyword', isToken: true }, + { name: 'expression', type: 'IExpressionSyntax', isOptional: true }, + { name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true } + ] + }, + { + name: 'ObjectCreationExpressionSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IPrimaryExpressionSyntax'], + children: [ + { name: 'newKeyword', isToken: true, excludeFromAST: true }, + { name: 'expression', type: 'IMemberExpressionSyntax' }, + { name: 'argumentList', type: 'ArgumentListSyntax', isOptional: true } + ] + }, + { + name: 'SwitchStatementSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IStatementSyntax'], + children: [ + { name: 'switchKeyword', isToken: true, excludeFromAST: true }, + { name: 'openParenToken', isToken: true, excludeFromAST: true }, + { name: 'expression', type: 'IExpressionSyntax' }, + { name: 'closeParenToken', isToken: true, excludeFromAST: true }, + { name: 'openBraceToken', isToken: true, excludeFromAST: true }, + { name: 'switchClauses', isList: true, elementType: 'ISwitchClauseSyntax' }, + { name: 'closeBraceToken', isToken: true, excludeFromAST: true } + ] + }, + { + name: 'CaseSwitchClauseSyntax', + baseType: 'ISyntaxNode', + interfaces: ['ISwitchClauseSyntax'], + children: [ + { name: 'caseKeyword', isToken: true, excludeFromAST: true }, + { name: 'expression', type: 'IExpressionSyntax' }, + { name: 'colonToken', isToken: true, excludeFromAST: true}, + { name: 'statements', isList: true, elementType: 'IStatementSyntax' } + ] + }, + { + name: 'DefaultSwitchClauseSyntax', + baseType: 'ISyntaxNode', + interfaces: ['ISwitchClauseSyntax'], + children: [ + { name: 'defaultKeyword', isToken: true, excludeFromAST: true }, + { name: 'colonToken', isToken: true, excludeFromAST: true }, + { name: 'statements', isList: true, elementType: 'IStatementSyntax' } + ] + }, + { + name: 'BreakStatementSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IStatementSyntax'], + children: [ + { name: 'breakKeyword', isToken: true }, + { name: 'identifier', isToken: true, isOptional: true, tokenKinds: ['IdentifierName'] }, + { name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true } + ] + }, + { + name: 'ContinueStatementSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IStatementSyntax'], + children: [ + { name: 'continueKeyword', isToken: true }, + { name: 'identifier', isToken: true, isOptional: true, tokenKinds: ['IdentifierName'] }, + { name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true } + ] + }, + { + name: 'ForStatementSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IStatementSyntax'], + children: [ + { name: 'forKeyword', isToken: true, excludeFromAST: true }, + { name: 'openParenToken', isToken: true, excludeFromAST: true }, + { name: 'variableDeclaration', type: 'VariableDeclarationSyntax', isOptional: true }, + { name: 'initializer', type: 'IExpressionSyntax', isOptional: true }, + { name: 'firstSemicolonToken', isToken: true, tokenKinds: ['SemicolonToken'], excludeFromAST: true }, + { name: 'condition', type: 'IExpressionSyntax', isOptional: true }, + { name: 'secondSemicolonToken', isToken: true, tokenKinds: ['SemicolonToken'], excludeFromAST: true }, + { name: 'incrementor', type: 'IExpressionSyntax', isOptional: true }, + { name: 'closeParenToken', isToken: true, excludeFromAST: true }, + { name: 'statement', type: 'IStatementSyntax' } + ] + }, + { + name: 'ForInStatementSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IStatementSyntax'], + children: [ + { name: 'forKeyword', isToken: true, excludeFromAST: true }, + { name: 'openParenToken', isToken: true, excludeFromAST: true }, + { name: 'variableDeclaration', type: 'VariableDeclarationSyntax', isOptional: true }, + { name: 'left', type: 'IExpressionSyntax', isOptional: true }, + { name: 'inKeyword', isToken: true, excludeFromAST: true }, + { name: 'expression', type: 'IExpressionSyntax' }, + { name: 'closeParenToken', isToken: true, excludeFromAST: true }, + { name: 'statement', type: 'IStatementSyntax' } + ] + }, + { + name: 'WhileStatementSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IStatementSyntax'], + children: [ + { name: 'whileKeyword', isToken: true, excludeFromAST: true }, + { name: 'openParenToken', isToken: true, excludeFromAST: true }, + { name: 'condition', type: 'IExpressionSyntax' }, + { name: 'closeParenToken', isToken: true, excludeFromAST: true }, + { name: 'statement', type: 'IStatementSyntax' } + ] + }, + { + name: 'WithStatementSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IStatementSyntax'], + children: [ + { name: 'withKeyword', isToken: true, excludeFromAST: true }, + { name: 'openParenToken', isToken: true, excludeFromAST: true }, + { name: 'condition', type: 'IExpressionSyntax' }, + { name: 'closeParenToken', isToken: true, excludeFromAST: true }, + { name: 'statement', type: 'IStatementSyntax' } + ] + }, + { + name: 'EnumDeclarationSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IModuleElementSyntax'], + children: [ + { name: 'modifiers', isList: true, elementType: 'ISyntaxToken' }, + { name: 'enumKeyword', isToken: true, excludeFromAST: true }, + { name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] }, + { name: 'openBraceToken', isToken: true, excludeFromAST: true }, + { name: 'enumElements', isSeparatedList: true, elementType: 'EnumElementSyntax' }, + { name: 'closeBraceToken', isToken: true, excludeFromAST: true } + ], + isTypeScriptSpecific: true + }, + { + name: 'EnumElementSyntax', + baseType: 'ISyntaxNode', + children: [ + { name: 'propertyName', isToken: true, tokenKinds: ['IdentifierName', 'StringLiteral', 'NumericLiteral'] }, + { name: 'equalsValueClause', type: 'EqualsValueClauseSyntax', isOptional: true } + ] + }, + { + name: 'CastExpressionSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IUnaryExpressionSyntax'], + children: [ + { name: 'lessThanToken', isToken: true, excludeFromAST: true }, + { name: 'type', type: 'ITypeSyntax' }, + { name: 'greaterThanToken', isToken: true, excludeFromAST: true }, + { name: 'expression', type: 'IUnaryExpressionSyntax' } + ], + isTypeScriptSpecific: true + }, + { + name: 'ObjectLiteralExpressionSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IPrimaryExpressionSyntax'], + children: [ + { name: 'openBraceToken', isToken: true, excludeFromAST: true }, + { name: 'propertyAssignments', isSeparatedList: true, elementType: 'IPropertyAssignmentSyntax' }, + { name: 'closeBraceToken', isToken: true, excludeFromAST: true } + ] + }, + { + name: 'SimplePropertyAssignmentSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IPropertyAssignmentSyntax'], + children: [ + { name: 'propertyName', isToken: true, tokenKinds: ['IdentifierName', 'StringLiteral', 'NumericLiteral'] }, + { name: 'colonToken', isToken: true, excludeFromAST: true }, + { name: 'expression', type: 'IExpressionSyntax' } + ] + }, + { + name: 'FunctionPropertyAssignmentSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IPropertyAssignmentSyntax'], + children: [ + { name: 'propertyName', isToken: true, tokenKinds: ['IdentifierName', 'StringLiteral', 'NumericLiteral'] }, + { name: 'callSignature', type: 'CallSignatureSyntax' }, + { name: 'block', type: 'BlockSyntax' } + ] + }, + { + name: 'FunctionExpressionSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IPrimaryExpressionSyntax'], + children: [ + { name: 'functionKeyword', isToken: true, excludeFromAST: true }, + { name: 'identifier', isToken: true, isOptional: true, tokenKinds: ['IdentifierName'] }, + { name: 'callSignature', type: 'CallSignatureSyntax' }, + { name: 'block', type: 'BlockSyntax' }] + }, + { + name: 'EmptyStatementSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IStatementSyntax'], + children: [ + { name: 'semicolonToken', isToken: true }] + }, + { + name: 'TryStatementSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IStatementSyntax'], + children: [ + { name: 'tryKeyword', isToken: true, excludeFromAST: true }, + { name: 'block', type: 'BlockSyntax' }, + { name: 'catchClause', type: 'CatchClauseSyntax', isOptional: true }, + { name: 'finallyClause', type: 'FinallyClauseSyntax', isOptional: true }] + }, + { + name: 'CatchClauseSyntax', + baseType: 'ISyntaxNode', + children: [ + { name: 'catchKeyword', isToken: true, excludeFromAST: true }, + { name: 'openParenToken', isToken: true, excludeFromAST: true }, + { name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] }, + { name: 'typeAnnotation', type: 'TypeAnnotationSyntax', isOptional: true, isTypeScriptSpecified: true }, + { name: 'closeParenToken', isToken: true, excludeFromAST: true }, + { name: 'block', type: 'BlockSyntax' }] + }, + { + name: 'FinallyClauseSyntax', + baseType: 'ISyntaxNode', + children: [ + { name: 'finallyKeyword', isToken: true, excludeFromAST: true }, + { name: 'block', type: 'BlockSyntax' }] + }, + { + name: 'LabeledStatementSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IStatementSyntax'], + children: [ + { name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] }, + { name: 'colonToken', isToken: true, excludeFromAST: true }, + { name: 'statement', type: 'IStatementSyntax' }] + }, + { + name: 'DoStatementSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IStatementSyntax'], + children: [ + { name: 'doKeyword', isToken: true, excludeFromAST: true }, + { name: 'statement', type: 'IStatementSyntax' }, + { name: 'whileKeyword', isToken: true, excludeFromAST: true }, + { name: 'openParenToken', isToken: true, excludeFromAST: true }, + { name: 'condition', type: 'IExpressionSyntax' }, + { name: 'closeParenToken', isToken: true, excludeFromAST: true }, + { name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }] + }, + { + name: 'TypeOfExpressionSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IUnaryExpressionSyntax'], + children: [ + { name: 'typeOfKeyword', isToken: true, excludeFromAST: true }, + { name: 'expression', type: 'IUnaryExpressionSyntax' }] + }, + { + name: 'DeleteExpressionSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IUnaryExpressionSyntax'], + children: [ + { name: 'deleteKeyword', isToken: true, excludeFromAST: true }, + { name: 'expression', type: 'IUnaryExpressionSyntax' }] + }, + { + name: 'VoidExpressionSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IUnaryExpressionSyntax'], + children: [ + { name: 'voidKeyword', isToken: true, excludeFromAST: true }, + { name: 'expression', type: 'IUnaryExpressionSyntax' }] + }, + { + name: 'DebuggerStatementSyntax', + baseType: 'ISyntaxNode', + interfaces: ['IStatementSyntax'], + children: [ + { name: 'debuggerKeyword', isToken: true }, + { name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }] + }]; + +function firstKind(definition: ITypeDefinition): TypeScript.SyntaxKind { + var kindName = definition.syntaxKinds ? definition.syntaxKinds[0] : getNameWithoutSuffix(definition); + //TypeScript.Environment.standardOut.WriteLine(kindName); + var kind = (TypeScript.SyntaxKind)[kindName]; + //TypeScript.Environment.standardOut.WriteLine(kind); + + return kind; +} + +var sortedDefinitions = definitions.sort((d1, d2) => firstKind(d1) - firstKind(d2)); + +//function endsWith(string: string, value: string): boolean { +// return string.substring(string.length - value.length, string.length) === value; +//} + +function getStringWithoutSuffix(definition: string) { + if (TypeScript.StringUtilities.endsWith(definition, "Syntax")) { + return definition.substring(0, definition.length - "Syntax".length); + } + + return definition; +} + +function getStringWithoutPrefix(definition: string) { + if (definition.charAt(0) == "I" && definition.charAt(1).toUpperCase() == definition.charAt(1)) { + return definition.substring(1); + } + + return definition; +} + +function getNameWithoutSuffix(definition: ITypeDefinition) { + return getStringWithoutSuffix(definition.name); +} + +function getType(child: IMemberDefinition): string { + if (child.isToken) { + return "ISyntaxToken"; + } + else if (child.isSeparatedList) { + return child.elementType + "[]"; + } + else if (child.isList) { + return child.elementType + "[]"; + } + else { + return child.type; + } +} + +var hasKind = false; + +function pascalCase(value: string): string { + return value.substr(0, 1).toUpperCase() + value.substr(1); +} + +function camelCase(value: string): string { + return value.substr(0, 1).toLowerCase() + value.substr(1); +} + +function getSafeName(child: IMemberDefinition) { + if (child.name === "arguments") { + return "_" + child.name; + } + + return child.name; +} + +function getPropertyAccess(child: IMemberDefinition, instance = "this"): string { + if (child.type === "SyntaxKind") { + return instance + "._kind"; + } + + return instance + "." + child.name; +} + +function generateProperties(definition: ITypeDefinition): string { + var result = ""; + + if (definition.name === "SourceUnitSyntax") { + result += " public syntaxTree: SyntaxTree = null;\r\n"; + } + + var newLine = false; + for (var i = 0; i < definition.children.length; i++) { + var child = definition.children[i]; + + if (getType(child) === "SyntaxKind") { + result += " private _" + child.name + ": " + getType(child) + ";\r\n"; + newLine = true; + } + else if (child.name === "arguments") { + result += " public " + child.name + ": " + getType(child) + ";\r\n"; + } + + hasKind = hasKind || (getType(child) === "SyntaxKind"); + } + + if (newLine) { + result += "\r\n"; + } + + return result; +} + +function generateNullChecks(definition: ITypeDefinition): string { + var result = ""; + + for (var i = 0; i < definition.children.length; i++) { + var child = definition.children[i]; + + if (!child.isOptional && !child.isToken) { + result += " if (" + child.name + " === null) { throw Errors.argumentNull('" + child.name + "'); }\r\n"; + } + } + + return result; +} + +function generateIfKindCheck(child: IMemberDefinition, tokenKinds: string[], indent: string): string { + var result = ""; + + result += indent + " if ("; + + for (var j = 0; j < tokenKinds.length; j++) { + if (j > 0) { + result += " && "; + } + + var tokenKind = tokenKinds[j]; + if (tokenKind === "IdentifierName") { + result += "!SyntaxFacts.isIdentifierName(" + child.name + ".tokenKind)"; + } + else { + result += child.name + ".tokenKind !== SyntaxKind." + tokenKind; + } + } + + result += ") { throw Errors.argument('" + child.name + "'); }\r\n"; + return result; +} + +function generateSwitchCase(tokenKind: string, indent: string): string { + return indent + " case SyntaxKind." + tokenKind + ":\r\n"; +} + +function generateBreakStatement(indent: string): string { + return indent + " break;\r\n"; +} + +function generateSwitchCases(tokenKinds: string[], indent: string): string { + var result = ""; + for (var j = 0; j < tokenKinds.length; j++) { + var tokenKind = tokenKinds[j]; + + result += generateSwitchCase(tokenKind, indent); + } + + if (tokenKinds.length > 0) { + result += generateBreakStatement(indent); + } + + return result; +} + +function generateDefaultCase(child: IMemberDefinition, indent: string): string { + var result = ""; + + result += indent + " default:\r\n"; + result += indent + " throw Errors.argument('" + child.name + "');\r\n"; + + return result; +} + +function generateSwitchKindCheck(child: IMemberDefinition, tokenKinds: string[], indent: string): string { + if (tokenKinds.length === 0) { + return ""; + } + + var result = ""; + + var identifierName = TypeScript.ArrayUtilities.where(tokenKinds, v => v.indexOf("IdentifierName") >= 0); + var notIdentifierName = TypeScript.ArrayUtilities.where(tokenKinds, v => v.indexOf("IdentifierName") < 0); + + if (identifierName.length > 0) { + result += indent + " if (!SyntaxFacts.isIdentifierName(" + child.name + ".tokenKind)) {\r\n"; + if (notIdentifierName.length === 0) { + result += indent + " throw Errors.argument('" + child.name + "');\r\n"; + result += indent + " }\r\n"; + return result; + } + + indent += " "; + } + + if (notIdentifierName.length <= 2) { + result += generateIfKindCheck(child, notIdentifierName, indent); + } + else if (notIdentifierName.length > 2) { + result += indent + " switch (" + child.name + ".tokenKind) {\r\n"; + result += generateSwitchCases(notIdentifierName, indent); + result += generateDefaultCase(child, indent); + result += indent + " }\r\n"; + } + + if (identifierName.length > 0) { + result += indent + " }\r\n"; + } + + // result += indent + " }\r\n"; + return result; +} + +function tokenKinds(child: IMemberDefinition): string[] { + return child.tokenKinds + ? child.tokenKinds + : [pascalCase(child.name)]; +} + +function generateKindCheck(child: IMemberDefinition): string { + var indent = ""; + var result = ""; + + if (child.isOptional) { + indent = " "; + + result += " if (" + child.name + " !== null) {\r\n"; + } + + var kinds = tokenKinds(child); + + if (kinds.length <= 2) { + result += generateIfKindCheck(child, kinds, indent); + } + else { + result += generateSwitchKindCheck(child, kinds, indent); + } + + if (child.isOptional) { + result += " }\r\n"; + } + + return result; +} + +function generateKindChecks(definition: ITypeDefinition): string { + var result = ""; + + for (var i = 0; i < definition.children.length; i++) { + var child = definition.children[i]; + + if (child.isToken) { + result += generateKindCheck(child); + } + } + + return result; +} + +function generateArgumentChecks(definition: ITypeDefinition): string { + var result = ""; + + if (argumentChecks) { + result += generateNullChecks(definition); + result += generateKindChecks(definition); + + if (definition.children.length > 0) { + result += "\r\n"; + } + } + + return result; +} + +function generateConstructor(definition: ITypeDefinition): string { + var i: number; + var child: IMemberDefinition; + var base = baseType(definition); + + var result = ""; + result += " constructor(" + + var children = definition.children; + var kindChild: IMemberDefinition = null; + for (i = 0; i < children.length; i++) { + child = children[i]; + + if (getType(child) === "SyntaxKind") { + kindChild = child; + } + + if (getType(child) !== "SyntaxKind" && child.name !== "arguments") { + result += "public "; + } + + result += getSafeName(child) + ": " + getType(child); + result += ",\r\n "; + } + + result += "data: number) {\r\n"; + + if (kindChild) { + result += " super(kind, data); \r\n"; + } + else { + result += " super(SyntaxKind." + getNameWithoutSuffix(definition) + ", data); \r\n"; + } + + if (definition.children.length > 0) { + result += "\r\n"; + } + + result += generateArgumentChecks(definition); + + for (i = 0; i < definition.children.length; i++) { + child = definition.children[i]; + + if (child.type === "SyntaxKind" || child.name === "arguments") { + result += " " + getPropertyAccess(child) + " = " + getSafeName(child) + ";\r\n"; + } + } + + for (i = 0; i < definition.children.length; i++) { + child = definition.children[i]; + + if (child.type !== "SyntaxKind") { + if (child.isOptional) { + result += " " + getSafeName(child) + " && (" + getSafeName(child) + ".parent = this);\r\n"; + } + else if (child.isList || child.isSeparatedList) { + result += " !isShared(" + getSafeName(child) + ") && (" + getSafeName(child) + ".parent = this);\r\n"; + } + else { + result += " " + getSafeName(child) + ".parent = this;\r\n"; + } + } + } + + //result += " Syntax.setParentForChildren(this);\r\n"; + result += " }\r\n"; + + return result; +} + +function isOptional(child: IMemberDefinition) { + if (child.isOptional) { + return true; + } + + if (child.isList && !child.requiresAtLeastOneItem) { + return true; + } + + if (child.isSeparatedList && !child.requiresAtLeastOneItem) { + return true; + } + + return false; +} + +function generateFactory1Method(definition: ITypeDefinition): string { + return ""; + + var mandatoryChildren = TypeScript.ArrayUtilities.where( + definition.children, c => !isOptional(c)); + if (mandatoryChildren.length === definition.children.length) { + return ""; + } + + var result = "\r\n public static create(" + var i: number; + var child: IMemberDefinition; + + for (i = 0; i < mandatoryChildren.length; i++) { + child = mandatoryChildren[i]; + + result += child.name + ": " + getType(child); + + if (i < mandatoryChildren.length - 1) { + result += ",\r\n "; + } + } + + result += "): " + definition.name + " {\r\n"; + + result += " return new " + definition.name + "("; + + for (i = 0; i < definition.children.length; i++) { + child = definition.children[i]; + + if (!isOptional(child)) { + result += child.name; + } + else if (child.isList) { + result += "Syntax.emptyList<" + child.elementType + ">()"; + } + else if (child.isSeparatedList) { + result += "Syntax.emptySeparatedList<" + child.elementType + ">()"; + } + else { + result += "null"; + } + + result += ", "; + } + + result += "/*data:*/ 0);\r\n"; + result += " }\r\n"; + + return result; +} + +function isKeywordOrPunctuation(kind: string): boolean { + if (TypeScript.StringUtilities.endsWith(kind, "Keyword")) { + return true; + } + + if (TypeScript.StringUtilities.endsWith(kind, "Token") && + kind !== "IdentifierName" && + kind !== "EndOfFileToken") { + return true; + } + + return false; +} + +function isDefaultConstructable(definition: ITypeDefinition): boolean { + if (definition === null) { + return false; + } + + for (var i = 0; i < definition.children.length; i++) { + if (isMandatory(definition.children[i])) { + // If any child is mandatory, then the type is not default constructable. + return false; + } + } + + // We can default construct this. + return true; +} + +function isMandatory(child: IMemberDefinition): boolean { + // If it's optional then it's not mandatory. + if (isOptional(child)) { + return false; + } + + // Kinds are always mandatory. As are non-optional lists. + if (child.type === "SyntaxKind" || child.isList || child.isSeparatedList) { + return true; + } + + // We have a non optional node or token. Tokens are mandatory if they're not keywords or + // punctuation. + if (child.isToken) { + var kinds = tokenKinds(child); + var isFixed = kinds.length === 1 && isKeywordOrPunctuation(kinds[0]); + + return !isFixed; + } + + // It's a node. It's mandatory if we can't default construct it. + return !isDefaultConstructable(memberDefinitionType(child)); +} + +function generateFactory2Method(definition: ITypeDefinition): string { + return ""; + + var mandatoryChildren: IMemberDefinition[] = TypeScript.ArrayUtilities.where(definition.children, isMandatory); + if (mandatoryChildren.length === definition.children.length) { + return ""; + } + + var i: number; + var child: IMemberDefinition; + var result = "\r\n public static create1(" + + for (i = 0; i < mandatoryChildren.length; i++) { + child = mandatoryChildren[i]; + + result += child.name + ": " + getType(child); + + if (i < mandatoryChildren.length - 1) { + result += ",\r\n "; + } + } + + result += "): " + definition.name + " {\r\n"; + result += " return new " + definition.name + "("; + + for (i = 0; i < definition.children.length; i++) { + child = definition.children[i]; + + if (isMandatory(child)) { + result += child.name; + } + else if (child.isList) { + result += "Syntax.emptyList<" + child.elementType + ">()"; + } + else if (child.isSeparatedList) { + result += "Syntax.emptySeparatedList<" + child.elementType + ">()"; + } + else if (isOptional(child)) { + result += "null"; + } + else if (child.isToken) { + result += "Syntax.token(SyntaxKind." + tokenKinds(child)[0] + ")"; + } + else { + result += child.type + ".create1()"; + } + + result += ", "; + } + + result += "/*data:*/ 0);\r\n"; + result += " }\r\n"; + + return result; +} + +function generateFactoryMethod(definition: ITypeDefinition): string { + return generateFactory1Method(definition) + generateFactory2Method(definition); +} + +function generateBrands(definition: ITypeDefinition, accessibility: boolean): string { + var properties = ""; + + var types: string[] = []; + if (definition.interfaces) { + var ifaces = definition.interfaces.slice(0); + var i: number; + for (i = 0; i < ifaces.length; i++) { + var current = ifaces[i]; + + while (current !== undefined) { + if (!TypeScript.ArrayUtilities.contains(ifaces, current)) { + ifaces.push(current); + } + + current = interfaces[current]; + } + } + + for (i = 0; i < ifaces.length; i++) { + var type = ifaces[i]; + type = getStringWithoutSuffix(type); + if (isInterface(type)) { + type = "_" + type.substr(1, 1).toLowerCase() + type.substr(2) + "Brand"; + } + + types.push(type); + } + } + + if (types.length > 0) { + properties += " "; + + for (var i = 0; i < types.length; i++) { + if (accessibility) { + properties += " public "; + } + + properties += types[i] + ": any;"; + } + + properties += "\r\n"; + } + + return properties; +} + +function generateKindMethod(definition: ITypeDefinition): string { + var result = ""; + + //if (!hasKind) { + // result += "\r\n"; + // result += " public get kind(): SyntaxKind {\r\n"; + // result += " return SyntaxKind." + getNameWithoutSuffix(definition) + ";\r\n"; + // result += " }\r\n"; + //} + + return result; +} + +function generateSlotMethods(definition: ITypeDefinition): string { + var result = ""; + return result; + + result += "\r\n"; + result += " public childCount(): number {\r\n"; + var slotCount = hasKind ? (definition.children.length - 1) : definition.children.length; + + result += " return " + slotCount + ";\r\n"; + result += " }\r\n\r\n"; + + result += " public childAt(slot: number): ISyntaxElement {\r\n"; + + if (slotCount === 0) { + result += " throw Errors.invalidOperation();\r\n"; + } + else { + result += " switch (slot) {\r\n"; + + var index = 0; + for (var i = 0; i < definition.children.length; i++) { + var child = definition.children[i]; + if (child.type === "SyntaxKind") { + continue; + } + + result += " case " + index + ": return this." + child.name + ";\r\n"; + index++; + } + + result += " default: throw Errors.invalidOperation();\r\n"; + result += " }\r\n"; + } + + result += " }\r\n"; + + return result; +} + +function generateFirstTokenMethod(definition: ITypeDefinition): string { + var result = ""; + + result += "\r\n"; + result += " public firstToken(): ISyntaxToken {\r\n"; + result += " var token = null;\r\n"; + + for (var i = 0; i < definition.children.length; i++) { + var child = definition.children[i]; + + if (getType(child) === "SyntaxKind") { + continue; + } + + if (child.name === "endOfFileToken") { + continue; + } + + result += " if ("; + + if (child.isOptional) { + result += getPropertyAccess(child) + " !== null && "; + } + + if (child.isToken) { + result += getPropertyAccess(child) + ".width() > 0"; + result += ") { return " + getPropertyAccess(child) + "; }\r\n"; + } + else { + result += "(token = " + getPropertyAccess(child) + ".firstToken()) !== null"; + result += ") { return token; }\r\n"; + } + } + + if (definition.name === "SourceUnitSyntax") { + result += " return this._endOfFileToken;\r\n"; + } + else { + result += " return null;\r\n"; + } + + result += " }\r\n"; + + result += " }\r\n"; + + return result; +} + +function generateLastTokenMethod(definition: ITypeDefinition): string { + var result = ""; + + result += "\r\n"; + result += " public lastToken(): ISyntaxToken {\r\n"; + + if (definition.name === "SourceUnitSyntax") { + result += " return this._endOfFileToken;\r\n"; + } + else { + result += " var token = null;\r\n"; + + for (var i = definition.children.length - 1; i >= 0; i--) { + var child = definition.children[i]; + + if (getType(child) === "SyntaxKind") { + continue; + } + + if (child.name === "endOfFileToken") { + continue; + } + + result += " if ("; + + if (child.isOptional) { + result += getPropertyAccess(child) + " !== null && "; + } + + if (child.isToken) { + result += getPropertyAccess(child) + ".width() > 0"; + result += ") { return " + getPropertyAccess(child) + "; }\r\n"; + } + else { + result += "(token = " + getPropertyAccess(child) + ".lastToken()) !== null"; + result += ") { return token; }\r\n"; + } + } + + result += " return null;\r\n"; + } + + result += " }\r\n"; + + return result; +} + +function baseType(definition: ITypeDefinition): ITypeDefinition { + return TypeScript.ArrayUtilities.firstOrDefault(definitions, d => d.name === definition.baseType); +} + +function memberDefinitionType(child: IMemberDefinition): ITypeDefinition { + // Debug.assert(child.type !== undefined); + return TypeScript.ArrayUtilities.firstOrDefault(definitions, d => d.name === child.type); +} + +function derivesFrom(def1: ITypeDefinition, def2: ITypeDefinition): boolean { + var current = def1; + while (current !== null) { + var base = baseType(current); + if (base === def2) { + return true; + } + + current = base; + } + + return false; +} + +function contains(definition: ITypeDefinition, child: IMemberDefinition) { + return TypeScript.ArrayUtilities.any(definition.children, + c => c.name === child.name && + c.isList === child.isList && + c.isSeparatedList === child.isSeparatedList && + c.isToken === child.isToken && + c.type === child.type); +} + +function generateAccessors(definition: ITypeDefinition): string { + var result = ""; + + //if (definition.name === "SourceUnitSyntax") { + // result += "\r\n"; + // result += " public syntaxTree(): SyntaxTree {\r\n"; + // result += " return this._syntaxTree;\r\n"; + // result += " }\r\n"; + //} + + //for (var i = 0; i < definition.children.length; i++) { + // var child = definition.children[i]; + + // if (child.type === "SyntaxKind") { + // result += "\r\n"; + // result += " public get " + child.name + "(): " + getType(child) + " {\r\n"; + // result += " return " + getPropertyAccess(child) + ";\r\n"; + // result += " }\r\n"; + // } + //} + + return result; +} + +function generateWithMethod(definition: ITypeDefinition, child: IMemberDefinition): string { + return ""; + + var result = ""; + result += "\r\n"; + result += " public with" + pascalCase(child.name) + "(" + getSafeName(child) + ": " + getType(child) + "): " + definition.name + " {\r\n"; + result += " return this.update(" + + for (var i = 0; i < definition.children.length; i++) { + if (i > 0) { + result += ", "; + } + + if (definition.children[i] === child) { + result += getSafeName(child); + } + else { + result += getPropertyAccess(definition.children[i]); + } + } + + result += ");\r\n"; + result += " }\r\n"; + + if (child.isList || child.isSeparatedList) { + if (TypeScript.StringUtilities.endsWith(child.name, "s")) { + var pascalName = pascalCase(child.name); + pascalName = pascalName.substring(0, pascalName.length - 1); + + var argName = getSafeName(child); + argName = argName.substring(0, argName.length - 1) + + result += "\r\n"; + result += " public with" + pascalName + "(" + argName + ": " + child.elementType + "): " + definition.name + " {\r\n"; + result += " return this.with" + pascalCase(child.name) + "(" + + if (child.isList) { + result += "Syntax.list<" + child.elementType + ">([" + argName + "])"; + } + else { + result += "Syntax.separatedList<" + child.elementType + ">([" + argName + "])"; + } + + result += ");\r\n"; + result += " }\r\n"; + } + } + + return result; +} + +function generateWithMethods(definition: ITypeDefinition): string { + var result = ""; + return ""; + + for (var i = 0; i < definition.children.length; i++) { + var child = definition.children[i]; + result += generateWithMethod(definition, child); + } + + return result; +} + +function generateTriviaMethods(definition: ITypeDefinition): string { + return ""; + + var result = "\r\n"; + result += " public withLeadingTrivia(trivia: ISyntaxTriviaList): " + definition.name + " {\r\n"; + result += " return <" + definition.name + ">super.withLeadingTrivia(trivia);\r\n"; + result += " }\r\n\r\n"; + result += " public withTrailingTrivia(trivia: ISyntaxTriviaList): " + definition.name + " {\r\n"; + result += " return <" + definition.name + ">super.withTrailingTrivia(trivia);\r\n"; + result += " }\r\n"; + + return result; +} + +function generateUpdateMethod(definition: ITypeDefinition): string { + // return ""; + + var result = ""; + + result += "\r\n"; + result += " public update("; + + var i: number; + var child: IMemberDefinition; + + for (i = 0; i < definition.children.length; i++) { + child = definition.children[i]; + + result += getSafeName(child) + ": " + getType(child); + + if (i < definition.children.length - 1) { + result += ",\r\n "; + } + } + + result += "): " + definition.name + " {\r\n"; + + if (definition.children.length === 0) { + result += " return this;\r\n"; + } + else { + result += " if ("; + + for (i = 0; i < definition.children.length; i++) { + child = definition.children[i]; + + if (i !== 0) { + result += " && "; + } + + result += getPropertyAccess(child) + " === " + getSafeName(child); + } + + result += ") {\r\n"; + result += " return this;\r\n"; + result += " }\r\n\r\n"; + + result += " return new " + definition.name + "("; + + for (i = 0; i < definition.children.length; i++) { + child = definition.children[i]; + + result += getSafeName(child); + result += ", "; + } + + result += "this.parsedInStrictMode() ? SyntaxConstants.NodeParsedInStrictModeMask : 0);\r\n"; + } + + result += " }\r\n"; + + return result; +} + +function generateNode(definition: ITypeDefinition, abstract: boolean): string { + var result = " export class " + definition.name + " extends SyntaxNode" + + if (definition.interfaces) { + result += " implements "; + result += definition.interfaces.join(", "); + } + + result += " {\r\n"; + + if (definition.name === "SourceUnitSyntax") { + result += " public syntaxTree: SyntaxTree = null;\r\n"; + } + + for (var i = 0; i < definition.children.length; i++) { + var child = definition.children[i]; + result += " public " + child.name + ": " + getType(child) + ";\r\n"; + } + + result += generateBrands(definition, /*accessibility:*/ true); + + result += " constructor(data: number"; + + for (var i = 0; i < definition.children.length; i++) { + var child = definition.children[i]; + result += ", " + getSafeName(child) + ": " + getType(child); + } + + result += ") {\r\n"; + result += " super(data);\r\n"; + + if (definition.name === "SourceUnitSyntax") { + result += " this.parent = null,\r\n"; + } + + if (definition.children) { + for (var i = 0; i < definition.children.length; i++) { + var child = definition.children[i]; + if (child.excludeFromAST && abstract) { + continue; + } + + result += " this." + child.name + " = " + getSafeName(child) + ",\r\n"; + } + } + + if (definition.children.length > 0) { + var first = true; + for (var i = 0; i < definition.children.length; i++) { + var child = definition.children[i]; + if (child.excludeFromAST && abstract) { + continue; + } + + if (!first) { + result += ",\r\n"; + } + first = false; + + if (child.isList || child.isSeparatedList) { + result += " !isShared(" + getSafeName(child) + ") && (" + getSafeName(child) + ".parent = this)"; + } + else if (child.isOptional) { + result += " " + getSafeName(child) + " && (" + getSafeName(child) + ".parent = this)"; + } + else { + result += " " + getSafeName(child) + ".parent = this"; + } + } + result += ";\r\n"; + } + + result += " }\r\n"; + + if (definition.name === "BinaryExpressionSyntax") { + result += " public kind(): SyntaxKind { return SyntaxFacts.getBinaryExpressionFromOperatorToken(this.operatorToken.kind()); }\r\n"; + } + else if (definition.name === "PrefixUnaryExpressionSyntax") { + result += " public kind(): SyntaxKind { return SyntaxFacts.getPrefixUnaryExpressionFromOperatorToken(this.operatorToken.kind()); }\r\n"; + } + else if (definition.name === "PostfixUnaryExpressionSyntax") { + result += " public kind(): SyntaxKind { return SyntaxFacts.getPostfixUnaryExpressionFromOperatorToken(this.operatorToken.kind()); }\r\n"; + } + else if (definition.name === "HeritageClauseSyntax") { + result += " public kind(): SyntaxKind { return this.extendsOrImplementsKeyword.kind() === SyntaxKind.ExtendsKeyword ? SyntaxKind.ExtendsHeritageClause : SyntaxKind.ImplementsHeritageClause; }\r\n"; + } + + result += " }"; + return result; +} + +function syntaxKindName(kind: TypeScript.SyntaxKind): string { + for (var name in TypeScript.SyntaxKind) { + if (TypeScript.SyntaxKind[name] === kind) { + return name; + } + } + + throw new Error(); +} + +function getDefinitionForKind(kind: TypeScript.SyntaxKind): ITypeDefinition { + var kindName = syntaxKindName(kind); + + return TypeScript.ArrayUtilities.firstOrDefault(definitions, d => { + if (getNameWithoutSuffix(d) === kindName) { + return true; + } + + if (d.syntaxKinds) { + return TypeScript.ArrayUtilities.contains(d.syntaxKinds, kindName); + } + + return false; + }); +} + +function generateSyntaxInterfaces(): string { + var result = "///\r\n\r\n"; + + result += "module TypeScript {\r\n"; + + for (var i = 0; i < definitions.length; i++) { + var definition = definitions[i]; + + if (i > 0) { + result += "\r\n"; + } + + result += generateSyntaxInterface(definition); + } + + result += "\r\n\r\n"; + + result += " export var nodeMetadata: string[][] = ["; + for (var i = 0; i <= TypeScript.SyntaxKind.LastNode; i++) { + if (i < TypeScript.SyntaxKind.FirstNode) { + result += "[],"; + continue; + } + + var kindName = syntaxKindName(i); + + var definition = getDefinitionForKind(i); + + var metadata = "["; + var children = definition.children.filter(m => m.type !== "SyntaxKind").map(m => '"' + m.name + '"'); + metadata += children.join(","); + metadata += "],"; + + result += metadata; + } + result += "];\r\n\r\n"; + + result += " export module Syntax {\r\n" + + result += " export interface ISyntaxFactory {\r\n"; + result += " isConcrete: boolean;\r\n"; + + for (var i = 0; i < definitions.length; i++) { + var definition = definitions[i]; + result += " " + definition.name + ": { new(data: number"; + + for (var j = 0; j < definition.children.length; j++) { + var child = definition.children[j]; + result += ", " + child.name + ": " + getType(child); + } + + result += "): " + definition.name + " };\r\n"; + } + + result += " }\r\n"; + result += " }\r\n"; + + result += "}"; + return result; +} + +function generateSyntaxInterface(definition: ITypeDefinition): string { + var result = " export interface " + definition.name + " extends ISyntaxNode" + + if (definition.interfaces) { + result += ", "; + result += definition.interfaces.join(", "); + } + + result += " {\r\n"; + + if (definition.name === "SourceUnitSyntax") { + result += " syntaxTree: SyntaxTree;\r\n"; + } + + for (var i = 0; i < definition.children.length; i++) { + var child = definition.children[i]; + result += " " + child.name + ": " + getType(child) + ";\r\n"; + } + + result += " }"; + + return result; +} + + +function generateNodes(abstract: boolean): string { + var result = "///\r\n\r\n"; + + result += "module TypeScript.Syntax."; + + var moduleName = abstract ? "Abstract" : "Concrete"; + result += moduleName; + + result += " {\r\n"; + result += " // Inject this module as the factory for producing syntax nodes in the parser.\r\n"; + result += " Parser.syntaxFactory = " + moduleName + ";\r\n"; + result += " export var isConcrete: boolean = " + !abstract + ";\r\n\r\n"; + + for (var i = 0; i < definitions.length; i++) { + var definition = definitions[i]; + + if (i > 0) { + result += "\r\n"; + } + + result += generateNode(definition, abstract); + } + + result += "\r\n\r\n "; + + for (var i = 0; i < definitions.length; i++) { + var definition = definitions[i]; + + if (definition.syntaxKinds) { + continue; + } + + if (i) { + result += ", " + } + + result += "(" + definition.name + ").prototype.__kind = SyntaxKind." + getNameWithoutSuffix(definition) + } + + result += ";\r\n"; + + result += "}"; + return result; +} + +function isInterface(name: string) { + return name.substr(0, 1) === "I" && name.substr(1, 1).toUpperCase() === name.substr(1, 1) +} + +function isNodeOrToken(child: IMemberDefinition) { + // IWhatever. + return child.type && isInterface(child.type); +} + +function generateRewriter(): string { + var result = "///\r\n\r\n"; + + result += "module TypeScript {\r\n" + +" export class SyntaxRewriter implements ISyntaxVisitor {\r\n" + +" public visitToken(token: ISyntaxToken): ISyntaxToken {\r\n" + +" return token;\r\n" + +" }\r\n" + +"\r\n" + +" public visitNode(node: ISyntaxNode): ISyntaxNode {\r\n" + +" return visitNodeOrToken(this, node);\r\n" + +" }\r\n" + +"\r\n" + +" public visitNodeOrToken(node: ISyntaxNodeOrToken): ISyntaxNodeOrToken {\r\n" + +" return isToken(node) ? this.visitToken(node) : this.visitNode(node);\r\n" + +" }\r\n" + +"\r\n" + +" public visitList(list: T[]): T[] {\r\n" + +" var newItems: T[] = null;\r\n" + +"\r\n" + +" for (var i = 0, n = list.length; i < n; i++) {\r\n" + +" var item = list[i];\r\n" + +" var newItem = this.visitNodeOrToken(item);\r\n" + +"\r\n" + +" if (item !== newItem && newItems === null) {\r\n" + +" newItems = [];\r\n" + +" for (var j = 0; j < i; j++) {\r\n" + +" newItems.push(list[j]);\r\n" + +" }\r\n" + +" }\r\n" + +"\r\n" + +" if (newItems) {\r\n" + +" newItems.push(newItem);\r\n" + +" }\r\n" + +" }\r\n" + +"\r\n" + +" // Debug.assert(newItems === null || newItems.length === childCount(list));\r\n" + +" return newItems === null ? list : Syntax.list(newItems);\r\n" + +" }\r\n" + +"\r\n" + +" public visitSeparatedList(list: T[]): T[] {\r\n" + +" var newItems: ISyntaxNodeOrToken[] = null;\r\n" + +"\r\n" + +" for (var i = 0, n = childCount(list); i < n; i++) {\r\n" + +" var item = childAt(list, i);\r\n" + +" var newItem = isToken(item) ? this.visitToken(item) : this.visitNode(item);\r\n" + +"\r\n" + +" if (item !== newItem && newItems === null) {\r\n" + +" newItems = [];\r\n" + +" for (var j = 0; j < i; j++) {\r\n" + +" newItems.push(childAt(list, j));\r\n" + +" }\r\n" + +" }\r\n" + +"\r\n" + +" if (newItems) {\r\n" + +" newItems.push(newItem);\r\n" + +" }\r\n" + +" }\r\n" + +"\r\n" + +" // Debug.assert(newItems === null || newItems.length === childCount(list));\r\n" + +" return newItems === null ? list : Syntax.separatedList(newItems);\r\n" + +" }\r\n"; + + for (var i = 0; i < definitions.length; i++) { + var definition = definitions[i]; + + result += "\r\n"; + result += " public visit" + getNameWithoutSuffix(definition) + "(node: " + definition.name + "): any {\r\n"; + + if (definition.children.length === 0) { + result += " return node;\r\n" + result += " }\r\n"; + continue; + } + + //if (definition.children.length === 1) { + // result += " return node.with" + pascalCase(definition.children[0].name) + "(\r\n"; + //} + //else { + result += " return node.update(\r\n"; + //} + + for (var j = 0; j < definition.children.length; j++) { + var child = definition.children[j]; + + result += " "; + if (child.isOptional) { + result += "node." + child.name + " === null ? null : "; + } + + if (child.isToken) { + result += "this.visitToken(node." + child.name + ")"; + } + else if (child.isList) { + result += "this.visitList(node." + child.name + ")"; + } + else if (child.isSeparatedList) { + result += "this.visitSeparatedList(node." + child.name + ")"; + } + else if (child.type === "SyntaxKind") { + result += "node.kind"; + } + else if (isNodeOrToken(child)) { + result += "<" + child.type + ">this.visitNodeOrToken(node." + child.name + ")"; + } + else { + result += "<" + child.type + ">this.visitNode(node." + child.name + ")"; + } + + if (j < definition.children.length - 1) { + result += ",\r\n"; + } + } + + result += ");\r\n"; + result += " }\r\n"; + } + + result += " }"; + result += "\r\n}"; + return result; +} + +function generateWalker(): string { + var result = ""; + + result += +"///\r\n"+ +"\r\n" + +"module TypeScript {\r\n" + +" export class SyntaxWalker implements ISyntaxVisitor {\r\n" + +" public visitToken(token: ISyntaxToken): void {\r\n" + +" }\r\n" + +"\r\n" + +" public visitNode(node: ISyntaxNode): void {\r\n" + +" visitNodeOrToken(this, node);\r\n" + +" }\r\n" + +"\r\n" + +" public visitNodeOrToken(nodeOrToken: ISyntaxNodeOrToken): void {\r\n" + +" if (isToken(nodeOrToken)) { \r\n" + +" this.visitToken(nodeOrToken);\r\n" + +" }\r\n" + +" else {\r\n" + +" this.visitNode(nodeOrToken);\r\n" + +" }\r\n" + +" }\r\n" + +"\r\n" + +" private visitOptionalToken(token: ISyntaxToken): void {\r\n" + +" if (token === null) {\r\n" + +" return;\r\n" + +" }\r\n" + +"\r\n" + +" this.visitToken(token);\r\n" + +" }\r\n" + +"\r\n" + +" public visitOptionalNode(node: ISyntaxNode): void {\r\n" + +" if (node === null) {\r\n" + +" return;\r\n" + +" }\r\n" + +"\r\n" + +" this.visitNode(node);\r\n" + +" }\r\n" + +"\r\n" + +" public visitOptionalNodeOrToken(nodeOrToken: ISyntaxNodeOrToken): void {\r\n" + +" if (nodeOrToken === null) {\r\n" + +" return;\r\n" + +" }\r\n" + +"\r\n" + +" this.visitNodeOrToken(nodeOrToken);\r\n" + +" }\r\n" + +"\r\n" + +" public visitList(list: ISyntaxNodeOrToken[]): void {\r\n" + +" for (var i = 0, n = list.length; i < n; i++) {\r\n" + +" this.visitNodeOrToken(list[i]);\r\n" + +" }\r\n" + +" }\r\n" + +"\r\n" + +" public visitSeparatedList(list: ISyntaxNodeOrToken[]): void {\r\n" + +" for (var i = 0, n = childCount(list); i < n; i++) {\r\n" + +" var item = childAt(list, i);\r\n" + +" this.visitNodeOrToken(item);\r\n" + +" }\r\n" + +" }\r\n"; + + for (var i = 0; i < definitions.length; i++) { + var definition = definitions[i]; + + result += "\r\n"; + result += " public visit" + getNameWithoutSuffix(definition) + "(node: " + definition.name + "): void {\r\n"; + + for (var j = 0; j < definition.children.length; j++) { + var child = definition.children[j]; + + if (child.isToken) { + if (child.isOptional) { + result += " this.visitOptionalToken(node." + child.name + ");\r\n"; + } + else { + result += " this.visitToken(node." + child.name + ");\r\n"; + } + } + else if (child.isList) { + result += " this.visitList(node." + child.name + ");\r\n"; + } + else if (child.isSeparatedList) { + result += " this.visitSeparatedList(node." + child.name + ");\r\n"; + } + else if (isNodeOrToken(child)) { + if (child.isOptional) { + result += " this.visitOptionalNodeOrToken(node." + child.name + ");\r\n"; + } + else { + result += " this.visitNodeOrToken(node." + child.name + ");\r\n"; + } + } + else if (child.type !== "SyntaxKind") { + if (child.isOptional) { + result += " this.visitOptionalNode(node." + child.name + ");\r\n"; + } + else { + result += " this.visitNode(node." + child.name + ");\r\n"; + } + } + } + + result += " }\r\n"; + } + + result += " }"; + result += "\r\n}"; + return result; +} + +function firstEnumName(e: any, value: number) { + for (var name in e) { + if (e[name] === value) { + return name; + } + } +} + +function groupBy(array: T[], func: (v: T) => string): any { + var result: TypeScript.IIndexable = {}; + + for (var i = 0, n = array.length; i < n; i++) { + var v: any = array[i]; + var k = func(v); + + var list: T[] = result[k] || []; + list.push(v); + result[k] = list; + } + + return result; +} + +function generateKeywordCondition(keywords: { text: string; kind: TypeScript.SyntaxKind; }[], currentCharacter: number, indent: string): string { + var length = keywords[0].text.length; + + var result = ""; + var index: string; + + if (keywords.length === 1) { + var keyword = keywords[0]; + + if (currentCharacter === length) { + return " return SyntaxKind." + firstEnumName(TypeScript.SyntaxKind, keyword.kind) + ";\r\n"; + } + + var keywordText = keywords[0].text; + result = " return (" + + for (var i = currentCharacter; i < length; i++) { + if (i > currentCharacter) { + result += " && "; + } + + index = i === 0 ? "start" : ("start + " + i); + result += "str.charCodeAt(" + index + ") === CharacterCodes." + keywordText.substr(i, 1); + } + + result += ") ? SyntaxKind." + firstEnumName(TypeScript.SyntaxKind, keyword.kind) + " : SyntaxKind.IdentifierName;\r\n"; + } + else { + result += " // " + TypeScript.ArrayUtilities.select(keywords, k => k.text).join(", ") + "\r\n" + // result += "\r\n"; + index = currentCharacter === 0 ? "start" : ("start + " + currentCharacter); + result += indent + "switch(str.charCodeAt(" + index + ")) {\r\n" + + var groupedKeywords = groupBy(keywords, k => k.text.substr(currentCharacter, 1)); + + for (var c in groupedKeywords) { + if (groupedKeywords.hasOwnProperty(c)) { + result += indent + " case CharacterCodes." + c + ":"; + result += generateKeywordCondition(groupedKeywords[c], currentCharacter + 1, indent + " "); + } + } + + result += indent + " default: return SyntaxKind.IdentifierName;\r\n"; + result += indent + "}\r\n"; + } + + return result; +} + +function min(array: T[], func: (v: T) => number): number { + // Debug.assert(array.length > 0); + var min = func(array[0]); + + for (var i = 1; i < array.length; i++) { + var next = func(array[i]); + if (next < min) { + min = next; + } + } + + return min; +} + +function max(array: T[], func: (v: T) => number): number { + // Debug.assert(array.length > 0); + var max = func(array[0]); + + for (var i = 1; i < array.length; i++) { + var next = func(array[i]); + if (next > max) { + max = next; + } + } + + return max; +} + +function generateScannerUtilities(): string { + var result = "///\r\n" + + "\r\n" + + "module TypeScript {\r\n" + + " export class ScannerUtilities {\r\n"; + + var i: number; + var keywords: { text: string; kind: TypeScript.SyntaxKind; }[] = []; + + for (i = TypeScript.SyntaxKind.FirstKeyword; i <= TypeScript.SyntaxKind.LastKeyword; i++) { + keywords.push({ kind: i, text: TypeScript.SyntaxFacts.getText(i) }); + } + + keywords.sort((a, b) => a.text.localeCompare(b.text)); + + result += " public static identifierKind(str: string, start: number, length: number): SyntaxKind {\r\n"; + + var minTokenLength = min(keywords, k => k.text.length); + var maxTokenLength = max(keywords, k => k.text.length); + result += " switch (length) {\r\n"; + + + for (i = minTokenLength; i <= maxTokenLength; i++) { + var keywordsOfLengthI = TypeScript.ArrayUtilities.where(keywords, k => k.text.length === i); + if (keywordsOfLengthI.length > 0) { + result += " case " + i + ":"; + result += generateKeywordCondition(keywordsOfLengthI, 0, " "); + } + } + + result += " default: return SyntaxKind.IdentifierName;\r\n"; + result += " }\r\n"; + result += " }\r\n"; + + result += " }\r\n"; + result += "}"; + + return result; +} + +function generateVisitor(): string { + var result = ""; + + result += "///\r\n\r\n"; + + result += "module TypeScript {\r\n"; + result += " export function visitNodeOrToken(visitor: ISyntaxVisitor, element: ISyntaxNodeOrToken): any {\r\n"; + result += " if (element === null) { return null; }\r\n"; + result += " if (isToken(element)) { return visitor.visitToken(element); }\r\n"; + result += " switch (element.kind()) {\r\n"; + + for (var i = 0; i < definitions.length; i++) { + var definition = definitions[i]; + + if (definition.syntaxKinds) { + result += " "; + for (var j = 0; j < definition.syntaxKinds.length; j++) { + result += " case SyntaxKind." + definition.syntaxKinds[j] + ":" + } + result += "\r\n "; + } + else { + result += " case SyntaxKind." + getNameWithoutSuffix(definition) + ": "; + } + + result += "return visitor.visit" + getNameWithoutSuffix(definition) + "(<" + definition.name + ">element);\r\n"; + } + + result += " }\r\n\r\n"; + result += " throw Errors.invalidOperation();\r\n"; + result += " }\r\n\r\n"; + + result += " export interface ISyntaxVisitor {\r\n"; + result += " visitToken(token: ISyntaxToken): any;\r\n"; + + for (i = 0; i < definitions.length; i++) { + definition = definitions[i]; + result += " visit" + getNameWithoutSuffix(definition) + "(node: " + definition.name + "): any;\r\n"; + } + + result += " }"; + + result += "\r\n}"; + + return result; +} + +function generateDefaultVisitor(): string { + var result = ""; + + result += "///\r\n\r\n"; + + result += "module TypeScript {\r\n"; + if (!forPrettyPrinter) { + result += " export class SyntaxVisitor implements ISyntaxVisitor {\r\n"; + result += " public defaultVisit(node: ISyntaxNodeOrToken): any {\r\n"; + result += " return null;\r\n"; + result += " }\r\n"; + result += "\r\n"; + result += " public visitToken(token: ISyntaxToken): any {\r\n"; + result += " return this.defaultVisit(token);\r\n"; + result += " }\r\n"; + + for (var i = 0; i < definitions.length; i++) { + var definition = definitions[i]; + + result += "\r\n public visit" + getNameWithoutSuffix(definition) + "(node: " + definition.name + "): any {\r\n"; + result += " return this.defaultVisit(node);\r\n"; + result += " }\r\n"; + } + + result += " }"; + } + + result += "\r\n}"; + + return result; +} + +function generateFactory(): string { + var result = "///\r\n"; + + result += "\r\nmodule TypeScript.Syntax {\r\n"; + result += " export interface IFactory {\r\n"; + + var i: number; + var j: number; + var definition: ITypeDefinition; + var child: IMemberDefinition; + + for (i = 0; i < definitions.length; i++) { + definition = definitions[i]; + result += " " + camelCase(getNameWithoutSuffix(definition)) + "("; + + for (j = 0; j < definition.children.length; j++) { + if (j > 0) { + result += ", "; + } + + child = definition.children[j]; + result += child.name + ": " + getType(child); + } + + result += "): " + definition.name + ";\r\n"; + } + + result += " }\r\n\r\n"; + + // TODO: stop exporting these once compiler bugs are fixed. + result += " export class NormalModeFactory implements IFactory {\r\n"; + + for (i = 0; i < definitions.length; i++) { + definition = definitions[i]; + result += " " + camelCase(getNameWithoutSuffix(definition)) + "("; + + for (j = 0; j < definition.children.length; j++) { + if (j > 0) { + result += ", "; + } + + child = definition.children[j]; + result += getSafeName(child) + ": " + getType(child); + } + + result += "): " + definition.name + " {\r\n"; + result += " return new " + definition.name + "("; + + for (j = 0; j < definition.children.length; j++) { + child = definition.children[j]; + result += getSafeName(child); + result += ", "; + } + + result += "/*data:*/ 0);\r\n"; + result += " }\r\n" + } + + result += " }\r\n\r\n"; + + // TODO: stop exporting these once compiler bugs are fixed. + result += " export class StrictModeFactory implements IFactory {\r\n"; + + for (i = 0; i < definitions.length; i++) { + definition = definitions[i]; + result += " " + camelCase(getNameWithoutSuffix(definition)) + "("; + + for (j = 0; j < definition.children.length; j++) { + if (j > 0) { + result += ", "; + } + + child = definition.children[j]; + result += getSafeName(child) + ": " + getType(child); + } + + result += "): " + definition.name + " {\r\n"; + result += " return new " + definition.name + "("; + + for (j = 0; j < definition.children.length; j++) { + child = definition.children[j]; + result += getSafeName(child); + result += ", "; + } + + result += "/*data:*/ SyntaxConstants.NodeParsedInStrictModeMask);\r\n"; + + result += " }\r\n" + } + + result += " }\r\n\r\n"; + + result += " export var normalModeFactory: IFactory = new NormalModeFactory();\r\n"; + result += " export var strictModeFactory: IFactory = new StrictModeFactory();\r\n"; + result += "}"; + + return result; +} + +function generateServicesUtilities(): string { + var result = ""; // "/// \r\n\r\n"; + + result += generateIsTypeScriptSpecific(); + + return result; +} + +function generateIsTypeScriptSpecific(): string { + var result = ""; + + result += "module TypeScript {\r\n"; + + result += " function isSeparatedListTypeScriptSpecific(list: ISyntaxNodeOrToken[]): boolean {\r\n" + result += " for (var i = 0, n = childCount(list); i < n; i++) {\r\n"; + result += " if (isTypeScriptSpecific(childAt(list, i))) {\r\n"; + result += " return true;\r\n"; + result += " }\r\n"; + result += " }\r\n\r\n"; + result += " return false;\r\n"; + result += " }\r\n\r\n"; + + result += " function isListTypeScriptSpecific(list: ISyntaxNodeOrToken[]): boolean {\r\n" + result += " for (var i = 0, n = list.length; i < n; i++) {\r\n"; + result += " if (isTypeScriptSpecific(list[i])) {\r\n"; + result += " return true;\r\n"; + result += " }\r\n"; + result += " }\r\n\r\n"; + result += " return false;\r\n"; + result += " }\r\n\r\n"; + + result += " export function isTypeScriptSpecific(element: ISyntaxElement): boolean {\r\n" + result += " if (element === null) { return false; }\r\n"; + result += " if (isToken(element)) { return false; }\r\n"; + result += " if (isList(element)) { return isListTypeScriptSpecific(element); }\r\n"; + result += " if (isSeparatedList(element)) { return isSeparatedListTypeScriptSpecific(element); }\r\n\r\n"; + result += " switch (element.kind()) {\r\n"; + + for (var i = 0; i < definitions.length; i++) { + var definition = definitions[i]; + if (!definition.isTypeScriptSpecific) { + continue; + } + + if (definition.syntaxKinds) { + for (var j = 0; j < definition.syntaxKinds.length; j++) { + result += " case SyntaxKind." + definition.syntaxKinds[j] + ":\r\n"; + } + } + else { + result += " case SyntaxKind." + getNameWithoutSuffix(definition) + ":\r\n"; + } + } + + result += " return true;\r\n"; + + var triviallyFalseDefinitions = definitions.filter(d => d.children.filter(c => c.type !== "SyntaxKind" && !c.isToken).length === 0); + for (var i = 0; i < triviallyFalseDefinitions.length; i++) { + var definition = triviallyFalseDefinitions[i]; + if (definition.isTypeScriptSpecific) { + continue; + } + + if (definition.syntaxKinds) { + for (var j = 0; j < definition.syntaxKinds.length; j++) { + result += " case SyntaxKind." + definition.syntaxKinds[j] + ":\r\n"; + } + } + else { + result += " case SyntaxKind." + getNameWithoutSuffix(definition) + ":\r\n"; + } + } + + result += " return false;\r\n"; + + for (var i = 0; i < definitions.length; i++) { + var definition = definitions[i]; + if (definition.isTypeScriptSpecific) { + continue; + } + + if (definition.children.filter(c => c.type !== "SyntaxKind" && !c.isToken).length === 0) { + continue; + } + + if (definition.syntaxKinds) { + result += " "; + for (var j = 0; j < definition.syntaxKinds.length; j++) { + result += " case SyntaxKind." + definition.syntaxKinds[j] + ":"; + } + } + else { + result += " case SyntaxKind." + getNameWithoutSuffix(definition) + ":"; + } + result += "\r\n"; + result += " return is" + getNameWithoutSuffix(definition) + "TypeScriptSpecific(<" + definition.name + ">element);\r\n"; + } + + result += " }\r\n"; + result += " }\r\n"; + + for (var i = 0; i < definitions.length; i++) { + var definition = definitions[i]; + if (definition.isTypeScriptSpecific) { + continue; + } + + var importantChildren = definition.children.filter(d => d.type !== "SyntaxKind" && !d.isToken); + if (importantChildren.length > 0) { + result += generateIsTypeScriptSpecificMethod(definition); + } + } + + result += "}"; + + return result; +} + +function generateIsTypeScriptSpecificMethod(definition: ITypeDefinition): string { + var result = "\r\n function is" + getNameWithoutSuffix(definition) + "TypeScriptSpecific(node: " + definition.name + "): boolean {\r\n"; + + result += " return "; + + var addedCheck = false; + for (var i = 0; i < definition.children.length; i++) { + var child = definition.children[i]; + + if (child.type === "SyntaxKind") { + continue; + } + + if (child.isToken) { + continue; + } + + if (addedCheck) { + result += " ||\r\n "; + } + + addedCheck = true; + + if (child.isTypeScriptSpecific) { + if (child.isList) { + result += getPropertyAccess(child, "node") + ".length > 0"; + } + else if (child.isSeparatedList) { + result += getPropertyAccess(child, "node") + ".childCount() > 0"; + } + else { + result += getPropertyAccess(child, "node") + " !== null"; + } + } + else { + result += "isTypeScriptSpecific(" + getPropertyAccess(child, "node") + ")"; + } + } + + if (!addedCheck) { + result += "false"; + } + + result += ";\r\n"; + result += " }\r\n"; + + return result; +} + +var syntaxNodesConcrete = generateNodes(/*abstract:*/ false); +var syntaxNodesAbstract = generateNodes(/*abstract:*/ true); +var syntaxInterfaces = generateSyntaxInterfaces(); +var rewriter = generateRewriter(); +var walker = generateWalker(); +var scannerUtilities = generateScannerUtilities(); +var visitor = generateVisitor(); +var defaultVisitor = generateDefaultVisitor(); +var servicesUtilities = generateServicesUtilities(); + +TypeScript.Environment.writeFile(TypeScript.Environment.currentDirectory() + "\\src\\compiler\\syntax\\syntaxNodes.concrete.generated.ts", syntaxNodesConcrete, false); +TypeScript.Environment.writeFile(TypeScript.Environment.currentDirectory() + "\\src\\compiler\\syntax\\syntaxNodes.abstract.generated.ts", syntaxNodesAbstract, false); +TypeScript.Environment.writeFile(TypeScript.Environment.currentDirectory() + "\\src\\compiler\\syntax\\syntaxNodes.interfaces.generated.ts", syntaxInterfaces, false); +TypeScript.Environment.writeFile(TypeScript.Environment.currentDirectory() + "\\src\\services\\syntaxRewriter.generated.ts", rewriter, false); +TypeScript.Environment.writeFile(TypeScript.Environment.currentDirectory() + "\\src\\compiler\\syntax\\syntaxWalker.generated.ts", walker, false); +TypeScript.Environment.writeFile(TypeScript.Environment.currentDirectory() + "\\src\\compiler\\syntax\\scannerUtilities.generated.ts", scannerUtilities, false); +TypeScript.Environment.writeFile(TypeScript.Environment.currentDirectory() + "\\src\\compiler\\syntax\\syntaxVisitor.generated.ts", visitor, false); +TypeScript.Environment.writeFile(TypeScript.Environment.currentDirectory() + "\\src\\compiler\\syntax\\defaultSyntaxVisitor.generated.ts", defaultVisitor, false); +TypeScript.Environment.writeFile(TypeScript.Environment.currentDirectory() + "\\src\\services\\syntaxUtilities.generated.ts", servicesUtilities, false); diff --git a/src/services/syntax/syntaxIndenter.ts b/src/services/syntax/syntaxIndenter.ts new file mode 100644 index 00000000000..17b79356854 --- /dev/null +++ b/src/services/syntax/syntaxIndenter.ts @@ -0,0 +1,164 @@ +/// + +module TypeScript { + export class SyntaxIndenter extends SyntaxRewriter { + private lastTriviaWasNewLine: boolean; + private indentationTrivia: ISyntaxTrivia; + + constructor(indentFirstToken: boolean, + private indentationAmount: number, + private options: FormattingOptions) { + super(); + this.lastTriviaWasNewLine = indentFirstToken; + this.indentationTrivia = Indentation.indentationTrivia(this.indentationAmount, this.options); + } + + public visitToken(token: ISyntaxToken): ISyntaxToken { + if (token.width() === 0) { + return token; + } + + var result = token; + if (this.lastTriviaWasNewLine) { + // have to add our indentation to every line that this token hits. + result = token.withLeadingTrivia(this.indentTriviaList(token.leadingTrivia())); + } + + this.lastTriviaWasNewLine = token.hasTrailingNewLine(); + return result; + } + + public indentTriviaList(triviaList: ISyntaxTriviaList): ISyntaxTriviaList { + var result: ISyntaxTrivia[] = []; + + // First, update any existing trivia with the indent amount. For example, combine the + // indent with any whitespace trivia, or prepend any comments with the trivia. + var indentNextTrivia = true; + for (var i = 0, n = triviaList.count(); i < n; i++) { + var trivia = triviaList.syntaxTriviaAt(i); + + var indentThisTrivia = indentNextTrivia; + indentNextTrivia = false; + + switch (trivia.kind()) { + case SyntaxKind.MultiLineCommentTrivia: + this.indentMultiLineComment(trivia, indentThisTrivia, result); + continue; + + case SyntaxKind.SingleLineCommentTrivia: + case SyntaxKind.SkippedTokenTrivia: + this.indentSingleLineOrSkippedText(trivia, indentThisTrivia, result); + continue; + + case SyntaxKind.WhitespaceTrivia: + this.indentWhitespace(trivia, indentThisTrivia, result); + continue; + + case SyntaxKind.NewLineTrivia: + // We hit a newline processing the trivia. We need to add the indentation to the + // next line as well. Note: don't bother indenting the newline itself. This will + // just insert ugly whitespace that most users probably will not want. + result.push(trivia); + indentNextTrivia = true; + continue; + + default: + throw Errors.invalidOperation(); + } + } + + // Then, if the last trivia was a newline (or there was no trivia at all), then just add the + // indentation in right before the token. + if (indentNextTrivia) { + result.push(this.indentationTrivia); + } + + return Syntax.triviaList(result); + } + + private indentSegment(segment: string): string { + // Find the position of the first non whitespace character in the segment. + var firstNonWhitespacePosition = Indentation.firstNonWhitespacePosition(segment); + + if (firstNonWhitespacePosition < segment.length && + CharacterInfo.isLineTerminator(segment.charCodeAt(firstNonWhitespacePosition))) { + + // If this segment was just a newline, then don't bother indenting it. That will just + // leave the user with an ugly indent in their output that they probably do not want. + return segment; + } + + // Convert that position to a column. + var firstNonWhitespaceColumn = Indentation.columnForPositionInString(segment, firstNonWhitespacePosition, this.options); + + // Find the new column we want the nonwhitespace text to start at. + var newFirstNonWhitespaceColumn = firstNonWhitespaceColumn + this.indentationAmount; + + // Compute an indentation string for that. + var indentationString = Indentation.indentationString(newFirstNonWhitespaceColumn, this.options); + + // Join the new indentation and the original string without its indentation. + return indentationString + segment.substring(firstNonWhitespacePosition); + } + + private indentWhitespace(trivia: ISyntaxTrivia, indentThisTrivia: boolean, result: ISyntaxTrivia[]): void { + if (!indentThisTrivia) { + // Line didn't start with this trivia. So no need to touch it. Just add to the result + // and continue on. + result.push(trivia); + return; + } + + // Line started with this trivia. We want to figure out what the final column this + // whitespace goes to will be. To do that we add the column it is at now to the column we + // want to indent to. We then compute the final tabs+whitespace string for that. + var newIndentation = this.indentSegment(trivia.fullText()); + result.push(Syntax.whitespace(newIndentation)); + } + + private indentSingleLineOrSkippedText(trivia: ISyntaxTrivia, indentThisTrivia: boolean, result: ISyntaxTrivia[]): void { + if (indentThisTrivia) { + // The line started with a comment or skipped text. Add an indentation based + // on the desired settings, and then add the trivia itself. + result.push(this.indentationTrivia); + } + + result.push(trivia); + } + + private indentMultiLineComment(trivia: ISyntaxTrivia, indentThisTrivia: boolean, result: ISyntaxTrivia[]): void { + if (indentThisTrivia) { + // The line started with a multiline comment. Add an indentation based + // on the desired settings, and then add the trivia itself. + result.push(this.indentationTrivia); + } + + // If the multiline comment spans multiple lines, we need to add the right indent amount to + // each successive line segment as well. + var segments = Syntax.splitMultiLineCommentTriviaIntoMultipleLines(trivia); + + for (var i = 1; i < segments.length; i++) { + segments[i] = this.indentSegment(segments[i]); + } + + var newText = segments.join(""); + result.push(Syntax.multiLineComment(newText)); + } + + public static indentNode(node: ISyntaxNode, indentFirstToken: boolean, indentAmount: number, options: FormattingOptions): SyntaxNode { + var indenter = new SyntaxIndenter(indentFirstToken, indentAmount, options); + return node.accept(indenter); + } + + public static indentNodes(nodes: SyntaxNode[], indentFirstToken: boolean, indentAmount: number, options: FormattingOptions): SyntaxNode[] { + // Note: it is necessary for correctness that we reuse the same SyntaxIndenter here. + // That's because when working on nodes 1-N, we need to know if the previous node ended + // with a newline. The indenter will track that for us. + + var indenter = new SyntaxIndenter(indentFirstToken, indentAmount, options); + var result: SyntaxNode[] = ArrayUtilities.select(nodes, n => n.accept(indenter)); + + return result; + } + } +} \ No newline at end of file diff --git a/src/services/syntax/syntaxInterfaces.generated.ts b/src/services/syntax/syntaxInterfaces.generated.ts new file mode 100644 index 00000000000..b7f99f68b28 --- /dev/null +++ b/src/services/syntax/syntaxInterfaces.generated.ts @@ -0,0 +1,499 @@ +/// + +module TypeScript { + export enum NodeFlags { + Export = 0x00000001, // Declarations + Ambient = 0x00000002, // Declarations + Optional = 0x00000004, // Parameter/Property/Method + Rest = 0x00000008, // Parameter + Public = 0x00000010, // Property/Method + Private = 0x00000020, // Property/Method + Static = 0x00000040, // Property/Method + } + + interface SyntaxElement { + kind: SyntaxKind; + } + + interface SyntaxNode extends SyntaxElement { + flags: NodeFlags; + } + + function nodeStart(node: Node): number { + } + + function nodeWidth(node: Node): number { + } + + interface SyntaxToken extends Name, PrimaryExpression { + } + + // The raw text of the token, as written in the original source. + function tokenText(token: SyntaxToken): string { + } + + // The token's javascript value. i.e. 0.0 in the text would have the javascript number value: 0. + function tokenValue(token: SyntaxToken): any { + } + + // The token's value in string form. i.e. \u0041 in the source text would result in a string with the text: A. + function tokenValueText(token: SyntaxToken): string { + } + + interface SyntaxList extends SyntaxElement { + length: number; + item(index: number): T; + } + + interface SourceUnit extends Node { + moduleElements: SyntaxList; + } + + interface QualifiedName extends Name { + left: Name; + right: SyntaxToken; + } + + interface ObjectType extends Type { + typeMembers: SyntaxList; + } + + interface FunctionType extends Type { + typeParameterList?: TypeParameterList; + parameterList: ParameterList; + type: Type; + } + + interface ArrayType extends Type { + type: Type; + } + + interface ConstructorType extends Type { + typeParameterList?: TypeParameterList; + parameterList: ParameterList; + type: Type; + } + + interface GenericType extends Type { + name: Name; + typeArgumentList: TypeArgumentList; + } + + interface TypeQuery extends Type { + name: Name; + } + + interface InterfaceDeclaration extends ModuleElement { + identifier: SyntaxToken; + typeParameterList?: TypeParameterList; + heritageClauses: SyntaxList; + body: ObjectType; + } + + interface FunctionDeclaration extends Statement { + identifier: SyntaxToken; + callSignature: CallSignature; + block?: Block; + } + + interface ModuleDeclaration extends ModuleElement { + name?: Name; + stringLiteral?: SyntaxToken; + moduleElements: SyntaxList; + } + + interface ClassDeclaration extends ModuleElement { + identifier: SyntaxToken; + typeParameterList?: TypeParameterList; + heritageClauses: SyntaxList; + classElements: SyntaxList; + } + + interface EnumDeclaration extends ModuleElement { + identifier: SyntaxToken; + enumElements: SyntaxList; + } + + interface ImportDeclaration extends ModuleElement { + identifier: SyntaxToken; + moduleReference: ModuleReference; + } + + interface ExportAssignment extends ModuleElement { + identifier: SyntaxToken; + } + + interface MemberFunctionDeclaration extends MemberDeclaration { + propertyName: SyntaxToken; + callSignature: CallSignature; + block?: Block; + } + + interface MemberVariableDeclaration extends MemberDeclaration { + variableDeclarator: VariableDeclarator; + } + + interface ConstructorDeclaration extends ClassElement { + callSignature: CallSignature; + block?: Block; + } + + interface IndexMemberDeclaration extends ClassElement { + indexSignature: IndexSignature; + } + + interface GetAccessor extends MemberDeclaration, PropertyAssignment { + propertyName: SyntaxToken; + callSignature: CallSignature; + block: Block; + } + + interface SetAccessor extends MemberDeclaration, PropertyAssignment { + propertyName: SyntaxToken; + callSignature: CallSignature; + block: Block; + } + + interface PropertySignature extends TypeMember { + propertyName: SyntaxToken; + typeAnnotation?: TypeAnnotation; + } + + interface CallSignature extends TypeMember { + typeParameterList?: TypeParameterList; + parameterList: ParameterList; + typeAnnotation?: TypeAnnotation; + } + + interface ConstructSignature extends TypeMember { + callSignature: CallSignature; + } + + interface IndexSignature extends TypeMember { + parameters: SyntaxList; + typeAnnotation?: TypeAnnotation; + } + + interface MethodSignature extends TypeMember { + propertyName: SyntaxToken; + callSignature: CallSignature; + } + + interface Block extends Statement { + statements: SyntaxList; + } + + interface IfStatement extends Statement { + condition: Expression; + statement: Statement; + elseClause?: ElseClause; + } + + interface VariableStatement extends Statement { + variableDeclaration: VariableDeclaration; + } + + interface ExpressionStatement extends Statement { + expression: Expression; + } + + interface ReturnStatement extends Statement { + expression?: Expression; + } + + interface SwitchStatement extends Statement { + expression: Expression; + switchClauses: SyntaxList; + } + + interface BreakStatement extends Statement { + identifier?: SyntaxToken; + } + + interface ContinueStatement extends Statement { + identifier?: SyntaxToken; + } + + interface ForStatement extends Statement { + variableDeclaration?: VariableDeclaration; + initializer?: Expression; + condition?: Expression; + incrementor?: Expression; + statement: Statement; + } + + interface ForInStatement extends Statement { + variableDeclaration?: VariableDeclaration; + left?: Expression; + expression: Expression; + statement: Statement; + } + + interface ThrowStatement extends Statement { + expression: Expression; + } + + interface WhileStatement extends Statement { + condition: Expression; + statement: Statement; + } + + interface TryStatement extends Statement { + block: Block; + catchClause?: CatchClause; + finallyClause?: FinallyClause; + } + + interface LabeledStatement extends Statement { + identifier: SyntaxToken; + statement: Statement; + } + + interface DoStatement extends Statement { + statement: Statement; + condition: Expression; + } + + interface WithStatement extends Statement { + condition: Expression; + statement: Statement; + } + + interface PrefixUnaryExpression extends UnaryExpression { + operand: UnaryExpression; + } + + interface DeleteExpression extends UnaryExpression { + expression: UnaryExpression; + } + + interface TypeOfExpression extends UnaryExpression { + expression: UnaryExpression; + } + + interface VoidExpression extends UnaryExpression { + expression: UnaryExpression; + } + + interface ConditionalExpression extends Expression { + condition: Expression; + whenTrue: Expression; + whenFalse: Expression; + } + + interface BinaryExpression extends Expression { + left: Expression; + right: Expression; + } + + interface PostfixUnaryExpression extends PostfixExpression { + operand: LeftHandSideExpression; + } + + interface MemberAccessExpression extends MemberExpression, CallExpression { + expression: LeftHandSideExpression; + name: SyntaxToken; + } + + interface InvocationExpression extends CallExpression { + expression: LeftHandSideExpression; + argumentList: ArgumentList; + } + + interface ArrayLiteralExpression extends PrimaryExpression { + expressions: SyntaxList; + } + + interface ObjectLiteralExpression extends PrimaryExpression { + propertyAssignments: SyntaxList; + } + + interface ObjectCreationExpression extends MemberExpression { + expression: MemberExpression; + argumentList?: ArgumentList; + } + + interface ParenthesizedExpression extends PrimaryExpression { + expression: Expression; + } + + interface ParenthesizedArrowFunctionExpression extends UnaryExpression { + callSignature: CallSignature; + block?: Block; + expression?: Expression; + } + + interface SimpleArrowFunctionExpression extends UnaryExpression { + parameter: Parameter; + block?: Block; + expression?: Expression; + } + + interface CastExpression extends UnaryExpression { + type: Type; + expression: UnaryExpression; + } + + interface ElementAccessExpression extends MemberExpression, CallExpression { + expression: LeftHandSideExpression; + argumentExpression: Expression; + } + + interface FunctionExpression extends PrimaryExpression { + identifier?: SyntaxToken; + callSignature: CallSignature; + block: Block; + } + + interface VariableDeclaration extends Node { + variableDeclarators: SyntaxList; + } + + interface VariableDeclarator extends Node { + propertyName: SyntaxToken; + typeAnnotation?: TypeAnnotation; + equalsValueClause?: EqualsValueClause; + } + + interface ArgumentList extends Node { + typeArgumentList?: TypeArgumentList; + arguments: SyntaxList; + } + + interface ParameterList extends Node { + parameters: SyntaxList; + } + + interface TypeArgumentList extends Node { + typeArguments: SyntaxList; + } + + interface TypeParameterList extends Node { + typeParameters: SyntaxList; + } + + interface HeritageClause extends Node { + typeNames: SyntaxList; + } + + interface EqualsValueClause extends Node { + value: Expression; + } + + interface CaseSwitchClause extends SwitchClause { + expression: Expression; + statements: SyntaxList; + } + + interface DefaultSwitchClause extends SwitchClause { + statements: SyntaxList; + } + + interface ElseClause extends Node { + statement: Statement; + } + + interface CatchClause extends Node { + identifier: SyntaxToken; + typeAnnotation?: TypeAnnotation; + block: Block; + } + + interface FinallyClause extends Node { + block: Block; + } + + interface TypeParameter extends Node { + identifier: SyntaxToken; + constraint?: Constraint; + } + + interface Constraint extends Node { + type: Type; + } + + interface SimplePropertyAssignment extends PropertyAssignment { + propertyName: SyntaxToken; + expression: Expression; + } + + interface FunctionPropertyAssignment extends PropertyAssignment { + propertyName: SyntaxToken; + callSignature: CallSignature; + block: Block; + } + + interface Parameter extends Node { + identifier: SyntaxToken; + typeAnnotation?: TypeAnnotation; + equalsValueClause?: EqualsValueClause; + } + + interface EnumElement extends Node { + propertyName: SyntaxToken; + equalsValueClause?: EqualsValueClause; + } + + interface TypeAnnotation extends Node { + type: Type; + } + + interface ExternalModuleReference extends ModuleReference { + stringLiteral: SyntaxToken; + } + + interface ModuleNameModuleReference extends ModuleReference { + moduleName: Name; + } + + interface MemberDeclaration extends ClassElement { + } + + interface Statement extends ModuleElement { + } + + interface Name extends Type { + } + + interface UnaryExpression extends Expression { + } + + interface PostfixExpression extends UnaryExpression { + } + + interface LeftHandSideExpression extends PostfixExpression { + } + + interface MemberExpression extends LeftHandSideExpression { + } + + interface CallExpression extends LeftHandSideExpression { + } + + interface PrimaryExpression extends MemberExpression { + } + + interface ModuleElement extends SyntaxElement { + } + + interface ModuleReference extends Node { + } + + interface ClassElement extends Node { + } + + interface TypeMember extends Node { + } + + interface PropertyAssignment extends Node { + } + + interface SwitchClause extends Node { + } + + interface Expression extends SyntaxElement { + } + + interface Type extends SyntaxElement { + } +} \ No newline at end of file diff --git a/src/services/syntax/syntaxKind.ts b/src/services/syntax/syntaxKind.ts new file mode 100644 index 00000000000..bcc6ab46eec --- /dev/null +++ b/src/services/syntax/syntaxKind.ts @@ -0,0 +1,337 @@ +// If you change anything in this enum, make sure you run SyntaxGenerator again! + +module TypeScript { + export enum SyntaxKind { + // Variable width tokens, trivia and lists. + None, + List, + SeparatedList, + TriviaList, + + // Trivia + WhitespaceTrivia, + NewLineTrivia, + MultiLineCommentTrivia, + SingleLineCommentTrivia, + SkippedTokenTrivia, + + // Note: all variable width tokens must come before all fixed width tokens. + + ErrorToken, + EndOfFileToken, + + // Tokens + IdentifierName, + + // LiteralTokens + RegularExpressionLiteral, + NumericLiteral, + StringLiteral, + + // All fixed width tokens follow. + + // Keywords + BreakKeyword, + CaseKeyword, + CatchKeyword, + ContinueKeyword, + DebuggerKeyword, + DefaultKeyword, + DeleteKeyword, + DoKeyword, + ElseKeyword, + FalseKeyword, + FinallyKeyword, + ForKeyword, + FunctionKeyword, + IfKeyword, + InKeyword, + InstanceOfKeyword, + NewKeyword, + NullKeyword, + ReturnKeyword, + SwitchKeyword, + ThisKeyword, + ThrowKeyword, + TrueKeyword, + TryKeyword, + TypeOfKeyword, + VarKeyword, + VoidKeyword, + WhileKeyword, + WithKeyword, + + // FutureReservedWords. + ClassKeyword, + ConstKeyword, + EnumKeyword, + ExportKeyword, + ExtendsKeyword, + ImportKeyword, + SuperKeyword, + + // FutureReservedStrictWords. + ImplementsKeyword, + InterfaceKeyword, + LetKeyword, + PackageKeyword, + PrivateKeyword, + ProtectedKeyword, + PublicKeyword, + StaticKeyword, + YieldKeyword, + + // TypeScript keywords. + AnyKeyword, + BooleanKeyword, + ConstructorKeyword, + DeclareKeyword, + GetKeyword, + ModuleKeyword, + RequireKeyword, + NumberKeyword, + SetKeyword, + StringKeyword, + + // Punctuators + OpenBraceToken, + CloseBraceToken, + OpenParenToken, + CloseParenToken, + OpenBracketToken, + CloseBracketToken, + DotToken, + DotDotDotToken, + SemicolonToken, + CommaToken, + LessThanToken, + GreaterThanToken, + LessThanEqualsToken, + GreaterThanEqualsToken, + EqualsEqualsToken, + EqualsGreaterThanToken, + ExclamationEqualsToken, + EqualsEqualsEqualsToken, + ExclamationEqualsEqualsToken, + PlusToken, + MinusToken, + AsteriskToken, + PercentToken, + PlusPlusToken, + MinusMinusToken, + LessThanLessThanToken, + GreaterThanGreaterThanToken, + GreaterThanGreaterThanGreaterThanToken, + AmpersandToken, + BarToken, + CaretToken, + ExclamationToken, + TildeToken, + AmpersandAmpersandToken, + BarBarToken, + QuestionToken, + ColonToken, + EqualsToken, + PlusEqualsToken, + MinusEqualsToken, + AsteriskEqualsToken, + PercentEqualsToken, + LessThanLessThanEqualsToken, + GreaterThanGreaterThanEqualsToken, + GreaterThanGreaterThanGreaterThanEqualsToken, + AmpersandEqualsToken, + BarEqualsToken, + CaretEqualsToken, + SlashToken, + SlashEqualsToken, + + // SyntaxNodes + SourceUnit, + + // Names + QualifiedName, + + // Types + ObjectType, + FunctionType, + ArrayType, + ConstructorType, + GenericType, + TypeQuery, + + // Module elements. + InterfaceDeclaration, + FunctionDeclaration, + ModuleDeclaration, + ClassDeclaration, + EnumDeclaration, + ImportDeclaration, + ExportAssignment, + + // ClassElements + MemberFunctionDeclaration, + MemberVariableDeclaration, + ConstructorDeclaration, + IndexMemberDeclaration, + + // ClassElement and PropertyAssignment + GetAccessor, + SetAccessor, + + // Type members. + PropertySignature, + CallSignature, + ConstructSignature, + IndexSignature, + MethodSignature, + + // Statements + Block, + IfStatement, + VariableStatement, + ExpressionStatement, + ReturnStatement, + SwitchStatement, + BreakStatement, + ContinueStatement, + ForStatement, + ForInStatement, + EmptyStatement, + ThrowStatement, + WhileStatement, + TryStatement, + LabeledStatement, + DoStatement, + DebuggerStatement, + WithStatement, + + // Expressions + PlusExpression, + NegateExpression, + BitwiseNotExpression, + LogicalNotExpression, + PreIncrementExpression, + PreDecrementExpression, + DeleteExpression, + TypeOfExpression, + VoidExpression, + CommaExpression, + AssignmentExpression, + AddAssignmentExpression, + SubtractAssignmentExpression, + MultiplyAssignmentExpression, + DivideAssignmentExpression, + ModuloAssignmentExpression, + AndAssignmentExpression, + ExclusiveOrAssignmentExpression, + OrAssignmentExpression, + LeftShiftAssignmentExpression, + SignedRightShiftAssignmentExpression, + UnsignedRightShiftAssignmentExpression, + ConditionalExpression, + LogicalOrExpression, + LogicalAndExpression, + BitwiseOrExpression, + BitwiseExclusiveOrExpression, + BitwiseAndExpression, + EqualsWithTypeConversionExpression, + NotEqualsWithTypeConversionExpression, + EqualsExpression, + NotEqualsExpression, + LessThanExpression, + GreaterThanExpression, + LessThanOrEqualExpression, + GreaterThanOrEqualExpression, + InstanceOfExpression, + InExpression, + LeftShiftExpression, + SignedRightShiftExpression, + UnsignedRightShiftExpression, + MultiplyExpression, + DivideExpression, + ModuloExpression, + AddExpression, + SubtractExpression, + PostIncrementExpression, + PostDecrementExpression, + MemberAccessExpression, + InvocationExpression, + ArrayLiteralExpression, + ObjectLiteralExpression, + ObjectCreationExpression, + ParenthesizedExpression, + ParenthesizedArrowFunctionExpression, + SimpleArrowFunctionExpression, + CastExpression, + ElementAccessExpression, + FunctionExpression, + OmittedExpression, + + // Variable declarations + VariableDeclaration, + VariableDeclarator, + + // Lists + ArgumentList, + ParameterList, + TypeArgumentList, + TypeParameterList, + + // Clauses + ExtendsHeritageClause, + ImplementsHeritageClause, + EqualsValueClause, + CaseSwitchClause, + DefaultSwitchClause, + ElseClause, + CatchClause, + FinallyClause, + + // Generics + TypeParameter, + Constraint, + + // Property Assignment + SimplePropertyAssignment, + // GetAccessorPropertyAssignment, + // SetAccessorPropertyAssignment, + FunctionPropertyAssignment, + + // Misc. + Parameter, + EnumElement, + TypeAnnotation, + ExternalModuleReference, + ModuleNameModuleReference, + + FirstStandardKeyword = BreakKeyword, + LastStandardKeyword = WithKeyword, + + FirstFutureReservedKeyword = ClassKeyword, + LastFutureReservedKeyword = SuperKeyword, + + FirstFutureReservedStrictKeyword = ImplementsKeyword, + LastFutureReservedStrictKeyword = YieldKeyword, + + FirstTypeScriptKeyword = AnyKeyword, + LastTypeScriptKeyword = StringKeyword, + + FirstKeyword = FirstStandardKeyword, + LastKeyword = LastTypeScriptKeyword, + + FirstToken = ErrorToken, + LastToken = SlashEqualsToken, + + FirstPunctuation = OpenBraceToken, + LastPunctuation = SlashEqualsToken, + + FirstFixedWidth = FirstKeyword, + LastFixedWidth = LastPunctuation, + + FirstTrivia = WhitespaceTrivia, + LastTrivia = SkippedTokenTrivia, + + FirstNode = SourceUnit, + LastNode = ModuleNameModuleReference, + } +} \ No newline at end of file diff --git a/src/services/syntax/syntaxList.ts b/src/services/syntax/syntaxList.ts new file mode 100644 index 00000000000..52bc02ecdca --- /dev/null +++ b/src/services/syntax/syntaxList.ts @@ -0,0 +1,95 @@ +/// + +interface Array { + data: number; + separators?: TypeScript.ISyntaxToken[]; + + kind(): TypeScript.SyntaxKind; + parent: TypeScript.ISyntaxElement; + + separatorCount(): number; + separatorAt(index: number): TypeScript.ISyntaxToken; +} + +module TypeScript.Syntax { + var _emptyList: ISyntaxNodeOrToken[] = []; + + var _emptySeparatedList: ISyntaxNodeOrToken[] = []; + var _emptySeparators: ISyntaxToken[] = []; + + _emptySeparatedList.separators = _emptySeparators; + + function assertEmptyLists() { + // Debug.assert(_emptyList.length === 0); + // var separators = _emptySeparatedList.separators; + // Debug.assert(!separators || separators.length === 0); + } + + Array.prototype.kind = function () { + return this.separators === undefined ? SyntaxKind.List : SyntaxKind.SeparatedList; + } + + Array.prototype.separatorCount = function (): number { + assertEmptyLists(); + // Debug.assert(this.kind === SyntaxKind.SeparatedList); + return this.separators.length; + } + + Array.prototype.separatorAt = function (index: number): ISyntaxToken { + assertEmptyLists(); + // Debug.assert(this.kind === SyntaxKind.SeparatedList); + // Debug.assert(index >= 0 && index < this.separators.length); + return this.separators[index]; + } + + export function emptyList(): T[] { + return _emptyList; + } + + export function emptySeparatedList(): T[] { + return _emptySeparatedList; + } + + export function list(nodes: T[]): T[] { + if (nodes === undefined || nodes === null || nodes.length === 0) { + return emptyList(); + } + + for (var i = 0, n = nodes.length; i < n; i++) { + nodes[i].parent = nodes; + } + + return nodes; + } + + export function separatedList(nodes: T[], separators: ISyntaxToken[]): T[] { + if (nodes === undefined || nodes === null || nodes.length === 0) { + return emptySeparatedList(); + } + + // Debug.assert(separators.length === nodes.length || separators.length == (nodes.length - 1)); + + for (var i = 0, n = nodes.length; i < n; i++) { + nodes[i].parent = nodes; + } + + for (var i = 0, n = separators.length; i < n; i++) { + separators[i].parent = nodes; + } + + + nodes.separators = separators.length === 0 ? _emptySeparators : separators; + + return nodes; + } + + export function nonSeparatorIndexOf(list: T[], ast: ISyntaxNodeOrToken): number { + for (var i = 0, n = list.length; i < n; i++) { + if (list[i] === ast) { + return i; + } + } + + return -1; + } +} \ No newline at end of file diff --git a/src/services/syntax/syntaxNode.ts b/src/services/syntax/syntaxNode.ts new file mode 100644 index 00000000000..464c59793aa --- /dev/null +++ b/src/services/syntax/syntaxNode.ts @@ -0,0 +1,19 @@ +/// + +module TypeScript { + export class SyntaxNode implements ISyntaxNodeOrToken { + private __kind: SyntaxKind; + public data: number; + public parent: ISyntaxElement; + + constructor(data: number) { + if (data) { + this.data = data; + } + } + + public kind(): SyntaxKind { + return this.__kind; + } + } +} \ No newline at end of file diff --git a/src/services/syntax/syntaxNodeInvariantsChecker.ts b/src/services/syntax/syntaxNodeInvariantsChecker.ts new file mode 100644 index 00000000000..259bd213fda --- /dev/null +++ b/src/services/syntax/syntaxNodeInvariantsChecker.ts @@ -0,0 +1,39 @@ +/// + +// A debug class that we use to make sure a syntax node is valid. Currently, this simply verifies +// that the same token does not appear in the tree multiple times. This is important for +// subsystems that want to map between tokens and positions. If a token shows up multiple times in +// the node, then it will not have a unique position, previous token, etc. etc. and that can screw +// many algorithms. For this reason, when generating trees, it is important that nodes that are +// reused are cloned before insertion. +module TypeScript { + export class SyntaxNodeInvariantsChecker extends SyntaxWalker { + private tokenTable = Collections.createHashTable(Collections.DefaultHashTableCapacity, Collections.identityHashCode); + + public static checkInvariants(node: ISyntaxNode): void { + visitNodeOrToken(new SyntaxNodeInvariantsChecker(), node); + } + + public visitNode(node: ISyntaxNode): void { + Debug.assert(node.kind === SyntaxKind.SourceUnit || node.parent); + super.visitNode(node); + } + + public visitList(list: ISyntaxNodeOrToken[]): void { + Debug.assert(isShared(list) || list.parent); + super.visitList(list); + } + + public visitSeparatedList(list: ISyntaxNodeOrToken[]): void { + Debug.assert(isShared(list) || list.parent); + super.visitSeparatedList(list); + } + + public visitToken(token: ISyntaxToken): void { + // We're calling 'add', so the table will throw if we try to put the same token in multiple + // times. + Debug.assert(token.parent); + this.tokenTable.add(token, token); + } + } +} \ No newline at end of file diff --git a/src/services/syntax/syntaxNodeOrToken.ts b/src/services/syntax/syntaxNodeOrToken.ts new file mode 100644 index 00000000000..695268d843f --- /dev/null +++ b/src/services/syntax/syntaxNodeOrToken.ts @@ -0,0 +1,6 @@ +/// + +module TypeScript { + export interface ISyntaxNodeOrToken extends ISyntaxElement { + } +} \ No newline at end of file diff --git a/src/services/syntax/syntaxNodes.abstract.generated.ts b/src/services/syntax/syntaxNodes.abstract.generated.ts new file mode 100644 index 00000000000..031b0363ca4 --- /dev/null +++ b/src/services/syntax/syntaxNodes.abstract.generated.ts @@ -0,0 +1,1194 @@ +/// + +module TypeScript.Syntax.Abstract { + // Inject this module as the factory for producing syntax nodes in the parser. + Parser.syntaxFactory = Abstract; + export var isConcrete: boolean = false; + + export class SourceUnitSyntax extends SyntaxNode { + public syntaxTree: SyntaxTree = null; + public moduleElements: IModuleElementSyntax[]; + public endOfFileToken: ISyntaxToken; + constructor(data: number, moduleElements: IModuleElementSyntax[], endOfFileToken: ISyntaxToken) { + super(data); + this.parent = null, + this.moduleElements = moduleElements, + this.endOfFileToken = endOfFileToken, + !isShared(moduleElements) && (moduleElements.parent = this), + endOfFileToken.parent = this; + } + } + export class QualifiedNameSyntax extends SyntaxNode implements INameSyntax { + public left: INameSyntax; + public dotToken: ISyntaxToken; + public right: ISyntaxToken; + public _nameBrand: any; public _typeBrand: any; + constructor(data: number, left: INameSyntax, dotToken: ISyntaxToken, right: ISyntaxToken) { + super(data); + this.left = left, + this.right = right, + left.parent = this, + right.parent = this; + } + } + export class ObjectTypeSyntax extends SyntaxNode implements ITypeSyntax { + public openBraceToken: ISyntaxToken; + public typeMembers: ITypeMemberSyntax[]; + public closeBraceToken: ISyntaxToken; + public _typeBrand: any; + constructor(data: number, openBraceToken: ISyntaxToken, typeMembers: ITypeMemberSyntax[], closeBraceToken: ISyntaxToken) { + super(data); + this.typeMembers = typeMembers, + !isShared(typeMembers) && (typeMembers.parent = this); + } + } + export class FunctionTypeSyntax extends SyntaxNode implements ITypeSyntax { + public typeParameterList: TypeParameterListSyntax; + public parameterList: ParameterListSyntax; + public equalsGreaterThanToken: ISyntaxToken; + public type: ITypeSyntax; + public _typeBrand: any; + constructor(data: number, typeParameterList: TypeParameterListSyntax, parameterList: ParameterListSyntax, equalsGreaterThanToken: ISyntaxToken, type: ITypeSyntax) { + super(data); + this.typeParameterList = typeParameterList, + this.parameterList = parameterList, + this.type = type, + typeParameterList && (typeParameterList.parent = this), + parameterList.parent = this, + type.parent = this; + } + } + export class ArrayTypeSyntax extends SyntaxNode implements ITypeSyntax { + public type: ITypeSyntax; + public openBracketToken: ISyntaxToken; + public closeBracketToken: ISyntaxToken; + public _typeBrand: any; + constructor(data: number, type: ITypeSyntax, openBracketToken: ISyntaxToken, closeBracketToken: ISyntaxToken) { + super(data); + this.type = type, + type.parent = this; + } + } + export class ConstructorTypeSyntax extends SyntaxNode implements ITypeSyntax { + public newKeyword: ISyntaxToken; + public typeParameterList: TypeParameterListSyntax; + public parameterList: ParameterListSyntax; + public equalsGreaterThanToken: ISyntaxToken; + public type: ITypeSyntax; + public _typeBrand: any; + constructor(data: number, newKeyword: ISyntaxToken, typeParameterList: TypeParameterListSyntax, parameterList: ParameterListSyntax, equalsGreaterThanToken: ISyntaxToken, type: ITypeSyntax) { + super(data); + this.typeParameterList = typeParameterList, + this.parameterList = parameterList, + this.type = type, + typeParameterList && (typeParameterList.parent = this), + parameterList.parent = this, + type.parent = this; + } + } + export class GenericTypeSyntax extends SyntaxNode implements ITypeSyntax { + public name: INameSyntax; + public typeArgumentList: TypeArgumentListSyntax; + public _typeBrand: any; + constructor(data: number, name: INameSyntax, typeArgumentList: TypeArgumentListSyntax) { + super(data); + this.name = name, + this.typeArgumentList = typeArgumentList, + name.parent = this, + typeArgumentList.parent = this; + } + } + export class TypeQuerySyntax extends SyntaxNode implements ITypeSyntax { + public typeOfKeyword: ISyntaxToken; + public name: INameSyntax; + public _typeBrand: any; + constructor(data: number, typeOfKeyword: ISyntaxToken, name: INameSyntax) { + super(data); + this.name = name, + name.parent = this; + } + } + export class InterfaceDeclarationSyntax extends SyntaxNode implements IModuleElementSyntax { + public modifiers: ISyntaxToken[]; + public interfaceKeyword: ISyntaxToken; + public identifier: ISyntaxToken; + public typeParameterList: TypeParameterListSyntax; + public heritageClauses: HeritageClauseSyntax[]; + public body: ObjectTypeSyntax; + public _moduleElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], interfaceKeyword: ISyntaxToken, identifier: ISyntaxToken, typeParameterList: TypeParameterListSyntax, heritageClauses: HeritageClauseSyntax[], body: ObjectTypeSyntax) { + super(data); + this.modifiers = modifiers, + this.identifier = identifier, + this.typeParameterList = typeParameterList, + this.heritageClauses = heritageClauses, + this.body = body, + !isShared(modifiers) && (modifiers.parent = this), + identifier.parent = this, + typeParameterList && (typeParameterList.parent = this), + !isShared(heritageClauses) && (heritageClauses.parent = this), + body.parent = this; + } + } + export class FunctionDeclarationSyntax extends SyntaxNode implements IStatementSyntax { + public modifiers: ISyntaxToken[]; + public functionKeyword: ISyntaxToken; + public identifier: ISyntaxToken; + public callSignature: CallSignatureSyntax; + public block: BlockSyntax; + public semicolonToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], functionKeyword: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax, semicolonToken: ISyntaxToken) { + super(data); + this.modifiers = modifiers, + this.identifier = identifier, + this.callSignature = callSignature, + this.block = block, + !isShared(modifiers) && (modifiers.parent = this), + identifier.parent = this, + callSignature.parent = this, + block && (block.parent = this); + } + } + export class ModuleDeclarationSyntax extends SyntaxNode implements IModuleElementSyntax { + public modifiers: ISyntaxToken[]; + public moduleKeyword: ISyntaxToken; + public name: INameSyntax; + public stringLiteral: ISyntaxToken; + public openBraceToken: ISyntaxToken; + public moduleElements: IModuleElementSyntax[]; + public closeBraceToken: ISyntaxToken; + public _moduleElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], moduleKeyword: ISyntaxToken, name: INameSyntax, stringLiteral: ISyntaxToken, openBraceToken: ISyntaxToken, moduleElements: IModuleElementSyntax[], closeBraceToken: ISyntaxToken) { + super(data); + this.modifiers = modifiers, + this.name = name, + this.stringLiteral = stringLiteral, + this.moduleElements = moduleElements, + !isShared(modifiers) && (modifiers.parent = this), + name && (name.parent = this), + stringLiteral && (stringLiteral.parent = this), + !isShared(moduleElements) && (moduleElements.parent = this); + } + } + export class ClassDeclarationSyntax extends SyntaxNode implements IModuleElementSyntax { + public modifiers: ISyntaxToken[]; + public classKeyword: ISyntaxToken; + public identifier: ISyntaxToken; + public typeParameterList: TypeParameterListSyntax; + public heritageClauses: HeritageClauseSyntax[]; + public openBraceToken: ISyntaxToken; + public classElements: IClassElementSyntax[]; + public closeBraceToken: ISyntaxToken; + public _moduleElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], classKeyword: ISyntaxToken, identifier: ISyntaxToken, typeParameterList: TypeParameterListSyntax, heritageClauses: HeritageClauseSyntax[], openBraceToken: ISyntaxToken, classElements: IClassElementSyntax[], closeBraceToken: ISyntaxToken) { + super(data); + this.modifiers = modifiers, + this.identifier = identifier, + this.typeParameterList = typeParameterList, + this.heritageClauses = heritageClauses, + this.classElements = classElements, + !isShared(modifiers) && (modifiers.parent = this), + identifier.parent = this, + typeParameterList && (typeParameterList.parent = this), + !isShared(heritageClauses) && (heritageClauses.parent = this), + !isShared(classElements) && (classElements.parent = this); + } + } + export class EnumDeclarationSyntax extends SyntaxNode implements IModuleElementSyntax { + public modifiers: ISyntaxToken[]; + public enumKeyword: ISyntaxToken; + public identifier: ISyntaxToken; + public openBraceToken: ISyntaxToken; + public enumElements: EnumElementSyntax[]; + public closeBraceToken: ISyntaxToken; + public _moduleElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], enumKeyword: ISyntaxToken, identifier: ISyntaxToken, openBraceToken: ISyntaxToken, enumElements: EnumElementSyntax[], closeBraceToken: ISyntaxToken) { + super(data); + this.modifiers = modifiers, + this.identifier = identifier, + this.enumElements = enumElements, + !isShared(modifiers) && (modifiers.parent = this), + identifier.parent = this, + !isShared(enumElements) && (enumElements.parent = this); + } + } + export class ImportDeclarationSyntax extends SyntaxNode implements IModuleElementSyntax { + public modifiers: ISyntaxToken[]; + public importKeyword: ISyntaxToken; + public identifier: ISyntaxToken; + public equalsToken: ISyntaxToken; + public moduleReference: IModuleReferenceSyntax; + public semicolonToken: ISyntaxToken; + public _moduleElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], importKeyword: ISyntaxToken, identifier: ISyntaxToken, equalsToken: ISyntaxToken, moduleReference: IModuleReferenceSyntax, semicolonToken: ISyntaxToken) { + super(data); + this.modifiers = modifiers, + this.identifier = identifier, + this.moduleReference = moduleReference, + !isShared(modifiers) && (modifiers.parent = this), + identifier.parent = this, + moduleReference.parent = this; + } + } + export class ExportAssignmentSyntax extends SyntaxNode implements IModuleElementSyntax { + public exportKeyword: ISyntaxToken; + public equalsToken: ISyntaxToken; + public identifier: ISyntaxToken; + public semicolonToken: ISyntaxToken; + public _moduleElementBrand: any; + constructor(data: number, exportKeyword: ISyntaxToken, equalsToken: ISyntaxToken, identifier: ISyntaxToken, semicolonToken: ISyntaxToken) { + super(data); + this.identifier = identifier, + identifier.parent = this; + } + } + export class MemberFunctionDeclarationSyntax extends SyntaxNode implements IMemberDeclarationSyntax { + public modifiers: ISyntaxToken[]; + public propertyName: ISyntaxToken; + public callSignature: CallSignatureSyntax; + public block: BlockSyntax; + public semicolonToken: ISyntaxToken; + public _memberDeclarationBrand: any; public _classElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], propertyName: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax, semicolonToken: ISyntaxToken) { + super(data); + this.modifiers = modifiers, + this.propertyName = propertyName, + this.callSignature = callSignature, + this.block = block, + !isShared(modifiers) && (modifiers.parent = this), + propertyName.parent = this, + callSignature.parent = this, + block && (block.parent = this); + } + } + export class MemberVariableDeclarationSyntax extends SyntaxNode implements IMemberDeclarationSyntax { + public modifiers: ISyntaxToken[]; + public variableDeclarator: VariableDeclaratorSyntax; + public semicolonToken: ISyntaxToken; + public _memberDeclarationBrand: any; public _classElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], variableDeclarator: VariableDeclaratorSyntax, semicolonToken: ISyntaxToken) { + super(data); + this.modifiers = modifiers, + this.variableDeclarator = variableDeclarator, + !isShared(modifiers) && (modifiers.parent = this), + variableDeclarator.parent = this; + } + } + export class ConstructorDeclarationSyntax extends SyntaxNode implements IClassElementSyntax { + public modifiers: ISyntaxToken[]; + public constructorKeyword: ISyntaxToken; + public callSignature: CallSignatureSyntax; + public block: BlockSyntax; + public semicolonToken: ISyntaxToken; + public _classElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], constructorKeyword: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax, semicolonToken: ISyntaxToken) { + super(data); + this.modifiers = modifiers, + this.constructorKeyword = constructorKeyword, + this.callSignature = callSignature, + this.block = block, + !isShared(modifiers) && (modifiers.parent = this), + constructorKeyword.parent = this, + callSignature.parent = this, + block && (block.parent = this); + } + } + export class IndexMemberDeclarationSyntax extends SyntaxNode implements IClassElementSyntax { + public modifiers: ISyntaxToken[]; + public indexSignature: IndexSignatureSyntax; + public semicolonToken: ISyntaxToken; + public _classElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], indexSignature: IndexSignatureSyntax, semicolonToken: ISyntaxToken) { + super(data); + this.modifiers = modifiers, + this.indexSignature = indexSignature, + !isShared(modifiers) && (modifiers.parent = this), + indexSignature.parent = this; + } + } + export class GetAccessorSyntax extends SyntaxNode implements IMemberDeclarationSyntax, IPropertyAssignmentSyntax { + public modifiers: ISyntaxToken[]; + public getKeyword: ISyntaxToken; + public propertyName: ISyntaxToken; + public callSignature: CallSignatureSyntax; + public block: BlockSyntax; + public _memberDeclarationBrand: any; public _propertyAssignmentBrand: any; public _classElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], getKeyword: ISyntaxToken, propertyName: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax) { + super(data); + this.modifiers = modifiers, + this.propertyName = propertyName, + this.callSignature = callSignature, + this.block = block, + !isShared(modifiers) && (modifiers.parent = this), + propertyName.parent = this, + callSignature.parent = this, + block.parent = this; + } + } + export class SetAccessorSyntax extends SyntaxNode implements IMemberDeclarationSyntax, IPropertyAssignmentSyntax { + public modifiers: ISyntaxToken[]; + public setKeyword: ISyntaxToken; + public propertyName: ISyntaxToken; + public callSignature: CallSignatureSyntax; + public block: BlockSyntax; + public _memberDeclarationBrand: any; public _propertyAssignmentBrand: any; public _classElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], setKeyword: ISyntaxToken, propertyName: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax) { + super(data); + this.modifiers = modifiers, + this.propertyName = propertyName, + this.callSignature = callSignature, + this.block = block, + !isShared(modifiers) && (modifiers.parent = this), + propertyName.parent = this, + callSignature.parent = this, + block.parent = this; + } + } + export class PropertySignatureSyntax extends SyntaxNode implements ITypeMemberSyntax { + public propertyName: ISyntaxToken; + public questionToken: ISyntaxToken; + public typeAnnotation: TypeAnnotationSyntax; + public _typeMemberBrand: any; + constructor(data: number, propertyName: ISyntaxToken, questionToken: ISyntaxToken, typeAnnotation: TypeAnnotationSyntax) { + super(data); + this.propertyName = propertyName, + this.questionToken = questionToken, + this.typeAnnotation = typeAnnotation, + propertyName.parent = this, + questionToken && (questionToken.parent = this), + typeAnnotation && (typeAnnotation.parent = this); + } + } + export class CallSignatureSyntax extends SyntaxNode implements ITypeMemberSyntax { + public typeParameterList: TypeParameterListSyntax; + public parameterList: ParameterListSyntax; + public typeAnnotation: TypeAnnotationSyntax; + public _typeMemberBrand: any; + constructor(data: number, typeParameterList: TypeParameterListSyntax, parameterList: ParameterListSyntax, typeAnnotation: TypeAnnotationSyntax) { + super(data); + this.typeParameterList = typeParameterList, + this.parameterList = parameterList, + this.typeAnnotation = typeAnnotation, + typeParameterList && (typeParameterList.parent = this), + parameterList.parent = this, + typeAnnotation && (typeAnnotation.parent = this); + } + } + export class ConstructSignatureSyntax extends SyntaxNode implements ITypeMemberSyntax { + public newKeyword: ISyntaxToken; + public callSignature: CallSignatureSyntax; + public _typeMemberBrand: any; + constructor(data: number, newKeyword: ISyntaxToken, callSignature: CallSignatureSyntax) { + super(data); + this.callSignature = callSignature, + callSignature.parent = this; + } + } + export class IndexSignatureSyntax extends SyntaxNode implements ITypeMemberSyntax { + public openBracketToken: ISyntaxToken; + public parameters: ParameterSyntax[]; + public closeBracketToken: ISyntaxToken; + public typeAnnotation: TypeAnnotationSyntax; + public _typeMemberBrand: any; + constructor(data: number, openBracketToken: ISyntaxToken, parameters: ParameterSyntax[], closeBracketToken: ISyntaxToken, typeAnnotation: TypeAnnotationSyntax) { + super(data); + this.openBracketToken = openBracketToken, + this.parameters = parameters, + this.closeBracketToken = closeBracketToken, + this.typeAnnotation = typeAnnotation, + openBracketToken.parent = this, + !isShared(parameters) && (parameters.parent = this), + closeBracketToken.parent = this, + typeAnnotation && (typeAnnotation.parent = this); + } + } + export class MethodSignatureSyntax extends SyntaxNode implements ITypeMemberSyntax { + public propertyName: ISyntaxToken; + public questionToken: ISyntaxToken; + public callSignature: CallSignatureSyntax; + public _typeMemberBrand: any; + constructor(data: number, propertyName: ISyntaxToken, questionToken: ISyntaxToken, callSignature: CallSignatureSyntax) { + super(data); + this.propertyName = propertyName, + this.questionToken = questionToken, + this.callSignature = callSignature, + propertyName.parent = this, + questionToken && (questionToken.parent = this), + callSignature.parent = this; + } + } + export class BlockSyntax extends SyntaxNode implements IStatementSyntax { + public openBraceToken: ISyntaxToken; + public statements: IStatementSyntax[]; + public closeBraceToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, openBraceToken: ISyntaxToken, statements: IStatementSyntax[], closeBraceToken: ISyntaxToken) { + super(data); + this.openBraceToken = openBraceToken, + this.statements = statements, + openBraceToken.parent = this, + !isShared(statements) && (statements.parent = this); + } + } + export class IfStatementSyntax extends SyntaxNode implements IStatementSyntax { + public ifKeyword: ISyntaxToken; + public openParenToken: ISyntaxToken; + public condition: IExpressionSyntax; + public closeParenToken: ISyntaxToken; + public statement: IStatementSyntax; + public elseClause: ElseClauseSyntax; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, ifKeyword: ISyntaxToken, openParenToken: ISyntaxToken, condition: IExpressionSyntax, closeParenToken: ISyntaxToken, statement: IStatementSyntax, elseClause: ElseClauseSyntax) { + super(data); + this.condition = condition, + this.statement = statement, + this.elseClause = elseClause, + condition.parent = this, + statement.parent = this, + elseClause && (elseClause.parent = this); + } + } + export class VariableStatementSyntax extends SyntaxNode implements IStatementSyntax { + public modifiers: ISyntaxToken[]; + public variableDeclaration: VariableDeclarationSyntax; + public semicolonToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], variableDeclaration: VariableDeclarationSyntax, semicolonToken: ISyntaxToken) { + super(data); + this.modifiers = modifiers, + this.variableDeclaration = variableDeclaration, + !isShared(modifiers) && (modifiers.parent = this), + variableDeclaration.parent = this; + } + } + export class ExpressionStatementSyntax extends SyntaxNode implements IStatementSyntax { + public expression: IExpressionSyntax; + public semicolonToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, expression: IExpressionSyntax, semicolonToken: ISyntaxToken) { + super(data); + this.expression = expression, + expression.parent = this; + } + } + export class ReturnStatementSyntax extends SyntaxNode implements IStatementSyntax { + public returnKeyword: ISyntaxToken; + public expression: IExpressionSyntax; + public semicolonToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, returnKeyword: ISyntaxToken, expression: IExpressionSyntax, semicolonToken: ISyntaxToken) { + super(data); + this.returnKeyword = returnKeyword, + this.expression = expression, + returnKeyword.parent = this, + expression && (expression.parent = this); + } + } + export class SwitchStatementSyntax extends SyntaxNode implements IStatementSyntax { + public switchKeyword: ISyntaxToken; + public openParenToken: ISyntaxToken; + public expression: IExpressionSyntax; + public closeParenToken: ISyntaxToken; + public openBraceToken: ISyntaxToken; + public switchClauses: ISwitchClauseSyntax[]; + public closeBraceToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, switchKeyword: ISyntaxToken, openParenToken: ISyntaxToken, expression: IExpressionSyntax, closeParenToken: ISyntaxToken, openBraceToken: ISyntaxToken, switchClauses: ISwitchClauseSyntax[], closeBraceToken: ISyntaxToken) { + super(data); + this.expression = expression, + this.switchClauses = switchClauses, + expression.parent = this, + !isShared(switchClauses) && (switchClauses.parent = this); + } + } + export class BreakStatementSyntax extends SyntaxNode implements IStatementSyntax { + public breakKeyword: ISyntaxToken; + public identifier: ISyntaxToken; + public semicolonToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, breakKeyword: ISyntaxToken, identifier: ISyntaxToken, semicolonToken: ISyntaxToken) { + super(data); + this.breakKeyword = breakKeyword, + this.identifier = identifier, + breakKeyword.parent = this, + identifier && (identifier.parent = this); + } + } + export class ContinueStatementSyntax extends SyntaxNode implements IStatementSyntax { + public continueKeyword: ISyntaxToken; + public identifier: ISyntaxToken; + public semicolonToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, continueKeyword: ISyntaxToken, identifier: ISyntaxToken, semicolonToken: ISyntaxToken) { + super(data); + this.continueKeyword = continueKeyword, + this.identifier = identifier, + continueKeyword.parent = this, + identifier && (identifier.parent = this); + } + } + export class ForStatementSyntax extends SyntaxNode implements IStatementSyntax { + public forKeyword: ISyntaxToken; + public openParenToken: ISyntaxToken; + public variableDeclaration: VariableDeclarationSyntax; + public initializer: IExpressionSyntax; + public firstSemicolonToken: ISyntaxToken; + public condition: IExpressionSyntax; + public secondSemicolonToken: ISyntaxToken; + public incrementor: IExpressionSyntax; + public closeParenToken: ISyntaxToken; + public statement: IStatementSyntax; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, forKeyword: ISyntaxToken, openParenToken: ISyntaxToken, variableDeclaration: VariableDeclarationSyntax, initializer: IExpressionSyntax, firstSemicolonToken: ISyntaxToken, condition: IExpressionSyntax, secondSemicolonToken: ISyntaxToken, incrementor: IExpressionSyntax, closeParenToken: ISyntaxToken, statement: IStatementSyntax) { + super(data); + this.variableDeclaration = variableDeclaration, + this.initializer = initializer, + this.condition = condition, + this.incrementor = incrementor, + this.statement = statement, + variableDeclaration && (variableDeclaration.parent = this), + initializer && (initializer.parent = this), + condition && (condition.parent = this), + incrementor && (incrementor.parent = this), + statement.parent = this; + } + } + export class ForInStatementSyntax extends SyntaxNode implements IStatementSyntax { + public forKeyword: ISyntaxToken; + public openParenToken: ISyntaxToken; + public variableDeclaration: VariableDeclarationSyntax; + public left: IExpressionSyntax; + public inKeyword: ISyntaxToken; + public expression: IExpressionSyntax; + public closeParenToken: ISyntaxToken; + public statement: IStatementSyntax; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, forKeyword: ISyntaxToken, openParenToken: ISyntaxToken, variableDeclaration: VariableDeclarationSyntax, left: IExpressionSyntax, inKeyword: ISyntaxToken, expression: IExpressionSyntax, closeParenToken: ISyntaxToken, statement: IStatementSyntax) { + super(data); + this.variableDeclaration = variableDeclaration, + this.left = left, + this.expression = expression, + this.statement = statement, + variableDeclaration && (variableDeclaration.parent = this), + left && (left.parent = this), + expression.parent = this, + statement.parent = this; + } + } + export class EmptyStatementSyntax extends SyntaxNode implements IStatementSyntax { + public semicolonToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, semicolonToken: ISyntaxToken) { + super(data); + this.semicolonToken = semicolonToken, + semicolonToken.parent = this; + } + } + export class ThrowStatementSyntax extends SyntaxNode implements IStatementSyntax { + public throwKeyword: ISyntaxToken; + public expression: IExpressionSyntax; + public semicolonToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, throwKeyword: ISyntaxToken, expression: IExpressionSyntax, semicolonToken: ISyntaxToken) { + super(data); + this.expression = expression, + expression.parent = this; + } + } + export class WhileStatementSyntax extends SyntaxNode implements IStatementSyntax { + public whileKeyword: ISyntaxToken; + public openParenToken: ISyntaxToken; + public condition: IExpressionSyntax; + public closeParenToken: ISyntaxToken; + public statement: IStatementSyntax; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, whileKeyword: ISyntaxToken, openParenToken: ISyntaxToken, condition: IExpressionSyntax, closeParenToken: ISyntaxToken, statement: IStatementSyntax) { + super(data); + this.condition = condition, + this.statement = statement, + condition.parent = this, + statement.parent = this; + } + } + export class TryStatementSyntax extends SyntaxNode implements IStatementSyntax { + public tryKeyword: ISyntaxToken; + public block: BlockSyntax; + public catchClause: CatchClauseSyntax; + public finallyClause: FinallyClauseSyntax; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, tryKeyword: ISyntaxToken, block: BlockSyntax, catchClause: CatchClauseSyntax, finallyClause: FinallyClauseSyntax) { + super(data); + this.block = block, + this.catchClause = catchClause, + this.finallyClause = finallyClause, + block.parent = this, + catchClause && (catchClause.parent = this), + finallyClause && (finallyClause.parent = this); + } + } + export class LabeledStatementSyntax extends SyntaxNode implements IStatementSyntax { + public identifier: ISyntaxToken; + public colonToken: ISyntaxToken; + public statement: IStatementSyntax; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, identifier: ISyntaxToken, colonToken: ISyntaxToken, statement: IStatementSyntax) { + super(data); + this.identifier = identifier, + this.statement = statement, + identifier.parent = this, + statement.parent = this; + } + } + export class DoStatementSyntax extends SyntaxNode implements IStatementSyntax { + public doKeyword: ISyntaxToken; + public statement: IStatementSyntax; + public whileKeyword: ISyntaxToken; + public openParenToken: ISyntaxToken; + public condition: IExpressionSyntax; + public closeParenToken: ISyntaxToken; + public semicolonToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, doKeyword: ISyntaxToken, statement: IStatementSyntax, whileKeyword: ISyntaxToken, openParenToken: ISyntaxToken, condition: IExpressionSyntax, closeParenToken: ISyntaxToken, semicolonToken: ISyntaxToken) { + super(data); + this.statement = statement, + this.condition = condition, + statement.parent = this, + condition.parent = this; + } + } + export class DebuggerStatementSyntax extends SyntaxNode implements IStatementSyntax { + public debuggerKeyword: ISyntaxToken; + public semicolonToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, debuggerKeyword: ISyntaxToken, semicolonToken: ISyntaxToken) { + super(data); + this.debuggerKeyword = debuggerKeyword, + debuggerKeyword.parent = this; + } + } + export class WithStatementSyntax extends SyntaxNode implements IStatementSyntax { + public withKeyword: ISyntaxToken; + public openParenToken: ISyntaxToken; + public condition: IExpressionSyntax; + public closeParenToken: ISyntaxToken; + public statement: IStatementSyntax; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, withKeyword: ISyntaxToken, openParenToken: ISyntaxToken, condition: IExpressionSyntax, closeParenToken: ISyntaxToken, statement: IStatementSyntax) { + super(data); + this.condition = condition, + this.statement = statement, + condition.parent = this, + statement.parent = this; + } + } + export class PrefixUnaryExpressionSyntax extends SyntaxNode implements IUnaryExpressionSyntax { + public operatorToken: ISyntaxToken; + public operand: IUnaryExpressionSyntax; + public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, operatorToken: ISyntaxToken, operand: IUnaryExpressionSyntax) { + super(data); + this.operatorToken = operatorToken, + this.operand = operand, + operatorToken.parent = this, + operand.parent = this; + } + public kind(): SyntaxKind { return SyntaxFacts.getPrefixUnaryExpressionFromOperatorToken(this.operatorToken.kind()); } + } + export class DeleteExpressionSyntax extends SyntaxNode implements IUnaryExpressionSyntax { + public deleteKeyword: ISyntaxToken; + public expression: IUnaryExpressionSyntax; + public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, deleteKeyword: ISyntaxToken, expression: IUnaryExpressionSyntax) { + super(data); + this.expression = expression, + expression.parent = this; + } + } + export class TypeOfExpressionSyntax extends SyntaxNode implements IUnaryExpressionSyntax { + public typeOfKeyword: ISyntaxToken; + public expression: IUnaryExpressionSyntax; + public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, typeOfKeyword: ISyntaxToken, expression: IUnaryExpressionSyntax) { + super(data); + this.expression = expression, + expression.parent = this; + } + } + export class VoidExpressionSyntax extends SyntaxNode implements IUnaryExpressionSyntax { + public voidKeyword: ISyntaxToken; + public expression: IUnaryExpressionSyntax; + public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, voidKeyword: ISyntaxToken, expression: IUnaryExpressionSyntax) { + super(data); + this.expression = expression, + expression.parent = this; + } + } + export class ConditionalExpressionSyntax extends SyntaxNode implements IExpressionSyntax { + public condition: IExpressionSyntax; + public questionToken: ISyntaxToken; + public whenTrue: IExpressionSyntax; + public colonToken: ISyntaxToken; + public whenFalse: IExpressionSyntax; + public _expressionBrand: any; + constructor(data: number, condition: IExpressionSyntax, questionToken: ISyntaxToken, whenTrue: IExpressionSyntax, colonToken: ISyntaxToken, whenFalse: IExpressionSyntax) { + super(data); + this.condition = condition, + this.whenTrue = whenTrue, + this.whenFalse = whenFalse, + condition.parent = this, + whenTrue.parent = this, + whenFalse.parent = this; + } + } + export class BinaryExpressionSyntax extends SyntaxNode implements IExpressionSyntax { + public left: IExpressionSyntax; + public operatorToken: ISyntaxToken; + public right: IExpressionSyntax; + public _expressionBrand: any; + constructor(data: number, left: IExpressionSyntax, operatorToken: ISyntaxToken, right: IExpressionSyntax) { + super(data); + this.left = left, + this.operatorToken = operatorToken, + this.right = right, + left.parent = this, + operatorToken.parent = this, + right.parent = this; + } + public kind(): SyntaxKind { return SyntaxFacts.getBinaryExpressionFromOperatorToken(this.operatorToken.kind()); } + } + export class PostfixUnaryExpressionSyntax extends SyntaxNode implements IPostfixExpressionSyntax { + public operand: ILeftHandSideExpressionSyntax; + public operatorToken: ISyntaxToken; + public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, operand: ILeftHandSideExpressionSyntax, operatorToken: ISyntaxToken) { + super(data); + this.operand = operand, + this.operatorToken = operatorToken, + operand.parent = this, + operatorToken.parent = this; + } + public kind(): SyntaxKind { return SyntaxFacts.getPostfixUnaryExpressionFromOperatorToken(this.operatorToken.kind()); } + } + export class MemberAccessExpressionSyntax extends SyntaxNode implements IMemberExpressionSyntax, ICallExpressionSyntax { + public expression: ILeftHandSideExpressionSyntax; + public dotToken: ISyntaxToken; + public name: ISyntaxToken; + public _memberExpressionBrand: any; public _callExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, expression: ILeftHandSideExpressionSyntax, dotToken: ISyntaxToken, name: ISyntaxToken) { + super(data); + this.expression = expression, + this.name = name, + expression.parent = this, + name.parent = this; + } + } + export class InvocationExpressionSyntax extends SyntaxNode implements ICallExpressionSyntax { + public expression: ILeftHandSideExpressionSyntax; + public argumentList: ArgumentListSyntax; + public _callExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, expression: ILeftHandSideExpressionSyntax, argumentList: ArgumentListSyntax) { + super(data); + this.expression = expression, + this.argumentList = argumentList, + expression.parent = this, + argumentList.parent = this; + } + } + export class ArrayLiteralExpressionSyntax extends SyntaxNode implements IPrimaryExpressionSyntax { + public openBracketToken: ISyntaxToken; + public expressions: IExpressionSyntax[]; + public closeBracketToken: ISyntaxToken; + public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, openBracketToken: ISyntaxToken, expressions: IExpressionSyntax[], closeBracketToken: ISyntaxToken) { + super(data); + this.expressions = expressions, + !isShared(expressions) && (expressions.parent = this); + } + } + export class ObjectLiteralExpressionSyntax extends SyntaxNode implements IPrimaryExpressionSyntax { + public openBraceToken: ISyntaxToken; + public propertyAssignments: IPropertyAssignmentSyntax[]; + public closeBraceToken: ISyntaxToken; + public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, openBraceToken: ISyntaxToken, propertyAssignments: IPropertyAssignmentSyntax[], closeBraceToken: ISyntaxToken) { + super(data); + this.propertyAssignments = propertyAssignments, + !isShared(propertyAssignments) && (propertyAssignments.parent = this); + } + } + export class ObjectCreationExpressionSyntax extends SyntaxNode implements IPrimaryExpressionSyntax { + public newKeyword: ISyntaxToken; + public expression: IMemberExpressionSyntax; + public argumentList: ArgumentListSyntax; + public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, newKeyword: ISyntaxToken, expression: IMemberExpressionSyntax, argumentList: ArgumentListSyntax) { + super(data); + this.expression = expression, + this.argumentList = argumentList, + expression.parent = this, + argumentList && (argumentList.parent = this); + } + } + export class ParenthesizedExpressionSyntax extends SyntaxNode implements IPrimaryExpressionSyntax { + public openParenToken: ISyntaxToken; + public expression: IExpressionSyntax; + public closeParenToken: ISyntaxToken; + public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, openParenToken: ISyntaxToken, expression: IExpressionSyntax, closeParenToken: ISyntaxToken) { + super(data); + this.expression = expression, + expression.parent = this; + } + } + export class ParenthesizedArrowFunctionExpressionSyntax extends SyntaxNode implements IUnaryExpressionSyntax { + public callSignature: CallSignatureSyntax; + public equalsGreaterThanToken: ISyntaxToken; + public block: BlockSyntax; + public expression: IExpressionSyntax; + public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, callSignature: CallSignatureSyntax, equalsGreaterThanToken: ISyntaxToken, block: BlockSyntax, expression: IExpressionSyntax) { + super(data); + this.callSignature = callSignature, + this.block = block, + this.expression = expression, + callSignature.parent = this, + block && (block.parent = this), + expression && (expression.parent = this); + } + } + export class SimpleArrowFunctionExpressionSyntax extends SyntaxNode implements IUnaryExpressionSyntax { + public parameter: ParameterSyntax; + public equalsGreaterThanToken: ISyntaxToken; + public block: BlockSyntax; + public expression: IExpressionSyntax; + public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, parameter: ParameterSyntax, equalsGreaterThanToken: ISyntaxToken, block: BlockSyntax, expression: IExpressionSyntax) { + super(data); + this.parameter = parameter, + this.block = block, + this.expression = expression, + parameter.parent = this, + block && (block.parent = this), + expression && (expression.parent = this); + } + } + export class CastExpressionSyntax extends SyntaxNode implements IUnaryExpressionSyntax { + public lessThanToken: ISyntaxToken; + public type: ITypeSyntax; + public greaterThanToken: ISyntaxToken; + public expression: IUnaryExpressionSyntax; + public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, lessThanToken: ISyntaxToken, type: ITypeSyntax, greaterThanToken: ISyntaxToken, expression: IUnaryExpressionSyntax) { + super(data); + this.type = type, + this.expression = expression, + type.parent = this, + expression.parent = this; + } + } + export class ElementAccessExpressionSyntax extends SyntaxNode implements IMemberExpressionSyntax, ICallExpressionSyntax { + public expression: ILeftHandSideExpressionSyntax; + public openBracketToken: ISyntaxToken; + public argumentExpression: IExpressionSyntax; + public closeBracketToken: ISyntaxToken; + public _memberExpressionBrand: any; public _callExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, expression: ILeftHandSideExpressionSyntax, openBracketToken: ISyntaxToken, argumentExpression: IExpressionSyntax, closeBracketToken: ISyntaxToken) { + super(data); + this.expression = expression, + this.argumentExpression = argumentExpression, + expression.parent = this, + argumentExpression.parent = this; + } + } + export class FunctionExpressionSyntax extends SyntaxNode implements IPrimaryExpressionSyntax { + public functionKeyword: ISyntaxToken; + public identifier: ISyntaxToken; + public callSignature: CallSignatureSyntax; + public block: BlockSyntax; + public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, functionKeyword: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax) { + super(data); + this.identifier = identifier, + this.callSignature = callSignature, + this.block = block, + identifier && (identifier.parent = this), + callSignature.parent = this, + block.parent = this; + } + } + export class OmittedExpressionSyntax extends SyntaxNode implements IExpressionSyntax { + public _expressionBrand: any; + constructor(data: number) { + super(data); + } + } + export class VariableDeclarationSyntax extends SyntaxNode { + public varKeyword: ISyntaxToken; + public variableDeclarators: VariableDeclaratorSyntax[]; + constructor(data: number, varKeyword: ISyntaxToken, variableDeclarators: VariableDeclaratorSyntax[]) { + super(data); + this.varKeyword = varKeyword, + this.variableDeclarators = variableDeclarators, + varKeyword.parent = this, + !isShared(variableDeclarators) && (variableDeclarators.parent = this); + } + } + export class VariableDeclaratorSyntax extends SyntaxNode { + public propertyName: ISyntaxToken; + public typeAnnotation: TypeAnnotationSyntax; + public equalsValueClause: EqualsValueClauseSyntax; + constructor(data: number, propertyName: ISyntaxToken, typeAnnotation: TypeAnnotationSyntax, equalsValueClause: EqualsValueClauseSyntax) { + super(data); + this.propertyName = propertyName, + this.typeAnnotation = typeAnnotation, + this.equalsValueClause = equalsValueClause, + propertyName.parent = this, + typeAnnotation && (typeAnnotation.parent = this), + equalsValueClause && (equalsValueClause.parent = this); + } + } + export class ArgumentListSyntax extends SyntaxNode { + public typeArgumentList: TypeArgumentListSyntax; + public openParenToken: ISyntaxToken; + public arguments: IExpressionSyntax[]; + public closeParenToken: ISyntaxToken; + constructor(data: number, typeArgumentList: TypeArgumentListSyntax, openParenToken: ISyntaxToken, _arguments: IExpressionSyntax[], closeParenToken: ISyntaxToken) { + super(data); + this.typeArgumentList = typeArgumentList, + this.arguments = _arguments, + typeArgumentList && (typeArgumentList.parent = this), + !isShared(_arguments) && (_arguments.parent = this); + } + } + export class ParameterListSyntax extends SyntaxNode { + public openParenToken: ISyntaxToken; + public parameters: ParameterSyntax[]; + public closeParenToken: ISyntaxToken; + constructor(data: number, openParenToken: ISyntaxToken, parameters: ParameterSyntax[], closeParenToken: ISyntaxToken) { + super(data); + this.parameters = parameters, + !isShared(parameters) && (parameters.parent = this); + } + } + export class TypeArgumentListSyntax extends SyntaxNode { + public lessThanToken: ISyntaxToken; + public typeArguments: ITypeSyntax[]; + public greaterThanToken: ISyntaxToken; + constructor(data: number, lessThanToken: ISyntaxToken, typeArguments: ITypeSyntax[], greaterThanToken: ISyntaxToken) { + super(data); + this.lessThanToken = lessThanToken, + this.typeArguments = typeArguments, + lessThanToken.parent = this, + !isShared(typeArguments) && (typeArguments.parent = this); + } + } + export class TypeParameterListSyntax extends SyntaxNode { + public lessThanToken: ISyntaxToken; + public typeParameters: TypeParameterSyntax[]; + public greaterThanToken: ISyntaxToken; + constructor(data: number, lessThanToken: ISyntaxToken, typeParameters: TypeParameterSyntax[], greaterThanToken: ISyntaxToken) { + super(data); + this.lessThanToken = lessThanToken, + this.typeParameters = typeParameters, + lessThanToken.parent = this, + !isShared(typeParameters) && (typeParameters.parent = this); + } + } + export class HeritageClauseSyntax extends SyntaxNode { + public extendsOrImplementsKeyword: ISyntaxToken; + public typeNames: INameSyntax[]; + constructor(data: number, extendsOrImplementsKeyword: ISyntaxToken, typeNames: INameSyntax[]) { + super(data); + this.extendsOrImplementsKeyword = extendsOrImplementsKeyword, + this.typeNames = typeNames, + extendsOrImplementsKeyword.parent = this, + !isShared(typeNames) && (typeNames.parent = this); + } + public kind(): SyntaxKind { return this.extendsOrImplementsKeyword.kind() === SyntaxKind.ExtendsKeyword ? SyntaxKind.ExtendsHeritageClause : SyntaxKind.ImplementsHeritageClause; } + } + export class EqualsValueClauseSyntax extends SyntaxNode { + public equalsToken: ISyntaxToken; + public value: IExpressionSyntax; + constructor(data: number, equalsToken: ISyntaxToken, value: IExpressionSyntax) { + super(data); + this.value = value, + value.parent = this; + } + } + export class CaseSwitchClauseSyntax extends SyntaxNode implements ISwitchClauseSyntax { + public caseKeyword: ISyntaxToken; + public expression: IExpressionSyntax; + public colonToken: ISyntaxToken; + public statements: IStatementSyntax[]; + public _switchClauseBrand: any; + constructor(data: number, caseKeyword: ISyntaxToken, expression: IExpressionSyntax, colonToken: ISyntaxToken, statements: IStatementSyntax[]) { + super(data); + this.expression = expression, + this.statements = statements, + expression.parent = this, + !isShared(statements) && (statements.parent = this); + } + } + export class DefaultSwitchClauseSyntax extends SyntaxNode implements ISwitchClauseSyntax { + public defaultKeyword: ISyntaxToken; + public colonToken: ISyntaxToken; + public statements: IStatementSyntax[]; + public _switchClauseBrand: any; + constructor(data: number, defaultKeyword: ISyntaxToken, colonToken: ISyntaxToken, statements: IStatementSyntax[]) { + super(data); + this.statements = statements, + !isShared(statements) && (statements.parent = this); + } + } + export class ElseClauseSyntax extends SyntaxNode { + public elseKeyword: ISyntaxToken; + public statement: IStatementSyntax; + constructor(data: number, elseKeyword: ISyntaxToken, statement: IStatementSyntax) { + super(data); + this.statement = statement, + statement.parent = this; + } + } + export class CatchClauseSyntax extends SyntaxNode { + public catchKeyword: ISyntaxToken; + public openParenToken: ISyntaxToken; + public identifier: ISyntaxToken; + public typeAnnotation: TypeAnnotationSyntax; + public closeParenToken: ISyntaxToken; + public block: BlockSyntax; + constructor(data: number, catchKeyword: ISyntaxToken, openParenToken: ISyntaxToken, identifier: ISyntaxToken, typeAnnotation: TypeAnnotationSyntax, closeParenToken: ISyntaxToken, block: BlockSyntax) { + super(data); + this.identifier = identifier, + this.typeAnnotation = typeAnnotation, + this.block = block, + identifier.parent = this, + typeAnnotation && (typeAnnotation.parent = this), + block.parent = this; + } + } + export class FinallyClauseSyntax extends SyntaxNode { + public finallyKeyword: ISyntaxToken; + public block: BlockSyntax; + constructor(data: number, finallyKeyword: ISyntaxToken, block: BlockSyntax) { + super(data); + this.block = block, + block.parent = this; + } + } + export class TypeParameterSyntax extends SyntaxNode { + public identifier: ISyntaxToken; + public constraint: ConstraintSyntax; + constructor(data: number, identifier: ISyntaxToken, constraint: ConstraintSyntax) { + super(data); + this.identifier = identifier, + this.constraint = constraint, + identifier.parent = this, + constraint && (constraint.parent = this); + } + } + export class ConstraintSyntax extends SyntaxNode { + public extendsKeyword: ISyntaxToken; + public typeOrExpression: ISyntaxNodeOrToken; + constructor(data: number, extendsKeyword: ISyntaxToken, typeOrExpression: ISyntaxNodeOrToken) { + super(data); + this.typeOrExpression = typeOrExpression, + typeOrExpression.parent = this; + } + } + export class SimplePropertyAssignmentSyntax extends SyntaxNode implements IPropertyAssignmentSyntax { + public propertyName: ISyntaxToken; + public colonToken: ISyntaxToken; + public expression: IExpressionSyntax; + public _propertyAssignmentBrand: any; + constructor(data: number, propertyName: ISyntaxToken, colonToken: ISyntaxToken, expression: IExpressionSyntax) { + super(data); + this.propertyName = propertyName, + this.expression = expression, + propertyName.parent = this, + expression.parent = this; + } + } + export class FunctionPropertyAssignmentSyntax extends SyntaxNode implements IPropertyAssignmentSyntax { + public propertyName: ISyntaxToken; + public callSignature: CallSignatureSyntax; + public block: BlockSyntax; + public _propertyAssignmentBrand: any; + constructor(data: number, propertyName: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax) { + super(data); + this.propertyName = propertyName, + this.callSignature = callSignature, + this.block = block, + propertyName.parent = this, + callSignature.parent = this, + block.parent = this; + } + } + export class ParameterSyntax extends SyntaxNode { + public dotDotDotToken: ISyntaxToken; + public modifiers: ISyntaxToken[]; + public identifier: ISyntaxToken; + public questionToken: ISyntaxToken; + public typeAnnotation: TypeAnnotationSyntax; + public equalsValueClause: EqualsValueClauseSyntax; + constructor(data: number, dotDotDotToken: ISyntaxToken, modifiers: ISyntaxToken[], identifier: ISyntaxToken, questionToken: ISyntaxToken, typeAnnotation: TypeAnnotationSyntax, equalsValueClause: EqualsValueClauseSyntax) { + super(data); + this.dotDotDotToken = dotDotDotToken, + this.modifiers = modifiers, + this.identifier = identifier, + this.questionToken = questionToken, + this.typeAnnotation = typeAnnotation, + this.equalsValueClause = equalsValueClause, + dotDotDotToken && (dotDotDotToken.parent = this), + !isShared(modifiers) && (modifiers.parent = this), + identifier.parent = this, + questionToken && (questionToken.parent = this), + typeAnnotation && (typeAnnotation.parent = this), + equalsValueClause && (equalsValueClause.parent = this); + } + } + export class EnumElementSyntax extends SyntaxNode { + public propertyName: ISyntaxToken; + public equalsValueClause: EqualsValueClauseSyntax; + constructor(data: number, propertyName: ISyntaxToken, equalsValueClause: EqualsValueClauseSyntax) { + super(data); + this.propertyName = propertyName, + this.equalsValueClause = equalsValueClause, + propertyName.parent = this, + equalsValueClause && (equalsValueClause.parent = this); + } + } + export class TypeAnnotationSyntax extends SyntaxNode { + public colonToken: ISyntaxToken; + public type: ITypeSyntax; + constructor(data: number, colonToken: ISyntaxToken, type: ITypeSyntax) { + super(data); + this.type = type, + type.parent = this; + } + } + export class ExternalModuleReferenceSyntax extends SyntaxNode implements IModuleReferenceSyntax { + public requireKeyword: ISyntaxToken; + public openParenToken: ISyntaxToken; + public stringLiteral: ISyntaxToken; + public closeParenToken: ISyntaxToken; + public _moduleReferenceBrand: any; + constructor(data: number, requireKeyword: ISyntaxToken, openParenToken: ISyntaxToken, stringLiteral: ISyntaxToken, closeParenToken: ISyntaxToken) { + super(data); + this.stringLiteral = stringLiteral, + stringLiteral.parent = this; + } + } + export class ModuleNameModuleReferenceSyntax extends SyntaxNode implements IModuleReferenceSyntax { + public moduleName: INameSyntax; + public _moduleReferenceBrand: any; + constructor(data: number, moduleName: INameSyntax) { + super(data); + this.moduleName = moduleName, + moduleName.parent = this; + } + } + + (SourceUnitSyntax).prototype.__kind = SyntaxKind.SourceUnit, (QualifiedNameSyntax).prototype.__kind = SyntaxKind.QualifiedName, (ObjectTypeSyntax).prototype.__kind = SyntaxKind.ObjectType, (FunctionTypeSyntax).prototype.__kind = SyntaxKind.FunctionType, (ArrayTypeSyntax).prototype.__kind = SyntaxKind.ArrayType, (ConstructorTypeSyntax).prototype.__kind = SyntaxKind.ConstructorType, (GenericTypeSyntax).prototype.__kind = SyntaxKind.GenericType, (TypeQuerySyntax).prototype.__kind = SyntaxKind.TypeQuery, (InterfaceDeclarationSyntax).prototype.__kind = SyntaxKind.InterfaceDeclaration, (FunctionDeclarationSyntax).prototype.__kind = SyntaxKind.FunctionDeclaration, (ModuleDeclarationSyntax).prototype.__kind = SyntaxKind.ModuleDeclaration, (ClassDeclarationSyntax).prototype.__kind = SyntaxKind.ClassDeclaration, (EnumDeclarationSyntax).prototype.__kind = SyntaxKind.EnumDeclaration, (ImportDeclarationSyntax).prototype.__kind = SyntaxKind.ImportDeclaration, (ExportAssignmentSyntax).prototype.__kind = SyntaxKind.ExportAssignment, (MemberFunctionDeclarationSyntax).prototype.__kind = SyntaxKind.MemberFunctionDeclaration, (MemberVariableDeclarationSyntax).prototype.__kind = SyntaxKind.MemberVariableDeclaration, (ConstructorDeclarationSyntax).prototype.__kind = SyntaxKind.ConstructorDeclaration, (IndexMemberDeclarationSyntax).prototype.__kind = SyntaxKind.IndexMemberDeclaration, (GetAccessorSyntax).prototype.__kind = SyntaxKind.GetAccessor, (SetAccessorSyntax).prototype.__kind = SyntaxKind.SetAccessor, (PropertySignatureSyntax).prototype.__kind = SyntaxKind.PropertySignature, (CallSignatureSyntax).prototype.__kind = SyntaxKind.CallSignature, (ConstructSignatureSyntax).prototype.__kind = SyntaxKind.ConstructSignature, (IndexSignatureSyntax).prototype.__kind = SyntaxKind.IndexSignature, (MethodSignatureSyntax).prototype.__kind = SyntaxKind.MethodSignature, (BlockSyntax).prototype.__kind = SyntaxKind.Block, (IfStatementSyntax).prototype.__kind = SyntaxKind.IfStatement, (VariableStatementSyntax).prototype.__kind = SyntaxKind.VariableStatement, (ExpressionStatementSyntax).prototype.__kind = SyntaxKind.ExpressionStatement, (ReturnStatementSyntax).prototype.__kind = SyntaxKind.ReturnStatement, (SwitchStatementSyntax).prototype.__kind = SyntaxKind.SwitchStatement, (BreakStatementSyntax).prototype.__kind = SyntaxKind.BreakStatement, (ContinueStatementSyntax).prototype.__kind = SyntaxKind.ContinueStatement, (ForStatementSyntax).prototype.__kind = SyntaxKind.ForStatement, (ForInStatementSyntax).prototype.__kind = SyntaxKind.ForInStatement, (EmptyStatementSyntax).prototype.__kind = SyntaxKind.EmptyStatement, (ThrowStatementSyntax).prototype.__kind = SyntaxKind.ThrowStatement, (WhileStatementSyntax).prototype.__kind = SyntaxKind.WhileStatement, (TryStatementSyntax).prototype.__kind = SyntaxKind.TryStatement, (LabeledStatementSyntax).prototype.__kind = SyntaxKind.LabeledStatement, (DoStatementSyntax).prototype.__kind = SyntaxKind.DoStatement, (DebuggerStatementSyntax).prototype.__kind = SyntaxKind.DebuggerStatement, (WithStatementSyntax).prototype.__kind = SyntaxKind.WithStatement, (DeleteExpressionSyntax).prototype.__kind = SyntaxKind.DeleteExpression, (TypeOfExpressionSyntax).prototype.__kind = SyntaxKind.TypeOfExpression, (VoidExpressionSyntax).prototype.__kind = SyntaxKind.VoidExpression, (ConditionalExpressionSyntax).prototype.__kind = SyntaxKind.ConditionalExpression, (MemberAccessExpressionSyntax).prototype.__kind = SyntaxKind.MemberAccessExpression, (InvocationExpressionSyntax).prototype.__kind = SyntaxKind.InvocationExpression, (ArrayLiteralExpressionSyntax).prototype.__kind = SyntaxKind.ArrayLiteralExpression, (ObjectLiteralExpressionSyntax).prototype.__kind = SyntaxKind.ObjectLiteralExpression, (ObjectCreationExpressionSyntax).prototype.__kind = SyntaxKind.ObjectCreationExpression, (ParenthesizedExpressionSyntax).prototype.__kind = SyntaxKind.ParenthesizedExpression, (ParenthesizedArrowFunctionExpressionSyntax).prototype.__kind = SyntaxKind.ParenthesizedArrowFunctionExpression, (SimpleArrowFunctionExpressionSyntax).prototype.__kind = SyntaxKind.SimpleArrowFunctionExpression, (CastExpressionSyntax).prototype.__kind = SyntaxKind.CastExpression, (ElementAccessExpressionSyntax).prototype.__kind = SyntaxKind.ElementAccessExpression, (FunctionExpressionSyntax).prototype.__kind = SyntaxKind.FunctionExpression, (OmittedExpressionSyntax).prototype.__kind = SyntaxKind.OmittedExpression, (VariableDeclarationSyntax).prototype.__kind = SyntaxKind.VariableDeclaration, (VariableDeclaratorSyntax).prototype.__kind = SyntaxKind.VariableDeclarator, (ArgumentListSyntax).prototype.__kind = SyntaxKind.ArgumentList, (ParameterListSyntax).prototype.__kind = SyntaxKind.ParameterList, (TypeArgumentListSyntax).prototype.__kind = SyntaxKind.TypeArgumentList, (TypeParameterListSyntax).prototype.__kind = SyntaxKind.TypeParameterList, (EqualsValueClauseSyntax).prototype.__kind = SyntaxKind.EqualsValueClause, (CaseSwitchClauseSyntax).prototype.__kind = SyntaxKind.CaseSwitchClause, (DefaultSwitchClauseSyntax).prototype.__kind = SyntaxKind.DefaultSwitchClause, (ElseClauseSyntax).prototype.__kind = SyntaxKind.ElseClause, (CatchClauseSyntax).prototype.__kind = SyntaxKind.CatchClause, (FinallyClauseSyntax).prototype.__kind = SyntaxKind.FinallyClause, (TypeParameterSyntax).prototype.__kind = SyntaxKind.TypeParameter, (ConstraintSyntax).prototype.__kind = SyntaxKind.Constraint, (SimplePropertyAssignmentSyntax).prototype.__kind = SyntaxKind.SimplePropertyAssignment, (FunctionPropertyAssignmentSyntax).prototype.__kind = SyntaxKind.FunctionPropertyAssignment, (ParameterSyntax).prototype.__kind = SyntaxKind.Parameter, (EnumElementSyntax).prototype.__kind = SyntaxKind.EnumElement, (TypeAnnotationSyntax).prototype.__kind = SyntaxKind.TypeAnnotation, (ExternalModuleReferenceSyntax).prototype.__kind = SyntaxKind.ExternalModuleReference, (ModuleNameModuleReferenceSyntax).prototype.__kind = SyntaxKind.ModuleNameModuleReference; +} \ No newline at end of file diff --git a/src/services/syntax/syntaxNodes.concrete.generated.ts b/src/services/syntax/syntaxNodes.concrete.generated.ts new file mode 100644 index 00000000000..cc493aa53a6 --- /dev/null +++ b/src/services/syntax/syntaxNodes.concrete.generated.ts @@ -0,0 +1,1424 @@ +/// + +module TypeScript.Syntax.Concrete { + // Inject this module as the factory for producing syntax nodes in the parser. + Parser.syntaxFactory = Concrete; + export var isConcrete: boolean = true; + + export class SourceUnitSyntax extends SyntaxNode { + public syntaxTree: SyntaxTree = null; + public moduleElements: IModuleElementSyntax[]; + public endOfFileToken: ISyntaxToken; + constructor(data: number, moduleElements: IModuleElementSyntax[], endOfFileToken: ISyntaxToken) { + super(data); + this.parent = null, + this.moduleElements = moduleElements, + this.endOfFileToken = endOfFileToken, + !isShared(moduleElements) && (moduleElements.parent = this), + endOfFileToken.parent = this; + } + } + export class QualifiedNameSyntax extends SyntaxNode implements INameSyntax { + public left: INameSyntax; + public dotToken: ISyntaxToken; + public right: ISyntaxToken; + public _nameBrand: any; public _typeBrand: any; + constructor(data: number, left: INameSyntax, dotToken: ISyntaxToken, right: ISyntaxToken) { + super(data); + this.left = left, + this.dotToken = dotToken, + this.right = right, + left.parent = this, + dotToken.parent = this, + right.parent = this; + } + } + export class ObjectTypeSyntax extends SyntaxNode implements ITypeSyntax { + public openBraceToken: ISyntaxToken; + public typeMembers: ITypeMemberSyntax[]; + public closeBraceToken: ISyntaxToken; + public _typeBrand: any; + constructor(data: number, openBraceToken: ISyntaxToken, typeMembers: ITypeMemberSyntax[], closeBraceToken: ISyntaxToken) { + super(data); + this.openBraceToken = openBraceToken, + this.typeMembers = typeMembers, + this.closeBraceToken = closeBraceToken, + openBraceToken.parent = this, + !isShared(typeMembers) && (typeMembers.parent = this), + closeBraceToken.parent = this; + } + } + export class FunctionTypeSyntax extends SyntaxNode implements ITypeSyntax { + public typeParameterList: TypeParameterListSyntax; + public parameterList: ParameterListSyntax; + public equalsGreaterThanToken: ISyntaxToken; + public type: ITypeSyntax; + public _typeBrand: any; + constructor(data: number, typeParameterList: TypeParameterListSyntax, parameterList: ParameterListSyntax, equalsGreaterThanToken: ISyntaxToken, type: ITypeSyntax) { + super(data); + this.typeParameterList = typeParameterList, + this.parameterList = parameterList, + this.equalsGreaterThanToken = equalsGreaterThanToken, + this.type = type, + typeParameterList && (typeParameterList.parent = this), + parameterList.parent = this, + equalsGreaterThanToken.parent = this, + type.parent = this; + } + } + export class ArrayTypeSyntax extends SyntaxNode implements ITypeSyntax { + public type: ITypeSyntax; + public openBracketToken: ISyntaxToken; + public closeBracketToken: ISyntaxToken; + public _typeBrand: any; + constructor(data: number, type: ITypeSyntax, openBracketToken: ISyntaxToken, closeBracketToken: ISyntaxToken) { + super(data); + this.type = type, + this.openBracketToken = openBracketToken, + this.closeBracketToken = closeBracketToken, + type.parent = this, + openBracketToken.parent = this, + closeBracketToken.parent = this; + } + } + export class ConstructorTypeSyntax extends SyntaxNode implements ITypeSyntax { + public newKeyword: ISyntaxToken; + public typeParameterList: TypeParameterListSyntax; + public parameterList: ParameterListSyntax; + public equalsGreaterThanToken: ISyntaxToken; + public type: ITypeSyntax; + public _typeBrand: any; + constructor(data: number, newKeyword: ISyntaxToken, typeParameterList: TypeParameterListSyntax, parameterList: ParameterListSyntax, equalsGreaterThanToken: ISyntaxToken, type: ITypeSyntax) { + super(data); + this.newKeyword = newKeyword, + this.typeParameterList = typeParameterList, + this.parameterList = parameterList, + this.equalsGreaterThanToken = equalsGreaterThanToken, + this.type = type, + newKeyword.parent = this, + typeParameterList && (typeParameterList.parent = this), + parameterList.parent = this, + equalsGreaterThanToken.parent = this, + type.parent = this; + } + } + export class GenericTypeSyntax extends SyntaxNode implements ITypeSyntax { + public name: INameSyntax; + public typeArgumentList: TypeArgumentListSyntax; + public _typeBrand: any; + constructor(data: number, name: INameSyntax, typeArgumentList: TypeArgumentListSyntax) { + super(data); + this.name = name, + this.typeArgumentList = typeArgumentList, + name.parent = this, + typeArgumentList.parent = this; + } + } + export class TypeQuerySyntax extends SyntaxNode implements ITypeSyntax { + public typeOfKeyword: ISyntaxToken; + public name: INameSyntax; + public _typeBrand: any; + constructor(data: number, typeOfKeyword: ISyntaxToken, name: INameSyntax) { + super(data); + this.typeOfKeyword = typeOfKeyword, + this.name = name, + typeOfKeyword.parent = this, + name.parent = this; + } + } + export class InterfaceDeclarationSyntax extends SyntaxNode implements IModuleElementSyntax { + public modifiers: ISyntaxToken[]; + public interfaceKeyword: ISyntaxToken; + public identifier: ISyntaxToken; + public typeParameterList: TypeParameterListSyntax; + public heritageClauses: HeritageClauseSyntax[]; + public body: ObjectTypeSyntax; + public _moduleElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], interfaceKeyword: ISyntaxToken, identifier: ISyntaxToken, typeParameterList: TypeParameterListSyntax, heritageClauses: HeritageClauseSyntax[], body: ObjectTypeSyntax) { + super(data); + this.modifiers = modifiers, + this.interfaceKeyword = interfaceKeyword, + this.identifier = identifier, + this.typeParameterList = typeParameterList, + this.heritageClauses = heritageClauses, + this.body = body, + !isShared(modifiers) && (modifiers.parent = this), + interfaceKeyword.parent = this, + identifier.parent = this, + typeParameterList && (typeParameterList.parent = this), + !isShared(heritageClauses) && (heritageClauses.parent = this), + body.parent = this; + } + } + export class FunctionDeclarationSyntax extends SyntaxNode implements IStatementSyntax { + public modifiers: ISyntaxToken[]; + public functionKeyword: ISyntaxToken; + public identifier: ISyntaxToken; + public callSignature: CallSignatureSyntax; + public block: BlockSyntax; + public semicolonToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], functionKeyword: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax, semicolonToken: ISyntaxToken) { + super(data); + this.modifiers = modifiers, + this.functionKeyword = functionKeyword, + this.identifier = identifier, + this.callSignature = callSignature, + this.block = block, + this.semicolonToken = semicolonToken, + !isShared(modifiers) && (modifiers.parent = this), + functionKeyword.parent = this, + identifier.parent = this, + callSignature.parent = this, + block && (block.parent = this), + semicolonToken && (semicolonToken.parent = this); + } + } + export class ModuleDeclarationSyntax extends SyntaxNode implements IModuleElementSyntax { + public modifiers: ISyntaxToken[]; + public moduleKeyword: ISyntaxToken; + public name: INameSyntax; + public stringLiteral: ISyntaxToken; + public openBraceToken: ISyntaxToken; + public moduleElements: IModuleElementSyntax[]; + public closeBraceToken: ISyntaxToken; + public _moduleElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], moduleKeyword: ISyntaxToken, name: INameSyntax, stringLiteral: ISyntaxToken, openBraceToken: ISyntaxToken, moduleElements: IModuleElementSyntax[], closeBraceToken: ISyntaxToken) { + super(data); + this.modifiers = modifiers, + this.moduleKeyword = moduleKeyword, + this.name = name, + this.stringLiteral = stringLiteral, + this.openBraceToken = openBraceToken, + this.moduleElements = moduleElements, + this.closeBraceToken = closeBraceToken, + !isShared(modifiers) && (modifiers.parent = this), + moduleKeyword.parent = this, + name && (name.parent = this), + stringLiteral && (stringLiteral.parent = this), + openBraceToken.parent = this, + !isShared(moduleElements) && (moduleElements.parent = this), + closeBraceToken.parent = this; + } + } + export class ClassDeclarationSyntax extends SyntaxNode implements IModuleElementSyntax { + public modifiers: ISyntaxToken[]; + public classKeyword: ISyntaxToken; + public identifier: ISyntaxToken; + public typeParameterList: TypeParameterListSyntax; + public heritageClauses: HeritageClauseSyntax[]; + public openBraceToken: ISyntaxToken; + public classElements: IClassElementSyntax[]; + public closeBraceToken: ISyntaxToken; + public _moduleElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], classKeyword: ISyntaxToken, identifier: ISyntaxToken, typeParameterList: TypeParameterListSyntax, heritageClauses: HeritageClauseSyntax[], openBraceToken: ISyntaxToken, classElements: IClassElementSyntax[], closeBraceToken: ISyntaxToken) { + super(data); + this.modifiers = modifiers, + this.classKeyword = classKeyword, + this.identifier = identifier, + this.typeParameterList = typeParameterList, + this.heritageClauses = heritageClauses, + this.openBraceToken = openBraceToken, + this.classElements = classElements, + this.closeBraceToken = closeBraceToken, + !isShared(modifiers) && (modifiers.parent = this), + classKeyword.parent = this, + identifier.parent = this, + typeParameterList && (typeParameterList.parent = this), + !isShared(heritageClauses) && (heritageClauses.parent = this), + openBraceToken.parent = this, + !isShared(classElements) && (classElements.parent = this), + closeBraceToken.parent = this; + } + } + export class EnumDeclarationSyntax extends SyntaxNode implements IModuleElementSyntax { + public modifiers: ISyntaxToken[]; + public enumKeyword: ISyntaxToken; + public identifier: ISyntaxToken; + public openBraceToken: ISyntaxToken; + public enumElements: EnumElementSyntax[]; + public closeBraceToken: ISyntaxToken; + public _moduleElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], enumKeyword: ISyntaxToken, identifier: ISyntaxToken, openBraceToken: ISyntaxToken, enumElements: EnumElementSyntax[], closeBraceToken: ISyntaxToken) { + super(data); + this.modifiers = modifiers, + this.enumKeyword = enumKeyword, + this.identifier = identifier, + this.openBraceToken = openBraceToken, + this.enumElements = enumElements, + this.closeBraceToken = closeBraceToken, + !isShared(modifiers) && (modifiers.parent = this), + enumKeyword.parent = this, + identifier.parent = this, + openBraceToken.parent = this, + !isShared(enumElements) && (enumElements.parent = this), + closeBraceToken.parent = this; + } + } + export class ImportDeclarationSyntax extends SyntaxNode implements IModuleElementSyntax { + public modifiers: ISyntaxToken[]; + public importKeyword: ISyntaxToken; + public identifier: ISyntaxToken; + public equalsToken: ISyntaxToken; + public moduleReference: IModuleReferenceSyntax; + public semicolonToken: ISyntaxToken; + public _moduleElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], importKeyword: ISyntaxToken, identifier: ISyntaxToken, equalsToken: ISyntaxToken, moduleReference: IModuleReferenceSyntax, semicolonToken: ISyntaxToken) { + super(data); + this.modifiers = modifiers, + this.importKeyword = importKeyword, + this.identifier = identifier, + this.equalsToken = equalsToken, + this.moduleReference = moduleReference, + this.semicolonToken = semicolonToken, + !isShared(modifiers) && (modifiers.parent = this), + importKeyword.parent = this, + identifier.parent = this, + equalsToken.parent = this, + moduleReference.parent = this, + semicolonToken && (semicolonToken.parent = this); + } + } + export class ExportAssignmentSyntax extends SyntaxNode implements IModuleElementSyntax { + public exportKeyword: ISyntaxToken; + public equalsToken: ISyntaxToken; + public identifier: ISyntaxToken; + public semicolonToken: ISyntaxToken; + public _moduleElementBrand: any; + constructor(data: number, exportKeyword: ISyntaxToken, equalsToken: ISyntaxToken, identifier: ISyntaxToken, semicolonToken: ISyntaxToken) { + super(data); + this.exportKeyword = exportKeyword, + this.equalsToken = equalsToken, + this.identifier = identifier, + this.semicolonToken = semicolonToken, + exportKeyword.parent = this, + equalsToken.parent = this, + identifier.parent = this, + semicolonToken && (semicolonToken.parent = this); + } + } + export class MemberFunctionDeclarationSyntax extends SyntaxNode implements IMemberDeclarationSyntax { + public modifiers: ISyntaxToken[]; + public propertyName: ISyntaxToken; + public callSignature: CallSignatureSyntax; + public block: BlockSyntax; + public semicolonToken: ISyntaxToken; + public _memberDeclarationBrand: any; public _classElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], propertyName: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax, semicolonToken: ISyntaxToken) { + super(data); + this.modifiers = modifiers, + this.propertyName = propertyName, + this.callSignature = callSignature, + this.block = block, + this.semicolonToken = semicolonToken, + !isShared(modifiers) && (modifiers.parent = this), + propertyName.parent = this, + callSignature.parent = this, + block && (block.parent = this), + semicolonToken && (semicolonToken.parent = this); + } + } + export class MemberVariableDeclarationSyntax extends SyntaxNode implements IMemberDeclarationSyntax { + public modifiers: ISyntaxToken[]; + public variableDeclarator: VariableDeclaratorSyntax; + public semicolonToken: ISyntaxToken; + public _memberDeclarationBrand: any; public _classElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], variableDeclarator: VariableDeclaratorSyntax, semicolonToken: ISyntaxToken) { + super(data); + this.modifiers = modifiers, + this.variableDeclarator = variableDeclarator, + this.semicolonToken = semicolonToken, + !isShared(modifiers) && (modifiers.parent = this), + variableDeclarator.parent = this, + semicolonToken && (semicolonToken.parent = this); + } + } + export class ConstructorDeclarationSyntax extends SyntaxNode implements IClassElementSyntax { + public modifiers: ISyntaxToken[]; + public constructorKeyword: ISyntaxToken; + public callSignature: CallSignatureSyntax; + public block: BlockSyntax; + public semicolonToken: ISyntaxToken; + public _classElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], constructorKeyword: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax, semicolonToken: ISyntaxToken) { + super(data); + this.modifiers = modifiers, + this.constructorKeyword = constructorKeyword, + this.callSignature = callSignature, + this.block = block, + this.semicolonToken = semicolonToken, + !isShared(modifiers) && (modifiers.parent = this), + constructorKeyword.parent = this, + callSignature.parent = this, + block && (block.parent = this), + semicolonToken && (semicolonToken.parent = this); + } + } + export class IndexMemberDeclarationSyntax extends SyntaxNode implements IClassElementSyntax { + public modifiers: ISyntaxToken[]; + public indexSignature: IndexSignatureSyntax; + public semicolonToken: ISyntaxToken; + public _classElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], indexSignature: IndexSignatureSyntax, semicolonToken: ISyntaxToken) { + super(data); + this.modifiers = modifiers, + this.indexSignature = indexSignature, + this.semicolonToken = semicolonToken, + !isShared(modifiers) && (modifiers.parent = this), + indexSignature.parent = this, + semicolonToken && (semicolonToken.parent = this); + } + } + export class GetAccessorSyntax extends SyntaxNode implements IMemberDeclarationSyntax, IPropertyAssignmentSyntax { + public modifiers: ISyntaxToken[]; + public getKeyword: ISyntaxToken; + public propertyName: ISyntaxToken; + public callSignature: CallSignatureSyntax; + public block: BlockSyntax; + public _memberDeclarationBrand: any; public _propertyAssignmentBrand: any; public _classElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], getKeyword: ISyntaxToken, propertyName: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax) { + super(data); + this.modifiers = modifiers, + this.getKeyword = getKeyword, + this.propertyName = propertyName, + this.callSignature = callSignature, + this.block = block, + !isShared(modifiers) && (modifiers.parent = this), + getKeyword.parent = this, + propertyName.parent = this, + callSignature.parent = this, + block.parent = this; + } + } + export class SetAccessorSyntax extends SyntaxNode implements IMemberDeclarationSyntax, IPropertyAssignmentSyntax { + public modifiers: ISyntaxToken[]; + public setKeyword: ISyntaxToken; + public propertyName: ISyntaxToken; + public callSignature: CallSignatureSyntax; + public block: BlockSyntax; + public _memberDeclarationBrand: any; public _propertyAssignmentBrand: any; public _classElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], setKeyword: ISyntaxToken, propertyName: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax) { + super(data); + this.modifiers = modifiers, + this.setKeyword = setKeyword, + this.propertyName = propertyName, + this.callSignature = callSignature, + this.block = block, + !isShared(modifiers) && (modifiers.parent = this), + setKeyword.parent = this, + propertyName.parent = this, + callSignature.parent = this, + block.parent = this; + } + } + export class PropertySignatureSyntax extends SyntaxNode implements ITypeMemberSyntax { + public propertyName: ISyntaxToken; + public questionToken: ISyntaxToken; + public typeAnnotation: TypeAnnotationSyntax; + public _typeMemberBrand: any; + constructor(data: number, propertyName: ISyntaxToken, questionToken: ISyntaxToken, typeAnnotation: TypeAnnotationSyntax) { + super(data); + this.propertyName = propertyName, + this.questionToken = questionToken, + this.typeAnnotation = typeAnnotation, + propertyName.parent = this, + questionToken && (questionToken.parent = this), + typeAnnotation && (typeAnnotation.parent = this); + } + } + export class CallSignatureSyntax extends SyntaxNode implements ITypeMemberSyntax { + public typeParameterList: TypeParameterListSyntax; + public parameterList: ParameterListSyntax; + public typeAnnotation: TypeAnnotationSyntax; + public _typeMemberBrand: any; + constructor(data: number, typeParameterList: TypeParameterListSyntax, parameterList: ParameterListSyntax, typeAnnotation: TypeAnnotationSyntax) { + super(data); + this.typeParameterList = typeParameterList, + this.parameterList = parameterList, + this.typeAnnotation = typeAnnotation, + typeParameterList && (typeParameterList.parent = this), + parameterList.parent = this, + typeAnnotation && (typeAnnotation.parent = this); + } + } + export class ConstructSignatureSyntax extends SyntaxNode implements ITypeMemberSyntax { + public newKeyword: ISyntaxToken; + public callSignature: CallSignatureSyntax; + public _typeMemberBrand: any; + constructor(data: number, newKeyword: ISyntaxToken, callSignature: CallSignatureSyntax) { + super(data); + this.newKeyword = newKeyword, + this.callSignature = callSignature, + newKeyword.parent = this, + callSignature.parent = this; + } + } + export class IndexSignatureSyntax extends SyntaxNode implements ITypeMemberSyntax { + public openBracketToken: ISyntaxToken; + public parameters: ParameterSyntax[]; + public closeBracketToken: ISyntaxToken; + public typeAnnotation: TypeAnnotationSyntax; + public _typeMemberBrand: any; + constructor(data: number, openBracketToken: ISyntaxToken, parameters: ParameterSyntax[], closeBracketToken: ISyntaxToken, typeAnnotation: TypeAnnotationSyntax) { + super(data); + this.openBracketToken = openBracketToken, + this.parameters = parameters, + this.closeBracketToken = closeBracketToken, + this.typeAnnotation = typeAnnotation, + openBracketToken.parent = this, + !isShared(parameters) && (parameters.parent = this), + closeBracketToken.parent = this, + typeAnnotation && (typeAnnotation.parent = this); + } + } + export class MethodSignatureSyntax extends SyntaxNode implements ITypeMemberSyntax { + public propertyName: ISyntaxToken; + public questionToken: ISyntaxToken; + public callSignature: CallSignatureSyntax; + public _typeMemberBrand: any; + constructor(data: number, propertyName: ISyntaxToken, questionToken: ISyntaxToken, callSignature: CallSignatureSyntax) { + super(data); + this.propertyName = propertyName, + this.questionToken = questionToken, + this.callSignature = callSignature, + propertyName.parent = this, + questionToken && (questionToken.parent = this), + callSignature.parent = this; + } + } + export class BlockSyntax extends SyntaxNode implements IStatementSyntax { + public openBraceToken: ISyntaxToken; + public statements: IStatementSyntax[]; + public closeBraceToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, openBraceToken: ISyntaxToken, statements: IStatementSyntax[], closeBraceToken: ISyntaxToken) { + super(data); + this.openBraceToken = openBraceToken, + this.statements = statements, + this.closeBraceToken = closeBraceToken, + openBraceToken.parent = this, + !isShared(statements) && (statements.parent = this), + closeBraceToken.parent = this; + } + } + export class IfStatementSyntax extends SyntaxNode implements IStatementSyntax { + public ifKeyword: ISyntaxToken; + public openParenToken: ISyntaxToken; + public condition: IExpressionSyntax; + public closeParenToken: ISyntaxToken; + public statement: IStatementSyntax; + public elseClause: ElseClauseSyntax; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, ifKeyword: ISyntaxToken, openParenToken: ISyntaxToken, condition: IExpressionSyntax, closeParenToken: ISyntaxToken, statement: IStatementSyntax, elseClause: ElseClauseSyntax) { + super(data); + this.ifKeyword = ifKeyword, + this.openParenToken = openParenToken, + this.condition = condition, + this.closeParenToken = closeParenToken, + this.statement = statement, + this.elseClause = elseClause, + ifKeyword.parent = this, + openParenToken.parent = this, + condition.parent = this, + closeParenToken.parent = this, + statement.parent = this, + elseClause && (elseClause.parent = this); + } + } + export class VariableStatementSyntax extends SyntaxNode implements IStatementSyntax { + public modifiers: ISyntaxToken[]; + public variableDeclaration: VariableDeclarationSyntax; + public semicolonToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, modifiers: ISyntaxToken[], variableDeclaration: VariableDeclarationSyntax, semicolonToken: ISyntaxToken) { + super(data); + this.modifiers = modifiers, + this.variableDeclaration = variableDeclaration, + this.semicolonToken = semicolonToken, + !isShared(modifiers) && (modifiers.parent = this), + variableDeclaration.parent = this, + semicolonToken && (semicolonToken.parent = this); + } + } + export class ExpressionStatementSyntax extends SyntaxNode implements IStatementSyntax { + public expression: IExpressionSyntax; + public semicolonToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, expression: IExpressionSyntax, semicolonToken: ISyntaxToken) { + super(data); + this.expression = expression, + this.semicolonToken = semicolonToken, + expression.parent = this, + semicolonToken && (semicolonToken.parent = this); + } + } + export class ReturnStatementSyntax extends SyntaxNode implements IStatementSyntax { + public returnKeyword: ISyntaxToken; + public expression: IExpressionSyntax; + public semicolonToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, returnKeyword: ISyntaxToken, expression: IExpressionSyntax, semicolonToken: ISyntaxToken) { + super(data); + this.returnKeyword = returnKeyword, + this.expression = expression, + this.semicolonToken = semicolonToken, + returnKeyword.parent = this, + expression && (expression.parent = this), + semicolonToken && (semicolonToken.parent = this); + } + } + export class SwitchStatementSyntax extends SyntaxNode implements IStatementSyntax { + public switchKeyword: ISyntaxToken; + public openParenToken: ISyntaxToken; + public expression: IExpressionSyntax; + public closeParenToken: ISyntaxToken; + public openBraceToken: ISyntaxToken; + public switchClauses: ISwitchClauseSyntax[]; + public closeBraceToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, switchKeyword: ISyntaxToken, openParenToken: ISyntaxToken, expression: IExpressionSyntax, closeParenToken: ISyntaxToken, openBraceToken: ISyntaxToken, switchClauses: ISwitchClauseSyntax[], closeBraceToken: ISyntaxToken) { + super(data); + this.switchKeyword = switchKeyword, + this.openParenToken = openParenToken, + this.expression = expression, + this.closeParenToken = closeParenToken, + this.openBraceToken = openBraceToken, + this.switchClauses = switchClauses, + this.closeBraceToken = closeBraceToken, + switchKeyword.parent = this, + openParenToken.parent = this, + expression.parent = this, + closeParenToken.parent = this, + openBraceToken.parent = this, + !isShared(switchClauses) && (switchClauses.parent = this), + closeBraceToken.parent = this; + } + } + export class BreakStatementSyntax extends SyntaxNode implements IStatementSyntax { + public breakKeyword: ISyntaxToken; + public identifier: ISyntaxToken; + public semicolonToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, breakKeyword: ISyntaxToken, identifier: ISyntaxToken, semicolonToken: ISyntaxToken) { + super(data); + this.breakKeyword = breakKeyword, + this.identifier = identifier, + this.semicolonToken = semicolonToken, + breakKeyword.parent = this, + identifier && (identifier.parent = this), + semicolonToken && (semicolonToken.parent = this); + } + } + export class ContinueStatementSyntax extends SyntaxNode implements IStatementSyntax { + public continueKeyword: ISyntaxToken; + public identifier: ISyntaxToken; + public semicolonToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, continueKeyword: ISyntaxToken, identifier: ISyntaxToken, semicolonToken: ISyntaxToken) { + super(data); + this.continueKeyword = continueKeyword, + this.identifier = identifier, + this.semicolonToken = semicolonToken, + continueKeyword.parent = this, + identifier && (identifier.parent = this), + semicolonToken && (semicolonToken.parent = this); + } + } + export class ForStatementSyntax extends SyntaxNode implements IStatementSyntax { + public forKeyword: ISyntaxToken; + public openParenToken: ISyntaxToken; + public variableDeclaration: VariableDeclarationSyntax; + public initializer: IExpressionSyntax; + public firstSemicolonToken: ISyntaxToken; + public condition: IExpressionSyntax; + public secondSemicolonToken: ISyntaxToken; + public incrementor: IExpressionSyntax; + public closeParenToken: ISyntaxToken; + public statement: IStatementSyntax; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, forKeyword: ISyntaxToken, openParenToken: ISyntaxToken, variableDeclaration: VariableDeclarationSyntax, initializer: IExpressionSyntax, firstSemicolonToken: ISyntaxToken, condition: IExpressionSyntax, secondSemicolonToken: ISyntaxToken, incrementor: IExpressionSyntax, closeParenToken: ISyntaxToken, statement: IStatementSyntax) { + super(data); + this.forKeyword = forKeyword, + this.openParenToken = openParenToken, + this.variableDeclaration = variableDeclaration, + this.initializer = initializer, + this.firstSemicolonToken = firstSemicolonToken, + this.condition = condition, + this.secondSemicolonToken = secondSemicolonToken, + this.incrementor = incrementor, + this.closeParenToken = closeParenToken, + this.statement = statement, + forKeyword.parent = this, + openParenToken.parent = this, + variableDeclaration && (variableDeclaration.parent = this), + initializer && (initializer.parent = this), + firstSemicolonToken.parent = this, + condition && (condition.parent = this), + secondSemicolonToken.parent = this, + incrementor && (incrementor.parent = this), + closeParenToken.parent = this, + statement.parent = this; + } + } + export class ForInStatementSyntax extends SyntaxNode implements IStatementSyntax { + public forKeyword: ISyntaxToken; + public openParenToken: ISyntaxToken; + public variableDeclaration: VariableDeclarationSyntax; + public left: IExpressionSyntax; + public inKeyword: ISyntaxToken; + public expression: IExpressionSyntax; + public closeParenToken: ISyntaxToken; + public statement: IStatementSyntax; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, forKeyword: ISyntaxToken, openParenToken: ISyntaxToken, variableDeclaration: VariableDeclarationSyntax, left: IExpressionSyntax, inKeyword: ISyntaxToken, expression: IExpressionSyntax, closeParenToken: ISyntaxToken, statement: IStatementSyntax) { + super(data); + this.forKeyword = forKeyword, + this.openParenToken = openParenToken, + this.variableDeclaration = variableDeclaration, + this.left = left, + this.inKeyword = inKeyword, + this.expression = expression, + this.closeParenToken = closeParenToken, + this.statement = statement, + forKeyword.parent = this, + openParenToken.parent = this, + variableDeclaration && (variableDeclaration.parent = this), + left && (left.parent = this), + inKeyword.parent = this, + expression.parent = this, + closeParenToken.parent = this, + statement.parent = this; + } + } + export class EmptyStatementSyntax extends SyntaxNode implements IStatementSyntax { + public semicolonToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, semicolonToken: ISyntaxToken) { + super(data); + this.semicolonToken = semicolonToken, + semicolonToken.parent = this; + } + } + export class ThrowStatementSyntax extends SyntaxNode implements IStatementSyntax { + public throwKeyword: ISyntaxToken; + public expression: IExpressionSyntax; + public semicolonToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, throwKeyword: ISyntaxToken, expression: IExpressionSyntax, semicolonToken: ISyntaxToken) { + super(data); + this.throwKeyword = throwKeyword, + this.expression = expression, + this.semicolonToken = semicolonToken, + throwKeyword.parent = this, + expression.parent = this, + semicolonToken && (semicolonToken.parent = this); + } + } + export class WhileStatementSyntax extends SyntaxNode implements IStatementSyntax { + public whileKeyword: ISyntaxToken; + public openParenToken: ISyntaxToken; + public condition: IExpressionSyntax; + public closeParenToken: ISyntaxToken; + public statement: IStatementSyntax; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, whileKeyword: ISyntaxToken, openParenToken: ISyntaxToken, condition: IExpressionSyntax, closeParenToken: ISyntaxToken, statement: IStatementSyntax) { + super(data); + this.whileKeyword = whileKeyword, + this.openParenToken = openParenToken, + this.condition = condition, + this.closeParenToken = closeParenToken, + this.statement = statement, + whileKeyword.parent = this, + openParenToken.parent = this, + condition.parent = this, + closeParenToken.parent = this, + statement.parent = this; + } + } + export class TryStatementSyntax extends SyntaxNode implements IStatementSyntax { + public tryKeyword: ISyntaxToken; + public block: BlockSyntax; + public catchClause: CatchClauseSyntax; + public finallyClause: FinallyClauseSyntax; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, tryKeyword: ISyntaxToken, block: BlockSyntax, catchClause: CatchClauseSyntax, finallyClause: FinallyClauseSyntax) { + super(data); + this.tryKeyword = tryKeyword, + this.block = block, + this.catchClause = catchClause, + this.finallyClause = finallyClause, + tryKeyword.parent = this, + block.parent = this, + catchClause && (catchClause.parent = this), + finallyClause && (finallyClause.parent = this); + } + } + export class LabeledStatementSyntax extends SyntaxNode implements IStatementSyntax { + public identifier: ISyntaxToken; + public colonToken: ISyntaxToken; + public statement: IStatementSyntax; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, identifier: ISyntaxToken, colonToken: ISyntaxToken, statement: IStatementSyntax) { + super(data); + this.identifier = identifier, + this.colonToken = colonToken, + this.statement = statement, + identifier.parent = this, + colonToken.parent = this, + statement.parent = this; + } + } + export class DoStatementSyntax extends SyntaxNode implements IStatementSyntax { + public doKeyword: ISyntaxToken; + public statement: IStatementSyntax; + public whileKeyword: ISyntaxToken; + public openParenToken: ISyntaxToken; + public condition: IExpressionSyntax; + public closeParenToken: ISyntaxToken; + public semicolonToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, doKeyword: ISyntaxToken, statement: IStatementSyntax, whileKeyword: ISyntaxToken, openParenToken: ISyntaxToken, condition: IExpressionSyntax, closeParenToken: ISyntaxToken, semicolonToken: ISyntaxToken) { + super(data); + this.doKeyword = doKeyword, + this.statement = statement, + this.whileKeyword = whileKeyword, + this.openParenToken = openParenToken, + this.condition = condition, + this.closeParenToken = closeParenToken, + this.semicolonToken = semicolonToken, + doKeyword.parent = this, + statement.parent = this, + whileKeyword.parent = this, + openParenToken.parent = this, + condition.parent = this, + closeParenToken.parent = this, + semicolonToken && (semicolonToken.parent = this); + } + } + export class DebuggerStatementSyntax extends SyntaxNode implements IStatementSyntax { + public debuggerKeyword: ISyntaxToken; + public semicolonToken: ISyntaxToken; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, debuggerKeyword: ISyntaxToken, semicolonToken: ISyntaxToken) { + super(data); + this.debuggerKeyword = debuggerKeyword, + this.semicolonToken = semicolonToken, + debuggerKeyword.parent = this, + semicolonToken && (semicolonToken.parent = this); + } + } + export class WithStatementSyntax extends SyntaxNode implements IStatementSyntax { + public withKeyword: ISyntaxToken; + public openParenToken: ISyntaxToken; + public condition: IExpressionSyntax; + public closeParenToken: ISyntaxToken; + public statement: IStatementSyntax; + public _statementBrand: any; public _moduleElementBrand: any; + constructor(data: number, withKeyword: ISyntaxToken, openParenToken: ISyntaxToken, condition: IExpressionSyntax, closeParenToken: ISyntaxToken, statement: IStatementSyntax) { + super(data); + this.withKeyword = withKeyword, + this.openParenToken = openParenToken, + this.condition = condition, + this.closeParenToken = closeParenToken, + this.statement = statement, + withKeyword.parent = this, + openParenToken.parent = this, + condition.parent = this, + closeParenToken.parent = this, + statement.parent = this; + } + } + export class PrefixUnaryExpressionSyntax extends SyntaxNode implements IUnaryExpressionSyntax { + public operatorToken: ISyntaxToken; + public operand: IUnaryExpressionSyntax; + public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, operatorToken: ISyntaxToken, operand: IUnaryExpressionSyntax) { + super(data); + this.operatorToken = operatorToken, + this.operand = operand, + operatorToken.parent = this, + operand.parent = this; + } + public kind(): SyntaxKind { return SyntaxFacts.getPrefixUnaryExpressionFromOperatorToken(this.operatorToken.kind()); } + } + export class DeleteExpressionSyntax extends SyntaxNode implements IUnaryExpressionSyntax { + public deleteKeyword: ISyntaxToken; + public expression: IUnaryExpressionSyntax; + public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, deleteKeyword: ISyntaxToken, expression: IUnaryExpressionSyntax) { + super(data); + this.deleteKeyword = deleteKeyword, + this.expression = expression, + deleteKeyword.parent = this, + expression.parent = this; + } + } + export class TypeOfExpressionSyntax extends SyntaxNode implements IUnaryExpressionSyntax { + public typeOfKeyword: ISyntaxToken; + public expression: IUnaryExpressionSyntax; + public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, typeOfKeyword: ISyntaxToken, expression: IUnaryExpressionSyntax) { + super(data); + this.typeOfKeyword = typeOfKeyword, + this.expression = expression, + typeOfKeyword.parent = this, + expression.parent = this; + } + } + export class VoidExpressionSyntax extends SyntaxNode implements IUnaryExpressionSyntax { + public voidKeyword: ISyntaxToken; + public expression: IUnaryExpressionSyntax; + public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, voidKeyword: ISyntaxToken, expression: IUnaryExpressionSyntax) { + super(data); + this.voidKeyword = voidKeyword, + this.expression = expression, + voidKeyword.parent = this, + expression.parent = this; + } + } + export class ConditionalExpressionSyntax extends SyntaxNode implements IExpressionSyntax { + public condition: IExpressionSyntax; + public questionToken: ISyntaxToken; + public whenTrue: IExpressionSyntax; + public colonToken: ISyntaxToken; + public whenFalse: IExpressionSyntax; + public _expressionBrand: any; + constructor(data: number, condition: IExpressionSyntax, questionToken: ISyntaxToken, whenTrue: IExpressionSyntax, colonToken: ISyntaxToken, whenFalse: IExpressionSyntax) { + super(data); + this.condition = condition, + this.questionToken = questionToken, + this.whenTrue = whenTrue, + this.colonToken = colonToken, + this.whenFalse = whenFalse, + condition.parent = this, + questionToken.parent = this, + whenTrue.parent = this, + colonToken.parent = this, + whenFalse.parent = this; + } + } + export class BinaryExpressionSyntax extends SyntaxNode implements IExpressionSyntax { + public left: IExpressionSyntax; + public operatorToken: ISyntaxToken; + public right: IExpressionSyntax; + public _expressionBrand: any; + constructor(data: number, left: IExpressionSyntax, operatorToken: ISyntaxToken, right: IExpressionSyntax) { + super(data); + this.left = left, + this.operatorToken = operatorToken, + this.right = right, + left.parent = this, + operatorToken.parent = this, + right.parent = this; + } + public kind(): SyntaxKind { return SyntaxFacts.getBinaryExpressionFromOperatorToken(this.operatorToken.kind()); } + } + export class PostfixUnaryExpressionSyntax extends SyntaxNode implements IPostfixExpressionSyntax { + public operand: ILeftHandSideExpressionSyntax; + public operatorToken: ISyntaxToken; + public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, operand: ILeftHandSideExpressionSyntax, operatorToken: ISyntaxToken) { + super(data); + this.operand = operand, + this.operatorToken = operatorToken, + operand.parent = this, + operatorToken.parent = this; + } + public kind(): SyntaxKind { return SyntaxFacts.getPostfixUnaryExpressionFromOperatorToken(this.operatorToken.kind()); } + } + export class MemberAccessExpressionSyntax extends SyntaxNode implements IMemberExpressionSyntax, ICallExpressionSyntax { + public expression: ILeftHandSideExpressionSyntax; + public dotToken: ISyntaxToken; + public name: ISyntaxToken; + public _memberExpressionBrand: any; public _callExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, expression: ILeftHandSideExpressionSyntax, dotToken: ISyntaxToken, name: ISyntaxToken) { + super(data); + this.expression = expression, + this.dotToken = dotToken, + this.name = name, + expression.parent = this, + dotToken.parent = this, + name.parent = this; + } + } + export class InvocationExpressionSyntax extends SyntaxNode implements ICallExpressionSyntax { + public expression: ILeftHandSideExpressionSyntax; + public argumentList: ArgumentListSyntax; + public _callExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, expression: ILeftHandSideExpressionSyntax, argumentList: ArgumentListSyntax) { + super(data); + this.expression = expression, + this.argumentList = argumentList, + expression.parent = this, + argumentList.parent = this; + } + } + export class ArrayLiteralExpressionSyntax extends SyntaxNode implements IPrimaryExpressionSyntax { + public openBracketToken: ISyntaxToken; + public expressions: IExpressionSyntax[]; + public closeBracketToken: ISyntaxToken; + public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, openBracketToken: ISyntaxToken, expressions: IExpressionSyntax[], closeBracketToken: ISyntaxToken) { + super(data); + this.openBracketToken = openBracketToken, + this.expressions = expressions, + this.closeBracketToken = closeBracketToken, + openBracketToken.parent = this, + !isShared(expressions) && (expressions.parent = this), + closeBracketToken.parent = this; + } + } + export class ObjectLiteralExpressionSyntax extends SyntaxNode implements IPrimaryExpressionSyntax { + public openBraceToken: ISyntaxToken; + public propertyAssignments: IPropertyAssignmentSyntax[]; + public closeBraceToken: ISyntaxToken; + public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, openBraceToken: ISyntaxToken, propertyAssignments: IPropertyAssignmentSyntax[], closeBraceToken: ISyntaxToken) { + super(data); + this.openBraceToken = openBraceToken, + this.propertyAssignments = propertyAssignments, + this.closeBraceToken = closeBraceToken, + openBraceToken.parent = this, + !isShared(propertyAssignments) && (propertyAssignments.parent = this), + closeBraceToken.parent = this; + } + } + export class ObjectCreationExpressionSyntax extends SyntaxNode implements IPrimaryExpressionSyntax { + public newKeyword: ISyntaxToken; + public expression: IMemberExpressionSyntax; + public argumentList: ArgumentListSyntax; + public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, newKeyword: ISyntaxToken, expression: IMemberExpressionSyntax, argumentList: ArgumentListSyntax) { + super(data); + this.newKeyword = newKeyword, + this.expression = expression, + this.argumentList = argumentList, + newKeyword.parent = this, + expression.parent = this, + argumentList && (argumentList.parent = this); + } + } + export class ParenthesizedExpressionSyntax extends SyntaxNode implements IPrimaryExpressionSyntax { + public openParenToken: ISyntaxToken; + public expression: IExpressionSyntax; + public closeParenToken: ISyntaxToken; + public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, openParenToken: ISyntaxToken, expression: IExpressionSyntax, closeParenToken: ISyntaxToken) { + super(data); + this.openParenToken = openParenToken, + this.expression = expression, + this.closeParenToken = closeParenToken, + openParenToken.parent = this, + expression.parent = this, + closeParenToken.parent = this; + } + } + export class ParenthesizedArrowFunctionExpressionSyntax extends SyntaxNode implements IUnaryExpressionSyntax { + public callSignature: CallSignatureSyntax; + public equalsGreaterThanToken: ISyntaxToken; + public block: BlockSyntax; + public expression: IExpressionSyntax; + public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, callSignature: CallSignatureSyntax, equalsGreaterThanToken: ISyntaxToken, block: BlockSyntax, expression: IExpressionSyntax) { + super(data); + this.callSignature = callSignature, + this.equalsGreaterThanToken = equalsGreaterThanToken, + this.block = block, + this.expression = expression, + callSignature.parent = this, + equalsGreaterThanToken.parent = this, + block && (block.parent = this), + expression && (expression.parent = this); + } + } + export class SimpleArrowFunctionExpressionSyntax extends SyntaxNode implements IUnaryExpressionSyntax { + public parameter: ParameterSyntax; + public equalsGreaterThanToken: ISyntaxToken; + public block: BlockSyntax; + public expression: IExpressionSyntax; + public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, parameter: ParameterSyntax, equalsGreaterThanToken: ISyntaxToken, block: BlockSyntax, expression: IExpressionSyntax) { + super(data); + this.parameter = parameter, + this.equalsGreaterThanToken = equalsGreaterThanToken, + this.block = block, + this.expression = expression, + parameter.parent = this, + equalsGreaterThanToken.parent = this, + block && (block.parent = this), + expression && (expression.parent = this); + } + } + export class CastExpressionSyntax extends SyntaxNode implements IUnaryExpressionSyntax { + public lessThanToken: ISyntaxToken; + public type: ITypeSyntax; + public greaterThanToken: ISyntaxToken; + public expression: IUnaryExpressionSyntax; + public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, lessThanToken: ISyntaxToken, type: ITypeSyntax, greaterThanToken: ISyntaxToken, expression: IUnaryExpressionSyntax) { + super(data); + this.lessThanToken = lessThanToken, + this.type = type, + this.greaterThanToken = greaterThanToken, + this.expression = expression, + lessThanToken.parent = this, + type.parent = this, + greaterThanToken.parent = this, + expression.parent = this; + } + } + export class ElementAccessExpressionSyntax extends SyntaxNode implements IMemberExpressionSyntax, ICallExpressionSyntax { + public expression: ILeftHandSideExpressionSyntax; + public openBracketToken: ISyntaxToken; + public argumentExpression: IExpressionSyntax; + public closeBracketToken: ISyntaxToken; + public _memberExpressionBrand: any; public _callExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, expression: ILeftHandSideExpressionSyntax, openBracketToken: ISyntaxToken, argumentExpression: IExpressionSyntax, closeBracketToken: ISyntaxToken) { + super(data); + this.expression = expression, + this.openBracketToken = openBracketToken, + this.argumentExpression = argumentExpression, + this.closeBracketToken = closeBracketToken, + expression.parent = this, + openBracketToken.parent = this, + argumentExpression.parent = this, + closeBracketToken.parent = this; + } + } + export class FunctionExpressionSyntax extends SyntaxNode implements IPrimaryExpressionSyntax { + public functionKeyword: ISyntaxToken; + public identifier: ISyntaxToken; + public callSignature: CallSignatureSyntax; + public block: BlockSyntax; + public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; + constructor(data: number, functionKeyword: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax) { + super(data); + this.functionKeyword = functionKeyword, + this.identifier = identifier, + this.callSignature = callSignature, + this.block = block, + functionKeyword.parent = this, + identifier && (identifier.parent = this), + callSignature.parent = this, + block.parent = this; + } + } + export class OmittedExpressionSyntax extends SyntaxNode implements IExpressionSyntax { + public _expressionBrand: any; + constructor(data: number) { + super(data); + } + } + export class VariableDeclarationSyntax extends SyntaxNode { + public varKeyword: ISyntaxToken; + public variableDeclarators: VariableDeclaratorSyntax[]; + constructor(data: number, varKeyword: ISyntaxToken, variableDeclarators: VariableDeclaratorSyntax[]) { + super(data); + this.varKeyword = varKeyword, + this.variableDeclarators = variableDeclarators, + varKeyword.parent = this, + !isShared(variableDeclarators) && (variableDeclarators.parent = this); + } + } + export class VariableDeclaratorSyntax extends SyntaxNode { + public propertyName: ISyntaxToken; + public typeAnnotation: TypeAnnotationSyntax; + public equalsValueClause: EqualsValueClauseSyntax; + constructor(data: number, propertyName: ISyntaxToken, typeAnnotation: TypeAnnotationSyntax, equalsValueClause: EqualsValueClauseSyntax) { + super(data); + this.propertyName = propertyName, + this.typeAnnotation = typeAnnotation, + this.equalsValueClause = equalsValueClause, + propertyName.parent = this, + typeAnnotation && (typeAnnotation.parent = this), + equalsValueClause && (equalsValueClause.parent = this); + } + } + export class ArgumentListSyntax extends SyntaxNode { + public typeArgumentList: TypeArgumentListSyntax; + public openParenToken: ISyntaxToken; + public arguments: IExpressionSyntax[]; + public closeParenToken: ISyntaxToken; + constructor(data: number, typeArgumentList: TypeArgumentListSyntax, openParenToken: ISyntaxToken, _arguments: IExpressionSyntax[], closeParenToken: ISyntaxToken) { + super(data); + this.typeArgumentList = typeArgumentList, + this.openParenToken = openParenToken, + this.arguments = _arguments, + this.closeParenToken = closeParenToken, + typeArgumentList && (typeArgumentList.parent = this), + openParenToken.parent = this, + !isShared(_arguments) && (_arguments.parent = this), + closeParenToken.parent = this; + } + } + export class ParameterListSyntax extends SyntaxNode { + public openParenToken: ISyntaxToken; + public parameters: ParameterSyntax[]; + public closeParenToken: ISyntaxToken; + constructor(data: number, openParenToken: ISyntaxToken, parameters: ParameterSyntax[], closeParenToken: ISyntaxToken) { + super(data); + this.openParenToken = openParenToken, + this.parameters = parameters, + this.closeParenToken = closeParenToken, + openParenToken.parent = this, + !isShared(parameters) && (parameters.parent = this), + closeParenToken.parent = this; + } + } + export class TypeArgumentListSyntax extends SyntaxNode { + public lessThanToken: ISyntaxToken; + public typeArguments: ITypeSyntax[]; + public greaterThanToken: ISyntaxToken; + constructor(data: number, lessThanToken: ISyntaxToken, typeArguments: ITypeSyntax[], greaterThanToken: ISyntaxToken) { + super(data); + this.lessThanToken = lessThanToken, + this.typeArguments = typeArguments, + this.greaterThanToken = greaterThanToken, + lessThanToken.parent = this, + !isShared(typeArguments) && (typeArguments.parent = this), + greaterThanToken.parent = this; + } + } + export class TypeParameterListSyntax extends SyntaxNode { + public lessThanToken: ISyntaxToken; + public typeParameters: TypeParameterSyntax[]; + public greaterThanToken: ISyntaxToken; + constructor(data: number, lessThanToken: ISyntaxToken, typeParameters: TypeParameterSyntax[], greaterThanToken: ISyntaxToken) { + super(data); + this.lessThanToken = lessThanToken, + this.typeParameters = typeParameters, + this.greaterThanToken = greaterThanToken, + lessThanToken.parent = this, + !isShared(typeParameters) && (typeParameters.parent = this), + greaterThanToken.parent = this; + } + } + export class HeritageClauseSyntax extends SyntaxNode { + public extendsOrImplementsKeyword: ISyntaxToken; + public typeNames: INameSyntax[]; + constructor(data: number, extendsOrImplementsKeyword: ISyntaxToken, typeNames: INameSyntax[]) { + super(data); + this.extendsOrImplementsKeyword = extendsOrImplementsKeyword, + this.typeNames = typeNames, + extendsOrImplementsKeyword.parent = this, + !isShared(typeNames) && (typeNames.parent = this); + } + public kind(): SyntaxKind { return this.extendsOrImplementsKeyword.kind() === SyntaxKind.ExtendsKeyword ? SyntaxKind.ExtendsHeritageClause : SyntaxKind.ImplementsHeritageClause; } + } + export class EqualsValueClauseSyntax extends SyntaxNode { + public equalsToken: ISyntaxToken; + public value: IExpressionSyntax; + constructor(data: number, equalsToken: ISyntaxToken, value: IExpressionSyntax) { + super(data); + this.equalsToken = equalsToken, + this.value = value, + equalsToken.parent = this, + value.parent = this; + } + } + export class CaseSwitchClauseSyntax extends SyntaxNode implements ISwitchClauseSyntax { + public caseKeyword: ISyntaxToken; + public expression: IExpressionSyntax; + public colonToken: ISyntaxToken; + public statements: IStatementSyntax[]; + public _switchClauseBrand: any; + constructor(data: number, caseKeyword: ISyntaxToken, expression: IExpressionSyntax, colonToken: ISyntaxToken, statements: IStatementSyntax[]) { + super(data); + this.caseKeyword = caseKeyword, + this.expression = expression, + this.colonToken = colonToken, + this.statements = statements, + caseKeyword.parent = this, + expression.parent = this, + colonToken.parent = this, + !isShared(statements) && (statements.parent = this); + } + } + export class DefaultSwitchClauseSyntax extends SyntaxNode implements ISwitchClauseSyntax { + public defaultKeyword: ISyntaxToken; + public colonToken: ISyntaxToken; + public statements: IStatementSyntax[]; + public _switchClauseBrand: any; + constructor(data: number, defaultKeyword: ISyntaxToken, colonToken: ISyntaxToken, statements: IStatementSyntax[]) { + super(data); + this.defaultKeyword = defaultKeyword, + this.colonToken = colonToken, + this.statements = statements, + defaultKeyword.parent = this, + colonToken.parent = this, + !isShared(statements) && (statements.parent = this); + } + } + export class ElseClauseSyntax extends SyntaxNode { + public elseKeyword: ISyntaxToken; + public statement: IStatementSyntax; + constructor(data: number, elseKeyword: ISyntaxToken, statement: IStatementSyntax) { + super(data); + this.elseKeyword = elseKeyword, + this.statement = statement, + elseKeyword.parent = this, + statement.parent = this; + } + } + export class CatchClauseSyntax extends SyntaxNode { + public catchKeyword: ISyntaxToken; + public openParenToken: ISyntaxToken; + public identifier: ISyntaxToken; + public typeAnnotation: TypeAnnotationSyntax; + public closeParenToken: ISyntaxToken; + public block: BlockSyntax; + constructor(data: number, catchKeyword: ISyntaxToken, openParenToken: ISyntaxToken, identifier: ISyntaxToken, typeAnnotation: TypeAnnotationSyntax, closeParenToken: ISyntaxToken, block: BlockSyntax) { + super(data); + this.catchKeyword = catchKeyword, + this.openParenToken = openParenToken, + this.identifier = identifier, + this.typeAnnotation = typeAnnotation, + this.closeParenToken = closeParenToken, + this.block = block, + catchKeyword.parent = this, + openParenToken.parent = this, + identifier.parent = this, + typeAnnotation && (typeAnnotation.parent = this), + closeParenToken.parent = this, + block.parent = this; + } + } + export class FinallyClauseSyntax extends SyntaxNode { + public finallyKeyword: ISyntaxToken; + public block: BlockSyntax; + constructor(data: number, finallyKeyword: ISyntaxToken, block: BlockSyntax) { + super(data); + this.finallyKeyword = finallyKeyword, + this.block = block, + finallyKeyword.parent = this, + block.parent = this; + } + } + export class TypeParameterSyntax extends SyntaxNode { + public identifier: ISyntaxToken; + public constraint: ConstraintSyntax; + constructor(data: number, identifier: ISyntaxToken, constraint: ConstraintSyntax) { + super(data); + this.identifier = identifier, + this.constraint = constraint, + identifier.parent = this, + constraint && (constraint.parent = this); + } + } + export class ConstraintSyntax extends SyntaxNode { + public extendsKeyword: ISyntaxToken; + public typeOrExpression: ISyntaxNodeOrToken; + constructor(data: number, extendsKeyword: ISyntaxToken, typeOrExpression: ISyntaxNodeOrToken) { + super(data); + this.extendsKeyword = extendsKeyword, + this.typeOrExpression = typeOrExpression, + extendsKeyword.parent = this, + typeOrExpression.parent = this; + } + } + export class SimplePropertyAssignmentSyntax extends SyntaxNode implements IPropertyAssignmentSyntax { + public propertyName: ISyntaxToken; + public colonToken: ISyntaxToken; + public expression: IExpressionSyntax; + public _propertyAssignmentBrand: any; + constructor(data: number, propertyName: ISyntaxToken, colonToken: ISyntaxToken, expression: IExpressionSyntax) { + super(data); + this.propertyName = propertyName, + this.colonToken = colonToken, + this.expression = expression, + propertyName.parent = this, + colonToken.parent = this, + expression.parent = this; + } + } + export class FunctionPropertyAssignmentSyntax extends SyntaxNode implements IPropertyAssignmentSyntax { + public propertyName: ISyntaxToken; + public callSignature: CallSignatureSyntax; + public block: BlockSyntax; + public _propertyAssignmentBrand: any; + constructor(data: number, propertyName: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax) { + super(data); + this.propertyName = propertyName, + this.callSignature = callSignature, + this.block = block, + propertyName.parent = this, + callSignature.parent = this, + block.parent = this; + } + } + export class ParameterSyntax extends SyntaxNode { + public dotDotDotToken: ISyntaxToken; + public modifiers: ISyntaxToken[]; + public identifier: ISyntaxToken; + public questionToken: ISyntaxToken; + public typeAnnotation: TypeAnnotationSyntax; + public equalsValueClause: EqualsValueClauseSyntax; + constructor(data: number, dotDotDotToken: ISyntaxToken, modifiers: ISyntaxToken[], identifier: ISyntaxToken, questionToken: ISyntaxToken, typeAnnotation: TypeAnnotationSyntax, equalsValueClause: EqualsValueClauseSyntax) { + super(data); + this.dotDotDotToken = dotDotDotToken, + this.modifiers = modifiers, + this.identifier = identifier, + this.questionToken = questionToken, + this.typeAnnotation = typeAnnotation, + this.equalsValueClause = equalsValueClause, + dotDotDotToken && (dotDotDotToken.parent = this), + !isShared(modifiers) && (modifiers.parent = this), + identifier.parent = this, + questionToken && (questionToken.parent = this), + typeAnnotation && (typeAnnotation.parent = this), + equalsValueClause && (equalsValueClause.parent = this); + } + } + export class EnumElementSyntax extends SyntaxNode { + public propertyName: ISyntaxToken; + public equalsValueClause: EqualsValueClauseSyntax; + constructor(data: number, propertyName: ISyntaxToken, equalsValueClause: EqualsValueClauseSyntax) { + super(data); + this.propertyName = propertyName, + this.equalsValueClause = equalsValueClause, + propertyName.parent = this, + equalsValueClause && (equalsValueClause.parent = this); + } + } + export class TypeAnnotationSyntax extends SyntaxNode { + public colonToken: ISyntaxToken; + public type: ITypeSyntax; + constructor(data: number, colonToken: ISyntaxToken, type: ITypeSyntax) { + super(data); + this.colonToken = colonToken, + this.type = type, + colonToken.parent = this, + type.parent = this; + } + } + export class ExternalModuleReferenceSyntax extends SyntaxNode implements IModuleReferenceSyntax { + public requireKeyword: ISyntaxToken; + public openParenToken: ISyntaxToken; + public stringLiteral: ISyntaxToken; + public closeParenToken: ISyntaxToken; + public _moduleReferenceBrand: any; + constructor(data: number, requireKeyword: ISyntaxToken, openParenToken: ISyntaxToken, stringLiteral: ISyntaxToken, closeParenToken: ISyntaxToken) { + super(data); + this.requireKeyword = requireKeyword, + this.openParenToken = openParenToken, + this.stringLiteral = stringLiteral, + this.closeParenToken = closeParenToken, + requireKeyword.parent = this, + openParenToken.parent = this, + stringLiteral.parent = this, + closeParenToken.parent = this; + } + } + export class ModuleNameModuleReferenceSyntax extends SyntaxNode implements IModuleReferenceSyntax { + public moduleName: INameSyntax; + public _moduleReferenceBrand: any; + constructor(data: number, moduleName: INameSyntax) { + super(data); + this.moduleName = moduleName, + moduleName.parent = this; + } + } + + (SourceUnitSyntax).prototype.__kind = SyntaxKind.SourceUnit, (QualifiedNameSyntax).prototype.__kind = SyntaxKind.QualifiedName, (ObjectTypeSyntax).prototype.__kind = SyntaxKind.ObjectType, (FunctionTypeSyntax).prototype.__kind = SyntaxKind.FunctionType, (ArrayTypeSyntax).prototype.__kind = SyntaxKind.ArrayType, (ConstructorTypeSyntax).prototype.__kind = SyntaxKind.ConstructorType, (GenericTypeSyntax).prototype.__kind = SyntaxKind.GenericType, (TypeQuerySyntax).prototype.__kind = SyntaxKind.TypeQuery, (InterfaceDeclarationSyntax).prototype.__kind = SyntaxKind.InterfaceDeclaration, (FunctionDeclarationSyntax).prototype.__kind = SyntaxKind.FunctionDeclaration, (ModuleDeclarationSyntax).prototype.__kind = SyntaxKind.ModuleDeclaration, (ClassDeclarationSyntax).prototype.__kind = SyntaxKind.ClassDeclaration, (EnumDeclarationSyntax).prototype.__kind = SyntaxKind.EnumDeclaration, (ImportDeclarationSyntax).prototype.__kind = SyntaxKind.ImportDeclaration, (ExportAssignmentSyntax).prototype.__kind = SyntaxKind.ExportAssignment, (MemberFunctionDeclarationSyntax).prototype.__kind = SyntaxKind.MemberFunctionDeclaration, (MemberVariableDeclarationSyntax).prototype.__kind = SyntaxKind.MemberVariableDeclaration, (ConstructorDeclarationSyntax).prototype.__kind = SyntaxKind.ConstructorDeclaration, (IndexMemberDeclarationSyntax).prototype.__kind = SyntaxKind.IndexMemberDeclaration, (GetAccessorSyntax).prototype.__kind = SyntaxKind.GetAccessor, (SetAccessorSyntax).prototype.__kind = SyntaxKind.SetAccessor, (PropertySignatureSyntax).prototype.__kind = SyntaxKind.PropertySignature, (CallSignatureSyntax).prototype.__kind = SyntaxKind.CallSignature, (ConstructSignatureSyntax).prototype.__kind = SyntaxKind.ConstructSignature, (IndexSignatureSyntax).prototype.__kind = SyntaxKind.IndexSignature, (MethodSignatureSyntax).prototype.__kind = SyntaxKind.MethodSignature, (BlockSyntax).prototype.__kind = SyntaxKind.Block, (IfStatementSyntax).prototype.__kind = SyntaxKind.IfStatement, (VariableStatementSyntax).prototype.__kind = SyntaxKind.VariableStatement, (ExpressionStatementSyntax).prototype.__kind = SyntaxKind.ExpressionStatement, (ReturnStatementSyntax).prototype.__kind = SyntaxKind.ReturnStatement, (SwitchStatementSyntax).prototype.__kind = SyntaxKind.SwitchStatement, (BreakStatementSyntax).prototype.__kind = SyntaxKind.BreakStatement, (ContinueStatementSyntax).prototype.__kind = SyntaxKind.ContinueStatement, (ForStatementSyntax).prototype.__kind = SyntaxKind.ForStatement, (ForInStatementSyntax).prototype.__kind = SyntaxKind.ForInStatement, (EmptyStatementSyntax).prototype.__kind = SyntaxKind.EmptyStatement, (ThrowStatementSyntax).prototype.__kind = SyntaxKind.ThrowStatement, (WhileStatementSyntax).prototype.__kind = SyntaxKind.WhileStatement, (TryStatementSyntax).prototype.__kind = SyntaxKind.TryStatement, (LabeledStatementSyntax).prototype.__kind = SyntaxKind.LabeledStatement, (DoStatementSyntax).prototype.__kind = SyntaxKind.DoStatement, (DebuggerStatementSyntax).prototype.__kind = SyntaxKind.DebuggerStatement, (WithStatementSyntax).prototype.__kind = SyntaxKind.WithStatement, (DeleteExpressionSyntax).prototype.__kind = SyntaxKind.DeleteExpression, (TypeOfExpressionSyntax).prototype.__kind = SyntaxKind.TypeOfExpression, (VoidExpressionSyntax).prototype.__kind = SyntaxKind.VoidExpression, (ConditionalExpressionSyntax).prototype.__kind = SyntaxKind.ConditionalExpression, (MemberAccessExpressionSyntax).prototype.__kind = SyntaxKind.MemberAccessExpression, (InvocationExpressionSyntax).prototype.__kind = SyntaxKind.InvocationExpression, (ArrayLiteralExpressionSyntax).prototype.__kind = SyntaxKind.ArrayLiteralExpression, (ObjectLiteralExpressionSyntax).prototype.__kind = SyntaxKind.ObjectLiteralExpression, (ObjectCreationExpressionSyntax).prototype.__kind = SyntaxKind.ObjectCreationExpression, (ParenthesizedExpressionSyntax).prototype.__kind = SyntaxKind.ParenthesizedExpression, (ParenthesizedArrowFunctionExpressionSyntax).prototype.__kind = SyntaxKind.ParenthesizedArrowFunctionExpression, (SimpleArrowFunctionExpressionSyntax).prototype.__kind = SyntaxKind.SimpleArrowFunctionExpression, (CastExpressionSyntax).prototype.__kind = SyntaxKind.CastExpression, (ElementAccessExpressionSyntax).prototype.__kind = SyntaxKind.ElementAccessExpression, (FunctionExpressionSyntax).prototype.__kind = SyntaxKind.FunctionExpression, (OmittedExpressionSyntax).prototype.__kind = SyntaxKind.OmittedExpression, (VariableDeclarationSyntax).prototype.__kind = SyntaxKind.VariableDeclaration, (VariableDeclaratorSyntax).prototype.__kind = SyntaxKind.VariableDeclarator, (ArgumentListSyntax).prototype.__kind = SyntaxKind.ArgumentList, (ParameterListSyntax).prototype.__kind = SyntaxKind.ParameterList, (TypeArgumentListSyntax).prototype.__kind = SyntaxKind.TypeArgumentList, (TypeParameterListSyntax).prototype.__kind = SyntaxKind.TypeParameterList, (EqualsValueClauseSyntax).prototype.__kind = SyntaxKind.EqualsValueClause, (CaseSwitchClauseSyntax).prototype.__kind = SyntaxKind.CaseSwitchClause, (DefaultSwitchClauseSyntax).prototype.__kind = SyntaxKind.DefaultSwitchClause, (ElseClauseSyntax).prototype.__kind = SyntaxKind.ElseClause, (CatchClauseSyntax).prototype.__kind = SyntaxKind.CatchClause, (FinallyClauseSyntax).prototype.__kind = SyntaxKind.FinallyClause, (TypeParameterSyntax).prototype.__kind = SyntaxKind.TypeParameter, (ConstraintSyntax).prototype.__kind = SyntaxKind.Constraint, (SimplePropertyAssignmentSyntax).prototype.__kind = SyntaxKind.SimplePropertyAssignment, (FunctionPropertyAssignmentSyntax).prototype.__kind = SyntaxKind.FunctionPropertyAssignment, (ParameterSyntax).prototype.__kind = SyntaxKind.Parameter, (EnumElementSyntax).prototype.__kind = SyntaxKind.EnumElement, (TypeAnnotationSyntax).prototype.__kind = SyntaxKind.TypeAnnotation, (ExternalModuleReferenceSyntax).prototype.__kind = SyntaxKind.ExternalModuleReference, (ModuleNameModuleReferenceSyntax).prototype.__kind = SyntaxKind.ModuleNameModuleReference; +} \ No newline at end of file diff --git a/src/services/syntax/syntaxNodes.interfaces.generated.ts b/src/services/syntax/syntaxNodes.interfaces.generated.ts new file mode 100644 index 00000000000..0ecc9cbf9c6 --- /dev/null +++ b/src/services/syntax/syntaxNodes.interfaces.generated.ts @@ -0,0 +1,573 @@ +/// + +module TypeScript { + export interface SourceUnitSyntax extends ISyntaxNode { + syntaxTree: SyntaxTree; + moduleElements: IModuleElementSyntax[]; + endOfFileToken: ISyntaxToken; + } + export interface QualifiedNameSyntax extends ISyntaxNode, INameSyntax { + left: INameSyntax; + dotToken: ISyntaxToken; + right: ISyntaxToken; + } + export interface ObjectTypeSyntax extends ISyntaxNode, ITypeSyntax { + openBraceToken: ISyntaxToken; + typeMembers: ITypeMemberSyntax[]; + closeBraceToken: ISyntaxToken; + } + export interface FunctionTypeSyntax extends ISyntaxNode, ITypeSyntax { + typeParameterList: TypeParameterListSyntax; + parameterList: ParameterListSyntax; + equalsGreaterThanToken: ISyntaxToken; + type: ITypeSyntax; + } + export interface ArrayTypeSyntax extends ISyntaxNode, ITypeSyntax { + type: ITypeSyntax; + openBracketToken: ISyntaxToken; + closeBracketToken: ISyntaxToken; + } + export interface ConstructorTypeSyntax extends ISyntaxNode, ITypeSyntax { + newKeyword: ISyntaxToken; + typeParameterList: TypeParameterListSyntax; + parameterList: ParameterListSyntax; + equalsGreaterThanToken: ISyntaxToken; + type: ITypeSyntax; + } + export interface GenericTypeSyntax extends ISyntaxNode, ITypeSyntax { + name: INameSyntax; + typeArgumentList: TypeArgumentListSyntax; + } + export interface TypeQuerySyntax extends ISyntaxNode, ITypeSyntax { + typeOfKeyword: ISyntaxToken; + name: INameSyntax; + } + export interface InterfaceDeclarationSyntax extends ISyntaxNode, IModuleElementSyntax { + modifiers: ISyntaxToken[]; + interfaceKeyword: ISyntaxToken; + identifier: ISyntaxToken; + typeParameterList: TypeParameterListSyntax; + heritageClauses: HeritageClauseSyntax[]; + body: ObjectTypeSyntax; + } + export interface FunctionDeclarationSyntax extends ISyntaxNode, IStatementSyntax { + modifiers: ISyntaxToken[]; + functionKeyword: ISyntaxToken; + identifier: ISyntaxToken; + callSignature: CallSignatureSyntax; + block: BlockSyntax; + semicolonToken: ISyntaxToken; + } + export interface ModuleDeclarationSyntax extends ISyntaxNode, IModuleElementSyntax { + modifiers: ISyntaxToken[]; + moduleKeyword: ISyntaxToken; + name: INameSyntax; + stringLiteral: ISyntaxToken; + openBraceToken: ISyntaxToken; + moduleElements: IModuleElementSyntax[]; + closeBraceToken: ISyntaxToken; + } + export interface ClassDeclarationSyntax extends ISyntaxNode, IModuleElementSyntax { + modifiers: ISyntaxToken[]; + classKeyword: ISyntaxToken; + identifier: ISyntaxToken; + typeParameterList: TypeParameterListSyntax; + heritageClauses: HeritageClauseSyntax[]; + openBraceToken: ISyntaxToken; + classElements: IClassElementSyntax[]; + closeBraceToken: ISyntaxToken; + } + export interface EnumDeclarationSyntax extends ISyntaxNode, IModuleElementSyntax { + modifiers: ISyntaxToken[]; + enumKeyword: ISyntaxToken; + identifier: ISyntaxToken; + openBraceToken: ISyntaxToken; + enumElements: EnumElementSyntax[]; + closeBraceToken: ISyntaxToken; + } + export interface ImportDeclarationSyntax extends ISyntaxNode, IModuleElementSyntax { + modifiers: ISyntaxToken[]; + importKeyword: ISyntaxToken; + identifier: ISyntaxToken; + equalsToken: ISyntaxToken; + moduleReference: IModuleReferenceSyntax; + semicolonToken: ISyntaxToken; + } + export interface ExportAssignmentSyntax extends ISyntaxNode, IModuleElementSyntax { + exportKeyword: ISyntaxToken; + equalsToken: ISyntaxToken; + identifier: ISyntaxToken; + semicolonToken: ISyntaxToken; + } + export interface MemberFunctionDeclarationSyntax extends ISyntaxNode, IMemberDeclarationSyntax { + modifiers: ISyntaxToken[]; + propertyName: ISyntaxToken; + callSignature: CallSignatureSyntax; + block: BlockSyntax; + semicolonToken: ISyntaxToken; + } + export interface MemberVariableDeclarationSyntax extends ISyntaxNode, IMemberDeclarationSyntax { + modifiers: ISyntaxToken[]; + variableDeclarator: VariableDeclaratorSyntax; + semicolonToken: ISyntaxToken; + } + export interface ConstructorDeclarationSyntax extends ISyntaxNode, IClassElementSyntax { + modifiers: ISyntaxToken[]; + constructorKeyword: ISyntaxToken; + callSignature: CallSignatureSyntax; + block: BlockSyntax; + semicolonToken: ISyntaxToken; + } + export interface IndexMemberDeclarationSyntax extends ISyntaxNode, IClassElementSyntax { + modifiers: ISyntaxToken[]; + indexSignature: IndexSignatureSyntax; + semicolonToken: ISyntaxToken; + } + export interface GetAccessorSyntax extends ISyntaxNode, IMemberDeclarationSyntax, IPropertyAssignmentSyntax { + modifiers: ISyntaxToken[]; + getKeyword: ISyntaxToken; + propertyName: ISyntaxToken; + callSignature: CallSignatureSyntax; + block: BlockSyntax; + } + export interface SetAccessorSyntax extends ISyntaxNode, IMemberDeclarationSyntax, IPropertyAssignmentSyntax { + modifiers: ISyntaxToken[]; + setKeyword: ISyntaxToken; + propertyName: ISyntaxToken; + callSignature: CallSignatureSyntax; + block: BlockSyntax; + } + export interface PropertySignatureSyntax extends ISyntaxNode, ITypeMemberSyntax { + propertyName: ISyntaxToken; + questionToken: ISyntaxToken; + typeAnnotation: TypeAnnotationSyntax; + } + export interface CallSignatureSyntax extends ISyntaxNode, ITypeMemberSyntax { + typeParameterList: TypeParameterListSyntax; + parameterList: ParameterListSyntax; + typeAnnotation: TypeAnnotationSyntax; + } + export interface ConstructSignatureSyntax extends ISyntaxNode, ITypeMemberSyntax { + newKeyword: ISyntaxToken; + callSignature: CallSignatureSyntax; + } + export interface IndexSignatureSyntax extends ISyntaxNode, ITypeMemberSyntax { + openBracketToken: ISyntaxToken; + parameters: ParameterSyntax[]; + closeBracketToken: ISyntaxToken; + typeAnnotation: TypeAnnotationSyntax; + } + export interface MethodSignatureSyntax extends ISyntaxNode, ITypeMemberSyntax { + propertyName: ISyntaxToken; + questionToken: ISyntaxToken; + callSignature: CallSignatureSyntax; + } + export interface BlockSyntax extends ISyntaxNode, IStatementSyntax { + openBraceToken: ISyntaxToken; + statements: IStatementSyntax[]; + closeBraceToken: ISyntaxToken; + } + export interface IfStatementSyntax extends ISyntaxNode, IStatementSyntax { + ifKeyword: ISyntaxToken; + openParenToken: ISyntaxToken; + condition: IExpressionSyntax; + closeParenToken: ISyntaxToken; + statement: IStatementSyntax; + elseClause: ElseClauseSyntax; + } + export interface VariableStatementSyntax extends ISyntaxNode, IStatementSyntax { + modifiers: ISyntaxToken[]; + variableDeclaration: VariableDeclarationSyntax; + semicolonToken: ISyntaxToken; + } + export interface ExpressionStatementSyntax extends ISyntaxNode, IStatementSyntax { + expression: IExpressionSyntax; + semicolonToken: ISyntaxToken; + } + export interface ReturnStatementSyntax extends ISyntaxNode, IStatementSyntax { + returnKeyword: ISyntaxToken; + expression: IExpressionSyntax; + semicolonToken: ISyntaxToken; + } + export interface SwitchStatementSyntax extends ISyntaxNode, IStatementSyntax { + switchKeyword: ISyntaxToken; + openParenToken: ISyntaxToken; + expression: IExpressionSyntax; + closeParenToken: ISyntaxToken; + openBraceToken: ISyntaxToken; + switchClauses: ISwitchClauseSyntax[]; + closeBraceToken: ISyntaxToken; + } + export interface BreakStatementSyntax extends ISyntaxNode, IStatementSyntax { + breakKeyword: ISyntaxToken; + identifier: ISyntaxToken; + semicolonToken: ISyntaxToken; + } + export interface ContinueStatementSyntax extends ISyntaxNode, IStatementSyntax { + continueKeyword: ISyntaxToken; + identifier: ISyntaxToken; + semicolonToken: ISyntaxToken; + } + export interface ForStatementSyntax extends ISyntaxNode, IStatementSyntax { + forKeyword: ISyntaxToken; + openParenToken: ISyntaxToken; + variableDeclaration: VariableDeclarationSyntax; + initializer: IExpressionSyntax; + firstSemicolonToken: ISyntaxToken; + condition: IExpressionSyntax; + secondSemicolonToken: ISyntaxToken; + incrementor: IExpressionSyntax; + closeParenToken: ISyntaxToken; + statement: IStatementSyntax; + } + export interface ForInStatementSyntax extends ISyntaxNode, IStatementSyntax { + forKeyword: ISyntaxToken; + openParenToken: ISyntaxToken; + variableDeclaration: VariableDeclarationSyntax; + left: IExpressionSyntax; + inKeyword: ISyntaxToken; + expression: IExpressionSyntax; + closeParenToken: ISyntaxToken; + statement: IStatementSyntax; + } + export interface EmptyStatementSyntax extends ISyntaxNode, IStatementSyntax { + semicolonToken: ISyntaxToken; + } + export interface ThrowStatementSyntax extends ISyntaxNode, IStatementSyntax { + throwKeyword: ISyntaxToken; + expression: IExpressionSyntax; + semicolonToken: ISyntaxToken; + } + export interface WhileStatementSyntax extends ISyntaxNode, IStatementSyntax { + whileKeyword: ISyntaxToken; + openParenToken: ISyntaxToken; + condition: IExpressionSyntax; + closeParenToken: ISyntaxToken; + statement: IStatementSyntax; + } + export interface TryStatementSyntax extends ISyntaxNode, IStatementSyntax { + tryKeyword: ISyntaxToken; + block: BlockSyntax; + catchClause: CatchClauseSyntax; + finallyClause: FinallyClauseSyntax; + } + export interface LabeledStatementSyntax extends ISyntaxNode, IStatementSyntax { + identifier: ISyntaxToken; + colonToken: ISyntaxToken; + statement: IStatementSyntax; + } + export interface DoStatementSyntax extends ISyntaxNode, IStatementSyntax { + doKeyword: ISyntaxToken; + statement: IStatementSyntax; + whileKeyword: ISyntaxToken; + openParenToken: ISyntaxToken; + condition: IExpressionSyntax; + closeParenToken: ISyntaxToken; + semicolonToken: ISyntaxToken; + } + export interface DebuggerStatementSyntax extends ISyntaxNode, IStatementSyntax { + debuggerKeyword: ISyntaxToken; + semicolonToken: ISyntaxToken; + } + export interface WithStatementSyntax extends ISyntaxNode, IStatementSyntax { + withKeyword: ISyntaxToken; + openParenToken: ISyntaxToken; + condition: IExpressionSyntax; + closeParenToken: ISyntaxToken; + statement: IStatementSyntax; + } + export interface PrefixUnaryExpressionSyntax extends ISyntaxNode, IUnaryExpressionSyntax { + operatorToken: ISyntaxToken; + operand: IUnaryExpressionSyntax; + } + export interface DeleteExpressionSyntax extends ISyntaxNode, IUnaryExpressionSyntax { + deleteKeyword: ISyntaxToken; + expression: IUnaryExpressionSyntax; + } + export interface TypeOfExpressionSyntax extends ISyntaxNode, IUnaryExpressionSyntax { + typeOfKeyword: ISyntaxToken; + expression: IUnaryExpressionSyntax; + } + export interface VoidExpressionSyntax extends ISyntaxNode, IUnaryExpressionSyntax { + voidKeyword: ISyntaxToken; + expression: IUnaryExpressionSyntax; + } + export interface ConditionalExpressionSyntax extends ISyntaxNode, IExpressionSyntax { + condition: IExpressionSyntax; + questionToken: ISyntaxToken; + whenTrue: IExpressionSyntax; + colonToken: ISyntaxToken; + whenFalse: IExpressionSyntax; + } + export interface BinaryExpressionSyntax extends ISyntaxNode, IExpressionSyntax { + left: IExpressionSyntax; + operatorToken: ISyntaxToken; + right: IExpressionSyntax; + } + export interface PostfixUnaryExpressionSyntax extends ISyntaxNode, IPostfixExpressionSyntax { + operand: ILeftHandSideExpressionSyntax; + operatorToken: ISyntaxToken; + } + export interface MemberAccessExpressionSyntax extends ISyntaxNode, IMemberExpressionSyntax, ICallExpressionSyntax { + expression: ILeftHandSideExpressionSyntax; + dotToken: ISyntaxToken; + name: ISyntaxToken; + } + export interface InvocationExpressionSyntax extends ISyntaxNode, ICallExpressionSyntax { + expression: ILeftHandSideExpressionSyntax; + argumentList: ArgumentListSyntax; + } + export interface ArrayLiteralExpressionSyntax extends ISyntaxNode, IPrimaryExpressionSyntax { + openBracketToken: ISyntaxToken; + expressions: IExpressionSyntax[]; + closeBracketToken: ISyntaxToken; + } + export interface ObjectLiteralExpressionSyntax extends ISyntaxNode, IPrimaryExpressionSyntax { + openBraceToken: ISyntaxToken; + propertyAssignments: IPropertyAssignmentSyntax[]; + closeBraceToken: ISyntaxToken; + } + export interface ObjectCreationExpressionSyntax extends ISyntaxNode, IPrimaryExpressionSyntax { + newKeyword: ISyntaxToken; + expression: IMemberExpressionSyntax; + argumentList: ArgumentListSyntax; + } + export interface ParenthesizedExpressionSyntax extends ISyntaxNode, IPrimaryExpressionSyntax { + openParenToken: ISyntaxToken; + expression: IExpressionSyntax; + closeParenToken: ISyntaxToken; + } + export interface ParenthesizedArrowFunctionExpressionSyntax extends ISyntaxNode, IUnaryExpressionSyntax { + callSignature: CallSignatureSyntax; + equalsGreaterThanToken: ISyntaxToken; + block: BlockSyntax; + expression: IExpressionSyntax; + } + export interface SimpleArrowFunctionExpressionSyntax extends ISyntaxNode, IUnaryExpressionSyntax { + parameter: ParameterSyntax; + equalsGreaterThanToken: ISyntaxToken; + block: BlockSyntax; + expression: IExpressionSyntax; + } + export interface CastExpressionSyntax extends ISyntaxNode, IUnaryExpressionSyntax { + lessThanToken: ISyntaxToken; + type: ITypeSyntax; + greaterThanToken: ISyntaxToken; + expression: IUnaryExpressionSyntax; + } + export interface ElementAccessExpressionSyntax extends ISyntaxNode, IMemberExpressionSyntax, ICallExpressionSyntax { + expression: ILeftHandSideExpressionSyntax; + openBracketToken: ISyntaxToken; + argumentExpression: IExpressionSyntax; + closeBracketToken: ISyntaxToken; + } + export interface FunctionExpressionSyntax extends ISyntaxNode, IPrimaryExpressionSyntax { + functionKeyword: ISyntaxToken; + identifier: ISyntaxToken; + callSignature: CallSignatureSyntax; + block: BlockSyntax; + } + export interface OmittedExpressionSyntax extends ISyntaxNode, IExpressionSyntax { + } + export interface VariableDeclarationSyntax extends ISyntaxNode { + varKeyword: ISyntaxToken; + variableDeclarators: VariableDeclaratorSyntax[]; + } + export interface VariableDeclaratorSyntax extends ISyntaxNode { + propertyName: ISyntaxToken; + typeAnnotation: TypeAnnotationSyntax; + equalsValueClause: EqualsValueClauseSyntax; + } + export interface ArgumentListSyntax extends ISyntaxNode { + typeArgumentList: TypeArgumentListSyntax; + openParenToken: ISyntaxToken; + arguments: IExpressionSyntax[]; + closeParenToken: ISyntaxToken; + } + export interface ParameterListSyntax extends ISyntaxNode { + openParenToken: ISyntaxToken; + parameters: ParameterSyntax[]; + closeParenToken: ISyntaxToken; + } + export interface TypeArgumentListSyntax extends ISyntaxNode { + lessThanToken: ISyntaxToken; + typeArguments: ITypeSyntax[]; + greaterThanToken: ISyntaxToken; + } + export interface TypeParameterListSyntax extends ISyntaxNode { + lessThanToken: ISyntaxToken; + typeParameters: TypeParameterSyntax[]; + greaterThanToken: ISyntaxToken; + } + export interface HeritageClauseSyntax extends ISyntaxNode { + extendsOrImplementsKeyword: ISyntaxToken; + typeNames: INameSyntax[]; + } + export interface EqualsValueClauseSyntax extends ISyntaxNode { + equalsToken: ISyntaxToken; + value: IExpressionSyntax; + } + export interface CaseSwitchClauseSyntax extends ISyntaxNode, ISwitchClauseSyntax { + caseKeyword: ISyntaxToken; + expression: IExpressionSyntax; + colonToken: ISyntaxToken; + statements: IStatementSyntax[]; + } + export interface DefaultSwitchClauseSyntax extends ISyntaxNode, ISwitchClauseSyntax { + defaultKeyword: ISyntaxToken; + colonToken: ISyntaxToken; + statements: IStatementSyntax[]; + } + export interface ElseClauseSyntax extends ISyntaxNode { + elseKeyword: ISyntaxToken; + statement: IStatementSyntax; + } + export interface CatchClauseSyntax extends ISyntaxNode { + catchKeyword: ISyntaxToken; + openParenToken: ISyntaxToken; + identifier: ISyntaxToken; + typeAnnotation: TypeAnnotationSyntax; + closeParenToken: ISyntaxToken; + block: BlockSyntax; + } + export interface FinallyClauseSyntax extends ISyntaxNode { + finallyKeyword: ISyntaxToken; + block: BlockSyntax; + } + export interface TypeParameterSyntax extends ISyntaxNode { + identifier: ISyntaxToken; + constraint: ConstraintSyntax; + } + export interface ConstraintSyntax extends ISyntaxNode { + extendsKeyword: ISyntaxToken; + typeOrExpression: ISyntaxNodeOrToken; + } + export interface SimplePropertyAssignmentSyntax extends ISyntaxNode, IPropertyAssignmentSyntax { + propertyName: ISyntaxToken; + colonToken: ISyntaxToken; + expression: IExpressionSyntax; + } + export interface FunctionPropertyAssignmentSyntax extends ISyntaxNode, IPropertyAssignmentSyntax { + propertyName: ISyntaxToken; + callSignature: CallSignatureSyntax; + block: BlockSyntax; + } + export interface ParameterSyntax extends ISyntaxNode { + dotDotDotToken: ISyntaxToken; + modifiers: ISyntaxToken[]; + identifier: ISyntaxToken; + questionToken: ISyntaxToken; + typeAnnotation: TypeAnnotationSyntax; + equalsValueClause: EqualsValueClauseSyntax; + } + export interface EnumElementSyntax extends ISyntaxNode { + propertyName: ISyntaxToken; + equalsValueClause: EqualsValueClauseSyntax; + } + export interface TypeAnnotationSyntax extends ISyntaxNode { + colonToken: ISyntaxToken; + type: ITypeSyntax; + } + export interface ExternalModuleReferenceSyntax extends ISyntaxNode, IModuleReferenceSyntax { + requireKeyword: ISyntaxToken; + openParenToken: ISyntaxToken; + stringLiteral: ISyntaxToken; + closeParenToken: ISyntaxToken; + } + export interface ModuleNameModuleReferenceSyntax extends ISyntaxNode, IModuleReferenceSyntax { + moduleName: INameSyntax; + } + + export var nodeMetadata: string[][] = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],["moduleElements","endOfFileToken"],["left","dotToken","right"],["openBraceToken","typeMembers","closeBraceToken"],["typeParameterList","parameterList","equalsGreaterThanToken","type"],["type","openBracketToken","closeBracketToken"],["newKeyword","typeParameterList","parameterList","equalsGreaterThanToken","type"],["name","typeArgumentList"],["typeOfKeyword","name"],["modifiers","interfaceKeyword","identifier","typeParameterList","heritageClauses","body"],["modifiers","functionKeyword","identifier","callSignature","block","semicolonToken"],["modifiers","moduleKeyword","name","stringLiteral","openBraceToken","moduleElements","closeBraceToken"],["modifiers","classKeyword","identifier","typeParameterList","heritageClauses","openBraceToken","classElements","closeBraceToken"],["modifiers","enumKeyword","identifier","openBraceToken","enumElements","closeBraceToken"],["modifiers","importKeyword","identifier","equalsToken","moduleReference","semicolonToken"],["exportKeyword","equalsToken","identifier","semicolonToken"],["modifiers","propertyName","callSignature","block","semicolonToken"],["modifiers","variableDeclarator","semicolonToken"],["modifiers","constructorKeyword","callSignature","block","semicolonToken"],["modifiers","indexSignature","semicolonToken"],["modifiers","getKeyword","propertyName","callSignature","block"],["modifiers","setKeyword","propertyName","callSignature","block"],["propertyName","questionToken","typeAnnotation"],["typeParameterList","parameterList","typeAnnotation"],["newKeyword","callSignature"],["openBracketToken","parameters","closeBracketToken","typeAnnotation"],["propertyName","questionToken","callSignature"],["openBraceToken","statements","closeBraceToken"],["ifKeyword","openParenToken","condition","closeParenToken","statement","elseClause"],["modifiers","variableDeclaration","semicolonToken"],["expression","semicolonToken"],["returnKeyword","expression","semicolonToken"],["switchKeyword","openParenToken","expression","closeParenToken","openBraceToken","switchClauses","closeBraceToken"],["breakKeyword","identifier","semicolonToken"],["continueKeyword","identifier","semicolonToken"],["forKeyword","openParenToken","variableDeclaration","initializer","firstSemicolonToken","condition","secondSemicolonToken","incrementor","closeParenToken","statement"],["forKeyword","openParenToken","variableDeclaration","left","inKeyword","expression","closeParenToken","statement"],["semicolonToken"],["throwKeyword","expression","semicolonToken"],["whileKeyword","openParenToken","condition","closeParenToken","statement"],["tryKeyword","block","catchClause","finallyClause"],["identifier","colonToken","statement"],["doKeyword","statement","whileKeyword","openParenToken","condition","closeParenToken","semicolonToken"],["debuggerKeyword","semicolonToken"],["withKeyword","openParenToken","condition","closeParenToken","statement"],["operatorToken","operand"],["operatorToken","operand"],["operatorToken","operand"],["operatorToken","operand"],["operatorToken","operand"],["operatorToken","operand"],["deleteKeyword","expression"],["typeOfKeyword","expression"],["voidKeyword","expression"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["condition","questionToken","whenTrue","colonToken","whenFalse"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["left","operatorToken","right"],["operand","operatorToken"],["operand","operatorToken"],["expression","dotToken","name"],["expression","argumentList"],["openBracketToken","expressions","closeBracketToken"],["openBraceToken","propertyAssignments","closeBraceToken"],["newKeyword","expression","argumentList"],["openParenToken","expression","closeParenToken"],["callSignature","equalsGreaterThanToken","block","expression"],["parameter","equalsGreaterThanToken","block","expression"],["lessThanToken","type","greaterThanToken","expression"],["expression","openBracketToken","argumentExpression","closeBracketToken"],["functionKeyword","identifier","callSignature","block"],[],["varKeyword","variableDeclarators"],["propertyName","typeAnnotation","equalsValueClause"],["typeArgumentList","openParenToken","arguments","closeParenToken"],["openParenToken","parameters","closeParenToken"],["lessThanToken","typeArguments","greaterThanToken"],["lessThanToken","typeParameters","greaterThanToken"],["extendsOrImplementsKeyword","typeNames"],["extendsOrImplementsKeyword","typeNames"],["equalsToken","value"],["caseKeyword","expression","colonToken","statements"],["defaultKeyword","colonToken","statements"],["elseKeyword","statement"],["catchKeyword","openParenToken","identifier","typeAnnotation","closeParenToken","block"],["finallyKeyword","block"],["identifier","constraint"],["extendsKeyword","typeOrExpression"],["propertyName","colonToken","expression"],["propertyName","callSignature","block"],["dotDotDotToken","modifiers","identifier","questionToken","typeAnnotation","equalsValueClause"],["propertyName","equalsValueClause"],["colonToken","type"],["requireKeyword","openParenToken","stringLiteral","closeParenToken"],["moduleName"],]; + + export module Syntax { + export interface ISyntaxFactory { + isConcrete: boolean; + SourceUnitSyntax: { new(data: number, moduleElements: IModuleElementSyntax[], endOfFileToken: ISyntaxToken): SourceUnitSyntax }; + QualifiedNameSyntax: { new(data: number, left: INameSyntax, dotToken: ISyntaxToken, right: ISyntaxToken): QualifiedNameSyntax }; + ObjectTypeSyntax: { new(data: number, openBraceToken: ISyntaxToken, typeMembers: ITypeMemberSyntax[], closeBraceToken: ISyntaxToken): ObjectTypeSyntax }; + FunctionTypeSyntax: { new(data: number, typeParameterList: TypeParameterListSyntax, parameterList: ParameterListSyntax, equalsGreaterThanToken: ISyntaxToken, type: ITypeSyntax): FunctionTypeSyntax }; + ArrayTypeSyntax: { new(data: number, type: ITypeSyntax, openBracketToken: ISyntaxToken, closeBracketToken: ISyntaxToken): ArrayTypeSyntax }; + ConstructorTypeSyntax: { new(data: number, newKeyword: ISyntaxToken, typeParameterList: TypeParameterListSyntax, parameterList: ParameterListSyntax, equalsGreaterThanToken: ISyntaxToken, type: ITypeSyntax): ConstructorTypeSyntax }; + GenericTypeSyntax: { new(data: number, name: INameSyntax, typeArgumentList: TypeArgumentListSyntax): GenericTypeSyntax }; + TypeQuerySyntax: { new(data: number, typeOfKeyword: ISyntaxToken, name: INameSyntax): TypeQuerySyntax }; + InterfaceDeclarationSyntax: { new(data: number, modifiers: ISyntaxToken[], interfaceKeyword: ISyntaxToken, identifier: ISyntaxToken, typeParameterList: TypeParameterListSyntax, heritageClauses: HeritageClauseSyntax[], body: ObjectTypeSyntax): InterfaceDeclarationSyntax }; + FunctionDeclarationSyntax: { new(data: number, modifiers: ISyntaxToken[], functionKeyword: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax, semicolonToken: ISyntaxToken): FunctionDeclarationSyntax }; + ModuleDeclarationSyntax: { new(data: number, modifiers: ISyntaxToken[], moduleKeyword: ISyntaxToken, name: INameSyntax, stringLiteral: ISyntaxToken, openBraceToken: ISyntaxToken, moduleElements: IModuleElementSyntax[], closeBraceToken: ISyntaxToken): ModuleDeclarationSyntax }; + ClassDeclarationSyntax: { new(data: number, modifiers: ISyntaxToken[], classKeyword: ISyntaxToken, identifier: ISyntaxToken, typeParameterList: TypeParameterListSyntax, heritageClauses: HeritageClauseSyntax[], openBraceToken: ISyntaxToken, classElements: IClassElementSyntax[], closeBraceToken: ISyntaxToken): ClassDeclarationSyntax }; + EnumDeclarationSyntax: { new(data: number, modifiers: ISyntaxToken[], enumKeyword: ISyntaxToken, identifier: ISyntaxToken, openBraceToken: ISyntaxToken, enumElements: EnumElementSyntax[], closeBraceToken: ISyntaxToken): EnumDeclarationSyntax }; + ImportDeclarationSyntax: { new(data: number, modifiers: ISyntaxToken[], importKeyword: ISyntaxToken, identifier: ISyntaxToken, equalsToken: ISyntaxToken, moduleReference: IModuleReferenceSyntax, semicolonToken: ISyntaxToken): ImportDeclarationSyntax }; + ExportAssignmentSyntax: { new(data: number, exportKeyword: ISyntaxToken, equalsToken: ISyntaxToken, identifier: ISyntaxToken, semicolonToken: ISyntaxToken): ExportAssignmentSyntax }; + MemberFunctionDeclarationSyntax: { new(data: number, modifiers: ISyntaxToken[], propertyName: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax, semicolonToken: ISyntaxToken): MemberFunctionDeclarationSyntax }; + MemberVariableDeclarationSyntax: { new(data: number, modifiers: ISyntaxToken[], variableDeclarator: VariableDeclaratorSyntax, semicolonToken: ISyntaxToken): MemberVariableDeclarationSyntax }; + ConstructorDeclarationSyntax: { new(data: number, modifiers: ISyntaxToken[], constructorKeyword: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax, semicolonToken: ISyntaxToken): ConstructorDeclarationSyntax }; + IndexMemberDeclarationSyntax: { new(data: number, modifiers: ISyntaxToken[], indexSignature: IndexSignatureSyntax, semicolonToken: ISyntaxToken): IndexMemberDeclarationSyntax }; + GetAccessorSyntax: { new(data: number, modifiers: ISyntaxToken[], getKeyword: ISyntaxToken, propertyName: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax): GetAccessorSyntax }; + SetAccessorSyntax: { new(data: number, modifiers: ISyntaxToken[], setKeyword: ISyntaxToken, propertyName: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax): SetAccessorSyntax }; + PropertySignatureSyntax: { new(data: number, propertyName: ISyntaxToken, questionToken: ISyntaxToken, typeAnnotation: TypeAnnotationSyntax): PropertySignatureSyntax }; + CallSignatureSyntax: { new(data: number, typeParameterList: TypeParameterListSyntax, parameterList: ParameterListSyntax, typeAnnotation: TypeAnnotationSyntax): CallSignatureSyntax }; + ConstructSignatureSyntax: { new(data: number, newKeyword: ISyntaxToken, callSignature: CallSignatureSyntax): ConstructSignatureSyntax }; + IndexSignatureSyntax: { new(data: number, openBracketToken: ISyntaxToken, parameters: ParameterSyntax[], closeBracketToken: ISyntaxToken, typeAnnotation: TypeAnnotationSyntax): IndexSignatureSyntax }; + MethodSignatureSyntax: { new(data: number, propertyName: ISyntaxToken, questionToken: ISyntaxToken, callSignature: CallSignatureSyntax): MethodSignatureSyntax }; + BlockSyntax: { new(data: number, openBraceToken: ISyntaxToken, statements: IStatementSyntax[], closeBraceToken: ISyntaxToken): BlockSyntax }; + IfStatementSyntax: { new(data: number, ifKeyword: ISyntaxToken, openParenToken: ISyntaxToken, condition: IExpressionSyntax, closeParenToken: ISyntaxToken, statement: IStatementSyntax, elseClause: ElseClauseSyntax): IfStatementSyntax }; + VariableStatementSyntax: { new(data: number, modifiers: ISyntaxToken[], variableDeclaration: VariableDeclarationSyntax, semicolonToken: ISyntaxToken): VariableStatementSyntax }; + ExpressionStatementSyntax: { new(data: number, expression: IExpressionSyntax, semicolonToken: ISyntaxToken): ExpressionStatementSyntax }; + ReturnStatementSyntax: { new(data: number, returnKeyword: ISyntaxToken, expression: IExpressionSyntax, semicolonToken: ISyntaxToken): ReturnStatementSyntax }; + SwitchStatementSyntax: { new(data: number, switchKeyword: ISyntaxToken, openParenToken: ISyntaxToken, expression: IExpressionSyntax, closeParenToken: ISyntaxToken, openBraceToken: ISyntaxToken, switchClauses: ISwitchClauseSyntax[], closeBraceToken: ISyntaxToken): SwitchStatementSyntax }; + BreakStatementSyntax: { new(data: number, breakKeyword: ISyntaxToken, identifier: ISyntaxToken, semicolonToken: ISyntaxToken): BreakStatementSyntax }; + ContinueStatementSyntax: { new(data: number, continueKeyword: ISyntaxToken, identifier: ISyntaxToken, semicolonToken: ISyntaxToken): ContinueStatementSyntax }; + ForStatementSyntax: { new(data: number, forKeyword: ISyntaxToken, openParenToken: ISyntaxToken, variableDeclaration: VariableDeclarationSyntax, initializer: IExpressionSyntax, firstSemicolonToken: ISyntaxToken, condition: IExpressionSyntax, secondSemicolonToken: ISyntaxToken, incrementor: IExpressionSyntax, closeParenToken: ISyntaxToken, statement: IStatementSyntax): ForStatementSyntax }; + ForInStatementSyntax: { new(data: number, forKeyword: ISyntaxToken, openParenToken: ISyntaxToken, variableDeclaration: VariableDeclarationSyntax, left: IExpressionSyntax, inKeyword: ISyntaxToken, expression: IExpressionSyntax, closeParenToken: ISyntaxToken, statement: IStatementSyntax): ForInStatementSyntax }; + EmptyStatementSyntax: { new(data: number, semicolonToken: ISyntaxToken): EmptyStatementSyntax }; + ThrowStatementSyntax: { new(data: number, throwKeyword: ISyntaxToken, expression: IExpressionSyntax, semicolonToken: ISyntaxToken): ThrowStatementSyntax }; + WhileStatementSyntax: { new(data: number, whileKeyword: ISyntaxToken, openParenToken: ISyntaxToken, condition: IExpressionSyntax, closeParenToken: ISyntaxToken, statement: IStatementSyntax): WhileStatementSyntax }; + TryStatementSyntax: { new(data: number, tryKeyword: ISyntaxToken, block: BlockSyntax, catchClause: CatchClauseSyntax, finallyClause: FinallyClauseSyntax): TryStatementSyntax }; + LabeledStatementSyntax: { new(data: number, identifier: ISyntaxToken, colonToken: ISyntaxToken, statement: IStatementSyntax): LabeledStatementSyntax }; + DoStatementSyntax: { new(data: number, doKeyword: ISyntaxToken, statement: IStatementSyntax, whileKeyword: ISyntaxToken, openParenToken: ISyntaxToken, condition: IExpressionSyntax, closeParenToken: ISyntaxToken, semicolonToken: ISyntaxToken): DoStatementSyntax }; + DebuggerStatementSyntax: { new(data: number, debuggerKeyword: ISyntaxToken, semicolonToken: ISyntaxToken): DebuggerStatementSyntax }; + WithStatementSyntax: { new(data: number, withKeyword: ISyntaxToken, openParenToken: ISyntaxToken, condition: IExpressionSyntax, closeParenToken: ISyntaxToken, statement: IStatementSyntax): WithStatementSyntax }; + PrefixUnaryExpressionSyntax: { new(data: number, operatorToken: ISyntaxToken, operand: IUnaryExpressionSyntax): PrefixUnaryExpressionSyntax }; + DeleteExpressionSyntax: { new(data: number, deleteKeyword: ISyntaxToken, expression: IUnaryExpressionSyntax): DeleteExpressionSyntax }; + TypeOfExpressionSyntax: { new(data: number, typeOfKeyword: ISyntaxToken, expression: IUnaryExpressionSyntax): TypeOfExpressionSyntax }; + VoidExpressionSyntax: { new(data: number, voidKeyword: ISyntaxToken, expression: IUnaryExpressionSyntax): VoidExpressionSyntax }; + ConditionalExpressionSyntax: { new(data: number, condition: IExpressionSyntax, questionToken: ISyntaxToken, whenTrue: IExpressionSyntax, colonToken: ISyntaxToken, whenFalse: IExpressionSyntax): ConditionalExpressionSyntax }; + BinaryExpressionSyntax: { new(data: number, left: IExpressionSyntax, operatorToken: ISyntaxToken, right: IExpressionSyntax): BinaryExpressionSyntax }; + PostfixUnaryExpressionSyntax: { new(data: number, operand: ILeftHandSideExpressionSyntax, operatorToken: ISyntaxToken): PostfixUnaryExpressionSyntax }; + MemberAccessExpressionSyntax: { new(data: number, expression: ILeftHandSideExpressionSyntax, dotToken: ISyntaxToken, name: ISyntaxToken): MemberAccessExpressionSyntax }; + InvocationExpressionSyntax: { new(data: number, expression: ILeftHandSideExpressionSyntax, argumentList: ArgumentListSyntax): InvocationExpressionSyntax }; + ArrayLiteralExpressionSyntax: { new(data: number, openBracketToken: ISyntaxToken, expressions: IExpressionSyntax[], closeBracketToken: ISyntaxToken): ArrayLiteralExpressionSyntax }; + ObjectLiteralExpressionSyntax: { new(data: number, openBraceToken: ISyntaxToken, propertyAssignments: IPropertyAssignmentSyntax[], closeBraceToken: ISyntaxToken): ObjectLiteralExpressionSyntax }; + ObjectCreationExpressionSyntax: { new(data: number, newKeyword: ISyntaxToken, expression: IMemberExpressionSyntax, argumentList: ArgumentListSyntax): ObjectCreationExpressionSyntax }; + ParenthesizedExpressionSyntax: { new(data: number, openParenToken: ISyntaxToken, expression: IExpressionSyntax, closeParenToken: ISyntaxToken): ParenthesizedExpressionSyntax }; + ParenthesizedArrowFunctionExpressionSyntax: { new(data: number, callSignature: CallSignatureSyntax, equalsGreaterThanToken: ISyntaxToken, block: BlockSyntax, expression: IExpressionSyntax): ParenthesizedArrowFunctionExpressionSyntax }; + SimpleArrowFunctionExpressionSyntax: { new(data: number, parameter: ParameterSyntax, equalsGreaterThanToken: ISyntaxToken, block: BlockSyntax, expression: IExpressionSyntax): SimpleArrowFunctionExpressionSyntax }; + CastExpressionSyntax: { new(data: number, lessThanToken: ISyntaxToken, type: ITypeSyntax, greaterThanToken: ISyntaxToken, expression: IUnaryExpressionSyntax): CastExpressionSyntax }; + ElementAccessExpressionSyntax: { new(data: number, expression: ILeftHandSideExpressionSyntax, openBracketToken: ISyntaxToken, argumentExpression: IExpressionSyntax, closeBracketToken: ISyntaxToken): ElementAccessExpressionSyntax }; + FunctionExpressionSyntax: { new(data: number, functionKeyword: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax): FunctionExpressionSyntax }; + OmittedExpressionSyntax: { new(data: number): OmittedExpressionSyntax }; + VariableDeclarationSyntax: { new(data: number, varKeyword: ISyntaxToken, variableDeclarators: VariableDeclaratorSyntax[]): VariableDeclarationSyntax }; + VariableDeclaratorSyntax: { new(data: number, propertyName: ISyntaxToken, typeAnnotation: TypeAnnotationSyntax, equalsValueClause: EqualsValueClauseSyntax): VariableDeclaratorSyntax }; + ArgumentListSyntax: { new(data: number, typeArgumentList: TypeArgumentListSyntax, openParenToken: ISyntaxToken, arguments: IExpressionSyntax[], closeParenToken: ISyntaxToken): ArgumentListSyntax }; + ParameterListSyntax: { new(data: number, openParenToken: ISyntaxToken, parameters: ParameterSyntax[], closeParenToken: ISyntaxToken): ParameterListSyntax }; + TypeArgumentListSyntax: { new(data: number, lessThanToken: ISyntaxToken, typeArguments: ITypeSyntax[], greaterThanToken: ISyntaxToken): TypeArgumentListSyntax }; + TypeParameterListSyntax: { new(data: number, lessThanToken: ISyntaxToken, typeParameters: TypeParameterSyntax[], greaterThanToken: ISyntaxToken): TypeParameterListSyntax }; + HeritageClauseSyntax: { new(data: number, extendsOrImplementsKeyword: ISyntaxToken, typeNames: INameSyntax[]): HeritageClauseSyntax }; + EqualsValueClauseSyntax: { new(data: number, equalsToken: ISyntaxToken, value: IExpressionSyntax): EqualsValueClauseSyntax }; + CaseSwitchClauseSyntax: { new(data: number, caseKeyword: ISyntaxToken, expression: IExpressionSyntax, colonToken: ISyntaxToken, statements: IStatementSyntax[]): CaseSwitchClauseSyntax }; + DefaultSwitchClauseSyntax: { new(data: number, defaultKeyword: ISyntaxToken, colonToken: ISyntaxToken, statements: IStatementSyntax[]): DefaultSwitchClauseSyntax }; + ElseClauseSyntax: { new(data: number, elseKeyword: ISyntaxToken, statement: IStatementSyntax): ElseClauseSyntax }; + CatchClauseSyntax: { new(data: number, catchKeyword: ISyntaxToken, openParenToken: ISyntaxToken, identifier: ISyntaxToken, typeAnnotation: TypeAnnotationSyntax, closeParenToken: ISyntaxToken, block: BlockSyntax): CatchClauseSyntax }; + FinallyClauseSyntax: { new(data: number, finallyKeyword: ISyntaxToken, block: BlockSyntax): FinallyClauseSyntax }; + TypeParameterSyntax: { new(data: number, identifier: ISyntaxToken, constraint: ConstraintSyntax): TypeParameterSyntax }; + ConstraintSyntax: { new(data: number, extendsKeyword: ISyntaxToken, typeOrExpression: ISyntaxNodeOrToken): ConstraintSyntax }; + SimplePropertyAssignmentSyntax: { new(data: number, propertyName: ISyntaxToken, colonToken: ISyntaxToken, expression: IExpressionSyntax): SimplePropertyAssignmentSyntax }; + FunctionPropertyAssignmentSyntax: { new(data: number, propertyName: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax): FunctionPropertyAssignmentSyntax }; + ParameterSyntax: { new(data: number, dotDotDotToken: ISyntaxToken, modifiers: ISyntaxToken[], identifier: ISyntaxToken, questionToken: ISyntaxToken, typeAnnotation: TypeAnnotationSyntax, equalsValueClause: EqualsValueClauseSyntax): ParameterSyntax }; + EnumElementSyntax: { new(data: number, propertyName: ISyntaxToken, equalsValueClause: EqualsValueClauseSyntax): EnumElementSyntax }; + TypeAnnotationSyntax: { new(data: number, colonToken: ISyntaxToken, type: ITypeSyntax): TypeAnnotationSyntax }; + ExternalModuleReferenceSyntax: { new(data: number, requireKeyword: ISyntaxToken, openParenToken: ISyntaxToken, stringLiteral: ISyntaxToken, closeParenToken: ISyntaxToken): ExternalModuleReferenceSyntax }; + ModuleNameModuleReferenceSyntax: { new(data: number, moduleName: INameSyntax): ModuleNameModuleReferenceSyntax }; + } + } +} \ No newline at end of file diff --git a/src/services/syntax/syntaxToken.ts b/src/services/syntax/syntaxToken.ts new file mode 100644 index 00000000000..19c522aee18 --- /dev/null +++ b/src/services/syntax/syntaxToken.ts @@ -0,0 +1,547 @@ +/// + +module TypeScript { + export interface ISyntaxToken extends ISyntaxNodeOrToken, INameSyntax, IPrimaryExpressionSyntax { + // Adjusts the full start of this token. Should only be called by the parser. + setFullStart(fullStart: number): void; + + // The absolute start of this element, including the leading trivia. + fullStart(): number; + + // With of this element, including leading and trailing trivia. + fullWidth(): number; + + // Text for this token, not including leading or trailing trivia. + text(): string; + fullText(text?: ISimpleText): string; + + hasLeadingTrivia(): boolean; + hasTrailingTrivia(): boolean; + + hasSkippedToken(): boolean; + + leadingTrivia(text?: ISimpleText): ISyntaxTriviaList; + trailingTrivia(text?: ISimpleText): ISyntaxTriviaList; + + leadingTriviaWidth(text?: ISimpleText): number; + trailingTriviaWidth(text?: ISimpleText): number; + + // True if this was a keyword that the parser converted to an identifier. i.e. if you have + // x.public + // + // then 'public' will be converted to an identifier. These tokens should are parser + // generated and, as such, should not be returned when the incremental parser source + // hands out tokens. Note: If it is included in a node then *that* node may still + // be reusuable. i.e. if i have: private Foo() { x.public = 1; } + // + // Then that entire method node is reusable even if the 'public' identifier is not. + isKeywordConvertedToIdentifier(): boolean; + + // True if this element cannot be reused in incremental parsing. There are several situations + // in which an element can not be reused. They are: + // + // 1) The element contained skipped text. + // 2) The element contained zero width tokens. + // 3) The element contains tokens generated by the parser (like >> or a keyword -> identifier + // conversion). + // 4) The element contains a regex token somewhere under it. A regex token is either a + // regex itself (i.e. /foo/), or is a token which could start a regex (i.e. "/" or "/="). This + // data is used by the incremental parser to decide if a node can be reused. Due to the + // lookahead nature of regex tokens, a node containing a regex token cannot be reused. Normally, + // changes to text only affect the tokens directly intersected. However, because regex tokens + // have such unbounded lookahead (technically bounded at the end of a line, but htat's minor), + // we need to recheck them to see if they've changed due to the edit. For example, if you had: + // + // while (true) /3; return; + // + // And you changed it to: + // + // while (true) /3; return/; + // + // Then even though only the 'return' and ';' colons were touched, we'd want to rescan the '/' + // token which we would then realize was a regex. + isIncrementallyUnusable(): boolean; + + clone(): ISyntaxToken; + } +} + +module TypeScript { + export function tokenValue(token: ISyntaxToken): any { + if (token.fullWidth() === 0) { + return null; + } + + var kind = token.kind(); + var text = token.text(); + + if (kind === SyntaxKind.IdentifierName) { + return massageEscapes(text); + } + + switch (kind) { + case SyntaxKind.TrueKeyword: + return true; + case SyntaxKind.FalseKeyword: + return false; + case SyntaxKind.NullKeyword: + return null; + } + + if (SyntaxFacts.isAnyKeyword(kind) || SyntaxFacts.isAnyPunctuation(kind)) { + return SyntaxFacts.getText(kind); + } + + if (kind === SyntaxKind.NumericLiteral) { + return IntegerUtilities.isHexInteger(text) ? parseInt(text, /*radix:*/ 16) : parseFloat(text); + } + else if (kind === SyntaxKind.StringLiteral) { + if (text.length > 1 && text.charCodeAt(text.length - 1) === text.charCodeAt(0)) { + // Properly terminated. Remove the quotes, and massage any escape characters we see. + return massageEscapes(text.substr(1, text.length - 2)); + } + else { + // Not property terminated. Remove the first quote and massage any escape characters we see. + return massageEscapes(text.substr(1)); + + } + } + else if (kind === SyntaxKind.RegularExpressionLiteral) { + return regularExpressionValue(text); + } + else if (kind === SyntaxKind.EndOfFileToken || kind === SyntaxKind.ErrorToken) { + return null; + } + else { + throw Errors.invalidOperation(); + } + } + + export function tokenValueText(token: ISyntaxToken): string { + var value = tokenValue(token); + return value === null ? "" : massageDisallowedIdentifiers(value.toString()); + } + + export function massageEscapes(text: string): string { + return text.indexOf("\\") >= 0 ? convertEscapes(text) : text; + } + + function regularExpressionValue(text: string): RegExp { + try { + var lastSlash = text.lastIndexOf("/"); + var body = text.substring(1, lastSlash); + var flags = text.substring(lastSlash + 1); + return new RegExp(body, flags); + } + catch (e) { + return null; + } + } + + function massageDisallowedIdentifiers(text: string): string { + // We routinely store the 'valueText' for a token as keys in dictionaries. However, as those + // dictionaries are usually just a javascript object, we run into issues when teh keys collide + // with certain predefined keys they depend on (like __proto__). To workaround this + // we ensure that the valueText of any token is not __proto__ but is instead ___proto__. + // + // We also prepend a _ to any identifier starting with two __ . That allows us to carve + // out the entire namespace of identifiers starting with __ for ourselves. + if (text.charCodeAt(0) === CharacterCodes._ && text.charCodeAt(1) === CharacterCodes._) { + return "_" + text; + } + + return text; + } + + var characterArray: number[] = []; + + function convertEscapes(text: string): string { + characterArray.length = 0; + var result = ""; + + for (var i = 0, n = text.length; i < n; i++) { + var ch = text.charCodeAt(i); + + if (ch === CharacterCodes.backslash) { + i++; + if (i < n) { + ch = text.charCodeAt(i); + switch (ch) { + case CharacterCodes._0: + characterArray.push(CharacterCodes.nullCharacter); + continue; + + case CharacterCodes.b: + characterArray.push(CharacterCodes.backspace); + continue; + + case CharacterCodes.f: + characterArray.push(CharacterCodes.formFeed); + continue; + + case CharacterCodes.n: + characterArray.push(CharacterCodes.lineFeed); + continue; + + case CharacterCodes.r: + characterArray.push(CharacterCodes.carriageReturn); + continue; + + case CharacterCodes.t: + characterArray.push(CharacterCodes.tab); + continue; + + case CharacterCodes.v: + characterArray.push(CharacterCodes.verticalTab); + continue; + + case CharacterCodes.x: + characterArray.push(hexValue(text, /*start:*/ i + 1, /*length:*/ 2)); + i += 2; + continue; + + case CharacterCodes.u: + characterArray.push(hexValue(text, /*start:*/ i + 1, /*length:*/ 4)); + i += 4; + continue; + + case CharacterCodes.carriageReturn: + var nextIndex = i + 1; + if (nextIndex < text.length && text.charCodeAt(nextIndex) === CharacterCodes.lineFeed) { + // Skip the entire \r\n sequence. + i++; + } + continue; + + case CharacterCodes.lineFeed: + case CharacterCodes.paragraphSeparator: + case CharacterCodes.lineSeparator: + // From ES5: LineContinuation is the empty character sequence. + continue; + + default: + // Any other character is ok as well. As per rule: + // EscapeSequence :: CharacterEscapeSequence + // CharacterEscapeSequence :: NonEscapeCharacter + // NonEscapeCharacter :: SourceCharacter but notEscapeCharacter or LineTerminator + // + // Intentional fall through + } + } + } + + characterArray.push(ch); + + if (i && !(i % 1024)) { + result = result.concat(String.fromCharCode.apply(null, characterArray)); + characterArray.length = 0; + } + } + + if (characterArray.length) { + result = result.concat(String.fromCharCode.apply(null, characterArray)); + } + + return result; + } + + function hexValue(text: string, start: number, length: number): number { + var intChar = 0; + for (var i = 0; i < length; i++) { + var ch2 = text.charCodeAt(start + i); + if (!CharacterInfo.isHexDigit(ch2)) { + break; + } + + intChar = (intChar << 4) + CharacterInfo.hexValue(ch2); + } + + return intChar; + } +} + +module TypeScript.Syntax { + export function realizeToken(token: ISyntaxToken, text: ISimpleText): ISyntaxToken { + return new RealizedToken(token.fullStart(), token.kind(), token.isKeywordConvertedToIdentifier(), token.leadingTrivia(text), token.text(), token.trailingTrivia(text)); + } + + export function convertKeywordToIdentifier(token: ISyntaxToken): ISyntaxToken { + return new ConvertedKeywordToken(token); + } + + export function withLeadingTrivia(token: ISyntaxToken, leadingTrivia: ISyntaxTriviaList, text: ISimpleText): ISyntaxToken { + return new RealizedToken(token.fullStart(), token.kind(), token.isKeywordConvertedToIdentifier(), leadingTrivia, token.text(), token.trailingTrivia(text)); + } + + export function withTrailingTrivia(token: ISyntaxToken, trailingTrivia: ISyntaxTriviaList, text: ISimpleText): ISyntaxToken { + return new RealizedToken(token.fullStart(), token.kind(), token.isKeywordConvertedToIdentifier(), token.leadingTrivia(text), token.text(), trailingTrivia); + } + + export function emptyToken(kind: SyntaxKind): ISyntaxToken { + return new EmptyToken(kind); + } + + class EmptyToken implements ISyntaxToken { + public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; public _typeBrand: any; + + constructor(private _kind: SyntaxKind) { + } + + public setFullStart(fullStart: number): void { + // An empty token is always at the -1 position. + } + + public kind(): SyntaxKind { + return this._kind; + } + + public clone(): ISyntaxToken { + return new EmptyToken(this.kind()); + } + + // Empty tokens are never incrementally reusable. + public isIncrementallyUnusable() { return true; } + + public isKeywordConvertedToIdentifier() { + return false; + } + + public fullWidth() { return 0; } + + private position(): number { + // It's hard for us to tell the position of an empty token at the eact time we create + // it. For example, we may have: + // + // a / finally + // + // There will be a missing token detected after the forward slash, so it would be + // tempting to set its position as the full-end of hte slash token. However, + // immediately after that, the 'finally' token will be skipped and will be attached + // as skipped text to the forward slash. This means the 'full-end' of the forward + // slash will change, and thus the empty token will now appear to be embedded inside + // another token. This violates are rule that all tokens must only touch at the end, + // and makes enforcing invariants much harder. + // + // To address this we create the empty token with no known position, and then we + // determine what it's position should be based on where it lies in the tree. + // Specifically, we find the previous non-zero-width syntax element, and we consider + // the full-start of this token to be at the full-end of that element. + + var previousElement = this.previousNonZeroWidthElement(); + return previousElement === null ? 0 : fullStart(previousElement) + fullWidth(previousElement); + } + + private previousNonZeroWidthElement(): ISyntaxElement { + var current: ISyntaxElement = this; + while (true) { + var parent = current.parent; + if (parent === null) { + Debug.assert(current.kind() === SyntaxKind.SourceUnit, "We had a node without a parent that was not the root node!"); + + // We walked all the way to the top, and never found a previous element. This + // can happen with code like: + // + // / b; + // + // We will have an empty identifier token as the first token in the tree. In + // this case, return null so that the position of the empty token will be + // considered to be 0. + return null; + } + + // Ok. We have a parent. First, find out which slot we're at in the parent. + for (var i = 0, n = childCount(parent); i < n; i++) { + if (childAt(parent, i) === current) { + break; + } + } + + Debug.assert(i !== n, "Could not find current element in parent's child list!"); + + // Walk backward from this element, looking for a non-zero-width sibling. + for (var j = i - 1; j >= 0; j--) { + var sibling = childAt(parent, j); + if (sibling && fullWidth(sibling) > 0) { + return sibling; + } + } + + // We couldn't find a non-zero-width sibling. We were either the first element, or + // all preceding elements are empty. So, move up to our parent so we we can find + // its preceding sibling. + current = current.parent; + } + } + + public fullStart(): number { + return this.position(); + } + + public text() { return ""; } + public fullText(): string { return ""; } + + public hasLeadingTrivia() { return false; } + public leadingTriviaWidth() { return 0; } + public hasTrailingTrivia() { return false; } + public hasSkippedToken() { return false; } + + public trailingTriviaWidth() { return 0; } + public leadingTrivia(): ISyntaxTriviaList { return Syntax.emptyTriviaList; } + public trailingTrivia(): ISyntaxTriviaList { return Syntax.emptyTriviaList; } + } + + class RealizedToken implements ISyntaxToken { + private _fullStart: number; + private _kind: SyntaxKind; + private _isKeywordConvertedToIdentifier: boolean; + private _leadingTrivia: ISyntaxTriviaList; + private _text: string; + private _trailingTrivia: ISyntaxTriviaList; + + public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; public _typeBrand: any; + + constructor(fullStart: number, + kind: SyntaxKind, + isKeywordConvertedToIdentifier: boolean, + leadingTrivia: ISyntaxTriviaList, + text: string, + trailingTrivia: ISyntaxTriviaList) { + this._fullStart = fullStart; + this._kind = kind; + this._isKeywordConvertedToIdentifier = isKeywordConvertedToIdentifier; + this._text = text; + + this._leadingTrivia = leadingTrivia.clone(); + this._trailingTrivia = trailingTrivia.clone(); + + if (!this._leadingTrivia.isShared()) { + this._leadingTrivia.parent = this; + } + + if (!this._trailingTrivia.isShared()) { + this._trailingTrivia.parent = this; + } + } + + public setFullStart(fullStart: number): void { + this._fullStart = fullStart; + } + + public kind(): SyntaxKind { + return this._kind; + } + + public clone(): ISyntaxToken { + return new RealizedToken(this._fullStart, this.kind(), this._isKeywordConvertedToIdentifier, this._leadingTrivia, this._text, this._trailingTrivia); + } + + // Realized tokens are created from the parser. They are *never* incrementally reusable. + public isIncrementallyUnusable() { return true; } + + public isKeywordConvertedToIdentifier() { + return this._isKeywordConvertedToIdentifier; + } + + public fullStart(): number { return this._fullStart; } + public fullWidth(): number { return this._leadingTrivia.fullWidth() + this._text.length + this._trailingTrivia.fullWidth(); } + + public text(): string { return this._text; } + public fullText(): string { return this._leadingTrivia.fullText() + this.text() + this._trailingTrivia.fullText(); } + + public hasLeadingTrivia(): boolean { return this._leadingTrivia.count() > 0; } + public hasTrailingTrivia(): boolean { return this._trailingTrivia.count() > 0; } + + public leadingTriviaWidth(): number { return this._leadingTrivia.fullWidth(); } + public trailingTriviaWidth(): number { return this._trailingTrivia.fullWidth(); } + + public hasSkippedToken(): boolean { return this._leadingTrivia.hasSkippedToken() || this._trailingTrivia.hasSkippedToken(); } + + public leadingTrivia(): ISyntaxTriviaList { return this._leadingTrivia; } + public trailingTrivia(): ISyntaxTriviaList { return this._trailingTrivia; } + } + + class ConvertedKeywordToken implements ISyntaxToken { + public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; public _typeBrand: any; + + constructor(private underlyingToken: ISyntaxToken) { + } + + public kind() { + return SyntaxKind.IdentifierName; + } + + public setFullStart(fullStart: number): void { + this.underlyingToken.setFullStart(fullStart); + } + + public fullStart(): number { + return this.underlyingToken.fullStart(); + } + + public fullWidth(): number { + return this.underlyingToken.fullWidth(); + } + + public text(): string { + return this.underlyingToken.text(); + } + + private syntaxTreeText(text: ISimpleText) { + var result = text || syntaxTree(this).text; + Debug.assert(result); + return result; + } + + public fullText(text?: ISimpleText): string { + return this.underlyingToken.fullText(this.syntaxTreeText(text)); + } + + public hasLeadingTrivia(): boolean { + return this.underlyingToken.hasLeadingTrivia(); + } + + public hasTrailingTrivia(): boolean { + return this.underlyingToken.hasTrailingTrivia(); + } + + public hasSkippedToken(): boolean { + return this.underlyingToken.hasSkippedToken(); + } + + public leadingTrivia(text?: ISimpleText): ISyntaxTriviaList { + var result = this.underlyingToken.leadingTrivia(this.syntaxTreeText(text)); + result.parent = this; + return result; + } + + public trailingTrivia(text?: ISimpleText): ISyntaxTriviaList { + var result = this.underlyingToken.trailingTrivia(this.syntaxTreeText(text)); + result.parent = this; + return result; + } + + public leadingTriviaWidth(text?: ISimpleText): number { + return this.underlyingToken.leadingTriviaWidth(this.syntaxTreeText(text)); + } + + public trailingTriviaWidth(text?: ISimpleText): number { + return this.underlyingToken.trailingTriviaWidth(this.syntaxTreeText(text)); + } + + public isKeywordConvertedToIdentifier(): boolean { + return true; + } + + public isIncrementallyUnusable(): boolean { + // We're incrementally unusable if our underlying token is unusable. + // For example, we may have: this.public \ + // In this case we will keyword converted to an identifier that is still unusable because + // it has a trailing skipped token. + return this.underlyingToken.isIncrementallyUnusable(); + } + + public clone(): ISyntaxToken { + return new ConvertedKeywordToken(this.underlyingToken); + } + } +} \ No newline at end of file diff --git a/src/services/syntax/syntaxTree.ts b/src/services/syntax/syntaxTree.ts new file mode 100644 index 00000000000..de4c4cf7add --- /dev/null +++ b/src/services/syntax/syntaxTree.ts @@ -0,0 +1,1615 @@ +/// + +module TypeScript { + export var syntaxDiagnosticsTime: number = 0; + + export class SyntaxTree { + private _isConcrete: boolean; + private _sourceUnit: SourceUnitSyntax; + private _isDeclaration: boolean; + private _parserDiagnostics: Diagnostic[]; + private _allDiagnostics: Diagnostic[] = null; + private _fileName: string; + private _lineMap: LineMap; + private _languageVersion: ts.ScriptTarget; + + // Computed on demand. + private _amdDependencies: string[]; + private _isExternalModule: boolean; + + constructor(isConcrete: boolean, + sourceUnit: SourceUnitSyntax, + isDeclaration: boolean, + diagnostics: Diagnostic[], + fileName: string, + public text: ISimpleText, + languageVersion: ts.ScriptTarget) { + this._isConcrete = isConcrete; + this._sourceUnit = sourceUnit; + this._isDeclaration = isDeclaration; + this._parserDiagnostics = diagnostics; + this._fileName = fileName; + this._lineMap = text.lineMap(); + this._languageVersion = languageVersion; + + sourceUnit.syntaxTree = this; + } + + public isConcrete(): boolean { + return this._isConcrete; + } + + public sourceUnit(): SourceUnitSyntax { + return this._sourceUnit; + } + + public isDeclaration(): boolean { + return this._isDeclaration; + } + + private computeDiagnostics(): Diagnostic[] { + if (this._parserDiagnostics.length > 0) { + return this._parserDiagnostics; + } + + // No parser reported diagnostics. Check for any additional grammar diagnostics. + var diagnostics: Diagnostic[] = []; + visitNodeOrToken(new GrammarCheckerWalker(this, diagnostics), this.sourceUnit()); + + return diagnostics; + } + + public diagnostics(): Diagnostic[] { + if (this._allDiagnostics === null) { + var start = new Date().getTime(); + this._allDiagnostics = this.computeDiagnostics(); + syntaxDiagnosticsTime += new Date().getTime() - start; + } + + return this._allDiagnostics; + } + + public fileName(): string { + return this._fileName; + } + + public lineMap(): LineMap { + return this._lineMap; + } + + public languageVersion(): ts.ScriptTarget { + return this._languageVersion; + } + + private cacheSyntaxTreeInfo(): void { + // If we're not keeping around the syntax tree, store the diagnostics and line + // map so they don't have to be recomputed. + var sourceUnit = this.sourceUnit(); + var firstToken = firstSyntaxTreeToken(this); + var leadingTrivia = firstToken.leadingTrivia(this.text); + + this._isExternalModule = externalModuleIndicatorSpanWorker(this, firstToken) !== null; + + var amdDependencies: string[] = []; + for (var i = 0, n = leadingTrivia.count(); i < n; i++) { + var trivia = leadingTrivia.syntaxTriviaAt(i); + if (trivia.isComment()) { + var amdDependency = this.getAmdDependency(trivia.fullText()); + if (amdDependency) { + amdDependencies.push(amdDependency); + } + } + } + + this._amdDependencies = amdDependencies; + } + + private getAmdDependency(comment: string): string { + var amdDependencyRegEx = /^\/\/\/\s* 0) { + var modifiers = parameter.modifiers; + + for (var i = 0, n = modifiers.length; i < n; i++) { + var modifier = modifiers[i]; + + if (this.checkParameterAccessibilityModifier(parameterList, modifier, i)) { + return true; + } + } + } + + return false; + } + + private checkParameterAccessibilityModifier(parameterList: ParameterListSyntax, modifier: ISyntaxToken, modifierIndex: number): boolean { + if (modifier.kind() !== SyntaxKind.PublicKeyword && modifier.kind() !== SyntaxKind.PrivateKeyword) { + this.pushDiagnostic(modifier, DiagnosticCode._0_modifier_cannot_appear_on_a_parameter, [modifier.text()]); + return true; + } + else { + if (modifierIndex > 0) { + this.pushDiagnostic(modifier, DiagnosticCode.Accessibility_modifier_already_seen); + return true; + } + } + + return false; + } + + private checkForTrailingComma(list: ISyntaxNodeOrToken[]): boolean { + // If we have at least one child, and we have an even number of children, then that + // means we have an illegal trailing separator. + if (childCount(list) === 0 || childCount(list) % 2 === 1) { + return false; + } + + var child = childAt(list, childCount(list) - 1); + this.pushDiagnostic(child, DiagnosticCode.Trailing_comma_not_allowed); + + return true; + } + + private checkForAtLeastOneElement(parent: ISyntaxElement, list: ISyntaxNodeOrToken[], reportToken: ISyntaxToken, listKind: string): boolean { + if (childCount(list) > 0) { + return false; + } + + this.pushDiagnostic(reportToken, DiagnosticCode._0_list_cannot_be_empty, [listKind]); + return true; + } + + public visitParameterList(node: ParameterListSyntax): void { + if (this.checkParameterListAcessibilityModifiers(node) || + this.checkParameterListOrder(node) || + this.checkForTrailingComma(node.parameters)) { + + return; + } + + super.visitParameterList(node); + } + + public visitHeritageClause(node: HeritageClauseSyntax): void { + if (this.checkForTrailingComma(node.typeNames) || + this.checkForAtLeastOneElement(node, node.typeNames, node.extendsOrImplementsKeyword, SyntaxFacts.getText(node.extendsOrImplementsKeyword.kind()))) { + return; + } + + super.visitHeritageClause(node); + } + + public visitArgumentList(node: ArgumentListSyntax): void { + if (this.checkForTrailingComma(node.arguments)) { + return; + } + + super.visitArgumentList(node); + } + + public visitVariableDeclaration(node: VariableDeclarationSyntax): void { + if (this.checkForAtLeastOneElement(node, node.variableDeclarators, node.varKeyword, getLocalizedText(DiagnosticCode.variable_declaration, null)) || + this.checkForTrailingComma(node.variableDeclarators)) { + return; + } + + super.visitVariableDeclaration(node); + } + + public visitTypeArgumentList(node: TypeArgumentListSyntax): void { + if (this.checkForTrailingComma(node.typeArguments) || + this.checkForAtLeastOneElement(node, node.typeArguments, node.lessThanToken, getLocalizedText(DiagnosticCode.type_argument, null))) { + return; + } + + super.visitTypeArgumentList(node); + } + + public visitTypeParameterList(node: TypeParameterListSyntax): void { + if (this.checkForTrailingComma(node.typeParameters) || + this.checkForAtLeastOneElement(node, node.typeParameters, node.lessThanToken, getLocalizedText(DiagnosticCode.type_parameter, null))) { + return; + } + + super.visitTypeParameterList(node); + } + + private checkIndexSignatureParameter(node: IndexSignatureSyntax): boolean { + if (node.parameters.length !== 1) { + this.pushDiagnostic(node.openBracketToken, DiagnosticCode.Index_signature_must_have_exactly_one_parameter); + return true; + } + + var parameter = node.parameters[0]; + + if (parameter.dotDotDotToken) { + this.pushDiagnostic(parameter, DiagnosticCode.Index_signatures_cannot_have_rest_parameters); + return true; + } + else if (parameter.modifiers.length > 0) { + this.pushDiagnostic(parameter, DiagnosticCode.Index_signature_parameter_cannot_have_accessibility_modifiers); + return true; + } + else if (parameter.questionToken) { + this.pushDiagnostic(parameter, DiagnosticCode.Index_signature_parameter_cannot_have_a_question_mark); + return true; + } + else if (parameter.equalsValueClause) { + this.pushDiagnostic(parameter, DiagnosticCode.Index_signature_parameter_cannot_have_an_initializer); + return true; + } + else if (!parameter.typeAnnotation) { + this.pushDiagnostic(parameter, DiagnosticCode.Index_signature_parameter_must_have_a_type_annotation); + return true; + } + else if (parameter.typeAnnotation.type.kind() !== SyntaxKind.StringKeyword && + parameter.typeAnnotation.type.kind() !== SyntaxKind.NumberKeyword) { + this.pushDiagnostic(parameter, DiagnosticCode.Index_signature_parameter_type_must_be_string_or_number); + return true; + } + + return false; + } + + public visitIndexSignature(node: IndexSignatureSyntax): void { + if (this.checkIndexSignatureParameter(node)) { + return; + } + + if (!node.typeAnnotation) { + this.pushDiagnostic(node, DiagnosticCode.Index_signature_must_have_a_type_annotation); + return; + } + + super.visitIndexSignature(node); + } + + private checkClassDeclarationHeritageClauses(node: ClassDeclarationSyntax): boolean { + var seenExtendsClause = false; + var seenImplementsClause = false; + + for (var i = 0, n = node.heritageClauses.length; i < n; i++) { + Debug.assert(i <= 2); + var heritageClause = node.heritageClauses[i]; + + if (heritageClause.extendsOrImplementsKeyword.kind() === SyntaxKind.ExtendsKeyword) { + if (seenExtendsClause) { + this.pushDiagnostic(heritageClause, DiagnosticCode.extends_clause_already_seen); + return true; + } + + if (seenImplementsClause) { + this.pushDiagnostic(heritageClause, DiagnosticCode.extends_clause_must_precede_implements_clause); + return true; + } + + if (heritageClause.typeNames.length > 1) { + this.pushDiagnostic(heritageClause, DiagnosticCode.Classes_can_only_extend_a_single_class); + return true; + } + + seenExtendsClause = true; + } + else { + Debug.assert(heritageClause.extendsOrImplementsKeyword.kind() === SyntaxKind.ImplementsKeyword); + if (seenImplementsClause) { + this.pushDiagnostic(heritageClause, DiagnosticCode.implements_clause_already_seen); + return true; + } + + seenImplementsClause = true; + } + } + + return false; + } + + private checkForDisallowedDeclareModifier(modifiers: ISyntaxToken[]): boolean { + if (this.inAmbientDeclaration) { + // If we're already in an ambient declaration, then 'declare' is not allowed. + var declareToken = SyntaxUtilities.getToken(modifiers, SyntaxKind.DeclareKeyword); + + if (declareToken) { + this.pushDiagnostic(declareToken, DiagnosticCode.A_declare_modifier_cannot_be_used_in_an_already_ambient_context); + return true; + } + } + + return false; + } + + private checkForRequiredDeclareModifier(moduleElement: IModuleElementSyntax, reportToken: ISyntaxToken, modifiers: ISyntaxToken[]): boolean { + if (!this.inAmbientDeclaration && this.syntaxTree.isDeclaration()) { + // We're at the top level in a declaration file, a 'declare' modifiers is required + // on most module elements. + if (!SyntaxUtilities.containsToken(modifiers, SyntaxKind.DeclareKeyword)) { + this.pushDiagnostic(reportToken, DiagnosticCode.A_declare_modifier_is_required_for_a_top_level_declaration_in_a_d_ts_file); + return true; + } + } + } + + public visitClassDeclaration(node: ClassDeclarationSyntax): void { + if (this.checkForDisallowedDeclareModifier(node.modifiers) || + this.checkForRequiredDeclareModifier(node, node.identifier, node.modifiers) || + this.checkModuleElementModifiers(node.modifiers) || + this.checkClassDeclarationHeritageClauses(node)) { + + return; + } + + var savedInAmbientDeclaration = this.inAmbientDeclaration; + this.inAmbientDeclaration = this.inAmbientDeclaration || this.syntaxTree.isDeclaration() || SyntaxUtilities.containsToken(node.modifiers, SyntaxKind.DeclareKeyword); + super.visitClassDeclaration(node); + this.inAmbientDeclaration = savedInAmbientDeclaration; + } + + private checkInterfaceDeclarationHeritageClauses(node: InterfaceDeclarationSyntax): boolean { + var seenExtendsClause = false; + + for (var i = 0, n = node.heritageClauses.length; i < n; i++) { + Debug.assert(i <= 1); + var heritageClause = node.heritageClauses[i]; + + if (heritageClause.extendsOrImplementsKeyword.kind() === SyntaxKind.ExtendsKeyword) { + if (seenExtendsClause) { + this.pushDiagnostic(heritageClause, DiagnosticCode.extends_clause_already_seen); + return true; + } + + seenExtendsClause = true; + } + else { + Debug.assert(heritageClause.extendsOrImplementsKeyword.kind() === SyntaxKind.ImplementsKeyword); + this.pushDiagnostic(heritageClause, DiagnosticCode.Interface_declaration_cannot_have_implements_clause); + return true; + } + } + + return false; + } + + private checkInterfaceModifiers(modifiers: ISyntaxToken[]): boolean { + for (var i = 0, n = modifiers.length; i < n; i++) { + var modifier = modifiers[i]; + if (modifier.kind() === SyntaxKind.DeclareKeyword) { + this.pushDiagnostic(modifier, + DiagnosticCode.A_declare_modifier_cannot_be_used_with_an_interface_declaration); + return true; + } + } + + return false; + } + + public visitInterfaceDeclaration(node: InterfaceDeclarationSyntax): void { + if (this.checkInterfaceModifiers(node.modifiers) || + this.checkModuleElementModifiers(node.modifiers) || + this.checkInterfaceDeclarationHeritageClauses(node)) { + + return; + } + + super.visitInterfaceDeclaration(node); + } + + private checkClassElementModifiers(list: ISyntaxToken[]): boolean { + var seenAccessibilityModifier = false; + var seenStaticModifier = false; + + for (var i = 0, n = list.length; i < n; i++) { + var modifier = list[i]; + if (modifier.kind() === SyntaxKind.PublicKeyword || + modifier.kind() === SyntaxKind.PrivateKeyword) { + + if (seenAccessibilityModifier) { + this.pushDiagnostic(modifier, DiagnosticCode.Accessibility_modifier_already_seen); + return true; + } + + if (seenStaticModifier) { + var previousToken = list[i - 1]; + this.pushDiagnostic(modifier, DiagnosticCode._0_modifier_must_precede_1_modifier, [modifier.text(), previousToken.text()]); + return true; + } + + seenAccessibilityModifier = true; + } + else if (modifier.kind() === SyntaxKind.StaticKeyword) { + if (seenStaticModifier) { + this.pushDiagnostic(modifier, DiagnosticCode._0_modifier_already_seen, [modifier.text()]); + return true; + } + + seenStaticModifier = true; + } + else { + this.pushDiagnostic(modifier, DiagnosticCode._0_modifier_cannot_appear_on_a_class_element, [modifier.text()]); + return true; + } + } + + return false; + } + + public visitMemberVariableDeclaration(node: MemberVariableDeclarationSyntax): void { + if (this.checkClassElementModifiers(node.modifiers)) { + return; + } + + super.visitMemberVariableDeclaration(node); + } + + public visitMemberFunctionDeclaration(node: MemberFunctionDeclarationSyntax): void { + if (this.checkClassElementModifiers(node.modifiers)) { + return; + } + + super.visitMemberFunctionDeclaration(node); + } + + private checkGetAccessorParameter(node: GetAccessorSyntax): boolean { + if (node.callSignature.parameterList.parameters.length !== 0) { + this.pushDiagnostic(node.propertyName, DiagnosticCode.get_accessor_cannot_have_parameters); + return true; + } + + return false; + } + + public visitIndexMemberDeclaration(node: IndexMemberDeclarationSyntax): void { + if (this.checkIndexMemberModifiers(node)) { + return; + } + + super.visitIndexMemberDeclaration(node); + } + + private checkIndexMemberModifiers(node: IndexMemberDeclarationSyntax): boolean { + if (node.modifiers.length > 0) { + this.pushDiagnostic(childAt(node.modifiers, 0), DiagnosticCode.Modifiers_cannot_appear_here); + return true; + } + + return false; + } + + private checkEcmaScriptVersionIsAtLeast(parent: ISyntaxElement, reportToken: ISyntaxToken, languageVersion: ts.ScriptTarget, diagnosticKey: string): boolean { + if (this.syntaxTree.languageVersion() < languageVersion) { + this.pushDiagnostic(reportToken, diagnosticKey); + return true; + } + + return false; + } + + public visitObjectLiteralExpression(node: ObjectLiteralExpressionSyntax): void { + var savedInObjectLiteralExpression = this.inObjectLiteralExpression; + this.inObjectLiteralExpression = true; + super.visitObjectLiteralExpression(node); + this.inObjectLiteralExpression = savedInObjectLiteralExpression; + } + + public visitGetAccessor(node: GetAccessorSyntax): void { + if (this.checkForAccessorDeclarationInAmbientContext(node) || + this.checkEcmaScriptVersionIsAtLeast(node, node.propertyName, ts.ScriptTarget.ES5, DiagnosticCode.Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher) || + this.checkForDisallowedModifiers(node, node.modifiers) || + this.checkClassElementModifiers(node.modifiers) || + this.checkForDisallowedAccessorTypeParameters(node.callSignature) || + this.checkGetAccessorParameter(node)) { + return; + } + + super.visitGetAccessor(node); + } + + private checkForDisallowedSetAccessorTypeAnnotation(accessor: SetAccessorSyntax): boolean { + if (accessor.callSignature.typeAnnotation) { + this.pushDiagnostic(accessor.callSignature.typeAnnotation, DiagnosticCode.Type_annotation_cannot_appear_on_a_set_accessor); + return true; + } + + return false; + } + + private checkForDisallowedAccessorTypeParameters(callSignature: CallSignatureSyntax): boolean { + if (callSignature.typeParameterList !== null) { + this.pushDiagnostic(callSignature.typeParameterList, DiagnosticCode.Type_parameters_cannot_appear_on_an_accessor); + return true; + } + + return false; + } + + private checkForAccessorDeclarationInAmbientContext(accessor: ISyntaxNode): boolean { + if (this.inAmbientDeclaration) { + this.pushDiagnostic(accessor, DiagnosticCode.Accessors_are_not_allowed_in_ambient_contexts); + return true; + } + + return false; + } + + private checkSetAccessorParameter(node: SetAccessorSyntax): boolean { + var parameters = node.callSignature.parameterList.parameters; + if (childCount(parameters) !== 1) { + this.pushDiagnostic(node.propertyName, DiagnosticCode.set_accessor_must_have_exactly_one_parameter); + return true; + } + + var parameter = parameters[0]; + + if (parameter.questionToken) { + this.pushDiagnostic(parameter, DiagnosticCode.set_accessor_parameter_cannot_be_optional); + return true; + } + + if (parameter.equalsValueClause) { + this.pushDiagnostic(parameter, DiagnosticCode.set_accessor_parameter_cannot_have_an_initializer); + return true; + } + + if (parameter.dotDotDotToken) { + this.pushDiagnostic(parameter, DiagnosticCode.set_accessor_cannot_have_rest_parameter); + return true; + } + + return false; + } + + public visitSetAccessor(node: SetAccessorSyntax): void { + if (this.checkForAccessorDeclarationInAmbientContext(node) || + this.checkEcmaScriptVersionIsAtLeast(node, node.propertyName, ts.ScriptTarget.ES5, DiagnosticCode.Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher) || + this.checkForDisallowedModifiers(node, node.modifiers) || + this.checkClassElementModifiers(node.modifiers) || + this.checkForDisallowedAccessorTypeParameters(node.callSignature) || + this.checkForDisallowedSetAccessorTypeAnnotation(node) || + this.checkSetAccessorParameter(node)) { + return; + } + + super.visitSetAccessor(node); + } + + public visitEnumDeclaration(node: EnumDeclarationSyntax): void { + if (this.checkForDisallowedDeclareModifier(node.modifiers) || + this.checkForRequiredDeclareModifier(node, node.identifier, node.modifiers) || + this.checkModuleElementModifiers(node.modifiers), + this.checkEnumElements(node)) { + + return; + } + + var savedInAmbientDeclaration = this.inAmbientDeclaration; + this.inAmbientDeclaration = this.inAmbientDeclaration || this.syntaxTree.isDeclaration() || SyntaxUtilities.containsToken(node.modifiers, SyntaxKind.DeclareKeyword); + super.visitEnumDeclaration(node); + this.inAmbientDeclaration = savedInAmbientDeclaration; + } + + private checkEnumElements(node: EnumDeclarationSyntax): boolean { + var previousValueWasComputed = false; + for (var i = 0, n = childCount(node.enumElements); i < n; i++) { + var child = childAt(node.enumElements, i); + + if (i % 2 === 0) { + var enumElement = child; + + if (!enumElement.equalsValueClause && previousValueWasComputed) { + this.pushDiagnostic(enumElement, DiagnosticCode.Enum_member_must_have_initializer); + return true; + } + + if (enumElement.equalsValueClause) { + var value = enumElement.equalsValueClause.value; + previousValueWasComputed = !Syntax.isIntegerLiteral(value); + } + } + } + + return false; + } + + public visitEnumElement(node: EnumElementSyntax): void { + if (this.inAmbientDeclaration && node.equalsValueClause) { + var expression = node.equalsValueClause.value; + if (!Syntax.isIntegerLiteral(expression)) { + this.pushDiagnostic(node.equalsValueClause.value, DiagnosticCode.Ambient_enum_elements_can_only_have_integer_literal_initializers); + return; + } + } + + super.visitEnumElement(node); + } + + public visitInvocationExpression(node: InvocationExpressionSyntax): void { + if (node.expression.kind() === SyntaxKind.SuperKeyword && + node.argumentList.typeArgumentList !== null) { + this.pushDiagnostic(node, DiagnosticCode.super_invocation_cannot_have_type_arguments); + } + + super.visitInvocationExpression(node); + } + + private checkModuleElementModifiers(modifiers: ISyntaxToken[]): boolean { + var seenExportModifier = false; + var seenDeclareModifier = false; + + for (var i = 0, n = modifiers.length; i < n; i++) { + var modifier = modifiers[i]; + if (modifier.kind() === SyntaxKind.PublicKeyword || + modifier.kind() === SyntaxKind.PrivateKeyword || + modifier.kind() === SyntaxKind.StaticKeyword) { + this.pushDiagnostic(modifier, DiagnosticCode._0_modifier_cannot_appear_on_a_module_element, [modifier.text()]); + return true; + } + + if (modifier.kind() === SyntaxKind.DeclareKeyword) { + if (seenDeclareModifier) { + this.pushDiagnostic(modifier, DiagnosticCode.Accessibility_modifier_already_seen); + return; + } + + seenDeclareModifier = true; + } + else if (modifier.kind() === SyntaxKind.ExportKeyword) { + if (seenExportModifier) { + this.pushDiagnostic(modifier, DiagnosticCode._0_modifier_already_seen, [modifier.text()]); + return; + } + + if (seenDeclareModifier) { + this.pushDiagnostic(modifier, DiagnosticCode._0_modifier_must_precede_1_modifier, + [SyntaxFacts.getText(SyntaxKind.ExportKeyword), SyntaxFacts.getText(SyntaxKind.DeclareKeyword)]); + return; + } + + seenExportModifier = true; + } + } + + return false; + } + + private checkForDisallowedImportDeclaration(node: ModuleDeclarationSyntax): boolean { + if (!node.stringLiteral) { + for (var i = 0, n = node.moduleElements.length; i < n; i++) { + var child = node.moduleElements[i]; + if (child.kind() === SyntaxKind.ImportDeclaration) { + var importDeclaration = child; + if (importDeclaration.moduleReference.kind() === SyntaxKind.ExternalModuleReference) { + this.pushDiagnostic(importDeclaration, DiagnosticCode.Import_declarations_in_an_internal_module_cannot_reference_an_external_module); + } + } + } + } + + return false; + } + + private checkForDisallowedDeclareModifierOnImportDeclaration(modifiers: ISyntaxToken[]): boolean { + var declareToken = SyntaxUtilities.getToken(modifiers, SyntaxKind.DeclareKeyword); + + if (declareToken) { + this.pushDiagnostic(declareToken, DiagnosticCode.A_declare_modifier_cannot_be_used_with_an_import_declaration); + return true; + } + } + + public visitImportDeclaration(node: ImportDeclarationSyntax): any { + if (this.checkForDisallowedDeclareModifierOnImportDeclaration(node.modifiers) || + this.checkModuleElementModifiers(node.modifiers)) { + return; + } + + super.visitImportDeclaration(node); + } + + public visitModuleDeclaration(node: ModuleDeclarationSyntax): void { + if (this.checkForDisallowedDeclareModifier(node.modifiers) || + this.checkForRequiredDeclareModifier(node, node.stringLiteral ? node.stringLiteral : firstToken(node.name), node.modifiers) || + this.checkModuleElementModifiers(node.modifiers) || + this.checkForDisallowedImportDeclaration(node)) { + + return; + } + + if (node.stringLiteral) { + if (!this.inAmbientDeclaration && !SyntaxUtilities.containsToken(node.modifiers, SyntaxKind.DeclareKeyword)) { + this.pushDiagnostic(node.stringLiteral, DiagnosticCode.Only_ambient_modules_can_use_quoted_names); + return; + } + } + + if (!node.stringLiteral && this.checkForDisallowedExportAssignment(node)) { + return; + } + + var savedInAmbientDeclaration = this.inAmbientDeclaration; + this.inAmbientDeclaration = this.inAmbientDeclaration || this.syntaxTree.isDeclaration() || SyntaxUtilities.containsToken(node.modifiers, SyntaxKind.DeclareKeyword); + super.visitModuleDeclaration(node); + this.inAmbientDeclaration = savedInAmbientDeclaration; + } + + private checkForDisallowedExportAssignment(node: ModuleDeclarationSyntax): boolean { + for (var i = 0, n = node.moduleElements.length; i < n; i++) { + var child = node.moduleElements[i]; + + if (child.kind() === SyntaxKind.ExportAssignment) { + this.pushDiagnostic(child, DiagnosticCode.Export_assignment_cannot_be_used_in_internal_modules); + return true; + } + } + + return false; + } + + public visitBlock(node: BlockSyntax): void { + if (this.checkForBlockInAmbientContext(node)) { + return; + } + + var savedInBlock = this.inBlock; + this.inBlock = true; + super.visitBlock(node); + this.inBlock = savedInBlock; + } + + private checkForBlockInAmbientContext(node: BlockSyntax): boolean { + if (this.inAmbientDeclaration || this.syntaxTree.isDeclaration()) { + // Provide a specialized message for a block as a statement versus the block as a + // function body. + if (node.parent.kind() === SyntaxKind.List) { + this.pushDiagnostic(firstToken(node), DiagnosticCode.Statements_are_not_allowed_in_ambient_contexts); + } + else { + this.pushDiagnostic(firstToken(node), DiagnosticCode.A_function_implementation_cannot_be_declared_in_an_ambient_context); + } + + return true; + } + + return false; + } + + private checkForStatementInAmbientContxt(node: IStatementSyntax): boolean { + if (this.inAmbientDeclaration || this.syntaxTree.isDeclaration()) { + this.pushDiagnostic(firstToken(node), DiagnosticCode.Statements_are_not_allowed_in_ambient_contexts); + return true; + } + + return false; + } + + public visitBreakStatement(node: BreakStatementSyntax): void { + if (this.checkForStatementInAmbientContxt(node) || + this.checkBreakStatementTarget(node)) { + return; + } + + super.visitBreakStatement(node); + } + + public visitContinueStatement(node: ContinueStatementSyntax): void { + if (this.checkForStatementInAmbientContxt(node) || + this.checkContinueStatementTarget(node)) { + return; + } + + super.visitContinueStatement(node); + } + + private checkBreakStatementTarget(node: BreakStatementSyntax): boolean { + // Invalid break statements are considered syntax errors in ES5. + + // Note: the order here is important. If the 'break' has a target, then it can jump to + // any enclosing laballed statment. If it has no target, it must be in an iteration or + // swtich statement. + if (node.identifier) { + var breakableLabels = this.getEnclosingLabels(node, /*breakable:*/ true, /*crossFunctions:*/ false); + + if (!ArrayUtilities.any(breakableLabels, s => tokenValueText(s.identifier) === tokenValueText(node.identifier))) { + // The target of the continue statement wasn't to a reachable label. + // + // Let hte user know, with a specialized message if the target was to an + // unreachable label (as opposed to a non-existed label) + var breakableLabels = this.getEnclosingLabels(node, /*breakable:*/ true, /*crossFunctions:*/ true); + if (ArrayUtilities.any(breakableLabels, s => tokenValueText(s.identifier) === tokenValueText(node.identifier))) { + this.pushDiagnostic(node, DiagnosticCode.Jump_target_cannot_cross_function_boundary); + } + else { + this.pushDiagnostic(node, DiagnosticCode.Jump_target_not_found); + } + + return true; + } + } + else if (!this.inIterationStatement(node, /*crossFunctions:*/ false) && !this.inSwitchStatement(node)) { + if (this.inIterationStatement(node, /*crossFunctions:*/ true)) { + this.pushDiagnostic(node, DiagnosticCode.Jump_target_cannot_cross_function_boundary); + } + else { + this.pushDiagnostic(node, DiagnosticCode.break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement); + } + + return true; + } + + return false; + } + + private inSwitchStatement(ast: ISyntaxElement): boolean { + while (ast) { + if (ast.kind() === SyntaxKind.SwitchStatement) { + return true; + } + + if (SyntaxUtilities.isAnyFunctionExpressionOrDeclaration(ast)) { + return false; + } + + ast = ast.parent; + } + + return false; + } + + private isIterationStatement(ast: ISyntaxElement): boolean { + switch (ast.kind()) { + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.DoStatement: + return true; + } + + return false; + } + + private inIterationStatement(element: ISyntaxElement, crossFunctions: boolean): boolean { + while (element) { + if (this.isIterationStatement(element)) { + return true; + } + + if (!crossFunctions && SyntaxUtilities.isAnyFunctionExpressionOrDeclaration(element)) { + return false; + } + + element = element.parent; + } + + return false; + } + + private getEnclosingLabels(element: ISyntaxElement, breakable: boolean, crossFunctions: boolean): LabeledStatementSyntax[] { + var result: LabeledStatementSyntax[] = []; + + element = element.parent; + while (element) { + if (element.kind() === SyntaxKind.LabeledStatement) { + var labeledStatement = element; + if (breakable) { + // Breakable labels can be placed on any construct + result.push(labeledStatement); + } + else { + // They're asking for continuable labels. Continuable labels must be on + // a loop construct. + if (this.labelIsOnContinuableConstruct(labeledStatement.statement)) { + result.push(labeledStatement); + } + } + } + + if (!crossFunctions && SyntaxUtilities.isAnyFunctionExpressionOrDeclaration(element)) { + break; + } + + element = element.parent; + } + + return result; + } + + private labelIsOnContinuableConstruct(statement: ISyntaxElement): boolean { + switch (statement.kind()) { + case SyntaxKind.LabeledStatement: + // Labels work transitively. i.e. if you have: + // foo: + // bar: + // while(...) + // + // Then both 'foo' and 'bar' are in the label set for 'while' and are thus + // continuable. + return this.labelIsOnContinuableConstruct((statement).statement); + + case SyntaxKind.WhileStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.DoStatement: + return true; + + default: + return false; + } + } + + private checkContinueStatementTarget(node: ContinueStatementSyntax): boolean { + // Invalid continue statements are considered syntax errors in ES5. + + if (!this.inIterationStatement(node, /*crossFunctions:*/ false)) { + if (this.inIterationStatement(node, /*crossFunctions:*/ true)) { + this.pushDiagnostic(node, DiagnosticCode.Jump_target_cannot_cross_function_boundary); + } + else { + this.pushDiagnostic(node, DiagnosticCode.continue_statement_can_only_be_used_within_an_enclosing_iteration_statement); + } + + return true; + } + else if (node.identifier) { + var continuableLabels = this.getEnclosingLabels(node, /*breakable:*/ false, /*crossFunctions:*/ false); + + if (!ArrayUtilities.any(continuableLabels, s => tokenValueText(s.identifier) === tokenValueText(node.identifier))) { + // The target of the continue statement wasn't to a reachable label. + // + // Let hte user know, with a specialized message if the target was to an + // unreachable label (as opposed to a non-existed label) + var continuableLabels = this.getEnclosingLabels(node, /*breakable:*/ false, /*crossFunctions:*/ true); + + if (ArrayUtilities.any(continuableLabels, s => tokenValueText(s.identifier) === tokenValueText(node.identifier))) { + this.pushDiagnostic(node, DiagnosticCode.Jump_target_cannot_cross_function_boundary); + } + else { + this.pushDiagnostic(node, DiagnosticCode.Jump_target_not_found); + } + + return true; + } + } + + return false; + } + + public visitDebuggerStatement(node: DebuggerStatementSyntax): void { + if (this.checkForStatementInAmbientContxt(node)) { + return; + } + + super.visitDebuggerStatement(node); + } + + public visitDoStatement(node: DoStatementSyntax): void { + if (this.checkForStatementInAmbientContxt(node)) { + return; + } + + super.visitDoStatement(node); + } + + public visitEmptyStatement(node: EmptyStatementSyntax): void { + if (this.checkForStatementInAmbientContxt(node)) { + return; + } + + super.visitEmptyStatement(node); + } + + public visitExpressionStatement(node: ExpressionStatementSyntax): void { + if (this.checkForStatementInAmbientContxt(node)) { + return; + } + + super.visitExpressionStatement(node); + } + + public visitForInStatement(node: ForInStatementSyntax): void { + if (this.checkForStatementInAmbientContxt(node) || + this.checkForInStatementVariableDeclaration(node) || + this.checkForInLeftHandSideExpression(node)) { + + return; + } + + super.visitForInStatement(node); + } + + private checkForInLeftHandSideExpression(node: ForInStatementSyntax): boolean { + if (node.left && !SyntaxUtilities.isLeftHandSizeExpression(node.left)) { + this.pushDiagnostic(node.left, DiagnosticCode.Invalid_left_hand_side_in_for_in_statement); + return true; + } + + return false; + } + + private checkForInStatementVariableDeclaration(node: ForInStatementSyntax): boolean { + // The parser accepts a Variable Declaration in a ForInStatement, but the grammar only + // allows a very restricted form. Specifically, there must be only a single Variable + // Declarator in the Declaration. + if (node.variableDeclaration && node.variableDeclaration.variableDeclarators.length > 1) { + this.pushDiagnostic(node.variableDeclaration, DiagnosticCode.Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement); + return true; + } + + return false; + } + + public visitForStatement(node: ForStatementSyntax): void { + if (this.checkForStatementInAmbientContxt(node)) { + return; + } + + super.visitForStatement(node); + } + + public visitIfStatement(node: IfStatementSyntax): void { + if (this.checkForStatementInAmbientContxt(node)) { + return; + } + + super.visitIfStatement(node); + } + + public visitLabeledStatement(node: LabeledStatementSyntax): void { + if (this.checkForStatementInAmbientContxt(node) || + this.checkForInvalidLabelIdentifier(node)) { + return; + } + + super.visitLabeledStatement(node); + } + + private checkForInvalidLabelIdentifier(node: LabeledStatementSyntax): boolean { + // Invalid break statements are considered syntax errors in ES5. + + // Note that break/continue are treated differently. ES5 says this about a break statement: + // A program is considered syntactically incorrect if ...: + // + // The program contains a break statement with the optional Identifier, where Identifier + // does not appear in the label set of an enclosing (but not crossing function boundaries) + // **Statement.** + // + // However, it says this about continue statements: + // + // The program contains a continue statement with the optional Identifier, where Identifier + // does not appear in the label set of an enclosing (but not crossing function boundaries) + // **IterationStatement.** + + // In other words, you can 'break' to any enclosing statement. But you can only 'continue' + // to an enclosing *iteration* statement. + var labelIdentifier = tokenValueText(node.identifier); + + var breakableLabels = this.getEnclosingLabels(node, /*breakable:*/ true, /*crossFunctions:*/ false); + + // It is invalid to have a label enclosed in a label of the same name. + var matchingLabel = ArrayUtilities.firstOrDefault(breakableLabels, s => tokenValueText(s.identifier) === labelIdentifier); + if (matchingLabel) { + this.pushDiagnostic(node.identifier, DiagnosticCode.Duplicate_identifier_0, [labelIdentifier]); + return true; + } + + return false; + } + + public visitReturnStatement(node: ReturnStatementSyntax): void { + if (this.checkForStatementInAmbientContxt(node) || + this.checkForReturnStatementNotInFunctionBody(node)) { + return; + } + + super.visitReturnStatement(node); + } + + public checkForReturnStatementNotInFunctionBody(node: ReturnStatementSyntax): boolean { + for (var element: ISyntaxElement = node; element; element = element.parent) { + if (SyntaxUtilities.isAnyFunctionExpressionOrDeclaration(element)) { + return false; + } + } + + this.pushDiagnostic(firstToken(node), DiagnosticCode.return_statement_must_be_contained_within_a_function_body); + return true; + } + + public visitSwitchStatement(node: SwitchStatementSyntax): void { + if (this.checkForStatementInAmbientContxt(node)) { + return; + } + + super.visitSwitchStatement(node); + } + + public visitThrowStatement(node: ThrowStatementSyntax): void { + if (this.checkForStatementInAmbientContxt(node)) { + return; + } + + super.visitThrowStatement(node); + } + + public visitTryStatement(node: TryStatementSyntax): void { + if (this.checkForStatementInAmbientContxt(node)) { + return; + } + + super.visitTryStatement(node); + } + + public visitWhileStatement(node: WhileStatementSyntax): void { + if (this.checkForStatementInAmbientContxt(node)) { + return; + } + + super.visitWhileStatement(node); + } + + public visitWithStatement(node: WithStatementSyntax): void { + if (this.checkForStatementInAmbientContxt(node) || + this.checkForWithInStrictMode(node)) { + return; + } + + super.visitWithStatement(node); + } + + private checkForWithInStrictMode(node: WithStatementSyntax): boolean { + if (parsedInStrictMode(node)) { + this.pushDiagnostic(firstToken(node), DiagnosticCode.with_statements_are_not_allowed_in_strict_mode); + return true; + } + + return false; + } + + private checkForDisallowedModifiers(parent: ISyntaxElement, modifiers: ISyntaxToken[]): boolean { + if (this.inBlock || this.inObjectLiteralExpression) { + if (modifiers.length > 0) { + this.pushDiagnostic(childAt(modifiers, 0), DiagnosticCode.Modifiers_cannot_appear_here); + return true; + } + } + + return false; + } + + public visitFunctionDeclaration(node: FunctionDeclarationSyntax): void { + if (this.checkForDisallowedDeclareModifier(node.modifiers) || + this.checkForDisallowedModifiers(node, node.modifiers) || + this.checkForRequiredDeclareModifier(node, node.identifier, node.modifiers) || + this.checkModuleElementModifiers(node.modifiers) || + this.checkForDisallowedEvalOrArguments(node, node.identifier)) { + + return; + } + + var savedInAmbientDeclaration = this.inAmbientDeclaration; + this.inAmbientDeclaration = this.inAmbientDeclaration || this.syntaxTree.isDeclaration() || SyntaxUtilities.containsToken(node.modifiers, SyntaxKind.DeclareKeyword); + super.visitFunctionDeclaration(node); + this.inAmbientDeclaration = savedInAmbientDeclaration; + } + + public visitFunctionExpression(node: FunctionExpressionSyntax): void { + if (this.checkForDisallowedEvalOrArguments(node, node.identifier)) { + return; + } + + super.visitFunctionExpression(node); + } + + public visitVariableStatement(node: VariableStatementSyntax): void { + if (this.checkForDisallowedDeclareModifier(node.modifiers) || + this.checkForDisallowedModifiers(node, node.modifiers) || + this.checkForRequiredDeclareModifier(node, node.variableDeclaration.varKeyword, node.modifiers) || + this.checkModuleElementModifiers(node.modifiers)) { + + return; + } + + var savedInAmbientDeclaration = this.inAmbientDeclaration; + this.inAmbientDeclaration = this.inAmbientDeclaration || this.syntaxTree.isDeclaration() || SyntaxUtilities.containsToken(node.modifiers, SyntaxKind.DeclareKeyword); + super.visitVariableStatement(node); + this.inAmbientDeclaration = savedInAmbientDeclaration; + } + + private checkListSeparators(parent: ISyntaxElement, list: T[], kind: SyntaxKind): boolean { + for (var i = 0, n = childCount(list); i < n; i++) { + var child = childAt(list, i); + if (i % 2 === 1 && child.kind() !== kind) { + this.pushDiagnostic(child, DiagnosticCode._0_expected, [SyntaxFacts.getText(kind)]); + } + } + + return false; + } + + public visitObjectType(node: ObjectTypeSyntax): void { + if (this.checkListSeparators(node, node.typeMembers, SyntaxKind.SemicolonToken)) { + return; + } + + // All code in an object type is implicitly ambient. (i.e. parameters can't have initializer, etc.) + var savedInAmbientDeclaration = this.inAmbientDeclaration; + this.inAmbientDeclaration = true; + super.visitObjectType(node); + this.inAmbientDeclaration = savedInAmbientDeclaration; + } + + public visitArrayType(node: ArrayTypeSyntax): void { + // All code in an object type is implicitly ambient. (i.e. parameters can't have initializer, etc.) + var savedInAmbientDeclaration = this.inAmbientDeclaration; + this.inAmbientDeclaration = true; + super.visitArrayType(node); + this.inAmbientDeclaration = savedInAmbientDeclaration; + } + + public visitFunctionType(node: FunctionTypeSyntax): void { + // All code in an object type is implicitly ambient. (i.e. parameters can't have initializer, etc.) + var savedInAmbientDeclaration = this.inAmbientDeclaration; + this.inAmbientDeclaration = true; + super.visitFunctionType(node); + this.inAmbientDeclaration = savedInAmbientDeclaration; + } + + public visitConstructorType(node: ConstructorTypeSyntax): void { + // All code in an object type is implicitly ambient. (i.e. parameters can't have initializer, etc.) + var savedInAmbientDeclaration = this.inAmbientDeclaration; + this.inAmbientDeclaration = true; + super.visitConstructorType(node); + this.inAmbientDeclaration = savedInAmbientDeclaration; + } + + public visitVariableDeclarator(node: VariableDeclaratorSyntax): void { + if (this.checkVariableDeclaratorInitializer(node) || + this.checkVariableDeclaratorIdentifier(node)) { + return; + } + + super.visitVariableDeclarator(node); + } + + private checkVariableDeclaratorIdentifier(node: VariableDeclaratorSyntax): boolean { + if (node.parent.kind() !== SyntaxKind.MemberVariableDeclaration) { + if (this.checkForDisallowedEvalOrArguments(node, node.propertyName)) { + return true; + } + } + + return false; + } + + private checkVariableDeclaratorInitializer(node: VariableDeclaratorSyntax): boolean { + if (this.inAmbientDeclaration && node.equalsValueClause) { + this.pushDiagnostic(firstToken(node.equalsValueClause.value), DiagnosticCode.Initializers_are_not_allowed_in_ambient_contexts); + return true; + } + + return false; + } + + public visitConstructorDeclaration(node: ConstructorDeclarationSyntax): void { + if (this.checkClassElementModifiers(node.modifiers) || + this.checkConstructorModifiers(node.modifiers) || + this.checkConstructorTypeParameterList(node) || + this.checkConstructorTypeAnnotation(node)) { + + return; + } + + super.visitConstructorDeclaration(node); + } + + private checkConstructorModifiers(modifiers: ISyntaxToken[]): boolean { + for (var i = 0, n = modifiers.length; i < n; i++) { + var child = modifiers[i]; + if (child.kind() !== SyntaxKind.PublicKeyword) { + this.pushDiagnostic(child, DiagnosticCode._0_modifier_cannot_appear_on_a_constructor_declaration, [SyntaxFacts.getText(child.kind())]); + return true; + } + } + + return false; + } + + private checkConstructorTypeParameterList(node: ConstructorDeclarationSyntax): boolean { + if (node.callSignature.typeParameterList) { + this.pushDiagnostic(node.callSignature.typeParameterList, DiagnosticCode.Type_parameters_cannot_appear_on_a_constructor_declaration); + return true; + } + + return false; + } + + private checkConstructorTypeAnnotation(node: ConstructorDeclarationSyntax): boolean { + if (node.callSignature.typeAnnotation) { + this.pushDiagnostic(node.callSignature.typeAnnotation, DiagnosticCode.Type_annotation_cannot_appear_on_a_constructor_declaration); + return true; + } + + return false; + } + + public visitBinaryExpression(node: BinaryExpressionSyntax): void { + if (this.checkIllegalAssignment(node)) { + return; + } + + super.visitBinaryExpression(node); + } + + public visitPrefixUnaryExpression(node: PrefixUnaryExpressionSyntax): void { + if (parsedInStrictMode(node) && this.isPreIncrementOrDecrementExpression(node) && this.isEvalOrArguments(node.operand)) { + this.pushDiagnostic(node.operatorToken, DiagnosticCode.Invalid_use_of_0_in_strict_mode, [this.getEvalOrArguments(node.operand)]); + } + + super.visitPrefixUnaryExpression(node); + } + + public visitPostfixUnaryExpression(node: PostfixUnaryExpressionSyntax): void { + if (parsedInStrictMode(node) && this.isEvalOrArguments(node.operand)) { + this.pushDiagnostic(node.operatorToken, DiagnosticCode.Invalid_use_of_0_in_strict_mode, [this.getEvalOrArguments(node.operand)]); + } + + super.visitPostfixUnaryExpression(node); + } + + public visitParameter(node: ParameterSyntax): void { + if (this.checkForDisallowedEvalOrArguments(node, node.identifier)) { + return; + } + + super.visitParameter(node); + } + + private checkForDisallowedEvalOrArguments(node: ISyntaxNode, token: ISyntaxToken): boolean { + if (token) { + if (parsedInStrictMode(node) && this.isEvalOrArguments(token)) { + this.pushDiagnostic(token, DiagnosticCode.Invalid_use_of_0_in_strict_mode, [this.getEvalOrArguments(token)]); + return true; + } + } + + return false; + } + + private isPreIncrementOrDecrementExpression(node: PrefixUnaryExpressionSyntax) { + switch (node.kind()) { + case SyntaxKind.PreDecrementExpression: + case SyntaxKind.PreIncrementExpression: + return true; + } + + return false; + } + + public visitDeleteExpression(node: DeleteExpressionSyntax): void { + if (parsedInStrictMode(node) && node.expression.kind() === SyntaxKind.IdentifierName) { + this.pushDiagnostic(firstToken(node), DiagnosticCode.delete_cannot_be_called_on_an_identifier_in_strict_mode); + return; + } + + super.visitDeleteExpression(node); + } + + private checkIllegalAssignment(node: BinaryExpressionSyntax): boolean { + if (parsedInStrictMode(node) && SyntaxFacts.isAssignmentOperatorToken(node.operatorToken.kind()) && this.isEvalOrArguments(node.left)) { + this.pushDiagnostic(node.operatorToken, DiagnosticCode.Invalid_use_of_0_in_strict_mode, [this.getEvalOrArguments(node.left)]); + return true; + } + + return false; + } + + private getEvalOrArguments(expr: IExpressionSyntax): string { + if (expr.kind() === SyntaxKind.IdentifierName) { + var text = tokenValueText(expr); + if (text === "eval" || text === "arguments") { + return text; + } + } + + return null; + } + + private isEvalOrArguments(expr: IExpressionSyntax): boolean { + return this.getEvalOrArguments(expr) !== null; + } + + public visitConstraint(node: ConstraintSyntax): void { + if (this.checkConstraintType(node)) { + return; + } + + super.visitConstraint(node); + } + + private checkConstraintType(node: ConstraintSyntax): boolean { + if (!SyntaxFacts.isType(node.typeOrExpression.kind())) { + this.pushDiagnostic(node.typeOrExpression, DiagnosticCode.Type_expected); + return true; + } + + return false; + } + } + + function firstSyntaxTreeToken(syntaxTree: SyntaxTree) { + // We don't just access the firstToken of the tree here as the tree may be abstract and may + // not have a firstToken in it. + var scanner = Scanner.createScanner(syntaxTree.languageVersion(), syntaxTree.text, () => { }); + return scanner.scan(/*allowContextualToken:*/ false); + } + + export function externalModuleIndicatorSpan(syntaxTree: SyntaxTree): TextSpan { + var firstToken = firstSyntaxTreeToken(syntaxTree); + return externalModuleIndicatorSpanWorker(syntaxTree, firstToken); + } + + export function externalModuleIndicatorSpanWorker(syntaxTree: SyntaxTree, firstToken: ISyntaxToken) { + var leadingTrivia = firstToken.leadingTrivia(syntaxTree.text); + return implicitImportSpan(leadingTrivia) || topLevelImportOrExportSpan(syntaxTree.sourceUnit()); + } + + function implicitImportSpan(sourceUnitLeadingTrivia: ISyntaxTriviaList): TextSpan { + for (var i = 0, n = sourceUnitLeadingTrivia.count(); i < n; i++) { + var trivia = sourceUnitLeadingTrivia.syntaxTriviaAt(i); + + if (trivia.isComment()) { + var span = implicitImportSpanWorker(trivia); + if (span) { + return span; + } + } + } + + return null; + } + + function implicitImportSpanWorker(trivia: ISyntaxTrivia): TextSpan { + var implicitImportRegEx = /^(\/\/\/\s*/gim; + var match = implicitImportRegEx.exec(trivia.fullText()); + + if (match) { + return new TextSpan(trivia.fullStart(), trivia.fullWidth()); + } + + return null; + } + + function topLevelImportOrExportSpan(node: SourceUnitSyntax): TextSpan { + for (var i = 0, n = node.moduleElements.length; i < n; i++) { + var moduleElement = node.moduleElements[i]; + + var _firstToken = firstToken(moduleElement); + if (_firstToken !== null && _firstToken.kind() === SyntaxKind.ExportKeyword) { + return new TextSpan(start(_firstToken), width(_firstToken)); + } + + if (moduleElement.kind() === SyntaxKind.ImportDeclaration) { + var importDecl = moduleElement; + if (importDecl.moduleReference.kind() === SyntaxKind.ExternalModuleReference) { + var literal = (importDecl.moduleReference).stringLiteral; + return new TextSpan(start(literal), width(literal)); + } + } + } + + return null; + } +} \ No newline at end of file diff --git a/src/services/syntax/syntaxTrivia.ts b/src/services/syntax/syntaxTrivia.ts new file mode 100644 index 00000000000..1c8d79cf6bf --- /dev/null +++ b/src/services/syntax/syntaxTrivia.ts @@ -0,0 +1,178 @@ +/// + +module TypeScript { + export interface ISyntaxTrivia { + parent?: ISyntaxTriviaList; + kind(): SyntaxKind; + + isWhitespace(): boolean; + isComment(): boolean; + isNewLine(): boolean; + isSkippedToken(): boolean; + + fullStart(): number; + fullWidth(): number; + + // Text for this trivia. + fullText(): string; + + // If this is a skipped token trivia, then this was the token that was skipped. + skippedToken(): ISyntaxToken; + + clone(): ISyntaxTrivia; + } +} + +module TypeScript.Syntax { + class AbstractTrivia implements ISyntaxTrivia { + constructor(private _kind: SyntaxKind) { + } + + public kind(): SyntaxKind { + return this._kind; + } + + public clone(): ISyntaxTrivia { + throw Errors.abstract(); + } + + public fullStart(): number { + throw Errors.abstract(); + } + + public fullWidth(): number { + throw Errors.abstract(); + } + + public fullText(): string { + throw Errors.abstract(); + } + + public skippedToken(): ISyntaxToken { + throw Errors.abstract(); + } + + public isWhitespace(): boolean { + return this.kind() === SyntaxKind.WhitespaceTrivia; + } + + public isComment(): boolean { + return this.kind() === SyntaxKind.SingleLineCommentTrivia || this.kind() === SyntaxKind.MultiLineCommentTrivia; + } + + public isNewLine(): boolean { + return this.kind() === SyntaxKind.NewLineTrivia; + } + + public isSkippedToken(): boolean { + return this.kind() === SyntaxKind.SkippedTokenTrivia; + } + } + + class SkippedTokenTrivia extends AbstractTrivia { + constructor(private _skippedToken: ISyntaxToken, private _fullText: string) { + super(SyntaxKind.SkippedTokenTrivia); + + _skippedToken.parent = this; + } + + public clone(): ISyntaxTrivia { + return new SkippedTokenTrivia(this._skippedToken.clone(), this._fullText); + } + + public fullStart(): number { + return this._skippedToken.fullStart(); + } + + public fullWidth(): number { + return this.fullText().length; + } + + public fullText(): string { + return this._fullText; + } + + public skippedToken(): ISyntaxToken { + return this._skippedToken; + } + } + + class DeferredTrivia extends AbstractTrivia { + constructor(kind: SyntaxKind, private _text: ISimpleText, private _fullStart: number, private _fullWidth: number) { + super(kind); + } + + public clone(): ISyntaxTrivia { + return new DeferredTrivia(this.kind(), this._text, this._fullStart, this._fullWidth); + } + + public fullStart(): number { + return this._fullStart; + } + + public fullWidth(): number { + return this._fullWidth; + } + + public fullText(): string { + return this._text.substr(this._fullStart, this._fullWidth); + } + + public skippedToken(): ISyntaxToken { + throw Errors.invalidOperation(); + } + } + + export function deferredTrivia(kind: SyntaxKind, text: ISimpleText, fullStart: number, fullWidth: number): ISyntaxTrivia { + return new DeferredTrivia(kind, text, fullStart, fullWidth); + } + + export function skippedTokenTrivia(token: ISyntaxToken, text: ISimpleText): ISyntaxTrivia { + Debug.assert(!token.hasLeadingTrivia()); + Debug.assert(!token.hasTrailingTrivia()); + Debug.assert(token.fullWidth() > 0); + return new SkippedTokenTrivia(token, token.fullText(text)); + } + + // Breaks a multiline trivia up into individual line components. If the trivia doesn't span + // any lines, then the result will be a single string with the entire text of the trivia. + // Otherwise, there will be one entry in the array for each line spanned by the trivia. Each + // entry will contain the line separator at the end of the string. + export function splitMultiLineCommentTriviaIntoMultipleLines(trivia: ISyntaxTrivia): string[] { + // Debug.assert(trivia.kind === SyntaxKind.MultiLineCommentTrivia); + var result: string[] = []; + + var triviaText = trivia.fullText(); + var currentIndex = 0; + + for (var i = 0; i < triviaText.length; i++) { + var ch = triviaText.charCodeAt(i); + + // When we run into a newline for the first time, create the string builder and copy + // all the values up to this newline into it. + var isCarriageReturnLineFeed = false; + switch (ch) { + case CharacterCodes.carriageReturn: + if (i < triviaText.length - 1 && triviaText.charCodeAt(i + 1) === CharacterCodes.lineFeed) { + // Consume the \r + i++; + } + + // Fall through. + + case CharacterCodes.lineFeed: + case CharacterCodes.paragraphSeparator: + case CharacterCodes.lineSeparator: + // Eat from the last starting position through to the end of the newline. + result.push(triviaText.substring(currentIndex, i + 1)); + + // Set the current index to *after* the newline. + currentIndex = i + 1; + continue; + } + } + + result.push(triviaText.substring(currentIndex)); + return result; + } +} \ No newline at end of file diff --git a/src/services/syntax/syntaxTriviaList.ts b/src/services/syntax/syntaxTriviaList.ts new file mode 100644 index 00000000000..937b66b129f --- /dev/null +++ b/src/services/syntax/syntaxTriviaList.ts @@ -0,0 +1,246 @@ +/// + +module TypeScript { + export interface ISyntaxTriviaList { + parent?: ISyntaxToken; + + isShared(): boolean; + + count(): number; + syntaxTriviaAt(index: number): ISyntaxTrivia; + + // With of this trivia list. + fullWidth(): number; + + // Text for this trivia list. + fullText(): string; + + hasComment(): boolean; + hasNewLine(): boolean; + hasSkippedToken(): boolean; + + last(): ISyntaxTrivia; + toArray(): ISyntaxTrivia[]; + + clone(): ISyntaxTriviaList; + } +} + +module TypeScript.Syntax { + class EmptyTriviaList implements ISyntaxTriviaList { + public kind() { + return SyntaxKind.TriviaList; + } + + public isShared(): boolean { + return true; + } + + public count(): number { + return 0; + } + + public syntaxTriviaAt(index: number): ISyntaxTrivia { + throw Errors.argumentOutOfRange("index"); + } + + public last(): ISyntaxTrivia { + throw Errors.argumentOutOfRange("index"); + } + + public fullWidth(): number { + return 0; + } + + public fullText(): string { + return ""; + } + + public hasComment(): boolean { + return false; + } + + public hasNewLine(): boolean { + return false; + } + + public hasSkippedToken(): boolean { + return false; + } + + public toArray(): ISyntaxTrivia[] { + return []; + } + + public clone() { + return this; + } + }; + + export var emptyTriviaList: ISyntaxTriviaList = new EmptyTriviaList(); + + function isComment(trivia: ISyntaxTrivia): boolean { + return trivia.kind() === SyntaxKind.MultiLineCommentTrivia || trivia.kind() === SyntaxKind.SingleLineCommentTrivia; + } + + class SingletonSyntaxTriviaList implements ISyntaxTriviaList { + private item: ISyntaxTrivia; + + constructor(item: ISyntaxTrivia) { + this.item = item.clone(); + this.item.parent = this; + } + + public kind() { + return SyntaxKind.TriviaList; + } + + public isShared(): boolean { + return false; + } + + public count(): number { + return 1; + } + + public syntaxTriviaAt(index: number): ISyntaxTrivia { + if (index !== 0) { + throw Errors.argumentOutOfRange("index"); + } + + return this.item; + } + + public last(): ISyntaxTrivia { + return this.item; + } + + public fullWidth(): number { + return this.item.fullWidth(); + } + + public fullText(): string { + return this.item.fullText(); + } + + public hasComment(): boolean { + return isComment(this.item); + } + + public hasNewLine(): boolean { + return this.item.kind() === SyntaxKind.NewLineTrivia; + } + + public hasSkippedToken(): boolean { + return this.item.kind() === SyntaxKind.SkippedTokenTrivia; + } + + public toArray(): ISyntaxTrivia[] { + return [this.item]; + } + + public clone(): ISyntaxTriviaList { + return new SingletonSyntaxTriviaList(this.item.clone()); + } + } + + class NormalSyntaxTriviaList implements ISyntaxTriviaList { + private trivia: ISyntaxTrivia[]; + + constructor(trivia: ISyntaxTrivia[]) { + this.trivia = trivia.map(t => { + var cloned = t.clone(); + cloned.parent = this; + return cloned; + }); + } + + public kind() { + return SyntaxKind.TriviaList; + } + + public isShared(): boolean { + return false; + } + + public count() { + return this.trivia.length; + } + + public syntaxTriviaAt(index: number): ISyntaxTrivia { + if (index < 0 || index >= this.trivia.length) { + throw Errors.argumentOutOfRange("index"); + } + + return this.trivia[index]; + } + + public last(): ISyntaxTrivia { + return this.trivia[this.trivia.length - 1]; + } + + public fullWidth(): number { + return ArrayUtilities.sum(this.trivia, t => t.fullWidth()); + } + + public fullText(): string { + var result: string[] = []; + + for (var i = 0, n = this.trivia.length; i < n; i++) { + result.push(this.trivia[i].fullText()); + } + + return result.join(""); + } + + public hasComment(): boolean { + for (var i = 0; i < this.trivia.length; i++) { + if (isComment(this.trivia[i])) { + return true; + } + } + + return false; + } + + public hasNewLine(): boolean { + for (var i = 0; i < this.trivia.length; i++) { + if (this.trivia[i].kind() === SyntaxKind.NewLineTrivia) { + return true; + } + } + + return false; + } + + public hasSkippedToken(): boolean { + for (var i = 0; i < this.trivia.length; i++) { + if (this.trivia[i].kind() === SyntaxKind.SkippedTokenTrivia) { + return true; + } + } + + return false; + } + + public toArray(): ISyntaxTrivia[] { + return this.trivia.slice(0); + } + + public clone(): ISyntaxTriviaList { + return new NormalSyntaxTriviaList(this.trivia.map(t => t.clone())); + } + } + + export function triviaList(trivia: ISyntaxTrivia[]): ISyntaxTriviaList { + if (trivia === undefined || trivia === null || trivia.length === 0) { + return Syntax.emptyTriviaList; + } + + if (trivia.length === 1) { + return new SingletonSyntaxTriviaList(trivia[0]); + } + + return new NormalSyntaxTriviaList(trivia); + } +} \ No newline at end of file diff --git a/src/services/syntax/syntaxUtilities.ts b/src/services/syntax/syntaxUtilities.ts new file mode 100644 index 00000000000..c5e122e927b --- /dev/null +++ b/src/services/syntax/syntaxUtilities.ts @@ -0,0 +1,336 @@ +/// + +module TypeScript { + export class SyntaxUtilities { + public static isAnyFunctionExpressionOrDeclaration(ast: ISyntaxElement): boolean { + switch (ast.kind()) { + case SyntaxKind.SimpleArrowFunctionExpression: + case SyntaxKind.ParenthesizedArrowFunctionExpression: + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.MemberFunctionDeclaration: + case SyntaxKind.FunctionPropertyAssignment: + case SyntaxKind.ConstructorDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return true; + } + + return false; + } + + public static isLastTokenOnLine(token: ISyntaxToken, text: ISimpleText): boolean { + var _nextToken = nextToken(token, text); + if (_nextToken === null) { + return true; + } + + var lineMap = text.lineMap(); + var tokenLine = lineMap.getLineNumberFromPosition(end(token, text)); + var nextTokenLine = lineMap.getLineNumberFromPosition(start(_nextToken, text)); + + return tokenLine !== nextTokenLine; + } + + public static isLeftHandSizeExpression(element: ISyntaxElement) { + if (element) { + switch (element.kind()) { + case SyntaxKind.MemberAccessExpression: + case SyntaxKind.ElementAccessExpression: + case SyntaxKind.ObjectCreationExpression: + case SyntaxKind.InvocationExpression: + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.ParenthesizedExpression: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.FunctionExpression: + case SyntaxKind.IdentifierName: + case SyntaxKind.RegularExpressionLiteral: + case SyntaxKind.NumericLiteral: + case SyntaxKind.StringLiteral: + case SyntaxKind.FalseKeyword: + case SyntaxKind.NullKeyword: + case SyntaxKind.ThisKeyword: + case SyntaxKind.TrueKeyword: + case SyntaxKind.SuperKeyword: + return true; + } + } + + return false; + } + + public static isExpression(element: ISyntaxElement) { + if (element) { + switch (element.kind()) { + case SyntaxKind.IdentifierName: + case SyntaxKind.RegularExpressionLiteral: + case SyntaxKind.NumericLiteral: + case SyntaxKind.StringLiteral: + case SyntaxKind.FalseKeyword: + case SyntaxKind.NullKeyword: + case SyntaxKind.ThisKeyword: + case SyntaxKind.TrueKeyword: + case SyntaxKind.SuperKeyword: + + case SyntaxKind.PlusExpression: + case SyntaxKind.NegateExpression: + case SyntaxKind.BitwiseNotExpression: + case SyntaxKind.LogicalNotExpression: + case SyntaxKind.PreIncrementExpression: + case SyntaxKind.PreDecrementExpression: + case SyntaxKind.DeleteExpression: + case SyntaxKind.TypeOfExpression: + case SyntaxKind.VoidExpression: + case SyntaxKind.CommaExpression: + case SyntaxKind.AssignmentExpression: + case SyntaxKind.AddAssignmentExpression: + case SyntaxKind.SubtractAssignmentExpression: + case SyntaxKind.MultiplyAssignmentExpression: + case SyntaxKind.DivideAssignmentExpression: + case SyntaxKind.ModuloAssignmentExpression: + case SyntaxKind.AndAssignmentExpression: + case SyntaxKind.ExclusiveOrAssignmentExpression: + case SyntaxKind.OrAssignmentExpression: + case SyntaxKind.LeftShiftAssignmentExpression: + case SyntaxKind.SignedRightShiftAssignmentExpression: + case SyntaxKind.UnsignedRightShiftAssignmentExpression: + case SyntaxKind.ConditionalExpression: + case SyntaxKind.LogicalOrExpression: + case SyntaxKind.LogicalAndExpression: + case SyntaxKind.BitwiseOrExpression: + case SyntaxKind.BitwiseExclusiveOrExpression: + case SyntaxKind.BitwiseAndExpression: + case SyntaxKind.EqualsWithTypeConversionExpression: + case SyntaxKind.NotEqualsWithTypeConversionExpression: + case SyntaxKind.EqualsExpression: + case SyntaxKind.NotEqualsExpression: + case SyntaxKind.LessThanExpression: + case SyntaxKind.GreaterThanExpression: + case SyntaxKind.LessThanOrEqualExpression: + case SyntaxKind.GreaterThanOrEqualExpression: + case SyntaxKind.InstanceOfExpression: + case SyntaxKind.InExpression: + case SyntaxKind.LeftShiftExpression: + case SyntaxKind.SignedRightShiftExpression: + case SyntaxKind.UnsignedRightShiftExpression: + case SyntaxKind.MultiplyExpression: + case SyntaxKind.DivideExpression: + case SyntaxKind.ModuloExpression: + case SyntaxKind.AddExpression: + case SyntaxKind.SubtractExpression: + case SyntaxKind.PostIncrementExpression: + case SyntaxKind.PostDecrementExpression: + case SyntaxKind.MemberAccessExpression: + case SyntaxKind.InvocationExpression: + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.ObjectCreationExpression: + case SyntaxKind.ParenthesizedExpression: + case SyntaxKind.ParenthesizedArrowFunctionExpression: + case SyntaxKind.SimpleArrowFunctionExpression: + case SyntaxKind.CastExpression: + case SyntaxKind.ElementAccessExpression: + case SyntaxKind.FunctionExpression: + case SyntaxKind.OmittedExpression: + return true; + } + } + + return false; + } + + public static isSwitchClause(element: ISyntaxElement) { + if (element) { + switch (element.kind()) { + case SyntaxKind.CaseSwitchClause: + case SyntaxKind.DefaultSwitchClause: + return true; + } + } + + return false; + } + + public static isTypeMember(element: ISyntaxElement) { + if (element) { + switch (element.kind()) { + case SyntaxKind.ConstructSignature: + case SyntaxKind.MethodSignature: + case SyntaxKind.IndexSignature: + case SyntaxKind.PropertySignature: + case SyntaxKind.CallSignature: + return true; + } + } + + return false; + } + + public static isClassElement(element: ISyntaxElement) { + if (element) { + switch (element.kind()) { + case SyntaxKind.ConstructorDeclaration: + case SyntaxKind.IndexMemberDeclaration: + case SyntaxKind.MemberFunctionDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.MemberFunctionDeclaration: + case SyntaxKind.MemberVariableDeclaration: + return true; + } + } + + return false; + } + + public static isModuleElement(element: ISyntaxElement) { + if (element) { + switch (element.kind()) { + case SyntaxKind.ImportDeclaration: + case SyntaxKind.ExportAssignment: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.EnumDeclaration: + + // Keep in sync with isStatement: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.VariableStatement: + case SyntaxKind.Block: + case SyntaxKind.IfStatement: + case SyntaxKind.ExpressionStatement: + case SyntaxKind.ThrowStatement: + case SyntaxKind.ReturnStatement: + case SyntaxKind.SwitchStatement: + case SyntaxKind.BreakStatement: + case SyntaxKind.ContinueStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.EmptyStatement: + case SyntaxKind.TryStatement: + case SyntaxKind.LabeledStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.DebuggerStatement: + return true; + } + } + + return false; + } + + public static isStatement(element: ISyntaxElement) { + if (element) { + switch (element.kind()) { + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.VariableStatement: + case SyntaxKind.Block: + case SyntaxKind.IfStatement: + case SyntaxKind.ExpressionStatement: + case SyntaxKind.ThrowStatement: + case SyntaxKind.ReturnStatement: + case SyntaxKind.SwitchStatement: + case SyntaxKind.BreakStatement: + case SyntaxKind.ContinueStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.EmptyStatement: + case SyntaxKind.TryStatement: + case SyntaxKind.LabeledStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.DebuggerStatement: + return true; + } + } + + return false; + } + + public static isAngleBracket(positionedElement: ISyntaxElement): boolean { + var element = positionedElement; + var parent = positionedElement.parent; + if (parent !== null && (element.kind() === SyntaxKind.LessThanToken || element.kind() === SyntaxKind.GreaterThanToken)) { + switch (parent.kind()) { + case SyntaxKind.TypeArgumentList: + case SyntaxKind.TypeParameterList: + case SyntaxKind.CastExpression: + return true; + } + } + + return false; + } + + public static getToken(list: ISyntaxToken[], kind: SyntaxKind): ISyntaxToken { + for (var i = 0, n = list.length; i < n; i++) { + var token = list[i]; + if (token.kind() === kind) { + return token; + } + } + + return null; + } + + public static containsToken(list: ISyntaxToken[], kind: SyntaxKind): boolean { + return SyntaxUtilities.getToken(list, kind) !== null; + } + + public static hasExportKeyword(moduleElement: IModuleElementSyntax): boolean { + return SyntaxUtilities.getExportKeyword(moduleElement) !== null; + } + + public static getExportKeyword(moduleElement: IModuleElementSyntax): ISyntaxToken { + switch (moduleElement.kind()) { + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.VariableStatement: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.ImportDeclaration: + return SyntaxUtilities.getToken((moduleElement).modifiers, SyntaxKind.ExportKeyword); + default: + return null; + } + } + + public static isAmbientDeclarationSyntax(positionNode: ISyntaxNode): boolean { + if (!positionNode) { + return false; + } + + var node = positionNode; + switch (node.kind()) { + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.VariableStatement: + case SyntaxKind.EnumDeclaration: + if (SyntaxUtilities.containsToken((node).modifiers, SyntaxKind.DeclareKeyword)) { + return true; + } + // Fall through to check if syntax container is ambient + + case SyntaxKind.ImportDeclaration: + case SyntaxKind.ConstructorDeclaration: + case SyntaxKind.MemberFunctionDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.MemberVariableDeclaration: + if (SyntaxUtilities.isClassElement(node) || SyntaxUtilities.isModuleElement(node)) { + return SyntaxUtilities.isAmbientDeclarationSyntax(Syntax.containingNode(positionNode)); + } + + case SyntaxKind.EnumElement: + return SyntaxUtilities.isAmbientDeclarationSyntax(Syntax.containingNode(Syntax.containingNode(positionNode))); + + default: + return SyntaxUtilities.isAmbientDeclarationSyntax(Syntax.containingNode(positionNode)); + } + } + } +} \ No newline at end of file diff --git a/src/services/syntax/syntaxVisitor.generated.ts b/src/services/syntax/syntaxVisitor.generated.ts new file mode 100644 index 00000000000..7081499105d --- /dev/null +++ b/src/services/syntax/syntaxVisitor.generated.ts @@ -0,0 +1,190 @@ +/// + +module TypeScript { + export function visitNodeOrToken(visitor: ISyntaxVisitor, element: ISyntaxNodeOrToken): any { + if (element === null) { return null; } + if (isToken(element)) { return visitor.visitToken(element); } + switch (element.kind()) { + case SyntaxKind.SourceUnit: return visitor.visitSourceUnit(element); + case SyntaxKind.QualifiedName: return visitor.visitQualifiedName(element); + case SyntaxKind.ObjectType: return visitor.visitObjectType(element); + case SyntaxKind.FunctionType: return visitor.visitFunctionType(element); + case SyntaxKind.ArrayType: return visitor.visitArrayType(element); + case SyntaxKind.ConstructorType: return visitor.visitConstructorType(element); + case SyntaxKind.GenericType: return visitor.visitGenericType(element); + case SyntaxKind.TypeQuery: return visitor.visitTypeQuery(element); + case SyntaxKind.InterfaceDeclaration: return visitor.visitInterfaceDeclaration(element); + case SyntaxKind.FunctionDeclaration: return visitor.visitFunctionDeclaration(element); + case SyntaxKind.ModuleDeclaration: return visitor.visitModuleDeclaration(element); + case SyntaxKind.ClassDeclaration: return visitor.visitClassDeclaration(element); + case SyntaxKind.EnumDeclaration: return visitor.visitEnumDeclaration(element); + case SyntaxKind.ImportDeclaration: return visitor.visitImportDeclaration(element); + case SyntaxKind.ExportAssignment: return visitor.visitExportAssignment(element); + case SyntaxKind.MemberFunctionDeclaration: return visitor.visitMemberFunctionDeclaration(element); + case SyntaxKind.MemberVariableDeclaration: return visitor.visitMemberVariableDeclaration(element); + case SyntaxKind.ConstructorDeclaration: return visitor.visitConstructorDeclaration(element); + case SyntaxKind.IndexMemberDeclaration: return visitor.visitIndexMemberDeclaration(element); + case SyntaxKind.GetAccessor: return visitor.visitGetAccessor(element); + case SyntaxKind.SetAccessor: return visitor.visitSetAccessor(element); + case SyntaxKind.PropertySignature: return visitor.visitPropertySignature(element); + case SyntaxKind.CallSignature: return visitor.visitCallSignature(element); + case SyntaxKind.ConstructSignature: return visitor.visitConstructSignature(element); + case SyntaxKind.IndexSignature: return visitor.visitIndexSignature(element); + case SyntaxKind.MethodSignature: return visitor.visitMethodSignature(element); + case SyntaxKind.Block: return visitor.visitBlock(element); + case SyntaxKind.IfStatement: return visitor.visitIfStatement(element); + case SyntaxKind.VariableStatement: return visitor.visitVariableStatement(element); + case SyntaxKind.ExpressionStatement: return visitor.visitExpressionStatement(element); + case SyntaxKind.ReturnStatement: return visitor.visitReturnStatement(element); + case SyntaxKind.SwitchStatement: return visitor.visitSwitchStatement(element); + case SyntaxKind.BreakStatement: return visitor.visitBreakStatement(element); + case SyntaxKind.ContinueStatement: return visitor.visitContinueStatement(element); + case SyntaxKind.ForStatement: return visitor.visitForStatement(element); + case SyntaxKind.ForInStatement: return visitor.visitForInStatement(element); + case SyntaxKind.EmptyStatement: return visitor.visitEmptyStatement(element); + case SyntaxKind.ThrowStatement: return visitor.visitThrowStatement(element); + case SyntaxKind.WhileStatement: return visitor.visitWhileStatement(element); + case SyntaxKind.TryStatement: return visitor.visitTryStatement(element); + case SyntaxKind.LabeledStatement: return visitor.visitLabeledStatement(element); + case SyntaxKind.DoStatement: return visitor.visitDoStatement(element); + case SyntaxKind.DebuggerStatement: return visitor.visitDebuggerStatement(element); + case SyntaxKind.WithStatement: return visitor.visitWithStatement(element); + case SyntaxKind.PreIncrementExpression: case SyntaxKind.PreDecrementExpression: case SyntaxKind.PlusExpression: case SyntaxKind.NegateExpression: case SyntaxKind.BitwiseNotExpression: case SyntaxKind.LogicalNotExpression: + return visitor.visitPrefixUnaryExpression(element); + case SyntaxKind.DeleteExpression: return visitor.visitDeleteExpression(element); + case SyntaxKind.TypeOfExpression: return visitor.visitTypeOfExpression(element); + case SyntaxKind.VoidExpression: return visitor.visitVoidExpression(element); + case SyntaxKind.ConditionalExpression: return visitor.visitConditionalExpression(element); + case SyntaxKind.MultiplyExpression: case SyntaxKind.DivideExpression: case SyntaxKind.ModuloExpression: case SyntaxKind.AddExpression: case SyntaxKind.SubtractExpression: case SyntaxKind.LeftShiftExpression: case SyntaxKind.SignedRightShiftExpression: case SyntaxKind.UnsignedRightShiftExpression: case SyntaxKind.LessThanExpression: case SyntaxKind.GreaterThanExpression: case SyntaxKind.LessThanOrEqualExpression: case SyntaxKind.GreaterThanOrEqualExpression: case SyntaxKind.InstanceOfExpression: case SyntaxKind.InExpression: case SyntaxKind.EqualsWithTypeConversionExpression: case SyntaxKind.NotEqualsWithTypeConversionExpression: case SyntaxKind.EqualsExpression: case SyntaxKind.NotEqualsExpression: case SyntaxKind.BitwiseAndExpression: case SyntaxKind.BitwiseExclusiveOrExpression: case SyntaxKind.BitwiseOrExpression: case SyntaxKind.LogicalAndExpression: case SyntaxKind.LogicalOrExpression: case SyntaxKind.OrAssignmentExpression: case SyntaxKind.AndAssignmentExpression: case SyntaxKind.ExclusiveOrAssignmentExpression: case SyntaxKind.LeftShiftAssignmentExpression: case SyntaxKind.SignedRightShiftAssignmentExpression: case SyntaxKind.UnsignedRightShiftAssignmentExpression: case SyntaxKind.AddAssignmentExpression: case SyntaxKind.SubtractAssignmentExpression: case SyntaxKind.MultiplyAssignmentExpression: case SyntaxKind.DivideAssignmentExpression: case SyntaxKind.ModuloAssignmentExpression: case SyntaxKind.AssignmentExpression: case SyntaxKind.CommaExpression: + return visitor.visitBinaryExpression(element); + case SyntaxKind.PostIncrementExpression: case SyntaxKind.PostDecrementExpression: + return visitor.visitPostfixUnaryExpression(element); + case SyntaxKind.MemberAccessExpression: return visitor.visitMemberAccessExpression(element); + case SyntaxKind.InvocationExpression: return visitor.visitInvocationExpression(element); + case SyntaxKind.ArrayLiteralExpression: return visitor.visitArrayLiteralExpression(element); + case SyntaxKind.ObjectLiteralExpression: return visitor.visitObjectLiteralExpression(element); + case SyntaxKind.ObjectCreationExpression: return visitor.visitObjectCreationExpression(element); + case SyntaxKind.ParenthesizedExpression: return visitor.visitParenthesizedExpression(element); + case SyntaxKind.ParenthesizedArrowFunctionExpression: return visitor.visitParenthesizedArrowFunctionExpression(element); + case SyntaxKind.SimpleArrowFunctionExpression: return visitor.visitSimpleArrowFunctionExpression(element); + case SyntaxKind.CastExpression: return visitor.visitCastExpression(element); + case SyntaxKind.ElementAccessExpression: return visitor.visitElementAccessExpression(element); + case SyntaxKind.FunctionExpression: return visitor.visitFunctionExpression(element); + case SyntaxKind.OmittedExpression: return visitor.visitOmittedExpression(element); + case SyntaxKind.VariableDeclaration: return visitor.visitVariableDeclaration(element); + case SyntaxKind.VariableDeclarator: return visitor.visitVariableDeclarator(element); + case SyntaxKind.ArgumentList: return visitor.visitArgumentList(element); + case SyntaxKind.ParameterList: return visitor.visitParameterList(element); + case SyntaxKind.TypeArgumentList: return visitor.visitTypeArgumentList(element); + case SyntaxKind.TypeParameterList: return visitor.visitTypeParameterList(element); + case SyntaxKind.ExtendsHeritageClause: case SyntaxKind.ImplementsHeritageClause: + return visitor.visitHeritageClause(element); + case SyntaxKind.EqualsValueClause: return visitor.visitEqualsValueClause(element); + case SyntaxKind.CaseSwitchClause: return visitor.visitCaseSwitchClause(element); + case SyntaxKind.DefaultSwitchClause: return visitor.visitDefaultSwitchClause(element); + case SyntaxKind.ElseClause: return visitor.visitElseClause(element); + case SyntaxKind.CatchClause: return visitor.visitCatchClause(element); + case SyntaxKind.FinallyClause: return visitor.visitFinallyClause(element); + case SyntaxKind.TypeParameter: return visitor.visitTypeParameter(element); + case SyntaxKind.Constraint: return visitor.visitConstraint(element); + case SyntaxKind.SimplePropertyAssignment: return visitor.visitSimplePropertyAssignment(element); + case SyntaxKind.FunctionPropertyAssignment: return visitor.visitFunctionPropertyAssignment(element); + case SyntaxKind.Parameter: return visitor.visitParameter(element); + case SyntaxKind.EnumElement: return visitor.visitEnumElement(element); + case SyntaxKind.TypeAnnotation: return visitor.visitTypeAnnotation(element); + case SyntaxKind.ExternalModuleReference: return visitor.visitExternalModuleReference(element); + case SyntaxKind.ModuleNameModuleReference: return visitor.visitModuleNameModuleReference(element); + } + + throw Errors.invalidOperation(); + } + + export interface ISyntaxVisitor { + visitToken(token: ISyntaxToken): any; + visitSourceUnit(node: SourceUnitSyntax): any; + visitQualifiedName(node: QualifiedNameSyntax): any; + visitObjectType(node: ObjectTypeSyntax): any; + visitFunctionType(node: FunctionTypeSyntax): any; + visitArrayType(node: ArrayTypeSyntax): any; + visitConstructorType(node: ConstructorTypeSyntax): any; + visitGenericType(node: GenericTypeSyntax): any; + visitTypeQuery(node: TypeQuerySyntax): any; + visitInterfaceDeclaration(node: InterfaceDeclarationSyntax): any; + visitFunctionDeclaration(node: FunctionDeclarationSyntax): any; + visitModuleDeclaration(node: ModuleDeclarationSyntax): any; + visitClassDeclaration(node: ClassDeclarationSyntax): any; + visitEnumDeclaration(node: EnumDeclarationSyntax): any; + visitImportDeclaration(node: ImportDeclarationSyntax): any; + visitExportAssignment(node: ExportAssignmentSyntax): any; + visitMemberFunctionDeclaration(node: MemberFunctionDeclarationSyntax): any; + visitMemberVariableDeclaration(node: MemberVariableDeclarationSyntax): any; + visitConstructorDeclaration(node: ConstructorDeclarationSyntax): any; + visitIndexMemberDeclaration(node: IndexMemberDeclarationSyntax): any; + visitGetAccessor(node: GetAccessorSyntax): any; + visitSetAccessor(node: SetAccessorSyntax): any; + visitPropertySignature(node: PropertySignatureSyntax): any; + visitCallSignature(node: CallSignatureSyntax): any; + visitConstructSignature(node: ConstructSignatureSyntax): any; + visitIndexSignature(node: IndexSignatureSyntax): any; + visitMethodSignature(node: MethodSignatureSyntax): any; + visitBlock(node: BlockSyntax): any; + visitIfStatement(node: IfStatementSyntax): any; + visitVariableStatement(node: VariableStatementSyntax): any; + visitExpressionStatement(node: ExpressionStatementSyntax): any; + visitReturnStatement(node: ReturnStatementSyntax): any; + visitSwitchStatement(node: SwitchStatementSyntax): any; + visitBreakStatement(node: BreakStatementSyntax): any; + visitContinueStatement(node: ContinueStatementSyntax): any; + visitForStatement(node: ForStatementSyntax): any; + visitForInStatement(node: ForInStatementSyntax): any; + visitEmptyStatement(node: EmptyStatementSyntax): any; + visitThrowStatement(node: ThrowStatementSyntax): any; + visitWhileStatement(node: WhileStatementSyntax): any; + visitTryStatement(node: TryStatementSyntax): any; + visitLabeledStatement(node: LabeledStatementSyntax): any; + visitDoStatement(node: DoStatementSyntax): any; + visitDebuggerStatement(node: DebuggerStatementSyntax): any; + visitWithStatement(node: WithStatementSyntax): any; + visitPrefixUnaryExpression(node: PrefixUnaryExpressionSyntax): any; + visitDeleteExpression(node: DeleteExpressionSyntax): any; + visitTypeOfExpression(node: TypeOfExpressionSyntax): any; + visitVoidExpression(node: VoidExpressionSyntax): any; + visitConditionalExpression(node: ConditionalExpressionSyntax): any; + visitBinaryExpression(node: BinaryExpressionSyntax): any; + visitPostfixUnaryExpression(node: PostfixUnaryExpressionSyntax): any; + visitMemberAccessExpression(node: MemberAccessExpressionSyntax): any; + visitInvocationExpression(node: InvocationExpressionSyntax): any; + visitArrayLiteralExpression(node: ArrayLiteralExpressionSyntax): any; + visitObjectLiteralExpression(node: ObjectLiteralExpressionSyntax): any; + visitObjectCreationExpression(node: ObjectCreationExpressionSyntax): any; + visitParenthesizedExpression(node: ParenthesizedExpressionSyntax): any; + visitParenthesizedArrowFunctionExpression(node: ParenthesizedArrowFunctionExpressionSyntax): any; + visitSimpleArrowFunctionExpression(node: SimpleArrowFunctionExpressionSyntax): any; + visitCastExpression(node: CastExpressionSyntax): any; + visitElementAccessExpression(node: ElementAccessExpressionSyntax): any; + visitFunctionExpression(node: FunctionExpressionSyntax): any; + visitOmittedExpression(node: OmittedExpressionSyntax): any; + visitVariableDeclaration(node: VariableDeclarationSyntax): any; + visitVariableDeclarator(node: VariableDeclaratorSyntax): any; + visitArgumentList(node: ArgumentListSyntax): any; + visitParameterList(node: ParameterListSyntax): any; + visitTypeArgumentList(node: TypeArgumentListSyntax): any; + visitTypeParameterList(node: TypeParameterListSyntax): any; + visitHeritageClause(node: HeritageClauseSyntax): any; + visitEqualsValueClause(node: EqualsValueClauseSyntax): any; + visitCaseSwitchClause(node: CaseSwitchClauseSyntax): any; + visitDefaultSwitchClause(node: DefaultSwitchClauseSyntax): any; + visitElseClause(node: ElseClauseSyntax): any; + visitCatchClause(node: CatchClauseSyntax): any; + visitFinallyClause(node: FinallyClauseSyntax): any; + visitTypeParameter(node: TypeParameterSyntax): any; + visitConstraint(node: ConstraintSyntax): any; + visitSimplePropertyAssignment(node: SimplePropertyAssignmentSyntax): any; + visitFunctionPropertyAssignment(node: FunctionPropertyAssignmentSyntax): any; + visitParameter(node: ParameterSyntax): any; + visitEnumElement(node: EnumElementSyntax): any; + visitTypeAnnotation(node: TypeAnnotationSyntax): any; + visitExternalModuleReference(node: ExternalModuleReferenceSyntax): any; + visitModuleNameModuleReference(node: ModuleNameModuleReferenceSyntax): any; + } +} \ No newline at end of file diff --git a/src/services/syntax/syntaxWalker.generated.ts b/src/services/syntax/syntaxWalker.generated.ts new file mode 100644 index 00000000000..73f70f1834b --- /dev/null +++ b/src/services/syntax/syntaxWalker.generated.ts @@ -0,0 +1,618 @@ +/// + +module TypeScript { + export class SyntaxWalker implements ISyntaxVisitor { + public visitToken(token: ISyntaxToken): void { + } + + public visitNode(node: ISyntaxNode): void { + visitNodeOrToken(this, node); + } + + public visitNodeOrToken(nodeOrToken: ISyntaxNodeOrToken): void { + if (isToken(nodeOrToken)) { + this.visitToken(nodeOrToken); + } + else { + this.visitNode(nodeOrToken); + } + } + + private visitOptionalToken(token: ISyntaxToken): void { + if (token === null) { + return; + } + + this.visitToken(token); + } + + public visitOptionalNode(node: ISyntaxNode): void { + if (node === null) { + return; + } + + this.visitNode(node); + } + + public visitOptionalNodeOrToken(nodeOrToken: ISyntaxNodeOrToken): void { + if (nodeOrToken === null) { + return; + } + + this.visitNodeOrToken(nodeOrToken); + } + + public visitList(list: ISyntaxNodeOrToken[]): void { + for (var i = 0, n = list.length; i < n; i++) { + this.visitNodeOrToken(list[i]); + } + } + + public visitSeparatedList(list: ISyntaxNodeOrToken[]): void { + for (var i = 0, n = childCount(list); i < n; i++) { + var item = childAt(list, i); + this.visitNodeOrToken(item); + } + } + + public visitSourceUnit(node: SourceUnitSyntax): void { + this.visitList(node.moduleElements); + this.visitToken(node.endOfFileToken); + } + + public visitQualifiedName(node: QualifiedNameSyntax): void { + this.visitNodeOrToken(node.left); + this.visitToken(node.dotToken); + this.visitToken(node.right); + } + + public visitObjectType(node: ObjectTypeSyntax): void { + this.visitToken(node.openBraceToken); + this.visitSeparatedList(node.typeMembers); + this.visitToken(node.closeBraceToken); + } + + public visitFunctionType(node: FunctionTypeSyntax): void { + this.visitOptionalNode(node.typeParameterList); + this.visitNode(node.parameterList); + this.visitToken(node.equalsGreaterThanToken); + this.visitNodeOrToken(node.type); + } + + public visitArrayType(node: ArrayTypeSyntax): void { + this.visitNodeOrToken(node.type); + this.visitToken(node.openBracketToken); + this.visitToken(node.closeBracketToken); + } + + public visitConstructorType(node: ConstructorTypeSyntax): void { + this.visitToken(node.newKeyword); + this.visitOptionalNode(node.typeParameterList); + this.visitNode(node.parameterList); + this.visitToken(node.equalsGreaterThanToken); + this.visitNodeOrToken(node.type); + } + + public visitGenericType(node: GenericTypeSyntax): void { + this.visitNodeOrToken(node.name); + this.visitNode(node.typeArgumentList); + } + + public visitTypeQuery(node: TypeQuerySyntax): void { + this.visitToken(node.typeOfKeyword); + this.visitNodeOrToken(node.name); + } + + public visitInterfaceDeclaration(node: InterfaceDeclarationSyntax): void { + this.visitList(node.modifiers); + this.visitToken(node.interfaceKeyword); + this.visitToken(node.identifier); + this.visitOptionalNode(node.typeParameterList); + this.visitList(node.heritageClauses); + this.visitNode(node.body); + } + + public visitFunctionDeclaration(node: FunctionDeclarationSyntax): void { + this.visitList(node.modifiers); + this.visitToken(node.functionKeyword); + this.visitToken(node.identifier); + this.visitNode(node.callSignature); + this.visitOptionalNode(node.block); + this.visitOptionalToken(node.semicolonToken); + } + + public visitModuleDeclaration(node: ModuleDeclarationSyntax): void { + this.visitList(node.modifiers); + this.visitToken(node.moduleKeyword); + this.visitOptionalNodeOrToken(node.name); + this.visitOptionalToken(node.stringLiteral); + this.visitToken(node.openBraceToken); + this.visitList(node.moduleElements); + this.visitToken(node.closeBraceToken); + } + + public visitClassDeclaration(node: ClassDeclarationSyntax): void { + this.visitList(node.modifiers); + this.visitToken(node.classKeyword); + this.visitToken(node.identifier); + this.visitOptionalNode(node.typeParameterList); + this.visitList(node.heritageClauses); + this.visitToken(node.openBraceToken); + this.visitList(node.classElements); + this.visitToken(node.closeBraceToken); + } + + public visitEnumDeclaration(node: EnumDeclarationSyntax): void { + this.visitList(node.modifiers); + this.visitToken(node.enumKeyword); + this.visitToken(node.identifier); + this.visitToken(node.openBraceToken); + this.visitSeparatedList(node.enumElements); + this.visitToken(node.closeBraceToken); + } + + public visitImportDeclaration(node: ImportDeclarationSyntax): void { + this.visitList(node.modifiers); + this.visitToken(node.importKeyword); + this.visitToken(node.identifier); + this.visitToken(node.equalsToken); + this.visitNodeOrToken(node.moduleReference); + this.visitOptionalToken(node.semicolonToken); + } + + public visitExportAssignment(node: ExportAssignmentSyntax): void { + this.visitToken(node.exportKeyword); + this.visitToken(node.equalsToken); + this.visitToken(node.identifier); + this.visitOptionalToken(node.semicolonToken); + } + + public visitMemberFunctionDeclaration(node: MemberFunctionDeclarationSyntax): void { + this.visitList(node.modifiers); + this.visitToken(node.propertyName); + this.visitNode(node.callSignature); + this.visitOptionalNode(node.block); + this.visitOptionalToken(node.semicolonToken); + } + + public visitMemberVariableDeclaration(node: MemberVariableDeclarationSyntax): void { + this.visitList(node.modifiers); + this.visitNode(node.variableDeclarator); + this.visitOptionalToken(node.semicolonToken); + } + + public visitConstructorDeclaration(node: ConstructorDeclarationSyntax): void { + this.visitList(node.modifiers); + this.visitToken(node.constructorKeyword); + this.visitNode(node.callSignature); + this.visitOptionalNode(node.block); + this.visitOptionalToken(node.semicolonToken); + } + + public visitIndexMemberDeclaration(node: IndexMemberDeclarationSyntax): void { + this.visitList(node.modifiers); + this.visitNode(node.indexSignature); + this.visitOptionalToken(node.semicolonToken); + } + + public visitGetAccessor(node: GetAccessorSyntax): void { + this.visitList(node.modifiers); + this.visitToken(node.getKeyword); + this.visitToken(node.propertyName); + this.visitNode(node.callSignature); + this.visitNode(node.block); + } + + public visitSetAccessor(node: SetAccessorSyntax): void { + this.visitList(node.modifiers); + this.visitToken(node.setKeyword); + this.visitToken(node.propertyName); + this.visitNode(node.callSignature); + this.visitNode(node.block); + } + + public visitPropertySignature(node: PropertySignatureSyntax): void { + this.visitToken(node.propertyName); + this.visitOptionalToken(node.questionToken); + this.visitOptionalNode(node.typeAnnotation); + } + + public visitCallSignature(node: CallSignatureSyntax): void { + this.visitOptionalNode(node.typeParameterList); + this.visitNode(node.parameterList); + this.visitOptionalNode(node.typeAnnotation); + } + + public visitConstructSignature(node: ConstructSignatureSyntax): void { + this.visitToken(node.newKeyword); + this.visitNode(node.callSignature); + } + + public visitIndexSignature(node: IndexSignatureSyntax): void { + this.visitToken(node.openBracketToken); + this.visitSeparatedList(node.parameters); + this.visitToken(node.closeBracketToken); + this.visitOptionalNode(node.typeAnnotation); + } + + public visitMethodSignature(node: MethodSignatureSyntax): void { + this.visitToken(node.propertyName); + this.visitOptionalToken(node.questionToken); + this.visitNode(node.callSignature); + } + + public visitBlock(node: BlockSyntax): void { + this.visitToken(node.openBraceToken); + this.visitList(node.statements); + this.visitToken(node.closeBraceToken); + } + + public visitIfStatement(node: IfStatementSyntax): void { + this.visitToken(node.ifKeyword); + this.visitToken(node.openParenToken); + this.visitNodeOrToken(node.condition); + this.visitToken(node.closeParenToken); + this.visitNodeOrToken(node.statement); + this.visitOptionalNode(node.elseClause); + } + + public visitVariableStatement(node: VariableStatementSyntax): void { + this.visitList(node.modifiers); + this.visitNode(node.variableDeclaration); + this.visitOptionalToken(node.semicolonToken); + } + + public visitExpressionStatement(node: ExpressionStatementSyntax): void { + this.visitNodeOrToken(node.expression); + this.visitOptionalToken(node.semicolonToken); + } + + public visitReturnStatement(node: ReturnStatementSyntax): void { + this.visitToken(node.returnKeyword); + this.visitOptionalNodeOrToken(node.expression); + this.visitOptionalToken(node.semicolonToken); + } + + public visitSwitchStatement(node: SwitchStatementSyntax): void { + this.visitToken(node.switchKeyword); + this.visitToken(node.openParenToken); + this.visitNodeOrToken(node.expression); + this.visitToken(node.closeParenToken); + this.visitToken(node.openBraceToken); + this.visitList(node.switchClauses); + this.visitToken(node.closeBraceToken); + } + + public visitBreakStatement(node: BreakStatementSyntax): void { + this.visitToken(node.breakKeyword); + this.visitOptionalToken(node.identifier); + this.visitOptionalToken(node.semicolonToken); + } + + public visitContinueStatement(node: ContinueStatementSyntax): void { + this.visitToken(node.continueKeyword); + this.visitOptionalToken(node.identifier); + this.visitOptionalToken(node.semicolonToken); + } + + public visitForStatement(node: ForStatementSyntax): void { + this.visitToken(node.forKeyword); + this.visitToken(node.openParenToken); + this.visitOptionalNode(node.variableDeclaration); + this.visitOptionalNodeOrToken(node.initializer); + this.visitToken(node.firstSemicolonToken); + this.visitOptionalNodeOrToken(node.condition); + this.visitToken(node.secondSemicolonToken); + this.visitOptionalNodeOrToken(node.incrementor); + this.visitToken(node.closeParenToken); + this.visitNodeOrToken(node.statement); + } + + public visitForInStatement(node: ForInStatementSyntax): void { + this.visitToken(node.forKeyword); + this.visitToken(node.openParenToken); + this.visitOptionalNode(node.variableDeclaration); + this.visitOptionalNodeOrToken(node.left); + this.visitToken(node.inKeyword); + this.visitNodeOrToken(node.expression); + this.visitToken(node.closeParenToken); + this.visitNodeOrToken(node.statement); + } + + public visitEmptyStatement(node: EmptyStatementSyntax): void { + this.visitToken(node.semicolonToken); + } + + public visitThrowStatement(node: ThrowStatementSyntax): void { + this.visitToken(node.throwKeyword); + this.visitNodeOrToken(node.expression); + this.visitOptionalToken(node.semicolonToken); + } + + public visitWhileStatement(node: WhileStatementSyntax): void { + this.visitToken(node.whileKeyword); + this.visitToken(node.openParenToken); + this.visitNodeOrToken(node.condition); + this.visitToken(node.closeParenToken); + this.visitNodeOrToken(node.statement); + } + + public visitTryStatement(node: TryStatementSyntax): void { + this.visitToken(node.tryKeyword); + this.visitNode(node.block); + this.visitOptionalNode(node.catchClause); + this.visitOptionalNode(node.finallyClause); + } + + public visitLabeledStatement(node: LabeledStatementSyntax): void { + this.visitToken(node.identifier); + this.visitToken(node.colonToken); + this.visitNodeOrToken(node.statement); + } + + public visitDoStatement(node: DoStatementSyntax): void { + this.visitToken(node.doKeyword); + this.visitNodeOrToken(node.statement); + this.visitToken(node.whileKeyword); + this.visitToken(node.openParenToken); + this.visitNodeOrToken(node.condition); + this.visitToken(node.closeParenToken); + this.visitOptionalToken(node.semicolonToken); + } + + public visitDebuggerStatement(node: DebuggerStatementSyntax): void { + this.visitToken(node.debuggerKeyword); + this.visitOptionalToken(node.semicolonToken); + } + + public visitWithStatement(node: WithStatementSyntax): void { + this.visitToken(node.withKeyword); + this.visitToken(node.openParenToken); + this.visitNodeOrToken(node.condition); + this.visitToken(node.closeParenToken); + this.visitNodeOrToken(node.statement); + } + + public visitPrefixUnaryExpression(node: PrefixUnaryExpressionSyntax): void { + this.visitToken(node.operatorToken); + this.visitNodeOrToken(node.operand); + } + + public visitDeleteExpression(node: DeleteExpressionSyntax): void { + this.visitToken(node.deleteKeyword); + this.visitNodeOrToken(node.expression); + } + + public visitTypeOfExpression(node: TypeOfExpressionSyntax): void { + this.visitToken(node.typeOfKeyword); + this.visitNodeOrToken(node.expression); + } + + public visitVoidExpression(node: VoidExpressionSyntax): void { + this.visitToken(node.voidKeyword); + this.visitNodeOrToken(node.expression); + } + + public visitConditionalExpression(node: ConditionalExpressionSyntax): void { + this.visitNodeOrToken(node.condition); + this.visitToken(node.questionToken); + this.visitNodeOrToken(node.whenTrue); + this.visitToken(node.colonToken); + this.visitNodeOrToken(node.whenFalse); + } + + public visitBinaryExpression(node: BinaryExpressionSyntax): void { + this.visitNodeOrToken(node.left); + this.visitToken(node.operatorToken); + this.visitNodeOrToken(node.right); + } + + public visitPostfixUnaryExpression(node: PostfixUnaryExpressionSyntax): void { + this.visitNodeOrToken(node.operand); + this.visitToken(node.operatorToken); + } + + public visitMemberAccessExpression(node: MemberAccessExpressionSyntax): void { + this.visitNodeOrToken(node.expression); + this.visitToken(node.dotToken); + this.visitToken(node.name); + } + + public visitInvocationExpression(node: InvocationExpressionSyntax): void { + this.visitNodeOrToken(node.expression); + this.visitNode(node.argumentList); + } + + public visitArrayLiteralExpression(node: ArrayLiteralExpressionSyntax): void { + this.visitToken(node.openBracketToken); + this.visitSeparatedList(node.expressions); + this.visitToken(node.closeBracketToken); + } + + public visitObjectLiteralExpression(node: ObjectLiteralExpressionSyntax): void { + this.visitToken(node.openBraceToken); + this.visitSeparatedList(node.propertyAssignments); + this.visitToken(node.closeBraceToken); + } + + public visitObjectCreationExpression(node: ObjectCreationExpressionSyntax): void { + this.visitToken(node.newKeyword); + this.visitNodeOrToken(node.expression); + this.visitOptionalNode(node.argumentList); + } + + public visitParenthesizedExpression(node: ParenthesizedExpressionSyntax): void { + this.visitToken(node.openParenToken); + this.visitNodeOrToken(node.expression); + this.visitToken(node.closeParenToken); + } + + public visitParenthesizedArrowFunctionExpression(node: ParenthesizedArrowFunctionExpressionSyntax): void { + this.visitNode(node.callSignature); + this.visitToken(node.equalsGreaterThanToken); + this.visitOptionalNode(node.block); + this.visitOptionalNodeOrToken(node.expression); + } + + public visitSimpleArrowFunctionExpression(node: SimpleArrowFunctionExpressionSyntax): void { + this.visitNode(node.parameter); + this.visitToken(node.equalsGreaterThanToken); + this.visitOptionalNode(node.block); + this.visitOptionalNodeOrToken(node.expression); + } + + public visitCastExpression(node: CastExpressionSyntax): void { + this.visitToken(node.lessThanToken); + this.visitNodeOrToken(node.type); + this.visitToken(node.greaterThanToken); + this.visitNodeOrToken(node.expression); + } + + public visitElementAccessExpression(node: ElementAccessExpressionSyntax): void { + this.visitNodeOrToken(node.expression); + this.visitToken(node.openBracketToken); + this.visitNodeOrToken(node.argumentExpression); + this.visitToken(node.closeBracketToken); + } + + public visitFunctionExpression(node: FunctionExpressionSyntax): void { + this.visitToken(node.functionKeyword); + this.visitOptionalToken(node.identifier); + this.visitNode(node.callSignature); + this.visitNode(node.block); + } + + public visitOmittedExpression(node: OmittedExpressionSyntax): void { + } + + public visitVariableDeclaration(node: VariableDeclarationSyntax): void { + this.visitToken(node.varKeyword); + this.visitSeparatedList(node.variableDeclarators); + } + + public visitVariableDeclarator(node: VariableDeclaratorSyntax): void { + this.visitToken(node.propertyName); + this.visitOptionalNode(node.typeAnnotation); + this.visitOptionalNode(node.equalsValueClause); + } + + public visitArgumentList(node: ArgumentListSyntax): void { + this.visitOptionalNode(node.typeArgumentList); + this.visitToken(node.openParenToken); + this.visitSeparatedList(node.arguments); + this.visitToken(node.closeParenToken); + } + + public visitParameterList(node: ParameterListSyntax): void { + this.visitToken(node.openParenToken); + this.visitSeparatedList(node.parameters); + this.visitToken(node.closeParenToken); + } + + public visitTypeArgumentList(node: TypeArgumentListSyntax): void { + this.visitToken(node.lessThanToken); + this.visitSeparatedList(node.typeArguments); + this.visitToken(node.greaterThanToken); + } + + public visitTypeParameterList(node: TypeParameterListSyntax): void { + this.visitToken(node.lessThanToken); + this.visitSeparatedList(node.typeParameters); + this.visitToken(node.greaterThanToken); + } + + public visitHeritageClause(node: HeritageClauseSyntax): void { + this.visitToken(node.extendsOrImplementsKeyword); + this.visitSeparatedList(node.typeNames); + } + + public visitEqualsValueClause(node: EqualsValueClauseSyntax): void { + this.visitToken(node.equalsToken); + this.visitNodeOrToken(node.value); + } + + public visitCaseSwitchClause(node: CaseSwitchClauseSyntax): void { + this.visitToken(node.caseKeyword); + this.visitNodeOrToken(node.expression); + this.visitToken(node.colonToken); + this.visitList(node.statements); + } + + public visitDefaultSwitchClause(node: DefaultSwitchClauseSyntax): void { + this.visitToken(node.defaultKeyword); + this.visitToken(node.colonToken); + this.visitList(node.statements); + } + + public visitElseClause(node: ElseClauseSyntax): void { + this.visitToken(node.elseKeyword); + this.visitNodeOrToken(node.statement); + } + + public visitCatchClause(node: CatchClauseSyntax): void { + this.visitToken(node.catchKeyword); + this.visitToken(node.openParenToken); + this.visitToken(node.identifier); + this.visitOptionalNode(node.typeAnnotation); + this.visitToken(node.closeParenToken); + this.visitNode(node.block); + } + + public visitFinallyClause(node: FinallyClauseSyntax): void { + this.visitToken(node.finallyKeyword); + this.visitNode(node.block); + } + + public visitTypeParameter(node: TypeParameterSyntax): void { + this.visitToken(node.identifier); + this.visitOptionalNode(node.constraint); + } + + public visitConstraint(node: ConstraintSyntax): void { + this.visitToken(node.extendsKeyword); + this.visitNodeOrToken(node.typeOrExpression); + } + + public visitSimplePropertyAssignment(node: SimplePropertyAssignmentSyntax): void { + this.visitToken(node.propertyName); + this.visitToken(node.colonToken); + this.visitNodeOrToken(node.expression); + } + + public visitFunctionPropertyAssignment(node: FunctionPropertyAssignmentSyntax): void { + this.visitToken(node.propertyName); + this.visitNode(node.callSignature); + this.visitNode(node.block); + } + + public visitParameter(node: ParameterSyntax): void { + this.visitOptionalToken(node.dotDotDotToken); + this.visitList(node.modifiers); + this.visitToken(node.identifier); + this.visitOptionalToken(node.questionToken); + this.visitOptionalNode(node.typeAnnotation); + this.visitOptionalNode(node.equalsValueClause); + } + + public visitEnumElement(node: EnumElementSyntax): void { + this.visitToken(node.propertyName); + this.visitOptionalNode(node.equalsValueClause); + } + + public visitTypeAnnotation(node: TypeAnnotationSyntax): void { + this.visitToken(node.colonToken); + this.visitNodeOrToken(node.type); + } + + public visitExternalModuleReference(node: ExternalModuleReferenceSyntax): void { + this.visitToken(node.requireKeyword); + this.visitToken(node.openParenToken); + this.visitToken(node.stringLiteral); + this.visitToken(node.closeParenToken); + } + + public visitModuleNameModuleReference(node: ModuleNameModuleReferenceSyntax): void { + this.visitNodeOrToken(node.moduleName); + } + } +} \ No newline at end of file diff --git a/src/services/syntax/testUtilities.ts b/src/services/syntax/testUtilities.ts new file mode 100644 index 00000000000..2dd0055e068 --- /dev/null +++ b/src/services/syntax/testUtilities.ts @@ -0,0 +1,209 @@ +module TypeScript { + function assertParent(parent: ISyntaxElement, child: ISyntaxElement) { + if (child && !TypeScript.isShared(child)) { + return Debug.assert(parent === child.parent); + } + } + + export function nodeStructuralEquals(node1: TypeScript.ISyntaxNode, node2: TypeScript.ISyntaxNode, checkParents: boolean, text1: ISimpleText, text2: ISimpleText): boolean { + if (node1 === node2) { return true; } + if (node1 === null || node2 === null) { return false; } + + Debug.assert(node1.kind() === TypeScript.SyntaxKind.SourceUnit || node1.parent); + Debug.assert(node2.kind() === TypeScript.SyntaxKind.SourceUnit || node2.parent); + + if (node1.kind() !== node2.kind()) { return false; } + if (childCount(node1) !== childCount(node2)) { return false; } + + for (var i = 0, n = childCount(node1); i < n; i++) { + var element1 = childAt(node1, i); + var element2 = childAt(node2, i); + + if (checkParents) { + assertParent(node1, element1); + assertParent(node2, element2); + } + + if (!elementStructuralEquals(element1, element2, checkParents, text1, text2)) { + return false; + } + } + + return true; + } + + export function nodeOrTokenStructuralEquals(node1: TypeScript.ISyntaxNodeOrToken, node2: TypeScript.ISyntaxNodeOrToken, checkParents: boolean, text1: ISimpleText, text2: ISimpleText): boolean { + if (node1 === node2) { + return true; + } + + if (node1 === null || node2 === null) { + return false; + } + + Debug.assert(node1.kind() === TypeScript.SyntaxKind.SourceUnit || node1.parent); + Debug.assert(node2.kind() === TypeScript.SyntaxKind.SourceUnit || node2.parent); + + if (TypeScript.isToken(node1)) { + return TypeScript.isToken(node2) ? tokenStructuralEquals(node1, node2, text1, text2) : false; + } + + return TypeScript.isNode(node2) ? nodeStructuralEquals(node1, node2, checkParents, text1, text2) : false; + } + + export function tokenStructuralEquals(token1: TypeScript.ISyntaxToken, token2: TypeScript.ISyntaxToken, text1: ISimpleText, text2: ISimpleText): boolean { + if (token1 === token2) { + return true; + } + + if (token1 === null || token2 === null) { + return false; + } + + Debug.assert(token1.parent); + Debug.assert(token2.parent); + + return token1.kind() === token2.kind() && + TypeScript.width(token1) === TypeScript.width(token2) && + token1.fullWidth() === token2.fullWidth() && + token1.fullStart() === token2.fullStart() && + TypeScript.fullEnd(token1) === TypeScript.fullEnd(token2) && + TypeScript.start(token1, text1) === TypeScript.start(token2, text2) && + TypeScript.end(token1, text1) === TypeScript.end(token2, text2) && + token1.text() === token2.text() && + triviaListStructuralEquals(token1.leadingTrivia(text1), token2.leadingTrivia(text2)) && + triviaListStructuralEquals(token1.trailingTrivia(text1), token2.trailingTrivia(text2)); + } + + export function triviaListStructuralEquals(triviaList1: TypeScript.ISyntaxTriviaList, triviaList2: TypeScript.ISyntaxTriviaList): boolean { + Debug.assert(triviaList1.isShared() || triviaList1.parent); + Debug.assert(triviaList1.isShared() || triviaList2.parent); + + if (triviaList1.count() !== triviaList2.count()) { + return false; + } + + for (var i = 0, n = triviaList1.count(); i < n; i++) { + if (!triviaStructuralEquals(triviaList1.syntaxTriviaAt(i), triviaList2.syntaxTriviaAt(i))) { + return false; + } + } + + return true; + } + + export function triviaStructuralEquals(trivia1: TypeScript.ISyntaxTrivia, trivia2: TypeScript.ISyntaxTrivia): boolean { + Debug.assert(trivia1.parent); + Debug.assert(trivia2.parent); + + return trivia1.kind === trivia2.kind && + trivia1.fullWidth() === trivia2.fullWidth() && + trivia1.fullText() === trivia2.fullText(); + } + + function listStructuralEquals(list1: T[], list2: T[], checkParents: boolean, text1: ISimpleText, text2: ISimpleText): boolean { + Debug.assert(TypeScript.isShared(list1) || list1.parent); + Debug.assert(TypeScript.isShared(list2) || list2.parent); + + if (childCount(list1) !== childCount(list2)) { + return false; + } + + for (var i = 0, n = childCount(list1); i < n; i++) { + var child1 = childAt(list1, i); + var child2 = childAt(list2, i); + + if (checkParents) { + assertParent(list1, child1); + assertParent(list2, child2); + } + + if (!nodeOrTokenStructuralEquals(child1, child2, checkParents, text1, text2)) { + return false; + } + } + + return true; + } + + function separatedListStructuralEquals(list1: T[], list2: T[], checkParents: boolean, text1: ISimpleText, text2: ISimpleText): boolean { + Debug.assert(TypeScript.isShared(list1) || list1.parent); + Debug.assert(TypeScript.isShared(list2) || list2.parent); + + if (childCount(list1) !== childCount(list2)) { + return false; + } + + for (var i = 0, n = childCount(list1); i < n; i++) { + var element1 = childAt(list1, i); + var element2 = childAt(list2, i); + + if (checkParents) { + assertParent(list1, element1); + assertParent(list2, element2); + } + + if (!nodeOrTokenStructuralEquals(element1, element2, checkParents, text1, text2)) { + return false; + } + } + + return true; + } + + export function elementStructuralEquals(element1: TypeScript.ISyntaxElement, element2: TypeScript.ISyntaxElement, checkParents: boolean, text1: ISimpleText, text2: ISimpleText) { + if (element1 === element2) { + return true; + } + + if (element1 === null || element2 === null) { + return false; + } + + Debug.assert(element1.kind() === SyntaxKind.SourceUnit || element1.parent); + Debug.assert(element2.kind() === SyntaxKind.SourceUnit || element2.parent); + + if (element2.kind() !== element2.kind()) { + return false; + } + + if (TypeScript.fullStart(element1) !== TypeScript.fullStart(element2)) { + return false; + } + + if (TypeScript.start(element1) !== TypeScript.start(element2)) { + return false; + } + + if (TypeScript.end(element1) !== TypeScript.end(element2)) { + return false; + } + + if (TypeScript.fullEnd(element1) !== TypeScript.fullEnd(element2)) { + return false; + } + + if (TypeScript.isToken(element1)) { + return tokenStructuralEquals(element1, element2, text1, text2); + } + else if (TypeScript.isNode(element1)) { + return nodeStructuralEquals(element1, element2, checkParents, text1, text2); + } + else if (TypeScript.isList(element1)) { + return listStructuralEquals(element1, element2, checkParents, text1, text2); + } + else if (TypeScript.isSeparatedList(element1)) { + return separatedListStructuralEquals(element1, element2, checkParents, text1, text2); + } + + throw TypeScript.Errors.invalidOperation(); + } + + export function treeStructuralEquals(tree1: TypeScript.SyntaxTree, tree2: TypeScript.SyntaxTree, checkParents: boolean): boolean { + if (!TypeScript.ArrayUtilities.sequenceEquals(tree1.diagnostics(), tree2.diagnostics(), TypeScript.Diagnostic.equals)) { + return false; + } + + return nodeStructuralEquals(tree1.sourceUnit(), tree2.sourceUnit(), checkParents, tree1.text, tree2.text); + } +} \ No newline at end of file diff --git a/src/services/syntax/unicode.ts b/src/services/syntax/unicode.ts new file mode 100644 index 00000000000..df2f88b74c5 --- /dev/null +++ b/src/services/syntax/unicode.ts @@ -0,0 +1,107 @@ +/// + +module TypeScript { + export class Unicode { + /* + As per ECMAScript Language Specification 3th Edition, Section 7.6: Identifiers + IdentifierStart :: + Can contain Unicode 3.0.0 categories: + “Uppercase letter (Lu)”, + “Lowercase letter (Ll)”, + “Titlecase letter (Lt)”, + “Modifier letter (Lm)”, + “Other letter (Lo)”, or + “Letter number (Nl)”. + IdentifierPart :: = + Can contain IdentifierStart + Unicode 3.0.0 categories: + “Non-spacing mark (Mn)”, + “Combining spacing mark (Mc)”, + “Decimal number (Nd)”, or + “Connector punctuation (Pc)”. + + Codepoint ranges for ES3 Identifiers are extracted from the Unicode 3.0.0 specification at: + http://www.unicode.org/Public/3.0-Update/UnicodeData-3.0.0.txt + */ + static unicodeES3IdentifierStart = [170,170, 181,181, 186,186, 192,214, 216,246, 248,543, 546,563, 592,685, 688,696, 699,705, 720,721, 736,740, 750,750, 890,890, 902,902, 904,906, 908,908, 910,929, 931,974, 976,983, 986,1011, 1024,1153, 1164,1220, 1223,1224, 1227,1228, 1232,1269, 1272,1273, 1329,1366, 1369,1369, 1377,1415, 1488,1514, 1520,1522, 1569,1594, 1600,1610, 1649,1747, 1749,1749, 1765,1766, 1786,1788, 1808,1808, 1810,1836, 1920,1957, 2309,2361, 2365,2365, 2384,2384, 2392,2401, 2437,2444, 2447,2448, 2451,2472, 2474,2480, 2482,2482, 2486,2489, 2524,2525, 2527,2529, 2544,2545, 2565,2570, 2575,2576, 2579,2600, 2602,2608, 2610,2611, 2613,2614, 2616,2617, 2649,2652, 2654,2654, 2674,2676, 2693,2699, 2701,2701, 2703,2705, 2707,2728, 2730,2736, 2738,2739, 2741,2745, 2749,2749, 2768,2768, 2784,2784, 2821,2828, 2831,2832, 2835,2856, 2858,2864, 2866,2867, 2870,2873, 2877,2877, 2908,2909, 2911,2913, 2949,2954, 2958,2960, 2962,2965, 2969,2970, 2972,2972, 2974,2975, 2979,2980, 2984,2986, 2990,2997, 2999,3001, 3077,3084, 3086,3088, 3090,3112, 3114,3123, 3125,3129, 3168,3169, 3205,3212, 3214,3216, 3218,3240, 3242,3251, 3253,3257, 3294,3294, 3296,3297, 3333,3340, 3342,3344, 3346,3368, 3370,3385, 3424,3425, 3461,3478, 3482,3505, 3507,3515, 3517,3517, 3520,3526, 3585,3632, 3634,3635, 3648,3654, 3713,3714, 3716,3716, 3719,3720, 3722,3722, 3725,3725, 3732,3735, 3737,3743, 3745,3747, 3749,3749, 3751,3751, 3754,3755, 3757,3760, 3762,3763, 3773,3773, 3776,3780, 3782,3782, 3804,3805, 3840,3840, 3904,3911, 3913,3946, 3976,3979, 4096,4129, 4131,4135, 4137,4138, 4176,4181, 4256,4293, 4304,4342, 4352,4441, 4447,4514, 4520,4601, 4608,4614, 4616,4678, 4680,4680, 4682,4685, 4688,4694, 4696,4696, 4698,4701, 4704,4742, 4744,4744, 4746,4749, 4752,4782, 4784,4784, 4786,4789, 4792,4798, 4800,4800, 4802,4805, 4808,4814, 4816,4822, 4824,4846, 4848,4878, 4880,4880, 4882,4885, 4888,4894, 4896,4934, 4936,4954, 5024,5108, 5121,5740, 5743,5750, 5761,5786, 5792,5866, 6016,6067, 6176,6263, 6272,6312, 7680,7835, 7840,7929, 7936,7957, 7960,7965, 7968,8005, 8008,8013, 8016,8023, 8025,8025, 8027,8027, 8029,8029, 8031,8061, 8064,8116, 8118,8124, 8126,8126, 8130,8132, 8134,8140, 8144,8147, 8150,8155, 8160,8172, 8178,8180, 8182,8188, 8319,8319, 8450,8450, 8455,8455, 8458,8467, 8469,8469, 8473,8477, 8484,8484, 8486,8486, 8488,8488, 8490,8493, 8495,8497, 8499,8505, 8544,8579, 12293,12295, 12321,12329, 12337,12341, 12344,12346, 12353,12436, 12445,12446, 12449,12538, 12540,12542, 12549,12588, 12593,12686, 12704,12727, 13312,19893, 19968,40869, 40960,42124, 44032,55203, 63744,64045, 64256,64262, 64275,64279, 64285,64285, 64287,64296, 64298,64310, 64312,64316, 64318,64318, 64320,64321, 64323,64324, 64326,64433, 64467,64829, 64848,64911, 64914,64967, 65008,65019, 65136,65138, 65140,65140, 65142,65276, 65313,65338, 65345,65370, 65382,65470, 65474,65479, 65482,65487, 65490,65495, 65498,65500, ]; + static unicodeES3IdentifierPart = [170,170, 181,181, 186,186, 192,214, 216,246, 248,543, 546,563, 592,685, 688,696, 699,705, 720,721, 736,740, 750,750, 768,846, 864,866, 890,890, 902,902, 904,906, 908,908, 910,929, 931,974, 976,983, 986,1011, 1024,1153, 1155,1158, 1164,1220, 1223,1224, 1227,1228, 1232,1269, 1272,1273, 1329,1366, 1369,1369, 1377,1415, 1425,1441, 1443,1465, 1467,1469, 1471,1471, 1473,1474, 1476,1476, 1488,1514, 1520,1522, 1569,1594, 1600,1621, 1632,1641, 1648,1747, 1749,1756, 1759,1768, 1770,1773, 1776,1788, 1808,1836, 1840,1866, 1920,1968, 2305,2307, 2309,2361, 2364,2381, 2384,2388, 2392,2403, 2406,2415, 2433,2435, 2437,2444, 2447,2448, 2451,2472, 2474,2480, 2482,2482, 2486,2489, 2492,2492, 2494,2500, 2503,2504, 2507,2509, 2519,2519, 2524,2525, 2527,2531, 2534,2545, 2562,2562, 2565,2570, 2575,2576, 2579,2600, 2602,2608, 2610,2611, 2613,2614, 2616,2617, 2620,2620, 2622,2626, 2631,2632, 2635,2637, 2649,2652, 2654,2654, 2662,2676, 2689,2691, 2693,2699, 2701,2701, 2703,2705, 2707,2728, 2730,2736, 2738,2739, 2741,2745, 2748,2757, 2759,2761, 2763,2765, 2768,2768, 2784,2784, 2790,2799, 2817,2819, 2821,2828, 2831,2832, 2835,2856, 2858,2864, 2866,2867, 2870,2873, 2876,2883, 2887,2888, 2891,2893, 2902,2903, 2908,2909, 2911,2913, 2918,2927, 2946,2947, 2949,2954, 2958,2960, 2962,2965, 2969,2970, 2972,2972, 2974,2975, 2979,2980, 2984,2986, 2990,2997, 2999,3001, 3006,3010, 3014,3016, 3018,3021, 3031,3031, 3047,3055, 3073,3075, 3077,3084, 3086,3088, 3090,3112, 3114,3123, 3125,3129, 3134,3140, 3142,3144, 3146,3149, 3157,3158, 3168,3169, 3174,3183, 3202,3203, 3205,3212, 3214,3216, 3218,3240, 3242,3251, 3253,3257, 3262,3268, 3270,3272, 3274,3277, 3285,3286, 3294,3294, 3296,3297, 3302,3311, 3330,3331, 3333,3340, 3342,3344, 3346,3368, 3370,3385, 3390,3395, 3398,3400, 3402,3405, 3415,3415, 3424,3425, 3430,3439, 3458,3459, 3461,3478, 3482,3505, 3507,3515, 3517,3517, 3520,3526, 3530,3530, 3535,3540, 3542,3542, 3544,3551, 3570,3571, 3585,3642, 3648,3662, 3664,3673, 3713,3714, 3716,3716, 3719,3720, 3722,3722, 3725,3725, 3732,3735, 3737,3743, 3745,3747, 3749,3749, 3751,3751, 3754,3755, 3757,3769, 3771,3773, 3776,3780, 3782,3782, 3784,3789, 3792,3801, 3804,3805, 3840,3840, 3864,3865, 3872,3881, 3893,3893, 3895,3895, 3897,3897, 3902,3911, 3913,3946, 3953,3972, 3974,3979, 3984,3991, 3993,4028, 4038,4038, 4096,4129, 4131,4135, 4137,4138, 4140,4146, 4150,4153, 4160,4169, 4176,4185, 4256,4293, 4304,4342, 4352,4441, 4447,4514, 4520,4601, 4608,4614, 4616,4678, 4680,4680, 4682,4685, 4688,4694, 4696,4696, 4698,4701, 4704,4742, 4744,4744, 4746,4749, 4752,4782, 4784,4784, 4786,4789, 4792,4798, 4800,4800, 4802,4805, 4808,4814, 4816,4822, 4824,4846, 4848,4878, 4880,4880, 4882,4885, 4888,4894, 4896,4934, 4936,4954, 4969,4977, 5024,5108, 5121,5740, 5743,5750, 5761,5786, 5792,5866, 6016,6099, 6112,6121, 6160,6169, 6176,6263, 6272,6313, 7680,7835, 7840,7929, 7936,7957, 7960,7965, 7968,8005, 8008,8013, 8016,8023, 8025,8025, 8027,8027, 8029,8029, 8031,8061, 8064,8116, 8118,8124, 8126,8126, 8130,8132, 8134,8140, 8144,8147, 8150,8155, 8160,8172, 8178,8180, 8182,8188, 8255,8256, 8319,8319, 8400,8412, 8417,8417, 8450,8450, 8455,8455, 8458,8467, 8469,8469, 8473,8477, 8484,8484, 8486,8486, 8488,8488, 8490,8493, 8495,8497, 8499,8505, 8544,8579, 12293,12295, 12321,12335, 12337,12341, 12344,12346, 12353,12436, 12441,12442, 12445,12446, 12449,12542, 12549,12588, 12593,12686, 12704,12727, 13312,19893, 19968,40869, 40960,42124, 44032,55203, 63744,64045, 64256,64262, 64275,64279, 64285,64296, 64298,64310, 64312,64316, 64318,64318, 64320,64321, 64323,64324, 64326,64433, 64467,64829, 64848,64911, 64914,64967, 65008,65019, 65056,65059, 65075,65076, 65101,65103, 65136,65138, 65140,65140, 65142,65276, 65296,65305, 65313,65338, 65343,65343, 65345,65370, 65381,65470, 65474,65479, 65482,65487, 65490,65495, 65498,65500, ]; + + /* + As per ECMAScript Language Specification 5th Edition, Section 7.6: ISyntaxToken Names and Identifiers + IdentifierStart :: + Can contain Unicode 6.2 categories: + “Uppercase letter (Lu)”, + “Lowercase letter (Ll)”, + “Titlecase letter (Lt)”, + “Modifier letter (Lm)”, + “Other letter (Lo)”, or + “Letter number (Nl)”. + IdentifierPart :: + Can contain IdentifierStart + Unicode 6.2 categories: + “Non-spacing mark (Mn)”, + “Combining spacing mark (Mc)”, + “Decimal number (Nd)”, + “Connector punctuation (Pc)”, + , or + . + + Codepoint ranges for ES5 Identifiers are extracted from the Unicode 6.2 specification at: + http://www.unicode.org/Public/6.2.0/ucd/UnicodeData.txt + */ + static unicodeES5IdentifierStart = [170,170, 181,181, 186,186, 192,214, 216,246, 248,705, 710,721, 736,740, 748,748, 750,750, 880,884, 886,887, 890,893, 902,902, 904,906, 908,908, 910,929, 931,1013, 1015,1153, 1162,1319, 1329,1366, 1369,1369, 1377,1415, 1488,1514, 1520,1522, 1568,1610, 1646,1647, 1649,1747, 1749,1749, 1765,1766, 1774,1775, 1786,1788, 1791,1791, 1808,1808, 1810,1839, 1869,1957, 1969,1969, 1994,2026, 2036,2037, 2042,2042, 2048,2069, 2074,2074, 2084,2084, 2088,2088, 2112,2136, 2208,2208, 2210,2220, 2308,2361, 2365,2365, 2384,2384, 2392,2401, 2417,2423, 2425,2431, 2437,2444, 2447,2448, 2451,2472, 2474,2480, 2482,2482, 2486,2489, 2493,2493, 2510,2510, 2524,2525, 2527,2529, 2544,2545, 2565,2570, 2575,2576, 2579,2600, 2602,2608, 2610,2611, 2613,2614, 2616,2617, 2649,2652, 2654,2654, 2674,2676, 2693,2701, 2703,2705, 2707,2728, 2730,2736, 2738,2739, 2741,2745, 2749,2749, 2768,2768, 2784,2785, 2821,2828, 2831,2832, 2835,2856, 2858,2864, 2866,2867, 2869,2873, 2877,2877, 2908,2909, 2911,2913, 2929,2929, 2947,2947, 2949,2954, 2958,2960, 2962,2965, 2969,2970, 2972,2972, 2974,2975, 2979,2980, 2984,2986, 2990,3001, 3024,3024, 3077,3084, 3086,3088, 3090,3112, 3114,3123, 3125,3129, 3133,3133, 3160,3161, 3168,3169, 3205,3212, 3214,3216, 3218,3240, 3242,3251, 3253,3257, 3261,3261, 3294,3294, 3296,3297, 3313,3314, 3333,3340, 3342,3344, 3346,3386, 3389,3389, 3406,3406, 3424,3425, 3450,3455, 3461,3478, 3482,3505, 3507,3515, 3517,3517, 3520,3526, 3585,3632, 3634,3635, 3648,3654, 3713,3714, 3716,3716, 3719,3720, 3722,3722, 3725,3725, 3732,3735, 3737,3743, 3745,3747, 3749,3749, 3751,3751, 3754,3755, 3757,3760, 3762,3763, 3773,3773, 3776,3780, 3782,3782, 3804,3807, 3840,3840, 3904,3911, 3913,3948, 3976,3980, 4096,4138, 4159,4159, 4176,4181, 4186,4189, 4193,4193, 4197,4198, 4206,4208, 4213,4225, 4238,4238, 4256,4293, 4295,4295, 4301,4301, 4304,4346, 4348,4680, 4682,4685, 4688,4694, 4696,4696, 4698,4701, 4704,4744, 4746,4749, 4752,4784, 4786,4789, 4792,4798, 4800,4800, 4802,4805, 4808,4822, 4824,4880, 4882,4885, 4888,4954, 4992,5007, 5024,5108, 5121,5740, 5743,5759, 5761,5786, 5792,5866, 5870,5872, 5888,5900, 5902,5905, 5920,5937, 5952,5969, 5984,5996, 5998,6000, 6016,6067, 6103,6103, 6108,6108, 6176,6263, 6272,6312, 6314,6314, 6320,6389, 6400,6428, 6480,6509, 6512,6516, 6528,6571, 6593,6599, 6656,6678, 6688,6740, 6823,6823, 6917,6963, 6981,6987, 7043,7072, 7086,7087, 7098,7141, 7168,7203, 7245,7247, 7258,7293, 7401,7404, 7406,7409, 7413,7414, 7424,7615, 7680,7957, 7960,7965, 7968,8005, 8008,8013, 8016,8023, 8025,8025, 8027,8027, 8029,8029, 8031,8061, 8064,8116, 8118,8124, 8126,8126, 8130,8132, 8134,8140, 8144,8147, 8150,8155, 8160,8172, 8178,8180, 8182,8188, 8305,8305, 8319,8319, 8336,8348, 8450,8450, 8455,8455, 8458,8467, 8469,8469, 8473,8477, 8484,8484, 8486,8486, 8488,8488, 8490,8493, 8495,8505, 8508,8511, 8517,8521, 8526,8526, 8544,8584, 11264,11310, 11312,11358, 11360,11492, 11499,11502, 11506,11507, 11520,11557, 11559,11559, 11565,11565, 11568,11623, 11631,11631, 11648,11670, 11680,11686, 11688,11694, 11696,11702, 11704,11710, 11712,11718, 11720,11726, 11728,11734, 11736,11742, 11823,11823, 12293,12295, 12321,12329, 12337,12341, 12344,12348, 12353,12438, 12445,12447, 12449,12538, 12540,12543, 12549,12589, 12593,12686, 12704,12730, 12784,12799, 13312,19893, 19968,40908, 40960,42124, 42192,42237, 42240,42508, 42512,42527, 42538,42539, 42560,42606, 42623,42647, 42656,42735, 42775,42783, 42786,42888, 42891,42894, 42896,42899, 42912,42922, 43000,43009, 43011,43013, 43015,43018, 43020,43042, 43072,43123, 43138,43187, 43250,43255, 43259,43259, 43274,43301, 43312,43334, 43360,43388, 43396,43442, 43471,43471, 43520,43560, 43584,43586, 43588,43595, 43616,43638, 43642,43642, 43648,43695, 43697,43697, 43701,43702, 43705,43709, 43712,43712, 43714,43714, 43739,43741, 43744,43754, 43762,43764, 43777,43782, 43785,43790, 43793,43798, 43808,43814, 43816,43822, 43968,44002, 44032,55203, 55216,55238, 55243,55291, 63744,64109, 64112,64217, 64256,64262, 64275,64279, 64285,64285, 64287,64296, 64298,64310, 64312,64316, 64318,64318, 64320,64321, 64323,64324, 64326,64433, 64467,64829, 64848,64911, 64914,64967, 65008,65019, 65136,65140, 65142,65276, 65313,65338, 65345,65370, 65382,65470, 65474,65479, 65482,65487, 65490,65495, 65498,65500, ]; + static unicodeES5IdentifierPart = [170,170, 181,181, 186,186, 192,214, 216,246, 248,705, 710,721, 736,740, 748,748, 750,750, 768,884, 886,887, 890,893, 902,902, 904,906, 908,908, 910,929, 931,1013, 1015,1153, 1155,1159, 1162,1319, 1329,1366, 1369,1369, 1377,1415, 1425,1469, 1471,1471, 1473,1474, 1476,1477, 1479,1479, 1488,1514, 1520,1522, 1552,1562, 1568,1641, 1646,1747, 1749,1756, 1759,1768, 1770,1788, 1791,1791, 1808,1866, 1869,1969, 1984,2037, 2042,2042, 2048,2093, 2112,2139, 2208,2208, 2210,2220, 2276,2302, 2304,2403, 2406,2415, 2417,2423, 2425,2431, 2433,2435, 2437,2444, 2447,2448, 2451,2472, 2474,2480, 2482,2482, 2486,2489, 2492,2500, 2503,2504, 2507,2510, 2519,2519, 2524,2525, 2527,2531, 2534,2545, 2561,2563, 2565,2570, 2575,2576, 2579,2600, 2602,2608, 2610,2611, 2613,2614, 2616,2617, 2620,2620, 2622,2626, 2631,2632, 2635,2637, 2641,2641, 2649,2652, 2654,2654, 2662,2677, 2689,2691, 2693,2701, 2703,2705, 2707,2728, 2730,2736, 2738,2739, 2741,2745, 2748,2757, 2759,2761, 2763,2765, 2768,2768, 2784,2787, 2790,2799, 2817,2819, 2821,2828, 2831,2832, 2835,2856, 2858,2864, 2866,2867, 2869,2873, 2876,2884, 2887,2888, 2891,2893, 2902,2903, 2908,2909, 2911,2915, 2918,2927, 2929,2929, 2946,2947, 2949,2954, 2958,2960, 2962,2965, 2969,2970, 2972,2972, 2974,2975, 2979,2980, 2984,2986, 2990,3001, 3006,3010, 3014,3016, 3018,3021, 3024,3024, 3031,3031, 3046,3055, 3073,3075, 3077,3084, 3086,3088, 3090,3112, 3114,3123, 3125,3129, 3133,3140, 3142,3144, 3146,3149, 3157,3158, 3160,3161, 3168,3171, 3174,3183, 3202,3203, 3205,3212, 3214,3216, 3218,3240, 3242,3251, 3253,3257, 3260,3268, 3270,3272, 3274,3277, 3285,3286, 3294,3294, 3296,3299, 3302,3311, 3313,3314, 3330,3331, 3333,3340, 3342,3344, 3346,3386, 3389,3396, 3398,3400, 3402,3406, 3415,3415, 3424,3427, 3430,3439, 3450,3455, 3458,3459, 3461,3478, 3482,3505, 3507,3515, 3517,3517, 3520,3526, 3530,3530, 3535,3540, 3542,3542, 3544,3551, 3570,3571, 3585,3642, 3648,3662, 3664,3673, 3713,3714, 3716,3716, 3719,3720, 3722,3722, 3725,3725, 3732,3735, 3737,3743, 3745,3747, 3749,3749, 3751,3751, 3754,3755, 3757,3769, 3771,3773, 3776,3780, 3782,3782, 3784,3789, 3792,3801, 3804,3807, 3840,3840, 3864,3865, 3872,3881, 3893,3893, 3895,3895, 3897,3897, 3902,3911, 3913,3948, 3953,3972, 3974,3991, 3993,4028, 4038,4038, 4096,4169, 4176,4253, 4256,4293, 4295,4295, 4301,4301, 4304,4346, 4348,4680, 4682,4685, 4688,4694, 4696,4696, 4698,4701, 4704,4744, 4746,4749, 4752,4784, 4786,4789, 4792,4798, 4800,4800, 4802,4805, 4808,4822, 4824,4880, 4882,4885, 4888,4954, 4957,4959, 4992,5007, 5024,5108, 5121,5740, 5743,5759, 5761,5786, 5792,5866, 5870,5872, 5888,5900, 5902,5908, 5920,5940, 5952,5971, 5984,5996, 5998,6000, 6002,6003, 6016,6099, 6103,6103, 6108,6109, 6112,6121, 6155,6157, 6160,6169, 6176,6263, 6272,6314, 6320,6389, 6400,6428, 6432,6443, 6448,6459, 6470,6509, 6512,6516, 6528,6571, 6576,6601, 6608,6617, 6656,6683, 6688,6750, 6752,6780, 6783,6793, 6800,6809, 6823,6823, 6912,6987, 6992,7001, 7019,7027, 7040,7155, 7168,7223, 7232,7241, 7245,7293, 7376,7378, 7380,7414, 7424,7654, 7676,7957, 7960,7965, 7968,8005, 8008,8013, 8016,8023, 8025,8025, 8027,8027, 8029,8029, 8031,8061, 8064,8116, 8118,8124, 8126,8126, 8130,8132, 8134,8140, 8144,8147, 8150,8155, 8160,8172, 8178,8180, 8182,8188, 8204,8205, 8255,8256, 8276,8276, 8305,8305, 8319,8319, 8336,8348, 8400,8412, 8417,8417, 8421,8432, 8450,8450, 8455,8455, 8458,8467, 8469,8469, 8473,8477, 8484,8484, 8486,8486, 8488,8488, 8490,8493, 8495,8505, 8508,8511, 8517,8521, 8526,8526, 8544,8584, 11264,11310, 11312,11358, 11360,11492, 11499,11507, 11520,11557, 11559,11559, 11565,11565, 11568,11623, 11631,11631, 11647,11670, 11680,11686, 11688,11694, 11696,11702, 11704,11710, 11712,11718, 11720,11726, 11728,11734, 11736,11742, 11744,11775, 11823,11823, 12293,12295, 12321,12335, 12337,12341, 12344,12348, 12353,12438, 12441,12442, 12445,12447, 12449,12538, 12540,12543, 12549,12589, 12593,12686, 12704,12730, 12784,12799, 13312,19893, 19968,40908, 40960,42124, 42192,42237, 42240,42508, 42512,42539, 42560,42607, 42612,42621, 42623,42647, 42655,42737, 42775,42783, 42786,42888, 42891,42894, 42896,42899, 42912,42922, 43000,43047, 43072,43123, 43136,43204, 43216,43225, 43232,43255, 43259,43259, 43264,43309, 43312,43347, 43360,43388, 43392,43456, 43471,43481, 43520,43574, 43584,43597, 43600,43609, 43616,43638, 43642,43643, 43648,43714, 43739,43741, 43744,43759, 43762,43766, 43777,43782, 43785,43790, 43793,43798, 43808,43814, 43816,43822, 43968,44010, 44012,44013, 44016,44025, 44032,55203, 55216,55238, 55243,55291, 63744,64109, 64112,64217, 64256,64262, 64275,64279, 64285,64296, 64298,64310, 64312,64316, 64318,64318, 64320,64321, 64323,64324, 64326,64433, 64467,64829, 64848,64911, 64914,64967, 65008,65019, 65024,65039, 65056,65062, 65075,65076, 65101,65103, 65136,65140, 65142,65276, 65296,65305, 65313,65338, 65343,65343, 65345,65370, 65382,65470, 65474,65479, 65482,65487, 65490,65495, 65498,65500, ]; + + static lookupInUnicodeMap(code: number, map: number[]): boolean { + // Bail out quickly if it couldn't possibly be in the map. + if (code < map[0]) { + return false; + } + + // Perform binary search in one of the unicode range maps + var lo: number = 0; + var hi: number = map.length; + var mid: number; + + while (lo + 1 < hi) { + mid = lo + (hi - lo) / 2; + // mid has to be even to catch a range's beginning + mid -= mid % 2; + if (map[mid] <= code && code <= map[mid + 1]) { + return true; + } + + if (code < map[mid]) { + hi = mid; + } + else { + lo = mid + 2; + } + } + + return false; + } + + public static isIdentifierStart(code: number, languageVersion: ts.ScriptTarget) { + if (languageVersion === ts.ScriptTarget.ES3) { + return Unicode.lookupInUnicodeMap(code, Unicode.unicodeES3IdentifierStart); + } + else if (languageVersion === ts.ScriptTarget.ES5) { + return Unicode.lookupInUnicodeMap(code, Unicode.unicodeES5IdentifierStart); + } + else { + throw Errors.argumentOutOfRange("languageVersion"); + } + } + + public static isIdentifierPart(code: number, languageVersion: ts.ScriptTarget) { + if (languageVersion === ts.ScriptTarget.ES3) { + return Unicode.lookupInUnicodeMap(code, Unicode.unicodeES3IdentifierPart); + } + else if (languageVersion === ts.ScriptTarget.ES5) { + return Unicode.lookupInUnicodeMap(code, Unicode.unicodeES5IdentifierPart); + } + else { + throw Errors.argumentOutOfRange("languageVersion"); + } + } + } +} \ No newline at end of file diff --git a/src/services/syntaxRewriter.generated.ts b/src/services/syntaxRewriter.generated.ts new file mode 100644 index 00000000000..110fdb22c2a --- /dev/null +++ b/src/services/syntaxRewriter.generated.ts @@ -0,0 +1,708 @@ +/// + +module TypeScript { + export class SyntaxRewriter implements ISyntaxVisitor { + public visitToken(token: ISyntaxToken): ISyntaxToken { + return token; + } + + public visitNode(node: ISyntaxNode): ISyntaxNode { + return visitNodeOrToken(this, node); + } + + public visitNodeOrToken(node: ISyntaxNodeOrToken): ISyntaxNodeOrToken { + return isToken(node) ? this.visitToken(node) : this.visitNode(node); + } + + public visitList(list: T[]): T[] { + var newItems: T[] = null; + + for (var i = 0, n = list.length; i < n; i++) { + var item = list[i]; + var newItem = this.visitNodeOrToken(item); + + if (item !== newItem && newItems === null) { + newItems = []; + for (var j = 0; j < i; j++) { + newItems.push(list[j]); + } + } + + if (newItems) { + newItems.push(newItem); + } + } + + // Debug.assert(newItems === null || newItems.length === childCount(list)); + return newItems === null ? list : Syntax.list(newItems); + } + + public visitSeparatedList(list: T[]): T[] { + var newItems: ISyntaxNodeOrToken[] = null; + + for (var i = 0, n = childCount(list); i < n; i++) { + var item = childAt(list, i); + var newItem = isToken(item) ? this.visitToken(item) : this.visitNode(item); + + if (item !== newItem && newItems === null) { + newItems = []; + for (var j = 0; j < i; j++) { + newItems.push(childAt(list, j)); + } + } + + if (newItems) { + newItems.push(newItem); + } + } + + // Debug.assert(newItems === null || newItems.length === childCount(list)); + return newItems === null ? list : Syntax.separatedList(newItems); + } + + public visitSourceUnit(node: SourceUnitSyntax): any { + return node.update( + this.visitList(node.moduleElements), + this.visitToken(node.endOfFileToken)); + } + + public visitQualifiedName(node: QualifiedNameSyntax): any { + return node.update( + this.visitNodeOrToken(node.left), + this.visitToken(node.dotToken), + this.visitToken(node.right)); + } + + public visitObjectType(node: ObjectTypeSyntax): any { + return node.update( + this.visitToken(node.openBraceToken), + this.visitSeparatedList(node.typeMembers), + this.visitToken(node.closeBraceToken)); + } + + public visitFunctionType(node: FunctionTypeSyntax): any { + return node.update( + node.typeParameterList === null ? null : this.visitNode(node.typeParameterList), + this.visitNode(node.parameterList), + this.visitToken(node.equalsGreaterThanToken), + this.visitNodeOrToken(node.type)); + } + + public visitArrayType(node: ArrayTypeSyntax): any { + return node.update( + this.visitNodeOrToken(node.type), + this.visitToken(node.openBracketToken), + this.visitToken(node.closeBracketToken)); + } + + public visitConstructorType(node: ConstructorTypeSyntax): any { + return node.update( + this.visitToken(node.newKeyword), + node.typeParameterList === null ? null : this.visitNode(node.typeParameterList), + this.visitNode(node.parameterList), + this.visitToken(node.equalsGreaterThanToken), + this.visitNodeOrToken(node.type)); + } + + public visitGenericType(node: GenericTypeSyntax): any { + return node.update( + this.visitNodeOrToken(node.name), + this.visitNode(node.typeArgumentList)); + } + + public visitTypeQuery(node: TypeQuerySyntax): any { + return node.update( + this.visitToken(node.typeOfKeyword), + this.visitNodeOrToken(node.name)); + } + + public visitInterfaceDeclaration(node: InterfaceDeclarationSyntax): any { + return node.update( + this.visitList(node.modifiers), + this.visitToken(node.interfaceKeyword), + this.visitToken(node.identifier), + node.typeParameterList === null ? null : this.visitNode(node.typeParameterList), + this.visitList(node.heritageClauses), + this.visitNode(node.body)); + } + + public visitFunctionDeclaration(node: FunctionDeclarationSyntax): any { + return node.update( + this.visitList(node.modifiers), + this.visitToken(node.functionKeyword), + this.visitToken(node.identifier), + this.visitNode(node.callSignature), + node.block === null ? null : this.visitNode(node.block), + node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); + } + + public visitModuleDeclaration(node: ModuleDeclarationSyntax): any { + return node.update( + this.visitList(node.modifiers), + this.visitToken(node.moduleKeyword), + node.name === null ? null : this.visitNodeOrToken(node.name), + node.stringLiteral === null ? null : this.visitToken(node.stringLiteral), + this.visitToken(node.openBraceToken), + this.visitList(node.moduleElements), + this.visitToken(node.closeBraceToken)); + } + + public visitClassDeclaration(node: ClassDeclarationSyntax): any { + return node.update( + this.visitList(node.modifiers), + this.visitToken(node.classKeyword), + this.visitToken(node.identifier), + node.typeParameterList === null ? null : this.visitNode(node.typeParameterList), + this.visitList(node.heritageClauses), + this.visitToken(node.openBraceToken), + this.visitList(node.classElements), + this.visitToken(node.closeBraceToken)); + } + + public visitEnumDeclaration(node: EnumDeclarationSyntax): any { + return node.update( + this.visitList(node.modifiers), + this.visitToken(node.enumKeyword), + this.visitToken(node.identifier), + this.visitToken(node.openBraceToken), + this.visitSeparatedList(node.enumElements), + this.visitToken(node.closeBraceToken)); + } + + public visitImportDeclaration(node: ImportDeclarationSyntax): any { + return node.update( + this.visitList(node.modifiers), + this.visitToken(node.importKeyword), + this.visitToken(node.identifier), + this.visitToken(node.equalsToken), + this.visitNodeOrToken(node.moduleReference), + node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); + } + + public visitExportAssignment(node: ExportAssignmentSyntax): any { + return node.update( + this.visitToken(node.exportKeyword), + this.visitToken(node.equalsToken), + this.visitToken(node.identifier), + node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); + } + + public visitMemberFunctionDeclaration(node: MemberFunctionDeclarationSyntax): any { + return node.update( + this.visitList(node.modifiers), + this.visitToken(node.propertyName), + this.visitNode(node.callSignature), + node.block === null ? null : this.visitNode(node.block), + node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); + } + + public visitMemberVariableDeclaration(node: MemberVariableDeclarationSyntax): any { + return node.update( + this.visitList(node.modifiers), + this.visitNode(node.variableDeclarator), + node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); + } + + public visitConstructorDeclaration(node: ConstructorDeclarationSyntax): any { + return node.update( + this.visitList(node.modifiers), + this.visitToken(node.constructorKeyword), + this.visitNode(node.callSignature), + node.block === null ? null : this.visitNode(node.block), + node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); + } + + public visitIndexMemberDeclaration(node: IndexMemberDeclarationSyntax): any { + return node.update( + this.visitList(node.modifiers), + this.visitNode(node.indexSignature), + node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); + } + + public visitGetAccessor(node: GetAccessorSyntax): any { + return node.update( + this.visitList(node.modifiers), + this.visitToken(node.getKeyword), + this.visitToken(node.propertyName), + this.visitNode(node.callSignature), + this.visitNode(node.block)); + } + + public visitSetAccessor(node: SetAccessorSyntax): any { + return node.update( + this.visitList(node.modifiers), + this.visitToken(node.setKeyword), + this.visitToken(node.propertyName), + this.visitNode(node.callSignature), + this.visitNode(node.block)); + } + + public visitPropertySignature(node: PropertySignatureSyntax): any { + return node.update( + this.visitToken(node.propertyName), + node.questionToken === null ? null : this.visitToken(node.questionToken), + node.typeAnnotation === null ? null : this.visitNode(node.typeAnnotation)); + } + + public visitCallSignature(node: CallSignatureSyntax): any { + return node.update( + node.typeParameterList === null ? null : this.visitNode(node.typeParameterList), + this.visitNode(node.parameterList), + node.typeAnnotation === null ? null : this.visitNode(node.typeAnnotation)); + } + + public visitConstructSignature(node: ConstructSignatureSyntax): any { + return node.update( + this.visitToken(node.newKeyword), + this.visitNode(node.callSignature)); + } + + public visitIndexSignature(node: IndexSignatureSyntax): any { + return node.update( + this.visitToken(node.openBracketToken), + this.visitSeparatedList(node.parameters), + this.visitToken(node.closeBracketToken), + node.typeAnnotation === null ? null : this.visitNode(node.typeAnnotation)); + } + + public visitMethodSignature(node: MethodSignatureSyntax): any { + return node.update( + this.visitToken(node.propertyName), + node.questionToken === null ? null : this.visitToken(node.questionToken), + this.visitNode(node.callSignature)); + } + + public visitBlock(node: BlockSyntax): any { + return node.update( + this.visitToken(node.openBraceToken), + this.visitList(node.statements), + this.visitToken(node.closeBraceToken)); + } + + public visitIfStatement(node: IfStatementSyntax): any { + return node.update( + this.visitToken(node.ifKeyword), + this.visitToken(node.openParenToken), + this.visitNodeOrToken(node.condition), + this.visitToken(node.closeParenToken), + this.visitNodeOrToken(node.statement), + node.elseClause === null ? null : this.visitNode(node.elseClause)); + } + + public visitVariableStatement(node: VariableStatementSyntax): any { + return node.update( + this.visitList(node.modifiers), + this.visitNode(node.variableDeclaration), + node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); + } + + public visitExpressionStatement(node: ExpressionStatementSyntax): any { + return node.update( + this.visitNodeOrToken(node.expression), + node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); + } + + public visitReturnStatement(node: ReturnStatementSyntax): any { + return node.update( + this.visitToken(node.returnKeyword), + node.expression === null ? null : this.visitNodeOrToken(node.expression), + node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); + } + + public visitSwitchStatement(node: SwitchStatementSyntax): any { + return node.update( + this.visitToken(node.switchKeyword), + this.visitToken(node.openParenToken), + this.visitNodeOrToken(node.expression), + this.visitToken(node.closeParenToken), + this.visitToken(node.openBraceToken), + this.visitList(node.switchClauses), + this.visitToken(node.closeBraceToken)); + } + + public visitBreakStatement(node: BreakStatementSyntax): any { + return node.update( + this.visitToken(node.breakKeyword), + node.identifier === null ? null : this.visitToken(node.identifier), + node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); + } + + public visitContinueStatement(node: ContinueStatementSyntax): any { + return node.update( + this.visitToken(node.continueKeyword), + node.identifier === null ? null : this.visitToken(node.identifier), + node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); + } + + public visitForStatement(node: ForStatementSyntax): any { + return node.update( + this.visitToken(node.forKeyword), + this.visitToken(node.openParenToken), + node.variableDeclaration === null ? null : this.visitNode(node.variableDeclaration), + node.initializer === null ? null : this.visitNodeOrToken(node.initializer), + this.visitToken(node.firstSemicolonToken), + node.condition === null ? null : this.visitNodeOrToken(node.condition), + this.visitToken(node.secondSemicolonToken), + node.incrementor === null ? null : this.visitNodeOrToken(node.incrementor), + this.visitToken(node.closeParenToken), + this.visitNodeOrToken(node.statement)); + } + + public visitForInStatement(node: ForInStatementSyntax): any { + return node.update( + this.visitToken(node.forKeyword), + this.visitToken(node.openParenToken), + node.variableDeclaration === null ? null : this.visitNode(node.variableDeclaration), + node.left === null ? null : this.visitNodeOrToken(node.left), + this.visitToken(node.inKeyword), + this.visitNodeOrToken(node.expression), + this.visitToken(node.closeParenToken), + this.visitNodeOrToken(node.statement)); + } + + public visitEmptyStatement(node: EmptyStatementSyntax): any { + return node.update( + this.visitToken(node.semicolonToken)); + } + + public visitThrowStatement(node: ThrowStatementSyntax): any { + return node.update( + this.visitToken(node.throwKeyword), + this.visitNodeOrToken(node.expression), + node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); + } + + public visitWhileStatement(node: WhileStatementSyntax): any { + return node.update( + this.visitToken(node.whileKeyword), + this.visitToken(node.openParenToken), + this.visitNodeOrToken(node.condition), + this.visitToken(node.closeParenToken), + this.visitNodeOrToken(node.statement)); + } + + public visitTryStatement(node: TryStatementSyntax): any { + return node.update( + this.visitToken(node.tryKeyword), + this.visitNode(node.block), + node.catchClause === null ? null : this.visitNode(node.catchClause), + node.finallyClause === null ? null : this.visitNode(node.finallyClause)); + } + + public visitLabeledStatement(node: LabeledStatementSyntax): any { + return node.update( + this.visitToken(node.identifier), + this.visitToken(node.colonToken), + this.visitNodeOrToken(node.statement)); + } + + public visitDoStatement(node: DoStatementSyntax): any { + return node.update( + this.visitToken(node.doKeyword), + this.visitNodeOrToken(node.statement), + this.visitToken(node.whileKeyword), + this.visitToken(node.openParenToken), + this.visitNodeOrToken(node.condition), + this.visitToken(node.closeParenToken), + node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); + } + + public visitDebuggerStatement(node: DebuggerStatementSyntax): any { + return node.update( + this.visitToken(node.debuggerKeyword), + node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); + } + + public visitWithStatement(node: WithStatementSyntax): any { + return node.update( + this.visitToken(node.withKeyword), + this.visitToken(node.openParenToken), + this.visitNodeOrToken(node.condition), + this.visitToken(node.closeParenToken), + this.visitNodeOrToken(node.statement)); + } + + public visitPrefixUnaryExpression(node: PrefixUnaryExpressionSyntax): any { + return node.update( + this.visitToken(node.operatorToken), + this.visitNodeOrToken(node.operand)); + } + + public visitDeleteExpression(node: DeleteExpressionSyntax): any { + return node.update( + this.visitToken(node.deleteKeyword), + this.visitNodeOrToken(node.expression)); + } + + public visitTypeOfExpression(node: TypeOfExpressionSyntax): any { + return node.update( + this.visitToken(node.typeOfKeyword), + this.visitNodeOrToken(node.expression)); + } + + public visitVoidExpression(node: VoidExpressionSyntax): any { + return node.update( + this.visitToken(node.voidKeyword), + this.visitNodeOrToken(node.expression)); + } + + public visitConditionalExpression(node: ConditionalExpressionSyntax): any { + return node.update( + this.visitNodeOrToken(node.condition), + this.visitToken(node.questionToken), + this.visitNodeOrToken(node.whenTrue), + this.visitToken(node.colonToken), + this.visitNodeOrToken(node.whenFalse)); + } + + public visitBinaryExpression(node: BinaryExpressionSyntax): any { + return node.update( + this.visitNodeOrToken(node.left), + this.visitToken(node.operatorToken), + this.visitNodeOrToken(node.right)); + } + + public visitPostfixUnaryExpression(node: PostfixUnaryExpressionSyntax): any { + return node.update( + this.visitNodeOrToken(node.operand), + this.visitToken(node.operatorToken)); + } + + public visitMemberAccessExpression(node: MemberAccessExpressionSyntax): any { + return node.update( + this.visitNodeOrToken(node.expression), + this.visitToken(node.dotToken), + this.visitToken(node.name)); + } + + public visitInvocationExpression(node: InvocationExpressionSyntax): any { + return node.update( + this.visitNodeOrToken(node.expression), + this.visitNode(node.argumentList)); + } + + public visitArrayLiteralExpression(node: ArrayLiteralExpressionSyntax): any { + return node.update( + this.visitToken(node.openBracketToken), + this.visitSeparatedList(node.expressions), + this.visitToken(node.closeBracketToken)); + } + + public visitObjectLiteralExpression(node: ObjectLiteralExpressionSyntax): any { + return node.update( + this.visitToken(node.openBraceToken), + this.visitSeparatedList(node.propertyAssignments), + this.visitToken(node.closeBraceToken)); + } + + public visitObjectCreationExpression(node: ObjectCreationExpressionSyntax): any { + return node.update( + this.visitToken(node.newKeyword), + this.visitNodeOrToken(node.expression), + node.argumentList === null ? null : this.visitNode(node.argumentList)); + } + + public visitParenthesizedExpression(node: ParenthesizedExpressionSyntax): any { + return node.update( + this.visitToken(node.openParenToken), + this.visitNodeOrToken(node.expression), + this.visitToken(node.closeParenToken)); + } + + public visitParenthesizedArrowFunctionExpression(node: ParenthesizedArrowFunctionExpressionSyntax): any { + return node.update( + this.visitNode(node.callSignature), + this.visitToken(node.equalsGreaterThanToken), + node.block === null ? null : this.visitNode(node.block), + node.expression === null ? null : this.visitNodeOrToken(node.expression)); + } + + public visitSimpleArrowFunctionExpression(node: SimpleArrowFunctionExpressionSyntax): any { + return node.update( + this.visitNode(node.parameter), + this.visitToken(node.equalsGreaterThanToken), + node.block === null ? null : this.visitNode(node.block), + node.expression === null ? null : this.visitNodeOrToken(node.expression)); + } + + public visitCastExpression(node: CastExpressionSyntax): any { + return node.update( + this.visitToken(node.lessThanToken), + this.visitNodeOrToken(node.type), + this.visitToken(node.greaterThanToken), + this.visitNodeOrToken(node.expression)); + } + + public visitElementAccessExpression(node: ElementAccessExpressionSyntax): any { + return node.update( + this.visitNodeOrToken(node.expression), + this.visitToken(node.openBracketToken), + this.visitNodeOrToken(node.argumentExpression), + this.visitToken(node.closeBracketToken)); + } + + public visitFunctionExpression(node: FunctionExpressionSyntax): any { + return node.update( + this.visitToken(node.functionKeyword), + node.identifier === null ? null : this.visitToken(node.identifier), + this.visitNode(node.callSignature), + this.visitNode(node.block)); + } + + public visitOmittedExpression(node: OmittedExpressionSyntax): any { + return node; + } + + public visitVariableDeclaration(node: VariableDeclarationSyntax): any { + return node.update( + this.visitToken(node.varKeyword), + this.visitSeparatedList(node.variableDeclarators)); + } + + public visitVariableDeclarator(node: VariableDeclaratorSyntax): any { + return node.update( + this.visitToken(node.propertyName), + node.typeAnnotation === null ? null : this.visitNode(node.typeAnnotation), + node.equalsValueClause === null ? null : this.visitNode(node.equalsValueClause)); + } + + public visitArgumentList(node: ArgumentListSyntax): any { + return node.update( + node.typeArgumentList === null ? null : this.visitNode(node.typeArgumentList), + this.visitToken(node.openParenToken), + this.visitSeparatedList(node.arguments), + this.visitToken(node.closeParenToken)); + } + + public visitParameterList(node: ParameterListSyntax): any { + return node.update( + this.visitToken(node.openParenToken), + this.visitSeparatedList(node.parameters), + this.visitToken(node.closeParenToken)); + } + + public visitTypeArgumentList(node: TypeArgumentListSyntax): any { + return node.update( + this.visitToken(node.lessThanToken), + this.visitSeparatedList(node.typeArguments), + this.visitToken(node.greaterThanToken)); + } + + public visitTypeParameterList(node: TypeParameterListSyntax): any { + return node.update( + this.visitToken(node.lessThanToken), + this.visitSeparatedList(node.typeParameters), + this.visitToken(node.greaterThanToken)); + } + + public visitHeritageClause(node: HeritageClauseSyntax): any { + return node.update( + this.visitToken(node.extendsOrImplementsKeyword), + this.visitSeparatedList(node.typeNames)); + } + + public visitEqualsValueClause(node: EqualsValueClauseSyntax): any { + return node.update( + this.visitToken(node.equalsToken), + this.visitNodeOrToken(node.value)); + } + + public visitCaseSwitchClause(node: CaseSwitchClauseSyntax): any { + return node.update( + this.visitToken(node.caseKeyword), + this.visitNodeOrToken(node.expression), + this.visitToken(node.colonToken), + this.visitList(node.statements)); + } + + public visitDefaultSwitchClause(node: DefaultSwitchClauseSyntax): any { + return node.update( + this.visitToken(node.defaultKeyword), + this.visitToken(node.colonToken), + this.visitList(node.statements)); + } + + public visitElseClause(node: ElseClauseSyntax): any { + return node.update( + this.visitToken(node.elseKeyword), + this.visitNodeOrToken(node.statement)); + } + + public visitCatchClause(node: CatchClauseSyntax): any { + return node.update( + this.visitToken(node.catchKeyword), + this.visitToken(node.openParenToken), + this.visitToken(node.identifier), + node.typeAnnotation === null ? null : this.visitNode(node.typeAnnotation), + this.visitToken(node.closeParenToken), + this.visitNode(node.block)); + } + + public visitFinallyClause(node: FinallyClauseSyntax): any { + return node.update( + this.visitToken(node.finallyKeyword), + this.visitNode(node.block)); + } + + public visitTypeParameter(node: TypeParameterSyntax): any { + return node.update( + this.visitToken(node.identifier), + node.constraint === null ? null : this.visitNode(node.constraint)); + } + + public visitConstraint(node: ConstraintSyntax): any { + return node.update( + this.visitToken(node.extendsKeyword), + this.visitNodeOrToken(node.typeOrExpression)); + } + + public visitSimplePropertyAssignment(node: SimplePropertyAssignmentSyntax): any { + return node.update( + this.visitToken(node.propertyName), + this.visitToken(node.colonToken), + this.visitNodeOrToken(node.expression)); + } + + public visitFunctionPropertyAssignment(node: FunctionPropertyAssignmentSyntax): any { + return node.update( + this.visitToken(node.propertyName), + this.visitNode(node.callSignature), + this.visitNode(node.block)); + } + + public visitParameter(node: ParameterSyntax): any { + return node.update( + node.dotDotDotToken === null ? null : this.visitToken(node.dotDotDotToken), + this.visitList(node.modifiers), + this.visitToken(node.identifier), + node.questionToken === null ? null : this.visitToken(node.questionToken), + node.typeAnnotation === null ? null : this.visitNode(node.typeAnnotation), + node.equalsValueClause === null ? null : this.visitNode(node.equalsValueClause)); + } + + public visitEnumElement(node: EnumElementSyntax): any { + return node.update( + this.visitToken(node.propertyName), + node.equalsValueClause === null ? null : this.visitNode(node.equalsValueClause)); + } + + public visitTypeAnnotation(node: TypeAnnotationSyntax): any { + return node.update( + this.visitToken(node.colonToken), + this.visitNodeOrToken(node.type)); + } + + public visitExternalModuleReference(node: ExternalModuleReferenceSyntax): any { + return node.update( + this.visitToken(node.requireKeyword), + this.visitToken(node.openParenToken), + this.visitToken(node.stringLiteral), + this.visitToken(node.closeParenToken)); + } + + public visitModuleNameModuleReference(node: ModuleNameModuleReferenceSyntax): any { + return node.update( + this.visitNodeOrToken(node.moduleName)); + } + } +} \ No newline at end of file diff --git a/src/services/syntaxUtilities.generated.ts b/src/services/syntaxUtilities.generated.ts new file mode 100644 index 00000000000..9ec244141fc --- /dev/null +++ b/src/services/syntaxUtilities.generated.ts @@ -0,0 +1,395 @@ +module TypeScript { + function isSeparatedListTypeScriptSpecific(list: ISyntaxNodeOrToken[]): boolean { + for (var i = 0, n = childCount(list); i < n; i++) { + if (isTypeScriptSpecific(childAt(list, i))) { + return true; + } + } + + return false; + } + + function isListTypeScriptSpecific(list: ISyntaxNodeOrToken[]): boolean { + for (var i = 0, n = list.length; i < n; i++) { + if (isTypeScriptSpecific(list[i])) { + return true; + } + } + + return false; + } + + export function isTypeScriptSpecific(element: ISyntaxElement): boolean { + if (element === null) { return false; } + if (isToken(element)) { return false; } + if (isList(element)) { return isListTypeScriptSpecific(element); } + if (isSeparatedList(element)) { return isSeparatedListTypeScriptSpecific(element); } + + switch (element.kind()) { + case SyntaxKind.QualifiedName: + case SyntaxKind.ObjectType: + case SyntaxKind.FunctionType: + case SyntaxKind.ArrayType: + case SyntaxKind.ConstructorType: + case SyntaxKind.GenericType: + case SyntaxKind.TypeQuery: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.ImportDeclaration: + case SyntaxKind.ExportAssignment: + case SyntaxKind.MemberFunctionDeclaration: + case SyntaxKind.MemberVariableDeclaration: + case SyntaxKind.ConstructorDeclaration: + case SyntaxKind.IndexMemberDeclaration: + case SyntaxKind.SetAccessor: + case SyntaxKind.PropertySignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.IndexSignature: + case SyntaxKind.ParenthesizedArrowFunctionExpression: + case SyntaxKind.SimpleArrowFunctionExpression: + case SyntaxKind.CastExpression: + case SyntaxKind.TypeArgumentList: + case SyntaxKind.TypeParameterList: + case SyntaxKind.ExtendsHeritageClause: + case SyntaxKind.ImplementsHeritageClause: + case SyntaxKind.TypeParameter: + case SyntaxKind.Constraint: + case SyntaxKind.TypeAnnotation: + case SyntaxKind.ExternalModuleReference: + case SyntaxKind.ModuleNameModuleReference: + return true; + case SyntaxKind.BreakStatement: + case SyntaxKind.ContinueStatement: + case SyntaxKind.EmptyStatement: + case SyntaxKind.DebuggerStatement: + case SyntaxKind.OmittedExpression: + return false; + case SyntaxKind.SourceUnit: + return isSourceUnitTypeScriptSpecific(element); + case SyntaxKind.FunctionDeclaration: + return isFunctionDeclarationTypeScriptSpecific(element); + case SyntaxKind.GetAccessor: + return isGetAccessorTypeScriptSpecific(element); + case SyntaxKind.CallSignature: + return isCallSignatureTypeScriptSpecific(element); + case SyntaxKind.MethodSignature: + return isMethodSignatureTypeScriptSpecific(element); + case SyntaxKind.Block: + return isBlockTypeScriptSpecific(element); + case SyntaxKind.IfStatement: + return isIfStatementTypeScriptSpecific(element); + case SyntaxKind.VariableStatement: + return isVariableStatementTypeScriptSpecific(element); + case SyntaxKind.ExpressionStatement: + return isExpressionStatementTypeScriptSpecific(element); + case SyntaxKind.ReturnStatement: + return isReturnStatementTypeScriptSpecific(element); + case SyntaxKind.SwitchStatement: + return isSwitchStatementTypeScriptSpecific(element); + case SyntaxKind.ForStatement: + return isForStatementTypeScriptSpecific(element); + case SyntaxKind.ForInStatement: + return isForInStatementTypeScriptSpecific(element); + case SyntaxKind.ThrowStatement: + return isThrowStatementTypeScriptSpecific(element); + case SyntaxKind.WhileStatement: + return isWhileStatementTypeScriptSpecific(element); + case SyntaxKind.TryStatement: + return isTryStatementTypeScriptSpecific(element); + case SyntaxKind.LabeledStatement: + return isLabeledStatementTypeScriptSpecific(element); + case SyntaxKind.DoStatement: + return isDoStatementTypeScriptSpecific(element); + case SyntaxKind.WithStatement: + return isWithStatementTypeScriptSpecific(element); + case SyntaxKind.PreIncrementExpression: case SyntaxKind.PreDecrementExpression: case SyntaxKind.PlusExpression: case SyntaxKind.NegateExpression: case SyntaxKind.BitwiseNotExpression: case SyntaxKind.LogicalNotExpression: + return isPrefixUnaryExpressionTypeScriptSpecific(element); + case SyntaxKind.DeleteExpression: + return isDeleteExpressionTypeScriptSpecific(element); + case SyntaxKind.TypeOfExpression: + return isTypeOfExpressionTypeScriptSpecific(element); + case SyntaxKind.VoidExpression: + return isVoidExpressionTypeScriptSpecific(element); + case SyntaxKind.ConditionalExpression: + return isConditionalExpressionTypeScriptSpecific(element); + case SyntaxKind.MultiplyExpression: case SyntaxKind.DivideExpression: case SyntaxKind.ModuloExpression: case SyntaxKind.AddExpression: case SyntaxKind.SubtractExpression: case SyntaxKind.LeftShiftExpression: case SyntaxKind.SignedRightShiftExpression: case SyntaxKind.UnsignedRightShiftExpression: case SyntaxKind.LessThanExpression: case SyntaxKind.GreaterThanExpression: case SyntaxKind.LessThanOrEqualExpression: case SyntaxKind.GreaterThanOrEqualExpression: case SyntaxKind.InstanceOfExpression: case SyntaxKind.InExpression: case SyntaxKind.EqualsWithTypeConversionExpression: case SyntaxKind.NotEqualsWithTypeConversionExpression: case SyntaxKind.EqualsExpression: case SyntaxKind.NotEqualsExpression: case SyntaxKind.BitwiseAndExpression: case SyntaxKind.BitwiseExclusiveOrExpression: case SyntaxKind.BitwiseOrExpression: case SyntaxKind.LogicalAndExpression: case SyntaxKind.LogicalOrExpression: case SyntaxKind.OrAssignmentExpression: case SyntaxKind.AndAssignmentExpression: case SyntaxKind.ExclusiveOrAssignmentExpression: case SyntaxKind.LeftShiftAssignmentExpression: case SyntaxKind.SignedRightShiftAssignmentExpression: case SyntaxKind.UnsignedRightShiftAssignmentExpression: case SyntaxKind.AddAssignmentExpression: case SyntaxKind.SubtractAssignmentExpression: case SyntaxKind.MultiplyAssignmentExpression: case SyntaxKind.DivideAssignmentExpression: case SyntaxKind.ModuloAssignmentExpression: case SyntaxKind.AssignmentExpression: case SyntaxKind.CommaExpression: + return isBinaryExpressionTypeScriptSpecific(element); + case SyntaxKind.PostIncrementExpression: case SyntaxKind.PostDecrementExpression: + return isPostfixUnaryExpressionTypeScriptSpecific(element); + case SyntaxKind.MemberAccessExpression: + return isMemberAccessExpressionTypeScriptSpecific(element); + case SyntaxKind.InvocationExpression: + return isInvocationExpressionTypeScriptSpecific(element); + case SyntaxKind.ArrayLiteralExpression: + return isArrayLiteralExpressionTypeScriptSpecific(element); + case SyntaxKind.ObjectLiteralExpression: + return isObjectLiteralExpressionTypeScriptSpecific(element); + case SyntaxKind.ObjectCreationExpression: + return isObjectCreationExpressionTypeScriptSpecific(element); + case SyntaxKind.ParenthesizedExpression: + return isParenthesizedExpressionTypeScriptSpecific(element); + case SyntaxKind.ElementAccessExpression: + return isElementAccessExpressionTypeScriptSpecific(element); + case SyntaxKind.FunctionExpression: + return isFunctionExpressionTypeScriptSpecific(element); + case SyntaxKind.VariableDeclaration: + return isVariableDeclarationTypeScriptSpecific(element); + case SyntaxKind.VariableDeclarator: + return isVariableDeclaratorTypeScriptSpecific(element); + case SyntaxKind.ArgumentList: + return isArgumentListTypeScriptSpecific(element); + case SyntaxKind.ParameterList: + return isParameterListTypeScriptSpecific(element); + case SyntaxKind.EqualsValueClause: + return isEqualsValueClauseTypeScriptSpecific(element); + case SyntaxKind.CaseSwitchClause: + return isCaseSwitchClauseTypeScriptSpecific(element); + case SyntaxKind.DefaultSwitchClause: + return isDefaultSwitchClauseTypeScriptSpecific(element); + case SyntaxKind.ElseClause: + return isElseClauseTypeScriptSpecific(element); + case SyntaxKind.CatchClause: + return isCatchClauseTypeScriptSpecific(element); + case SyntaxKind.FinallyClause: + return isFinallyClauseTypeScriptSpecific(element); + case SyntaxKind.SimplePropertyAssignment: + return isSimplePropertyAssignmentTypeScriptSpecific(element); + case SyntaxKind.FunctionPropertyAssignment: + return isFunctionPropertyAssignmentTypeScriptSpecific(element); + case SyntaxKind.Parameter: + return isParameterTypeScriptSpecific(element); + case SyntaxKind.EnumElement: + return isEnumElementTypeScriptSpecific(element); + } + } + + function isSourceUnitTypeScriptSpecific(node: SourceUnitSyntax): boolean { + return isTypeScriptSpecific(node.moduleElements); + } + + function isFunctionDeclarationTypeScriptSpecific(node: FunctionDeclarationSyntax): boolean { + return node.modifiers.length > 0 || + isTypeScriptSpecific(node.callSignature) || + isTypeScriptSpecific(node.block); + } + + function isGetAccessorTypeScriptSpecific(node: GetAccessorSyntax): boolean { + return node.modifiers.length > 0 || + isTypeScriptSpecific(node.callSignature) || + isTypeScriptSpecific(node.block); + } + + function isCallSignatureTypeScriptSpecific(node: CallSignatureSyntax): boolean { + return node.typeParameterList !== null || + isTypeScriptSpecific(node.parameterList) || + node.typeAnnotation !== null; + } + + function isMethodSignatureTypeScriptSpecific(node: MethodSignatureSyntax): boolean { + return isTypeScriptSpecific(node.callSignature); + } + + function isBlockTypeScriptSpecific(node: BlockSyntax): boolean { + return isTypeScriptSpecific(node.statements); + } + + function isIfStatementTypeScriptSpecific(node: IfStatementSyntax): boolean { + return isTypeScriptSpecific(node.condition) || + isTypeScriptSpecific(node.statement) || + isTypeScriptSpecific(node.elseClause); + } + + function isVariableStatementTypeScriptSpecific(node: VariableStatementSyntax): boolean { + return node.modifiers.length > 0 || + isTypeScriptSpecific(node.variableDeclaration); + } + + function isExpressionStatementTypeScriptSpecific(node: ExpressionStatementSyntax): boolean { + return isTypeScriptSpecific(node.expression); + } + + function isReturnStatementTypeScriptSpecific(node: ReturnStatementSyntax): boolean { + return isTypeScriptSpecific(node.expression); + } + + function isSwitchStatementTypeScriptSpecific(node: SwitchStatementSyntax): boolean { + return isTypeScriptSpecific(node.expression) || + isTypeScriptSpecific(node.switchClauses); + } + + function isForStatementTypeScriptSpecific(node: ForStatementSyntax): boolean { + return isTypeScriptSpecific(node.variableDeclaration) || + isTypeScriptSpecific(node.initializer) || + isTypeScriptSpecific(node.condition) || + isTypeScriptSpecific(node.incrementor) || + isTypeScriptSpecific(node.statement); + } + + function isForInStatementTypeScriptSpecific(node: ForInStatementSyntax): boolean { + return isTypeScriptSpecific(node.variableDeclaration) || + isTypeScriptSpecific(node.left) || + isTypeScriptSpecific(node.expression) || + isTypeScriptSpecific(node.statement); + } + + function isThrowStatementTypeScriptSpecific(node: ThrowStatementSyntax): boolean { + return isTypeScriptSpecific(node.expression); + } + + function isWhileStatementTypeScriptSpecific(node: WhileStatementSyntax): boolean { + return isTypeScriptSpecific(node.condition) || + isTypeScriptSpecific(node.statement); + } + + function isTryStatementTypeScriptSpecific(node: TryStatementSyntax): boolean { + return isTypeScriptSpecific(node.block) || + isTypeScriptSpecific(node.catchClause) || + isTypeScriptSpecific(node.finallyClause); + } + + function isLabeledStatementTypeScriptSpecific(node: LabeledStatementSyntax): boolean { + return isTypeScriptSpecific(node.statement); + } + + function isDoStatementTypeScriptSpecific(node: DoStatementSyntax): boolean { + return isTypeScriptSpecific(node.statement) || + isTypeScriptSpecific(node.condition); + } + + function isWithStatementTypeScriptSpecific(node: WithStatementSyntax): boolean { + return isTypeScriptSpecific(node.condition) || + isTypeScriptSpecific(node.statement); + } + + function isPrefixUnaryExpressionTypeScriptSpecific(node: PrefixUnaryExpressionSyntax): boolean { + return isTypeScriptSpecific(node.operand); + } + + function isDeleteExpressionTypeScriptSpecific(node: DeleteExpressionSyntax): boolean { + return isTypeScriptSpecific(node.expression); + } + + function isTypeOfExpressionTypeScriptSpecific(node: TypeOfExpressionSyntax): boolean { + return isTypeScriptSpecific(node.expression); + } + + function isVoidExpressionTypeScriptSpecific(node: VoidExpressionSyntax): boolean { + return isTypeScriptSpecific(node.expression); + } + + function isConditionalExpressionTypeScriptSpecific(node: ConditionalExpressionSyntax): boolean { + return isTypeScriptSpecific(node.condition) || + isTypeScriptSpecific(node.whenTrue) || + isTypeScriptSpecific(node.whenFalse); + } + + function isBinaryExpressionTypeScriptSpecific(node: BinaryExpressionSyntax): boolean { + return isTypeScriptSpecific(node.left) || + isTypeScriptSpecific(node.right); + } + + function isPostfixUnaryExpressionTypeScriptSpecific(node: PostfixUnaryExpressionSyntax): boolean { + return isTypeScriptSpecific(node.operand); + } + + function isMemberAccessExpressionTypeScriptSpecific(node: MemberAccessExpressionSyntax): boolean { + return isTypeScriptSpecific(node.expression); + } + + function isInvocationExpressionTypeScriptSpecific(node: InvocationExpressionSyntax): boolean { + return isTypeScriptSpecific(node.expression) || + isTypeScriptSpecific(node.argumentList); + } + + function isArrayLiteralExpressionTypeScriptSpecific(node: ArrayLiteralExpressionSyntax): boolean { + return isTypeScriptSpecific(node.expressions); + } + + function isObjectLiteralExpressionTypeScriptSpecific(node: ObjectLiteralExpressionSyntax): boolean { + return isTypeScriptSpecific(node.propertyAssignments); + } + + function isObjectCreationExpressionTypeScriptSpecific(node: ObjectCreationExpressionSyntax): boolean { + return isTypeScriptSpecific(node.expression) || + isTypeScriptSpecific(node.argumentList); + } + + function isParenthesizedExpressionTypeScriptSpecific(node: ParenthesizedExpressionSyntax): boolean { + return isTypeScriptSpecific(node.expression); + } + + function isElementAccessExpressionTypeScriptSpecific(node: ElementAccessExpressionSyntax): boolean { + return isTypeScriptSpecific(node.expression) || + isTypeScriptSpecific(node.argumentExpression); + } + + function isFunctionExpressionTypeScriptSpecific(node: FunctionExpressionSyntax): boolean { + return isTypeScriptSpecific(node.callSignature) || + isTypeScriptSpecific(node.block); + } + + function isVariableDeclarationTypeScriptSpecific(node: VariableDeclarationSyntax): boolean { + return isTypeScriptSpecific(node.variableDeclarators); + } + + function isVariableDeclaratorTypeScriptSpecific(node: VariableDeclaratorSyntax): boolean { + return node.typeAnnotation !== null || + isTypeScriptSpecific(node.equalsValueClause); + } + + function isArgumentListTypeScriptSpecific(node: ArgumentListSyntax): boolean { + return isTypeScriptSpecific(node.typeArgumentList) || + isTypeScriptSpecific(node.arguments); + } + + function isParameterListTypeScriptSpecific(node: ParameterListSyntax): boolean { + return isTypeScriptSpecific(node.parameters); + } + + function isEqualsValueClauseTypeScriptSpecific(node: EqualsValueClauseSyntax): boolean { + return isTypeScriptSpecific(node.value); + } + + function isCaseSwitchClauseTypeScriptSpecific(node: CaseSwitchClauseSyntax): boolean { + return isTypeScriptSpecific(node.expression) || + isTypeScriptSpecific(node.statements); + } + + function isDefaultSwitchClauseTypeScriptSpecific(node: DefaultSwitchClauseSyntax): boolean { + return isTypeScriptSpecific(node.statements); + } + + function isElseClauseTypeScriptSpecific(node: ElseClauseSyntax): boolean { + return isTypeScriptSpecific(node.statement); + } + + function isCatchClauseTypeScriptSpecific(node: CatchClauseSyntax): boolean { + return isTypeScriptSpecific(node.typeAnnotation) || + isTypeScriptSpecific(node.block); + } + + function isFinallyClauseTypeScriptSpecific(node: FinallyClauseSyntax): boolean { + return isTypeScriptSpecific(node.block); + } + + function isSimplePropertyAssignmentTypeScriptSpecific(node: SimplePropertyAssignmentSyntax): boolean { + return isTypeScriptSpecific(node.expression); + } + + function isFunctionPropertyAssignmentTypeScriptSpecific(node: FunctionPropertyAssignmentSyntax): boolean { + return isTypeScriptSpecific(node.callSignature) || + isTypeScriptSpecific(node.block); + } + + function isParameterTypeScriptSpecific(node: ParameterSyntax): boolean { + return isTypeScriptSpecific(node.modifiers) || + node.typeAnnotation !== null || + node.equalsValueClause !== null; + } + + function isEnumElementTypeScriptSpecific(node: EnumElementSyntax): boolean { + return isTypeScriptSpecific(node.equalsValueClause); + } +} \ No newline at end of file diff --git a/src/services/text/characterCodes.ts b/src/services/text/characterCodes.ts new file mode 100644 index 00000000000..040e0c41c6b --- /dev/null +++ b/src/services/text/characterCodes.ts @@ -0,0 +1,138 @@ +/// + +module TypeScript { + export enum CharacterCodes { + nullCharacter = 0, + maxAsciiCharacter = 127, + + lineFeed = 10, // \n + carriageReturn = 13, // \r + lineSeparator = 0x2028, + paragraphSeparator = 0x2029, + + // REVIEW: do we need to support this? The scanner doesn't, but our IText does. This seems + // like an odd disparity? (Or maybe it's completely fine for them to be different). + nextLine = 0x0085, + + // Unicode 3.0 space characters + space = 0x0020, // " " + nonBreakingSpace = 0x00A0, // + enQuad = 0x2000, + emQuad = 0x2001, + enSpace = 0x2002, + emSpace = 0x2003, + threePerEmSpace = 0x2004, + fourPerEmSpace = 0x2005, + sixPerEmSpace = 0x2006, + figureSpace = 0x2007, + punctuationSpace = 0x2008, + thinSpace = 0x2009, + hairSpace = 0x200A, + zeroWidthSpace = 0x200B, + narrowNoBreakSpace = 0x202F, + ideographicSpace = 0x3000, + + _ = 95, + $ = 36, + + _0 = 48, + _1 = 49, + _2 = 50, + _3 = 51, + _4 = 52, + _5 = 53, + _6 = 54, + _7 = 55, + _8 = 56, + _9 = 57, + + a = 97, + b = 98, + c = 99, + d = 100, + e = 101, + f = 102, + g = 103, + h = 104, + i = 105, + j = 106, + k = 107, + l = 108, + m = 109, + n = 110, + o = 111, + p = 112, + q = 113, + r = 114, + s = 115, + t = 116, + u = 117, + v = 118, + w = 119, + x = 120, + y = 121, + z = 122, + + A = 65, + B = 66, + C = 67, + D = 68, + E = 69, + F = 70, + G = 71, + H = 72, + I = 73, + J = 74, + K = 75, + L = 76, + M = 77, + N = 78, + O = 79, + P = 80, + Q = 81, + R = 82, + S = 83, + T = 84, + U = 85, + V = 86, + W = 87, + X = 88, + Y = 89, + Z = 90, + + ampersand = 38, // & + asterisk = 42, // * + at = 64, // @ + backslash = 92, // \ + bar = 124, // | + caret = 94, // ^ + closeBrace = 125, // } + closeBracket = 93, // ] + closeParen = 41, // ) + colon = 58, // : + comma = 44, // , + dot = 46, // . + doubleQuote = 34, // " + equals = 61, // = + exclamation = 33, // ! + greaterThan = 62, // > + lessThan = 60, // < + minus = 45, // - + openBrace = 123, // { + openBracket = 91, // [ + openParen = 40, // ( + percent = 37, // % + plus = 43, // + + question = 63, // ? + semicolon = 59, // ; + singleQuote = 39, // ' + slash = 47, // / + tilde = 126, // ~ + + backspace = 8, // \b + formFeed = 12, // \f + byteOrderMark = 0xFEFF, + tab = 9, // \t + verticalTab = 11, // \v + } +} \ No newline at end of file diff --git a/src/services/text/lineMap.ts b/src/services/text/lineMap.ts new file mode 100644 index 00000000000..15fbbe47e84 --- /dev/null +++ b/src/services/text/lineMap.ts @@ -0,0 +1,17 @@ +/// + +module TypeScript { + export module LineMap1 { + export function fromSimpleText(text: ISimpleText): LineMap { + return new LineMap(() => TextUtilities.parseLineStarts({ charCodeAt: index => text.charCodeAt(index), length: text.length() }), text.length()); + } + + export function fromScriptSnapshot(scriptSnapshot: IScriptSnapshot): LineMap { + return new LineMap(() => scriptSnapshot.getLineStartPositions(), scriptSnapshot.getLength()); + } + + export function fromString(text: string): LineMap { + return new LineMap(() => TextUtilities.parseLineStarts(text), text.length); + } + } +} \ No newline at end of file diff --git a/src/services/text/references.ts b/src/services/text/references.ts new file mode 100644 index 00000000000..e50975146b4 --- /dev/null +++ b/src/services/text/references.ts @@ -0,0 +1,12 @@ +/// + +/// +/// +/// +/// +/// +/// +/// + +// TextChangeRange depends on TextSpan. +/// \ No newline at end of file diff --git a/src/services/text/scriptSnapshot.ts b/src/services/text/scriptSnapshot.ts new file mode 100644 index 00000000000..41b5ed37c41 --- /dev/null +++ b/src/services/text/scriptSnapshot.ts @@ -0,0 +1,57 @@ +/// + +module TypeScript { + // Represents an immutable snapshot of a script at a specified time. Once acquired, the + // snapshot is observably immutable. i.e. the same calls with the same parameters will return + // the same values. + export interface IScriptSnapshot { + // Get's a portion of the script snapshot specified by [start, end). + getText(start: number, end: number): string; + + // Get's the length of this script snapshot. + getLength(): number; + + // This call returns the array containing the start position of every line. + // i.e."[0, 10, 55]". TODO: consider making this optional. The language service could + // always determine this (albeit in a more expensive manner). + getLineStartPositions(): number[]; + + // Returns a text change range representing what text has changed since the specified version. + // If the change cannot be determined (say, because a file was opened/closed), then 'null' + // should be returned. + getTextChangeRangeSinceVersion(scriptVersion: number): TextChangeRange; + } + + export module ScriptSnapshot { + class StringScriptSnapshot implements IScriptSnapshot { + private _lineStartPositions: number[] = null; + + constructor(private text: string) { + } + + public getText(start: number, end: number): string { + return this.text.substring(start, end); + } + + public getLength(): number { + return this.text.length; + } + + public getLineStartPositions(): number[]{ + if (!this._lineStartPositions) { + this._lineStartPositions = TextUtilities.parseLineStarts(this.text); + } + + return this._lineStartPositions; + } + + public getTextChangeRangeSinceVersion(scriptVersion: number): TypeScript.TextChangeRange { + throw Errors.notYetImplemented(); + } + } + + export function fromString(text: string): IScriptSnapshot { + return new StringScriptSnapshot(text); + } + } +} \ No newline at end of file diff --git a/src/services/text/text.ts b/src/services/text/text.ts new file mode 100644 index 00000000000..80756c301fd --- /dev/null +++ b/src/services/text/text.ts @@ -0,0 +1,21 @@ +/// + +/** + * Represents an immutable snapshot of text. + */ +module TypeScript { + /** + * Represents an immutable snapshot of text. + */ + export interface ISimpleText { + /** + * Total number of characters in the text source. + */ + length(): number; + + substr(start: number, length: number): string; + + charCodeAt(index: number): number; + lineMap(): LineMap; + } +} \ No newline at end of file diff --git a/src/services/text/textChangeRange.ts b/src/services/text/textChangeRange.ts new file mode 100644 index 00000000000..b45dc8a0318 --- /dev/null +++ b/src/services/text/textChangeRange.ts @@ -0,0 +1,168 @@ +/// + +module TypeScript { + export class TextChangeRange { + public static unchanged = new TextChangeRange(new TextSpan(0, 0), 0); + + private _span: TextSpan; + private _newLength: number; + + /** + * Initializes a new instance of TextChangeRange. + */ + constructor(span: TextSpan, newLength: number) { + if (newLength < 0) { + throw Errors.argumentOutOfRange("newLength"); + } + + this._span = span; + this._newLength = newLength; + } + + /** + * The span of text before the edit which is being changed + */ + public span(): TextSpan { + return this._span; + } + + /** + * Width of the span after the edit. A 0 here would represent a delete + */ + public newLength(): number { + return this._newLength; + } + + public newSpan(): TextSpan { + return new TextSpan(this.span().start(), this.newLength()); + } + + public isUnchanged(): boolean { + return this.span().isEmpty() && this.newLength() === 0; + } + + /** + * Called to merge all the changes that occurred across several versions of a script snapshot + * into a single change. i.e. if a user keeps making successive edits to a script we will + * have a text change from V1 to V2, V2 to V3, ..., Vn. + * + * This function will then merge those changes into a single change range valid between V1 and + * Vn. + */ + public static collapseChangesAcrossMultipleVersions(changes: TextChangeRange[]): TextChangeRange { + if (changes.length === 0) { + return TextChangeRange.unchanged; + } + + if (changes.length === 1) { + return changes[0]; + } + + // We change from talking about { { oldStart, oldLength }, newLength } to { oldStart, oldEnd, newEnd } + // as it makes things much easier to reason about. + var change0 = changes[0]; + + var oldStartN = change0.span().start(); + var oldEndN = change0.span().end(); + var newEndN = oldStartN + change0.newLength(); + + for (var i = 1; i < changes.length; i++) { + var nextChange = changes[i]; + + // Consider the following case: + // i.e. two edits. The first represents the text change range { { 10, 50 }, 30 }. i.e. The span starting + // at 10, with length 50 is reduced to length 30. The second represents the text change range { { 30, 30 }, 40 }. + // i.e. the span starting at 30 with length 30 is increased to length 40. + // + // 0 10 20 30 40 50 60 70 80 90 100 + // ------------------------------------------------------------------------------------------------------- + // | / + // | /---- + // T1 | /---- + // | /---- + // | /---- + // ------------------------------------------------------------------------------------------------------- + // | \ + // | \ + // T2 | \ + // | \ + // | \ + // ------------------------------------------------------------------------------------------------------- + // + // Merging these turns out to not be too difficult. First, determining the new start of the change is trivial + // it's just the min of the old and new starts. i.e.: + // + // 0 10 20 30 40 50 60 70 80 90 100 + // ------------------------------------------------------------*------------------------------------------ + // | / + // | /---- + // T1 | /---- + // | /---- + // | /---- + // ----------------------------------------$-------------------$------------------------------------------ + // . | \ + // . | \ + // T2 . | \ + // . | \ + // . | \ + // ----------------------------------------------------------------------*-------------------------------- + // + // (Note the dots represent the newly inferrred start. + // Determining the new and old end is also pretty simple. Basically it boils down to paying attention to the + // absolute positions at the asterixes, and the relative change between the dollar signs. Basically, we see + // which if the two $'s precedes the other, and we move that one forward until they line up. in this case that + // means: + // + // 0 10 20 30 40 50 60 70 80 90 100 + // --------------------------------------------------------------------------------*---------------------- + // | / + // | /---- + // T1 | /---- + // | /---- + // | /---- + // ------------------------------------------------------------$------------------------------------------ + // . | \ + // . | \ + // T2 . | \ + // . | \ + // . | \ + // ----------------------------------------------------------------------*-------------------------------- + // + // In other words (in this case), we're recognizing that the second edit happened after where the first edit + // ended with a delta of 20 characters (60 - 40). Thus, if we go back in time to where the first edit started + // that's the same as if we started at char 80 instead of 60. + // + // As it so happens, the same logic applies if the second edit precedes the first edit. In that case rahter + // than pusing the first edit forward to match the second, we'll push the second edit forward to match the + // first. + // + // In this case that means we have { oldStart: 10, oldEnd: 80, newEnd: 70 } or, in TextChangeRange + // semantics: { { start: 10, length: 70 }, newLength: 60 } + // + // The math then works out as follows. + // If we have { oldStart1, oldEnd1, newEnd1 } and { oldStart2, oldEnd2, newEnd2 } then we can compute the + // final result like so: + // + // { + // oldStart3: Min(oldStart1, oldStart2), + // oldEnd3 : Max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)), + // newEnd3 : Max(newEnd2, newEnd2 + (newEnd1 - oldEnd2)) + // } + + var oldStart1 = oldStartN; + var oldEnd1 = oldEndN; + var newEnd1 = newEndN; + + var oldStart2 = nextChange.span().start(); + var oldEnd2 = nextChange.span().end(); + var newEnd2 = oldStart2 + nextChange.newLength(); + + oldStartN = Math.min(oldStart1, oldStart2); + oldEndN = Math.max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)); + newEndN = Math.max(newEnd2, newEnd2 + (newEnd1 - oldEnd2)); + } + + return new TextChangeRange(TextSpan.fromBounds(oldStartN, oldEndN), /*newLength: */newEndN - oldStartN); + } + } +} \ No newline at end of file diff --git a/src/services/text/textFactory.ts b/src/services/text/textFactory.ts new file mode 100644 index 00000000000..21d215c291e --- /dev/null +++ b/src/services/text/textFactory.ts @@ -0,0 +1,66 @@ +/// + +module TypeScript.SimpleText { + class SimpleStringText implements ISimpleText { + private _lineMap: LineMap = null; + + constructor(private value: string) { + } + + public length(): number { + return this.value.length; + } + + public substr(start: number, length: number): string { + return this.value.substr(start, length); + } + + public charCodeAt(index: number): number { + return this.value.charCodeAt(index); + } + + public lineMap(): LineMap { + if (!this._lineMap) { + this._lineMap = LineMap1.fromString(this.value); + } + + return this._lineMap; + } + } + + // Class which wraps a host IScriptSnapshot and exposes an ISimpleText for newer compiler code. + class SimpleScriptSnapshotText implements ISimpleText { + private _lineMap: LineMap = null; + + constructor(public scriptSnapshot: IScriptSnapshot) { + } + + public charCodeAt(index: number): number { + return this.scriptSnapshot.getText(index, index + 1).charCodeAt(0); + } + + public length(): number { + return this.scriptSnapshot.getLength(); + } + + public substr(start: number, length: number): string { + return this.scriptSnapshot.getText(start, start + length); + } + + public lineMap(): LineMap { + if (this._lineMap === null) { + this._lineMap = new LineMap(() => this.scriptSnapshot.getLineStartPositions(), this.length()); + } + + return this._lineMap; + } + } + + export function fromString(value: string): ISimpleText { + return new SimpleStringText(value); + } + + export function fromScriptSnapshot(scriptSnapshot: IScriptSnapshot): ISimpleText { + return new SimpleScriptSnapshotText(scriptSnapshot); + } +} \ No newline at end of file diff --git a/src/services/text/textSpan.ts b/src/services/text/textSpan.ts new file mode 100644 index 00000000000..b0da8279841 --- /dev/null +++ b/src/services/text/textSpan.ts @@ -0,0 +1,141 @@ +/// + +module TypeScript { + export interface ISpan { + start(): number; + end(): number; + } + + export class TextSpan implements ISpan { + private _start: number; + private _length: number; + + /** + * Creates a TextSpan instance beginning with the position Start and having the Length + * specified with length. + */ + constructor(start: number, length: number) { + if (start < 0) { + Errors.argument("start"); + } + + if (length < 0) { + Errors.argument("length"); + } + + this._start = start; + this._length = length; + } + + public start(): number { + return this._start; + } + + public length(): number { + return this._length; + } + + public end(): number { + return this._start + this._length; + } + + public isEmpty(): boolean { + return this._length === 0; + } + + /** + * Determines whether the position lies within the span. Returns true if the position is greater than or equal to Start and strictly less + * than End, otherwise false. + * @param position The position to check. + */ + public containsPosition(position: number): boolean { + return position >= this._start && position < this.end(); + } + + /** + * Determines whether span falls completely within this span. Returns true if the specified span falls completely within this span, otherwise false. + * @param span The span to check. + */ + public containsTextSpan(span: TextSpan): boolean { + return span._start >= this._start && span.end() <= this.end(); + } + + /** + * Determines whether the given span overlaps this span. Two spans are considered to overlap + * if they have positions in common and neither is empty. Empty spans do not overlap with any + * other span. Returns true if the spans overlap, false otherwise. + * @param span The span to check. + */ + public overlapsWith(span: TextSpan): boolean { + var overlapStart = Math.max(this._start, span._start); + var overlapEnd = Math.min(this.end(), span.end()); + + return overlapStart < overlapEnd; + } + + /** + * Returns the overlap with the given span, or null if there is no overlap. + * @param span The span to check. + */ + public overlap(span: TextSpan): TextSpan { + var overlapStart = Math.max(this._start, span._start); + var overlapEnd = Math.min(this.end(), span.end()); + + if (overlapStart < overlapEnd) { + return TextSpan.fromBounds(overlapStart, overlapEnd); + } + + return null; + } + + /** + * Determines whether span intersects this span. Two spans are considered to + * intersect if they have positions in common or the end of one span + * coincides with the start of the other span. Returns true if the spans intersect, false otherwise. + * @param The span to check. + */ + public intersectsWithTextSpan(span: TextSpan): boolean { + return span._start <= this.end() && span.end() >= this._start; + } + + public intersectsWith(start: number, length: number): boolean { + var end = start + length; + return start <= this.end() && end >= this._start; + } + + /** + * Determines whether the given position intersects this span. + * A position is considered to intersect if it is between the start and + * end positions (inclusive) of this span. Returns true if the position intersects, false otherwise. + * @param position The position to check. + */ + public intersectsWithPosition(position: number): boolean { + return position <= this.end() && position >= this._start; + } + + /** + * Returns the intersection with the given span, or null if there is no intersection. + * @param span The span to check. + */ + public intersection(span: TextSpan): TextSpan { + var intersectStart = Math.max(this._start, span._start); + var intersectEnd = Math.min(this.end(), span.end()); + + if (intersectStart <= intersectEnd) { + return TextSpan.fromBounds(intersectStart, intersectEnd); + } + + return null; + } + + /** + * Creates a new TextSpan from the given start and end positions + * as opposed to a position and length. + */ + public static fromBounds(start: number, end: number): TextSpan { + Debug.assert(start >= 0); + Debug.assert(end - start >= 0); + return new TextSpan(start, end - start); + } + } +} \ No newline at end of file diff --git a/src/services/text/textUtilities.ts b/src/services/text/textUtilities.ts new file mode 100644 index 00000000000..a495f97e941 --- /dev/null +++ b/src/services/text/textUtilities.ts @@ -0,0 +1,94 @@ +/// + +module TypeScript.TextUtilities { + export interface ICharacterSequence { + charCodeAt(index: number): number; + length: number; + } + + export function parseLineStarts(text: ICharacterSequence): number[]{ + var length = text.length; + + // Corner case check + if (0 === length) { + var result = new Array(); + result.push(0); + return result; + } + + var position = 0; + var index = 0; + var arrayBuilder = new Array(); + var lineNumber = 0; + + // The following loop goes through every character in the text. It is highly + // performance critical, and thus inlines knowledge about common line breaks + // and non-line breaks. + while (index < length) { + var c = text.charCodeAt(index); + var lineBreakLength: number; + + // common case - ASCII & not a line break + if (c > CharacterCodes.carriageReturn && c <= 127) { + index++; + continue; + } + else if (c === CharacterCodes.carriageReturn && index + 1 < length && text.charCodeAt(index + 1) === CharacterCodes.lineFeed) { + lineBreakLength = 2; + } + else if (c === CharacterCodes.lineFeed) { + lineBreakLength = 1; + } + else { + lineBreakLength = TextUtilities.getLengthOfLineBreak(text, index); + } + + if (0 === lineBreakLength) { + index++; + } + else { + arrayBuilder.push(position); + index += lineBreakLength; + position = index; + lineNumber++; + } + } + + // Create a start for the final line. + arrayBuilder.push(position); + + return arrayBuilder; + } + + export function getLengthOfLineBreakSlow(text: ICharacterSequence, index: number, c: number): number { + if (c === CharacterCodes.carriageReturn) { + var next = index + 1; + return (next < text.length) && CharacterCodes.lineFeed === text.charCodeAt(next) ? 2 : 1; + } + else if (isAnyLineBreakCharacter(c)) { + return 1; + } + else { + return 0; + } + } + + export function getLengthOfLineBreak(text: ICharacterSequence, index: number): number { + var c = text.charCodeAt(index); + + // common case - ASCII & not a line break + if (c > CharacterCodes.carriageReturn && c <= 127) { + return 0; + } + + return getLengthOfLineBreakSlow(text, index, c); + } + + export function isAnyLineBreakCharacter(c: number): boolean { + return c === CharacterCodes.lineFeed || + c === CharacterCodes.carriageReturn || + c === CharacterCodes.nextLine || + c === CharacterCodes.lineSeparator || + c === CharacterCodes.paragraphSeparator; + } +} \ No newline at end of file diff --git a/src/services/typescriptServices.ts b/src/services/typescriptServices.ts new file mode 100644 index 00000000000..908b9bf063a --- /dev/null +++ b/src/services/typescriptServices.ts @@ -0,0 +1,243 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + + +/// +/// +/// +/// + +/// + +/// +/// +/// +/// +/// + +/// +/// +/// +/// +/// +/// + + +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// + + +/// + +module TypeScript { + + export var sentinelEmptyArray = []; + + export enum EmitOutputResult { + Succeeded, + FailedBecauseOfSyntaxErrors, + FailedBecauseOfCompilerOptionsErrors, + FailedToGenerateDeclarationsBecauseOfSemanticErrors + } + + export class EmitOutput { + public outputFiles: OutputFile[] = []; + public emitOutputResult: EmitOutputResult; + constructor(emitOutputResult = EmitOutputResult.Succeeded) { + this.emitOutputResult = emitOutputResult; + } + } + + export enum OutputFileType { + JavaScript, + SourceMap, + Declaration + } + + export class OutputFile { + constructor(public name: string, + public writeByteOrderMark: boolean, + public text: string, + public fileType: OutputFileType, + public sourceMapOutput: any = null) { + } + } + + export interface ICancellationToken { + isCancellationRequested(): boolean; + } + + export class OperationCanceledException { } + + export class CancellationToken { + + public static None: CancellationToken = new CancellationToken(null) + + constructor(private cancellationToken: ICancellationToken) { + } + + public isCancellationRequested() { + return this.cancellationToken && this.cancellationToken.isCancellationRequested(); + } + + public throwIfCancellationRequested(): void { + if (this.isCancellationRequested()) { + throw new OperationCanceledException(); + } + } + } + + export function compareDataObjects(dst: any, src: any): boolean { + for (var e in dst) { + if (typeof dst[e] === "object") { + if (!compareDataObjects(dst[e], src[e])) + return false; + } + else if (typeof dst[e] !== "function") { + if (dst[e] !== src[e]) + return false; + } + } + return true; + } + + export var version = "1.0.3.0"; + export var fileResolutionTime = 0; + export var fileResolutionIOTime = 0; + export var fileResolutionScanImportsTime = 0; + export var fileResolutionImportFileSearchTime = 0; + export var fileResolutionGetDefaultLibraryTime = 0; +} + + +module TypeScript.Services { + export function copyDataObject(dst: any, src: any): any { + for (var e in dst) { + if (typeof dst[e] == "object") { + copyDataObject(dst[e], src[e]); + } + else if (typeof dst[e] != "function") { + dst[e] = src[e]; + } + } + return dst; + } + + export class TypeScriptServicesFactory implements IShimFactory { + private _shims: IShim[] = []; + private documentRegistry: DocumentRegistry = new DocumentRegistry(); + + public createPullLanguageService(host: TypeScript.Services.ILanguageServiceHost): TypeScript.Services.ILanguageService { + try { + return new TypeScript.Services.LanguageService(host, this.documentRegistry); + } + catch (err) { + TypeScript.Services.logInternalError(host, err); + throw err; + } + } + + public createLanguageServiceShim(host: ILanguageServiceShimHost): ILanguageServiceShim { + try { + var hostAdapter = new LanguageServiceShimHostAdapter(host); + var pullLanguageService = this.createPullLanguageService(hostAdapter); + return new LanguageServiceShim(this, host, pullLanguageService); + } + catch (err) { + TypeScript.Services.logInternalError(host, err); + throw err; + } + } + + public createClassifier(host: TypeScript.Services.IClassifierHost): TypeScript.Services.Classifier { + try { + return new TypeScript.Services.Classifier(host); + } + catch (err) { + TypeScript.Services.logInternalError(host, err); + throw err; + } + } + + public createClassifierShim(host: TypeScript.Services.IClassifierHost): ClassifierShim { + try { + return new ClassifierShim(this, host); + } + catch (err) { + TypeScript.Services.logInternalError(host, err); + throw err; + } + } + + public createCoreServices(host: TypeScript.Services.ICoreServicesHost): TypeScript.Services.CoreServices { + try { + return new TypeScript.Services.CoreServices(host); + } + catch (err) { + TypeScript.Services.logInternalError(host.logger, err); + throw err; + } + } + + public createCoreServicesShim(host: TypeScript.Services.ICoreServicesHost): CoreServicesShim { + try { + return new CoreServicesShim(this, host); + } + catch (err) { + TypeScript.Services.logInternalError(host.logger, err); + throw err; + } + } + + public close(): void { + // Forget all the registered shims + this._shims = []; + this.documentRegistry = new DocumentRegistry(); + } + + public registerShim(shim: IShim): void { + this._shims.push(shim); + } + + public unregisterShim(shim: IShim): void { + for(var i =0, n = this._shims.length; i Date: Fri, 18 Jul 2014 17:46:41 -0700 Subject: [PATCH 02/59] push newline to compilerhost instead of using sys directelly. This allows the language service to set it, as sys is not defined in language service scenarios --- src/compiler/checker.ts | 4 ++-- src/compiler/core.ts | 4 ++-- src/compiler/emitter.ts | 5 +++-- src/compiler/parser.ts | 4 ++-- src/compiler/tc.ts | 3 ++- src/compiler/types.ts | 1 + 6 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 004a4f3b260..b2b55085afe 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2387,7 +2387,7 @@ module ts { var errorInfo = chainDiagnosticMessages(undefined, Diagnostics.Named_properties_0_of_types_1_and_2_are_not_identical, prop.name, typeName1, typeName2); errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Interface_0_cannot_simultaneously_extend_types_1_and_2_Colon, typeToString(type), typeName1, typeName2); - addDiagnostic(createDiagnosticForNodeFromMessageChain(typeNode, errorInfo)); + addDiagnostic(createDiagnosticForNodeFromMessageChain(typeNode, errorInfo, program.getCompilerHost().getNewLine())); } } } @@ -2434,7 +2434,7 @@ module ts { error(errorNode, Diagnostics.Excessive_stack_depth_comparing_types_0_and_1, typeToString(source), typeToString(target)); } else if (errorInfo) { - addDiagnostic(createDiagnosticForNodeFromMessageChain(errorNode, errorInfo)); + addDiagnostic(createDiagnosticForNodeFromMessageChain(errorNode, errorInfo, program.getCompilerHost().getNewLine())); } return result; diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 8e59408f151..6f9f2629a80 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -214,7 +214,7 @@ module ts { } } - export function flattenDiagnosticChain(file: SourceFile, start: number, length: number, diagnosticChain: DiagnosticMessageChain): Diagnostic { + export function flattenDiagnosticChain(file: SourceFile, start: number, length: number, diagnosticChain: DiagnosticMessageChain, newLine: string): Diagnostic { var code = diagnosticChain.code; var category = diagnosticChain.category; var messageText = ""; @@ -222,7 +222,7 @@ module ts { var indent = 0; while (diagnosticChain) { if (indent) { - messageText += sys.newLine; + messageText += newLine; for (var i = 0; i < indent; i++) { messageText += " "; diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index d1e2367babb..a80845d852b 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -22,6 +22,7 @@ module ts { var compilerOptions = program.getCompilerOptions(); var sourceMapDataList: SourceMapData[] = compilerOptions.sourceMap ? [] : undefined; var diagnostics: Diagnostic[] = []; + var newLine = program.getCompilerHost().getNewLine(); function getSourceFilePathInNewDir(newDirPath: string, sourceFile: SourceFile) { var sourceFilePath = getNormalizedPathFromPathCompoments(getNormalizedPathComponents(sourceFile.filename, compilerHost.getCurrentDirectory())); @@ -126,7 +127,7 @@ module ts { function writeLine() { if (!lineStart) { - output += sys.newLine; + output += newLine; lineCount++; linePos = output.length; lineStart = true; @@ -2252,7 +2253,7 @@ module ts { compilerHost.getCurrentDirectory(), /*isAbsolutePathAnUrl*/ false); - referencePathsOutput += "/// " + sys.newLine; + referencePathsOutput += "/// " + newLine; } if (root) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index f0f7c36e447..1536d0c00d8 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -88,12 +88,12 @@ module ts { return createFileDiagnostic(file, start, length, message, arg0, arg1, arg2); } - export function createDiagnosticForNodeFromMessageChain(node: Node, messageChain: DiagnosticMessageChain): Diagnostic { + export function createDiagnosticForNodeFromMessageChain(node: Node, messageChain: DiagnosticMessageChain, newLine: string): Diagnostic { node = getErrorSpanForNode(node); var file = getSourceFileOfNode(node); var start = skipTrivia(file.text, node.pos); var length = node.end - start; - return flattenDiagnosticChain(file, start, length, messageChain); + return flattenDiagnosticChain(file, start, length, messageChain, newLine); } export function getErrorSpanForNode(node: Node): Node { diff --git a/src/compiler/tc.ts b/src/compiler/tc.ts index d44d1b9724c..26dc7631b9f 100644 --- a/src/compiler/tc.ts +++ b/src/compiler/tc.ts @@ -162,7 +162,8 @@ module ts { writeFile: writeFile, getCurrentDirectory: () => currentDirectory || (currentDirectory = sys.getCurrentDirectory()), useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames, - getCanonicalFileName: getCanonicalFileName + getCanonicalFileName: getCanonicalFileName, + getNewLine: () => sys.newLine }; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 6b846768c15..825e2147586 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1104,5 +1104,6 @@ module ts { getCurrentDirectory(): string; getCanonicalFileName(fileName: string): string; useCaseSensitiveFileNames(): boolean; + getNewLine(): string; } } From 33433b8fca6a3ab8ba198dc636296f2f4bf4a231 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Fri, 18 Jul 2014 17:47:04 -0700 Subject: [PATCH 03/59] cleanup --- src/services/coreServices.ts | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/src/services/coreServices.ts b/src/services/coreServices.ts index 3db06ba3a8f..2e34f646649 100644 --- a/src/services/coreServices.ts +++ b/src/services/coreServices.ts @@ -35,32 +35,7 @@ module TypeScript.Services { } public getDefaultCompilationSettings(): ts.CompilerOptions { - // Set "ES5" target by default for language service - return { - target: ts.ScriptTarget.ES5 - } - } - - public dumpMemory(): string { - if (!debugObjectHost || !debugObjectHost.Debug || !debugObjectHost.Debug.dumpHeap) { - throw new Error(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.This_version_of_the_Javascript_runtime_does_not_support_the_0_function, ['Debug.dumpHeap()'])); - } - - var objects = debugObjectHost.Debug.dumpHeap(2); - var totalSize = 0; - for (var i = 0; i < objects.length; i++) { - totalSize += objects[i].size; - } - - return "There are " + objects.length + " object(s) accessible from 'global', for a total of " + totalSize + " byte(s)."; - } - - public getMemoryInfo(): any[] { - if (!debugObjectHost || !debugObjectHost.Debug || !debugObjectHost.Debug.getMemoryInfo) { - throw new Error(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.This_version_of_the_Javascript_runtime_does_not_support_the_0_function, ['Debug.getMemoryInfo()'])); - } - - return debugObjectHost.Debug.getMemoryInfo(); + return getDefaultCompilerOptions(); } public collectGarbage(): void { From 5819fd4fd4c8c645d9bdabaa9f670a1e5f93449f Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Sat, 19 Jul 2014 10:45:54 -0700 Subject: [PATCH 04/59] Change classes into interfaces --- src/services/breakpoints.ts | 15 +- .../getScriptLexicalStructureWalker.ts | 27 ++-- src/services/languageService.ts | 140 ++++++++---------- 3 files changed, 92 insertions(+), 90 deletions(-) diff --git a/src/services/breakpoints.ts b/src/services/breakpoints.ts index c1e3535d432..237df5afce0 100644 --- a/src/services/breakpoints.ts +++ b/src/services/breakpoints.ts @@ -10,7 +10,10 @@ module TypeScript.Services.Breakpoints { } if (childElements.length == 0) { - return new SpanInfo(TypeScript.start(parentElement), TypeScript.end(parentElement)); + return { + minChar: TypeScript.start(parentElement), + limChar: TypeScript.end(parentElement) + }; } var start: number; @@ -25,11 +28,17 @@ module TypeScript.Services.Breakpoints { } } - return new SpanInfo(start, end); + return { + minChar: start, + limChar: end + }; } function createBreakpointSpanInfoWithLimChar(startElement: TypeScript.ISyntaxElement, limChar: number): SpanInfo { - return new SpanInfo(start(startElement), limChar); + return { + minChar: start(startElement), + limChar: limChar + }; } class BreakpointResolver { diff --git a/src/services/getScriptLexicalStructureWalker.ts b/src/services/getScriptLexicalStructureWalker.ts index c62ef11136d..66d930784dd 100644 --- a/src/services/getScriptLexicalStructureWalker.ts +++ b/src/services/getScriptLexicalStructureWalker.ts @@ -81,17 +81,17 @@ module TypeScript.Services { return; } - var item = new NavigateToItem(); - item.name = name; - item.kind = kind; - item.matchKind = MatchKind.exact; - item.fileName = this.fileName; - item.kindModifiers = this.getKindModifiers(modifiers); - item.minChar = start(node); - item.limChar = end(node); - item.containerName = this.nameStack.join("."); - item.containerKind = this.kindStack.length === 0 ? "" : TypeScript.ArrayUtilities.last(this.kindStack); - + var item: NavigateToItem = { + name: name, + kind: kind, + matchKind: MatchKind.exact, + fileName: this.fileName, + kindModifiers: this.getKindModifiers(modifiers), + minChar: start(node), + limChar: end(node), + containerName: this.nameStack.join("."), + containerKind: this.kindStack.length === 0 ? "" : TypeScript.ArrayUtilities.last(this.kindStack), + }; this.currentScope.items[key] = item; this.currentScope.itemNames.push(key); } @@ -104,7 +104,10 @@ module TypeScript.Services { Debug.assert(item !== undefined); var start = TypeScript.start(node); - var span = new SpanInfo(start, start + width(node)); + var span: SpanInfo = { + minChar: start, + limChar: start + width(node) + }; if (item.additionalSpans) { diff --git a/src/services/languageService.ts b/src/services/languageService.ts index efaf0283373..de526c9ee6b 100644 --- a/src/services/languageService.ts +++ b/src/services/languageService.ts @@ -78,7 +78,7 @@ module TypeScript.Services { getEmitOutput(fileName: string): TypeScript.EmitOutput; - getSyntaxTree(fileName: string): TypeScript.SyntaxTree; + //getSyntaxTree(fileName: string): TypeScript.SyntaxTree; dispose(): void; } @@ -87,31 +87,24 @@ module TypeScript.Services { logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message); } - export class ReferenceEntry { - public fileName: string = "" - public minChar: number = -1; - public limChar: number = -1; - public isWriteAccess: boolean = false; - - constructor(fileName: string, minChar: number, limChar: number, isWriteAccess: boolean) { - this.fileName = fileName; - this.minChar = minChar; - this.limChar = limChar; - this.isWriteAccess = isWriteAccess; - } + export interface ReferenceEntry { + fileName: string; + minChar: number; + limChar: number; + isWriteAccess: boolean; } - export class NavigateToItem { - public name: string = ""; - public kind: string = ""; // see ScriptElementKind - public kindModifiers: string = ""; // see ScriptElementKindModifier, comma separated - public matchKind: string = ""; - public fileName: string = ""; - public minChar: number = -1; - public limChar: number = -1; - public additionalSpans: SpanInfo[] = null; - public containerName: string = ""; - public containerKind: string = ""; // see ScriptElementKind + export interface NavigateToItem { + name: string; + kind: string; // see ScriptElementKind + kindModifiers: string; // see ScriptElementKindModifier, comma separated + matchKind: string; + fileName: string; + minChar: number; + limChar: number; + additionalSpans?: SpanInfo[]; + containerName: string; + containerKind: string; // see ScriptElementKind } export class TextEdit { @@ -169,73 +162,69 @@ module TypeScript.Services { } } - export class DefinitionInfo { - constructor( - public fileName: string, - public minChar: number, - public limChar: number, - public kind: string, - public name: string, - public containerKind: string, - public containerName: string) { - } + export interface DefinitionInfo { + fileName: string; + minChar: number; + limChar: number; + kind: string; + name: string; + containerKind: string; + containerName: string; } - export class TypeInfo { - constructor( - public memberName: TypeScript.MemberName, - public docComment: string, - public fullSymbolName: string, - public kind: string, - public minChar: number, - public limChar: number) { - } + export interface TypeInfo { + memberName: TypeScript.MemberName; + docComment: string; + fullSymbolName: string; + kind: string; + minChar: number; + limChar: number; } - export class SpanInfo { - constructor(public minChar: number, public limChar: number, public text: string = null) { - } + export interface SpanInfo { + minChar: number; + limChar: number; + // text?: string; } - export class SignatureInfo { - public actual: ActualSignatureInfo; - public formal: FormalSignatureItemInfo[] = []; // Formal signatures - public activeFormal: number; // Index of the "best match" formal signature + export interface SignatureInfo { + actual: ActualSignatureInfo; + formal: FormalSignatureItemInfo[]; // Formal signatures + activeFormal: number; // Index of the "best match" formal signature } - export class FormalSignatureItemInfo { - public signatureInfo: string; - public typeParameters: FormalTypeParameterInfo[] = []; - public parameters: FormalParameterInfo[] = []; // Array of parameters - public docComment: string; // Help for the signature + export interface FormalSignatureItemInfo { + signatureInfo: string; + typeParameters: FormalTypeParameterInfo[]; + parameters: FormalParameterInfo[]; // Array of parameters + docComment: string; // Help for the signature } - export class FormalTypeParameterInfo { - public name: string; // Type parameter name - public docComment: string; // Comments that contain help for the parameter - public minChar: number; // minChar for parameter info in the formal signature info string - public limChar: number; // lim char for parameter info in the formal signature info string + export interface FormalTypeParameterInfo { + name: string; // Type parameter name + docComment: string; // Comments that contain help for the parameter + minChar: number; // minChar for parameter info in the formal signature info string + limChar: number; // lim char for parameter info in the formal signature info string } - export class FormalParameterInfo { - public name: string; // Parameter name - public isVariable: boolean; // true if parameter is var args - public docComment: string; // Comments that contain help for the parameter - public minChar: number; // minChar for parameter info in the formal signature info string - public limChar: number; // lim char for parameter info in the formal signature info string + export interface FormalParameterInfo { + name: string; // Parameter name + isVariable: boolean; // true if parameter is var args + docComment: string; // Comments that contain help for the parameter + minChar: number; // minChar for parameter info in the formal signature info string + limChar: number; // lim char for parameter info in the formal signature info string } - export class ActualSignatureInfo { - public parameterMinChar: number; - public parameterLimChar: number; - public currentParameterIsTypeParameter: boolean; // current parameter is a type argument or a normal argument - public currentParameter: number; // Index of active parameter in "parameters" or "typeParamters" array + export interface ActualSignatureInfo { + parameterMinChar: number; + parameterLimChar: number; + currentParameterIsTypeParameter: boolean; // current parameter is a type argument or a normal argument + currentParameter: number; // Index of active parameter in "parameters" or "typeParamters" array } - export class CompletionInfo { - public maybeInaccurate = false; - public isMemberCompletion = false; - public entries: CompletionEntry[] = []; + export interface CompletionInfo { + isMemberCompletion: boolean; + entries: CompletionEntry[]; } export interface CompletionEntry { @@ -254,6 +243,7 @@ module TypeScript.Services { } + // TODO: move these to enums export class ScriptElementKind { static unknown = ""; From 9395eeaedbb4279480c306f88e7916fa9694de31 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Sat, 19 Jul 2014 10:47:57 -0700 Subject: [PATCH 05/59] add module to defaults, and cleanup document management --- src/services/pullLanguageService.ts | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/services/pullLanguageService.ts b/src/services/pullLanguageService.ts index 93d2251d0d7..41ae8e94cf4 100644 --- a/src/services/pullLanguageService.ts +++ b/src/services/pullLanguageService.ts @@ -31,7 +31,10 @@ module TypeScript.Services { export function getDefaultCompilerOptions(): ts.CompilerOptions { // Set "ES5" target by default for language service - return { target: ts.ScriptTarget.ES5 }; + return { + target: ts.ScriptTarget.ES5, + module: ts.ModuleKind.None, + }; } // Cache host information about scripts. Should be refreshed @@ -442,6 +445,7 @@ module TypeScript.Services { getCancellationToken: () => this.cancellationToken, getCanonicalFileName: (filename) => this.useCaseSensitivefilenames ? filename : filename.toLowerCase(), useCaseSensitiveFileNames: () => this.useCaseSensitivefilenames, + getNewLine: ()=> "\n", // Need something that doesn't depend on sys.ts here getDefaultLibFilename: (): string => { throw Error("TOD:: getDefaultLibfilename"); @@ -466,9 +470,6 @@ module TypeScript.Services { // 2. compilation settings are identical // Now, remove any files from the compiler that are no longer in the host. - var oldDocumentsByName = this.documentsByName; - this.documentsByName = {}; - var oldProgram = this.program; if (oldProgram) { var oldSettings = this.program.getCompilerOptions(); @@ -481,6 +482,7 @@ module TypeScript.Services { var filename = oldSourceFiles[i].filename; if (!this.hostCache.contains(filename) || changesInCompilationSettingsAffectSyntax) { this.documentRegistry.releaseDocument(filename, oldSettings); + delete this.documentsByName[filename]; } } } @@ -497,7 +499,7 @@ module TypeScript.Services { var isOpen = this.hostCache.isOpen(filename); var scriptSnapshot = this.hostCache.getScriptSnapshot(filename); - var document: Document = oldDocumentsByName[filename]; + var document: Document = this.documentsByName[filename]; if (document) { // // If the document is the same, assume no update @@ -622,7 +624,7 @@ module TypeScript.Services { return ast; } } - getNameOrDottedNameSpan(filename: string, startPos: number, endPos: number) { + getNameOrDottedNameSpan(filename: string, startPos: number, endPos: number): SpanInfo { filename = TypeScript.switchToForwardSlashes(filename); var node = this.getTypeInfoEligiblePath(filename, startPos, false); @@ -638,8 +640,10 @@ module TypeScript.Services { } } - var spanInfo = new SpanInfo(start(node), end(node)); - return spanInfo; + return { + minChar: start(node), + limChar: end(node) + }; } getBreakpointStatementAtPosition(filename: string, position: number) { // doesn't use compiler - no need to synchronize with host From 05eeba5bc95f9a39ceb9c17b5674ed7135d74aed Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Sat, 19 Jul 2014 11:30:10 -0700 Subject: [PATCH 06/59] Do not use noResolve with the LS --- src/services/shims.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/services/shims.ts b/src/services/shims.ts index 48026856d14..53e44b262e7 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -317,7 +317,15 @@ module TypeScript.Services { throw Error("LanguageServiceShimHostAdapter.getCompilationSettings: empty compilationSettings"); return null; } - return compilationSettingsToCompilerOptions(JSON.parse(settingsJson)); + var options = compilationSettingsToCompilerOptions(JSON.parse(settingsJson)); + + /// TODO: this should be pushed into VS. + /// We can not ask the LS instance to resolve, as this will lead to asking the host about files it does not know about, + /// something it is not desinged to handle. for now make sure we never get a noresolve=true. + /// This value should not matter, as the host runs resolution logic independentlly + options.noResolve = true; + + return options; } public getScriptFileNames(): string[] { From f8767a561793f75dcbfcea574c2d3eeae865237d Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 22 Jul 2014 14:36:29 -0700 Subject: [PATCH 07/59] wire quick info --- src/compiler/checker.ts | 23 ++-- src/compiler/types.ts | 4 + src/services/pullLanguageService.ts | 119 +++++++++++++++++++- src/services/services.ts | 162 ---------------------------- src/services/typescriptServices.ts | 1 + 5 files changed, 137 insertions(+), 172 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b2b55085afe..4ea24b834c5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -739,10 +739,10 @@ module ts { }; } - function typeToString(type: Type, flags?: TypeFormatFlags): string { + function typeToString(type: Type, enclosingDeclaration?:Node, flags?: TypeFormatFlags): string { var stringWriter = createSingleLineTextWriter(); // TODO(shkamat): typeToString should take enclosingDeclaration as input, once we have implemented enclosingDeclaration - writeTypeToTextWriter(type, /*enclosingDeclaration*/ null, flags, stringWriter); + writeTypeToTextWriter(type, enclosingDeclaration, flags, stringWriter); return stringWriter.getText(); } @@ -1379,7 +1379,7 @@ module ts { type.baseTypes.push(baseType); } else { - error(declaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, TypeFormatFlags.WriteArrayAsGenericType)); + error(declaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType)); } } else { @@ -1420,7 +1420,7 @@ module ts { type.baseTypes.push(baseType); } else { - error(declaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, TypeFormatFlags.WriteArrayAsGenericType)); + error(declaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType)); } } else { @@ -1987,7 +1987,7 @@ module ts { type = createTypeReference(type, map(node.typeArguments, t => getTypeFromTypeNode(t))); } else { - error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, typeToString(type, TypeFormatFlags.WriteArrayAsGenericType), typeParameters.length); + error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType), typeParameters.length); type = undefined; } } @@ -6194,7 +6194,12 @@ module ts { function getSymbolOfIdentifier(identifier: Identifier) { if (isExpression(identifier)) { if (isRightSideOfQualifiedName()) { - // TODO + var node = identifier.parent; + var symbol = getNodeLinks(node).resolvedSymbol; + if (!symbol) { + checkPropertyAccess(node); + } + return getNodeLinks(node).resolvedSymbol; } return resolveEntityName(identifier, identifier, SymbolFlags.Value); } @@ -6425,7 +6430,11 @@ module ts { getReturnTypeOfSignature: getReturnTypeOfSignature, resolveEntityName: resolveEntityName, getSymbolsInScope: getSymbolsInScope, - getSymbolOfIdentifier: getSymbolOfIdentifier + getSymbolOfIdentifier: getSymbolOfIdentifier, + getTypeOfExpression: checkExpression, + typeToString: typeToString, + symbolToString: symbolToString, + writeTypeToTextWriter: writeTypeToTextWriter }; return checker; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 825e2147586..9078e8a4b56 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -599,6 +599,10 @@ module ts { resolveEntityName(location: Node, name: EntityName, meaning: SymbolFlags): Symbol; getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[]; getSymbolOfIdentifier(identifier: Identifier): Symbol; + getTypeOfExpression(node: Expression, contextualType?: Type, contextualMapper?: TypeMapper): Type; + typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string; + symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string; + writeTypeToTextWriter(type: Type, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter): void; } export interface TextWriter { diff --git a/src/services/pullLanguageService.ts b/src/services/pullLanguageService.ts index 41ae8e94cf4..9286c4ea203 100644 --- a/src/services/pullLanguageService.ts +++ b/src/services/pullLanguageService.ts @@ -564,8 +564,122 @@ module TypeScript.Services { getCompletionEntryDetails(filename: string, position: number, entryName: string) { return undefined; } - getTypeAtPosition(filename: string, position: number) { - return undefined; + + private getNodeAtPosition(sourceFile: ts.SourceFile, position: number) { + var current: ts.Node = sourceFile; + outer: while (true) { + // find the child that has this + for (var i = 0, n = current.getChildCount(); i < n; i++) { + var child = current.getChildAt(i); + if (ts.getTokenPosOfNode(child) <= position && position < child.end) { + current = child; + continue outer; + } + if (child.end > position) break; + } + return current; + } + } + + getEnclosingDeclaration(node: ts.Node): ts.Node { + while (true) { + node = node.parent; + if (!node) { + return node; + } + switch (node.kind) { + case ts.SyntaxKind.Method: + case ts.SyntaxKind.FunctionDeclaration: + case ts.SyntaxKind.FunctionExpression: + case ts.SyntaxKind.GetAccessor: + case ts.SyntaxKind.SetAccessor: + case ts.SyntaxKind.ClassDeclaration: + case ts.SyntaxKind.InterfaceDeclaration: + case ts.SyntaxKind.EnumDeclaration: + case ts.SyntaxKind.ModuleDeclaration: + return node; + } + } + } + + + getSymbolKind(symbol: ts.Symbol): string { + var flags = symbol.getFlags(); + if (flags & ts.SymbolFlags.Module) return ScriptElementKind.moduleElement; + if (flags & ts.SymbolFlags.Class) return ScriptElementKind.classElement; + if (flags & ts.SymbolFlags.Interface) return ScriptElementKind.interfaceElement; + if (flags & ts.SymbolFlags.Enum) return ScriptElementKind.enumElement; + if (flags & ts.SymbolFlags.Variable) return ScriptElementKind.variableElement; + if (flags & ts.SymbolFlags.Function) return ScriptElementKind.functionElement; + if (flags & ts.SymbolFlags.GetAccessor) return ScriptElementKind.memberGetAccessorElement; + if (flags & ts.SymbolFlags.SetAccessor) return ScriptElementKind.memberSetAccessorElement; + if (flags & ts.SymbolFlags.Method) return ScriptElementKind.memberFunctionElement; + if (flags & ts.SymbolFlags.Property) return ScriptElementKind.memberVariableElement; + if (flags & ts.SymbolFlags.IndexSignature) return ScriptElementKind.indexSignatureElement; + if (flags & ts.SymbolFlags.ConstructSignature) return ScriptElementKind.constructSignatureElement; + if (flags & ts.SymbolFlags.CallSignature) return ScriptElementKind.callSignatureElement; + if (flags & ts.SymbolFlags.Constructor) return ScriptElementKind.constructorImplementationElement; + if (flags & ts.SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; + if (flags & ts.SymbolFlags.EnumMember) return ScriptElementKind.variableElement; + return ScriptElementKind.unknown; + } + + getTypeKind(type: ts.Type): string { + var flags = type.getFlags(); + if (flags & ts.TypeFlags.Enum) return ScriptElementKind.enumElement; + if (flags & ts.TypeFlags.Class) return ScriptElementKind.classElement; + if (flags & ts.TypeFlags.Interface) return ScriptElementKind.interfaceElement; + if (flags & ts.TypeFlags.TypeParameter) return ScriptElementKind.typeParameterElement; + if (flags & ts.TypeFlags.Intrinsic) return ScriptElementKind.primitiveType; + if (flags & ts.TypeFlags.StringLiteral) return ScriptElementKind.primitiveType; + return ScriptElementKind.unknown; + } + + getTypeAtPosition(filename: string, position: number): TypeInfo { + this.synchronizeHostData(); + + filename = TypeScript.switchToForwardSlashes(filename); + var document = this.documentsByName[filename]; + var node = this.getNodeAtPosition(document.sourceFile(), position); + if (!node) return undefined; + + switch (node.kind) { + // A declaration + case ts.SyntaxKind.Identifier: + if (node.parent.kind === ts.SyntaxKind.CallExpression || node.parent.kind === ts.SyntaxKind.NewExpression) { + // TODO: handle new and call expressions + } + + var symbol = this.typeChecker. getSymbolOfIdentifier(node); + Debug.assert(symbol, "getTypeAtPosition: Could not find symbol for node"); + var type = this.typeChecker.getTypeOfSymbol(symbol); + + return { + memberName: new MemberNameString(this.typeChecker.typeToString(type)), + docComment: "", + fullSymbolName: this.typeChecker.symbolToString(symbol, this.getEnclosingDeclaration(node)), + kind: this.getSymbolKind(symbol), + minChar: node.pos, + limChar: node.end + }; + + // An Expression + case ts.SyntaxKind.ThisKeyword: + case ts.SyntaxKind.QualifiedName: + case ts.SyntaxKind.SuperKeyword: + case ts.SyntaxKind.StringLiteral: + var type = this.typeChecker.getTypeOfExpression(node); + Debug.assert(type, "getTypeAtPosition: Could not find type for node"); + return { + memberName: new MemberNameString(""), + docComment: "", + fullSymbolName: this.typeChecker.typeToString(type, this.getEnclosingDeclaration(node)), + kind: this.getTypeKind(type), + minChar: node.pos, + limChar: node.end + }; + break; + } } getSignatureAtPosition(filename: string, position: number) { return undefined; @@ -589,7 +703,6 @@ module TypeScript.Services { return undefined; } - private getTypeInfoEligiblePath(filename: string, position: number, isConstructorValidPosition: boolean) { var sourceUnit = this._syntaxTreeCache.getCurrentFileSyntaxTree(filename).sourceUnit(); diff --git a/src/services/services.ts b/src/services/services.ts index 69685d79fc0..5f9d3a2f708 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -41,88 +41,6 @@ module ts { getReturnType(): Type; } - interface HostFileInformation { - version: string; - isOpen: boolean; - byteOrderMark: ByteOrderMark; - sourceText?: IScriptSnapshot; - } - - // - // Public services of a language service instance associated - // with a language service host instance - // - export interface LanguageService { - getSyntacticDiagnostics(filename: string): Diagnostic[]; - getSemanticDiagnostics(filename: string): Diagnostic[]; - } - - // - // Public interface of the host of a language service instance. - // - export interface LanguageServiceHost { - log(s: string): void; - - getCompilationSettings(): CompilerOptions; - - getScriptFileNames(): string[]; - getScriptVersion(filename: string): string; - getScriptIsOpen(filename: string): boolean; - getScriptByteOrderMark(filename: string): ByteOrderMark; - getScriptSnapshot(filename: string): IScriptSnapshot; - getLocalizedDiagnosticMessages(): any; - //getCancellationToken(): CancellationToken; - } - - // Represents an immutable snapshot of a script at a specified time. Once acquired, the - // snapshot is observably immutable. i.e. the same calls with the same parameters will return - // the same values. - export interface IScriptSnapshot { - // Get's a portion of the script snapshot specified by [start, end). - getText(start: number, end: number): string; - - // Get's the length of this script snapshot. - getLength(): number; - - // This call returns the array containing the start position of every line. - // i.e."[0, 10, 55]". TODO: consider making this optional. The language service could - // always determine this (albeit in a more expensive manner). - getLineStartPositions(): number[]; - - // Gets the TextChangeRange that describe how the text changed between this text and - // an older version. This informatoin is used by the incremental parser to determine - // what sections of the script need to be reparsed. 'null' can be returned if the - // change range cannot be determined. However, in that case, incremental parsing will - // not happen and the entire document will be reparsed. - getChangeRange(oldSnapshot: IScriptSnapshot): TextChangeRange; - } - - export interface Span { - start(): number; - end(): number; - } - - export interface TextChange { - span: Span; - newText: string; - } - - export interface TextChangeRange { - span(): Span; - newLength(): number; - } - - export enum ByteOrderMark { - None = 0, - Utf8 = 1, - Utf16BigEndian = 2, - Utf16LittleEndian = 3, - } - - export interface CancellationToken { - isCancellationRequested(): boolean; - } - var scanner: Scanner = createScanner(ScriptTarget.ES5); var emptyArray: any [] = []; @@ -335,86 +253,6 @@ module ts { } } - export function createLanguageService(host: LanguageServiceHost): LanguageService { - - var program: Program; - var typeChecker: TypeChecker; - var filesByName: Map; - - function createCompilerHost(): CompilerHost { - return { - getSourceFile: (filename, languageVersion) => { - var hostFile = filesByName[filename]; - - // TODO use the document registry to get or update - - if (!hostFile.sourceText) { - hostFile.sourceText = host.getScriptSnapshot(filename); - } - - // TODO add support for IScriptSnapshot in the parser - return createSourceFile(filename, hostFile.sourceText.getText(0, hostFile.sourceText.getLength()), languageVersion); - }, - // Need something that doesn't depend on sys.ts here - getDefaultLibFilename: () => combinePaths(getDirectoryPath(normalizePath(sys.getExecutingFilePath())), "lib.d.ts"), - getCancellationToken: (): CancellationToken => undefined, - writeFile: (fileName, data) => { - throw Error("TODO: write file"); - }, - getCurrentDirectory: (): string => { - throw Error("TODO: getCurrentDirectory"); - }, - getCanonicalFileName: getCanonicalFileName, - useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames - }; - } - - function synchronizeHostData(): void { - // Build the cache - filesByName = {}; - var files = host.getScriptFileNames(); - forEach(files, (f) => { - filesByName[f] = { - version: host.getScriptVersion(f), - isOpen: host.getScriptIsOpen(f), - byteOrderMark: host.getScriptByteOrderMark(f) - }; - }); - - var currentProgram = program; - - var options = host.getCompilationSettings(); - - // update the program - program = createProgram(files, options, createCompilerHost()); - - // Update the typeChecker - typeChecker = program.getTypeChecker(); - - // TODO release old sources from the registry - if (currentProgram) { - - } - } - - function getSyntacticDiagnostics(filename: string): Diagnostic[] { - synchronizeHostData(); - var sourceFile = program.getSourceFile(filename); - return sourceFile ? program.getDiagnostics(sourceFile) : []; - } - - function getSemanticDiagnostics(filename: string): Diagnostic[] { - synchronizeHostData(); - var sourceFile = program.getSourceFile(filename); - return sourceFile ? typeChecker.getDiagnostics(sourceFile) : []; - } - - return { - getSyntacticDiagnostics: getSyntacticDiagnostics, - getSemanticDiagnostics: getSemanticDiagnostics, - }; - } - function initializeServices() { objectAllocator = { getNodeConstructor: kind => { diff --git a/src/services/typescriptServices.ts b/src/services/typescriptServices.ts index 908b9bf063a..9c79c2db5b0 100644 --- a/src/services/typescriptServices.ts +++ b/src/services/typescriptServices.ts @@ -13,6 +13,7 @@ // limitations under the License. // +/// /// /// From 8eda35afa0803eaa21b49ea0014d9dfd920dbc92 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 22 Jul 2014 14:37:18 -0700 Subject: [PATCH 08/59] Ensure SimpleArrowFunctionExpression has a NodeArray as its paramter as ForEachChild expexts that --- src/compiler/parser.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 1536d0c00d8..d1e2b83a2b7 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1624,7 +1624,12 @@ module ts { parameter.name = identifier; finishNode(parameter); - var signature = { parameters: [parameter] }; + var parameters = >[]; + parameters.push(parameter); + parameters.pos = parameter.pos; + parameters.end = parameter.end; + + var signature = { parameters: parameters }; return parseArrowExpressionTail(identifier.pos, signature, /*noIn:*/ false); } From 346809ba2b4ab2050a99c593d117c36d342b57a3 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 23 Jul 2014 16:52:21 -0700 Subject: [PATCH 09/59] wire in getCompletions --- src/compiler/checker.ts | 122 ++++++++++----- src/compiler/parser.ts | 8 + src/compiler/types.ts | 1 + src/services/completionHelpers.ts | 72 ++++----- src/services/keywordCompletions.ts | 13 +- src/services/pullLanguageService.ts | 229 +++++++++++++++++++++++++++- src/services/services.ts | 4 + src/services/typescriptServices.ts | 2 + 8 files changed, 365 insertions(+), 86 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4ea24b834c5..ab32682c90a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -63,7 +63,33 @@ module ts { var diagnostics: Diagnostic[] = []; var diagnosticsModified: boolean = false; - var checker: TypeChecker; + var checker: TypeChecker = { + getProgram: () => program, + getDiagnostics: getDiagnostics, + getGlobalDiagnostics: getGlobalDiagnostics, + getNodeCount: () => sum(program.getSourceFiles(), "nodeCount"), + getIdentifierCount: () => sum(program.getSourceFiles(), "identifierCount"), + getSymbolCount: () => sum(program.getSourceFiles(), "symbolCount"), + getTypeCount: () => typeCount, + checkProgram: checkProgram, + emitFiles: invokeEmitter, + getSymbolOfNode: getSymbolOfNode, + getParentOfSymbol: getParentOfSymbol, + getTypeOfSymbol: getTypeOfSymbol, + getDeclaredTypeOfSymbol: getDeclaredTypeOfSymbol, + getPropertiesOfType: getPropertiesOfType, + getSignaturesOfType: getSignaturesOfType, + getIndexTypeOfType: getIndexTypeOfType, + getReturnTypeOfSignature: getReturnTypeOfSignature, + resolveEntityName: resolveEntityName, + getSymbolsInScope: getSymbolsInScope, + getSymbolOfIdentifier: getSymbolOfIdentifier, + getTypeOfExpression: getTypeOfExpression, + typeToString: typeToString, + symbolToString: symbolToString, + writeTypeToTextWriter: writeTypeToTextWriter, + getAugmentedPropertiesOfApparentType: getAugmentedPropertiesOfApparentType + }; function addDiagnostic(diagnostic: Diagnostic) { diagnostics.push(diagnostic); @@ -4784,14 +4810,6 @@ module ts { return (node.flags & NodeFlags.Private) && isInAmbientContext(node); } - function isInAmbientContext(node: Node): boolean { - while (node) { - if (node.flags & (NodeFlags.Ambient | NodeFlags.DeclarationFile)) return true; - node = node.parent; - } - return false; - } - function checkSpecializedSignatureDeclaration(signatureDeclarationNode: SignatureDeclaration): void { var signature = getSignatureFromDeclaration(signatureDeclarationNode); if (!signature.hasStringLiterals) { @@ -6191,9 +6209,14 @@ module ts { return false; } + function isRightSideOfQualifiedName(node: Node) { + return (node.parent.kind === SyntaxKind.QualifiedName || node.parent.kind === SyntaxKind.PropertyAccess) && + (node.parent).right === node; + } + function getSymbolOfIdentifier(identifier: Identifier) { if (isExpression(identifier)) { - if (isRightSideOfQualifiedName()) { + if (isRightSideOfQualifiedName(identifier)) { var node = identifier.parent; var symbol = getNodeLinks(node).resolvedSymbol; if (!symbol) { @@ -6207,16 +6230,58 @@ module ts { return getSymbolOfNode(identifier.parent); } if (isTypeReferenceIdentifier(identifier)) { - var entityName = isRightSideOfQualifiedName() ? identifier.parent : identifier; + var entityName = isRightSideOfQualifiedName(identifier) ? identifier.parent : identifier; var meaning = entityName.parent.kind === SyntaxKind.TypeReference ? SymbolFlags.Type : SymbolFlags.Namespace; return resolveEntityName(entityName, entityName, meaning); } - function isRightSideOfQualifiedName() { - return (identifier.parent.kind === SyntaxKind.QualifiedName || identifier.parent.kind === SyntaxKind.PropertyAccess) && - (identifier.parent).right === identifier; - } } + function getTypeOfExpression(node: Node) { + if (isExpression(node)) { + while (isRightSideOfQualifiedName(node)) { + node = node.parent; + } + return getApparentType(checkExpression(node)); + } + return unknownType; + } + + function getAugmentedPropertiesOfApparentType(type: Type): Symbol[]{ + var apparentType = getApparentType(type); + + if (apparentType.flags & TypeFlags.ObjectType) { + // Augment the apprent type with Function and Object memeber as applicaple + var propertiesByName: Map = {}; + var results: Symbol[] = []; + + forEach(getPropertiesOfType(apparentType), (s) => { + propertiesByName[s.name] = s; + results.push(s); + }); + + var resolved = resolveObjectTypeMembers(type); + forEachValue(resolved.members, (s) => { + if (symbolIsValue(s) && !propertiesByName[s.name]) { + propertiesByName[s.name] = s; + results.push(s); + } + }); + + if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) { + forEach(getPropertiesOfType(globalFunctionType), (s) => { + if (!propertiesByName[s.name]) { + propertiesByName[s.name] = s; + results.push(s); + } + }); + } + + return results; + } + else { + return getPropertiesOfType(apparentType); + } + } // Emitter support function isExternalModuleSymbol(symbol: Symbol): boolean { @@ -6410,32 +6475,7 @@ module ts { } initializeTypeChecker(); - checker = { - getProgram: () => program, - getDiagnostics: getDiagnostics, - getGlobalDiagnostics: getGlobalDiagnostics, - getNodeCount: () => sum(program.getSourceFiles(), "nodeCount"), - getIdentifierCount: () => sum(program.getSourceFiles(), "identifierCount"), - getSymbolCount: () => sum(program.getSourceFiles(), "symbolCount"), - getTypeCount: () => typeCount, - checkProgram: checkProgram, - emitFiles: invokeEmitter, - getSymbolOfNode: getSymbolOfNode, - getParentOfSymbol: getParentOfSymbol, - getTypeOfSymbol: getTypeOfSymbol, - getDeclaredTypeOfSymbol: getDeclaredTypeOfSymbol, - getPropertiesOfType: getPropertiesOfType, - getSignaturesOfType: getSignaturesOfType, - getIndexTypeOfType: getIndexTypeOfType, - getReturnTypeOfSignature: getReturnTypeOfSignature, - resolveEntityName: resolveEntityName, - getSymbolsInScope: getSymbolsInScope, - getSymbolOfIdentifier: getSymbolOfIdentifier, - getTypeOfExpression: checkExpression, - typeToString: typeToString, - symbolToString: symbolToString, - writeTypeToTextWriter: writeTypeToTextWriter - }; + return checker; } } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index d1e2b83a2b7..bd4b0510b9a 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -327,6 +327,14 @@ module ts { return s.parameters.length > 0 && (s.parameters[s.parameters.length - 1].flags & NodeFlags.Rest) !== 0; } + export function isInAmbientContext(node: Node): boolean { + while (node) { + if (node.flags & (NodeFlags.Ambient | NodeFlags.DeclarationFile)) return true; + node = node.parent; + } + return false; + } + enum ParsingContext { SourceElements, // Elements in source file ModuleElements, // Elements in module declaration diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9078e8a4b56..71d1c9d1e84 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -603,6 +603,7 @@ module ts { typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string; symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string; writeTypeToTextWriter(type: Type, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter): void; + getAugmentedPropertiesOfApparentType(type: Type): Symbol[]; } export interface TextWriter { diff --git a/src/services/completionHelpers.ts b/src/services/completionHelpers.ts index c5cb961af79..17a68d097b0 100644 --- a/src/services/completionHelpers.ts +++ b/src/services/completionHelpers.ts @@ -9,46 +9,46 @@ module TypeScript.Services { return new TextSpan(start(ast), width(ast)); } - private static symbolDeclarationIntersectsPosition(symbol: PullSymbol, fileName: string, position: number) { - var decl = symbol.getDeclarations()[0]; - if (decl.fileName() === fileName && this.getSpan(decl.ast()).intersectsWithPosition(position)) { - // This is the symbol declaration from the given position in the file - return true; - } + //private static symbolDeclarationIntersectsPosition(symbol: PullSymbol, fileName: string, position: number) { + // var decl = symbol.getDeclarations()[0]; + // if (decl.fileName() === fileName && this.getSpan(decl.ast()).intersectsWithPosition(position)) { + // // This is the symbol declaration from the given position in the file + // return true; + // } - return false; - } + // return false; + //} - public static filterContextualMembersList(contextualMemberSymbols: TypeScript.PullSymbol[], existingMembers: TypeScript.PullVisibleSymbolsInfo, fileName: string, position: number): TypeScript.PullSymbol[] { - if (!existingMembers || !existingMembers.symbols || existingMembers.symbols.length === 0) { - return contextualMemberSymbols; - } + //public static filterContextualMembersList(contextualMemberSymbols: TypeScript.PullSymbol[], existingMembers: TypeScript.PullVisibleSymbolsInfo, fileName: string, position: number): TypeScript.PullSymbol[] { + // if (!existingMembers || !existingMembers.symbols || existingMembers.symbols.length === 0) { + // return contextualMemberSymbols; + // } - var existingMemberSymbols = existingMembers.symbols; - var existingMemberNames = TypeScript.createIntrinsicsObject(); - for (var i = 0, n = existingMemberSymbols.length; i < n; i++) { - if (this.symbolDeclarationIntersectsPosition(existingMemberSymbols[i], fileName, position)) { - // If this is the current item we are editing right now, do not filter it out - continue; - } + // var existingMemberSymbols = existingMembers.symbols; + // var existingMemberNames = TypeScript.createIntrinsicsObject(); + // for (var i = 0, n = existingMemberSymbols.length; i < n; i++) { + // if (this.symbolDeclarationIntersectsPosition(existingMemberSymbols[i], fileName, position)) { + // // If this is the current item we are editing right now, do not filter it out + // continue; + // } - existingMemberNames[TypeScript.stripStartAndEndQuotes(existingMemberSymbols[i].getDisplayName())] = true; - } + // existingMemberNames[TypeScript.stripStartAndEndQuotes(existingMemberSymbols[i].getDisplayName())] = true; + // } - var filteredMembers: TypeScript.PullSymbol[] = []; - for (var j = 0, m = contextualMemberSymbols.length; j < m; j++) { - var contextualMemberSymbol = contextualMemberSymbols[j]; - if (!existingMemberNames[TypeScript.stripStartAndEndQuotes(contextualMemberSymbol.getDisplayName())]) { - if (this.symbolDeclarationIntersectsPosition(contextualMemberSymbol, fileName, position)) { - // If this contextual member symbol was created as part of editing the current position, do not use it - continue; - } - filteredMembers.push(contextualMemberSymbol); - } - } + // var filteredMembers: TypeScript.PullSymbol[] = []; + // for (var j = 0, m = contextualMemberSymbols.length; j < m; j++) { + // var contextualMemberSymbol = contextualMemberSymbols[j]; + // if (!existingMemberNames[TypeScript.stripStartAndEndQuotes(contextualMemberSymbol.getDisplayName())]) { + // if (this.symbolDeclarationIntersectsPosition(contextualMemberSymbol, fileName, position)) { + // // If this contextual member symbol was created as part of editing the current position, do not use it + // continue; + // } + // filteredMembers.push(contextualMemberSymbol); + // } + // } - return filteredMembers; - } + // return filteredMembers; + //} public static isCompletionListBlocker(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean { // We shouldn't be getting a possition that is outside the file because @@ -173,7 +173,7 @@ module TypeScript.Services { return false; } - public static getValidCompletionEntryDisplayName(displayName: string): string { + public static getValidCompletionEntryDisplayName(displayName: string, target: ts.ScriptTarget): string { if (displayName && displayName.length > 0) { var firstChar = displayName.charCodeAt(0); if (firstChar === TypeScript.CharacterCodes.singleQuote || firstChar === TypeScript.CharacterCodes.doubleQuote) { @@ -182,7 +182,7 @@ module TypeScript.Services { displayName = TypeScript.stripStartAndEndQuotes(displayName); } - if (TypeScript.Scanner.isValidIdentifier(TypeScript.SimpleText.fromString(displayName), TypeScript.LanguageVersion.EcmaScript5)) { + if (TypeScript.Scanner.isValidIdentifier(TypeScript.SimpleText.fromString(displayName), target)) { return displayName; } } diff --git a/src/services/keywordCompletions.ts b/src/services/keywordCompletions.ts index 90ebc5bdd53..3233a0f95a7 100644 --- a/src/services/keywordCompletions.ts +++ b/src/services/keywordCompletions.ts @@ -53,15 +53,18 @@ module TypeScript.Services { "with", ]; - private static keywordCompletions: ResolvedCompletionEntry[] = null; + private static keywordCompletions: CompletionEntry[] = null; - public static getKeywordCompltions(): ResolvedCompletionEntry[]{ + public static getKeywordCompltions(): CompletionEntry[]{ if (KeywordCompletions.keywordCompletions === null) { - var completions: ResolvedCompletionEntry[] = []; + var completions: CompletionEntry[] = []; for (var i = 0, n = KeywordCompletions.keywords.length; i < n; i++) { var keyword = KeywordCompletions.keywords[i]; - var entry = new ResolvedCompletionEntry(/*name*/ keyword, ScriptElementKind.keyword, ScriptElementKindModifier.none, /*type*/null, /*fullName*/ keyword, /*docComment*/ null); - completions.push(entry); + completions.push({ + name: keyword, + kind: ScriptElementKind.keyword, + kindModifiers: ScriptElementKindModifier.none + }); } KeywordCompletions.keywordCompletions = completions; diff --git a/src/services/pullLanguageService.ts b/src/services/pullLanguageService.ts index 9286c4ea203..7b97c1a9d63 100644 --- a/src/services/pullLanguageService.ts +++ b/src/services/pullLanguageService.ts @@ -7,6 +7,15 @@ /// module TypeScript.Services { + interface CompletionSession { + filename: string; // the file where the completion was requested + position: number; // position in the file where the completion was requested + entries: CompletionEntry[]; // entries for this completion + symbols: ts.Map; // symbols by entry name map + location: ts.Node; // the node where the completion was requested + typeChecker: ts.TypeChecker;// the typeChecker used to generate this completion + } + // Information about a specific host file. class HostFileInformation { private _sourceText: TypeScript.IScriptSnapshot; @@ -420,6 +429,7 @@ module TypeScript.Services { private documentsByName: ts.Map = {}; private documentRegistry: IDocumentRegistry private cancellationToken: CancellationToken; + private activeCompletionSession: CompletionSession; constructor(public host: ILanguageServiceHost, documentRegistry: IDocumentRegistry) { this.logger = this.host; @@ -558,11 +568,206 @@ module TypeScript.Services { this.synchronizeHostData(); return this.program.getGlobalDiagnostics(); } + + private getCompletionEntriesFromSymbols(symbols: ts.Symbol[], session:CompletionSession): void { + ts.forEach(symbols, (symbol) => { + var entry = this.createCompletionEntry(symbol); + if (entry) { + session.entries.push(entry); + session.symbols[entry.name] = symbol; + } + }); + } + + private createCompletionEntry(symbol: ts.Symbol): CompletionEntry { + // Try to get a valid display name for this symbol, if we could not find one, then ignore it. + // We would like to only show things that can be added after a dot, so for instance numeric properties can + // not be accessed with a dot (a.1 <- invalid) + var displayName = CompletionHelpers.getValidCompletionEntryDisplayName(symbol.getName(), this.program.getCompilerOptions().target); + if (!displayName) { + return undefined; + } + + var declarations = symbol.getDeclarations(); + var firstDeclaration = [0]; + return { + name: displayName, + kind: this.getSymbolKind(symbol), + kindModifiers: declarations ? this.getNodeModifiers(declarations[0]) : ScriptElementKindModifier.none + }; + } + getCompletionsAtPosition(filename: string, position: number, isMemberCompletion: boolean) { - return undefined; + this.synchronizeHostData(); + + filename = TypeScript.switchToForwardSlashes(filename); + + var document = this.documentsByName[filename]; + var sourceUnit = document.sourceUnit(); + + if (CompletionHelpers.isCompletionListBlocker(document.syntaxTree().sourceUnit(), position)) { + this.logger.log("Returning an empty list because completion was blocked."); + return null; + } + + var node = TypeScript.ASTHelpers.getAstAtPosition(sourceUnit, position, /*useTrailingTriviaAsLimChar*/ true, /*forceInclusive*/ true); + + if (node && node.kind() === TypeScript.SyntaxKind.IdentifierName && + start(node) === end(node)) { + // Ignore missing name nodes + node = node.parent; + } + + var isRightOfDot = false; + if (node && + node.kind() === TypeScript.SyntaxKind.MemberAccessExpression && + end((node).expression) < position) { + + isRightOfDot = true; + node = (node).expression; + } + else if (node && + node.kind() === TypeScript.SyntaxKind.QualifiedName && + end((node).left) < position) { + + isRightOfDot = true; + node = (node).left; + } + else if (node && node.parent && + node.kind() === TypeScript.SyntaxKind.IdentifierName && + node.parent.kind() === TypeScript.SyntaxKind.MemberAccessExpression && + (node.parent).name === node) { + + isRightOfDot = true; + node = (node.parent).expression; + } + else if (node && node.parent && + node.kind() === TypeScript.SyntaxKind.IdentifierName && + node.parent.kind() === TypeScript.SyntaxKind.QualifiedName && + (node.parent).right === node) { + + isRightOfDot = true; + node = (node.parent).left; + } + + // TODO: this is a hack for now, we need a proper walking mechanism to verify that we have the correct node + var mappedNode = this.getNodeAtPosition(document.sourceFile(), end(node) - 1); + + Debug.assert(mappedNode, "Could not map a Fidelity node to an AST node"); + + // Get the completions + this.activeCompletionSession = { + filename: filename, + position: position, + entries: [], + symbols: {}, + location: mappedNode, + typeChecker: this.typeChecker + }; + + // Right of dot member completion list + if (isRightOfDot) { + var type: ts.Type = this.typeChecker.getTypeOfExpression(mappedNode); + if (!type) { + return undefined; + } + + var symbols = type.getApparentProperties(); + isMemberCompletion = true; + this.getCompletionEntriesFromSymbols(symbols, this.activeCompletionSession); + } + else { + var containingObjectLiteral = CompletionHelpers.getContainingObjectLiteralApplicableForCompletion(document.syntaxTree().sourceUnit(), position); + + // Object literal expression, look up possible property names from contextual type + if (containingObjectLiteral) { + var searchPosition = Math.min(position, end(containingObjectLiteral)); + var path = TypeScript.ASTHelpers.getAstAtPosition(sourceUnit, searchPosition); + // Get the object literal node + + while (node && node.kind() !== TypeScript.SyntaxKind.ObjectLiteralExpression) { + node = node.parent; + } + + if (!node || node.kind() !== TypeScript.SyntaxKind.ObjectLiteralExpression) { + // AST Path look up did not result in the same node as Fidelity Syntax Tree look up. + // Once we remove AST this will no longer be a problem. + return null; + } + + isMemberCompletion = true; + + //// Try to get the object members form contextual typing + //var contextualMembers = this.compiler.getContextualMembersFromAST(node, document); + //if (contextualMembers && contextualMembers.symbols && contextualMembers.symbols.length > 0) { + // // get existing members + // var existingMembers = this.compiler.getVisibleMemberSymbolsFromAST(node, document); + + // // Add filtterd items to the completion list + // this.getCompletionEntriesFromSymbols({ + // symbols: CompletionHelpers.filterContextualMembersList(contextualMembers.symbols, existingMembers, filename, position), + // enclosingScopeSymbol: contextualMembers.enclosingScopeSymbol + // }, entries); + //} + } + // Get scope memebers + else { + isMemberCompletion = false; + /// TODO filter meaning based on the current context + var symbolMeanings = ts.SymbolFlags.Type | ts.SymbolFlags.Value | ts.SymbolFlags.Namespace; + var symbols = this.typeChecker.getSymbolsInScope(mappedNode, symbolMeanings); + + this.getCompletionEntriesFromSymbols(symbols, this.activeCompletionSession); + } + } + + // Add keywords if this is not a member completion list + if (!isMemberCompletion) { + Array.prototype.push.apply(this.activeCompletionSession.entries, KeywordCompletions.getKeywordCompltions()); + } + + return { + isMemberCompletion: isMemberCompletion, + entries: this.activeCompletionSession.entries + }; } getCompletionEntryDetails(filename: string, position: number, entryName: string) { - return undefined; + // Note: No need to call synchronizeHostData, as we have captured all the data we need + // in the getCompletionsAtPosition erlier + filename = TypeScript.switchToForwardSlashes(filename); + + var session = this.activeCompletionSession; + + // Ensure that the current active completion session is still valid for this request + if (!session || session.filename !== filename || session.position !== position) { + return undefined; + } + + var symbol = this.activeCompletionSession.symbols[entryName]; + if (symbol) { + var type = session.typeChecker.getTypeOfSymbol(symbol); + Debug.assert(type, "Could not find type for symbol"); + var completionEntry = this.createCompletionEntry(symbol); + return { + name: entryName, + kind: completionEntry.kind, + kindModifiers: completionEntry.kindModifiers, + type: session.typeChecker.typeToString(type, session.location), + fullSymbolName: this.typeChecker.symbolToString(symbol, session.location), + docComment: "" + }; + } + else { + // No symbol, it is a keyword + return { + name: entryName, + kind: ScriptElementKind.keyword, + kindModifiers: ScriptElementKindModifier.none, + type: undefined, + fullSymbolName: entryName, + docComment: undefined + }; + } } private getNodeAtPosition(sourceFile: ts.SourceFile, position: number) { @@ -581,7 +786,7 @@ module TypeScript.Services { } } - getEnclosingDeclaration(node: ts.Node): ts.Node { + private getEnclosingDeclaration(node: ts.Node): ts.Node { while (true) { node = node.parent; if (!node) { @@ -601,10 +806,10 @@ module TypeScript.Services { } } } - getSymbolKind(symbol: ts.Symbol): string { var flags = symbol.getFlags(); + if (flags & ts.SymbolFlags.Module) return ScriptElementKind.moduleElement; if (flags & ts.SymbolFlags.Class) return ScriptElementKind.classElement; if (flags & ts.SymbolFlags.Interface) return ScriptElementKind.interfaceElement; @@ -621,20 +826,36 @@ module TypeScript.Services { if (flags & ts.SymbolFlags.Constructor) return ScriptElementKind.constructorImplementationElement; if (flags & ts.SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; if (flags & ts.SymbolFlags.EnumMember) return ScriptElementKind.variableElement; + return ScriptElementKind.unknown; } getTypeKind(type: ts.Type): string { var flags = type.getFlags(); + if (flags & ts.TypeFlags.Enum) return ScriptElementKind.enumElement; if (flags & ts.TypeFlags.Class) return ScriptElementKind.classElement; if (flags & ts.TypeFlags.Interface) return ScriptElementKind.interfaceElement; if (flags & ts.TypeFlags.TypeParameter) return ScriptElementKind.typeParameterElement; if (flags & ts.TypeFlags.Intrinsic) return ScriptElementKind.primitiveType; if (flags & ts.TypeFlags.StringLiteral) return ScriptElementKind.primitiveType; + return ScriptElementKind.unknown; } + getNodeModifiers(node: ts.Node): string { + var flags = node.flags; + var result: string[] = []; + + if (flags & ts.NodeFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier); + if (flags & ts.NodeFlags.Public) result.push(ScriptElementKindModifier.publicMemberModifier); + if (flags & ts.NodeFlags.Static) result.push(ScriptElementKindModifier.staticModifier); + if (flags & ts.NodeFlags.Export) result.push(ScriptElementKindModifier.exportedModifier); + if (ts.isInAmbientContext(node)) result.push(ScriptElementKindModifier.ambientModifier); + + return result.length > 0 ? result.join(',') : ScriptElementKindModifier.none; + } + getTypeAtPosition(filename: string, position: number): TypeInfo { this.synchronizeHostData(); diff --git a/src/services/services.ts b/src/services/services.ts index 5f9d3a2f708..e8cd12002fd 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -28,6 +28,7 @@ module ts { getFlags(): TypeFlags; getSymbol(): Symbol; getProperties(): Symbol[]; + getApparentProperties(): Symbol[]; getCallSignatures(): Signature[]; getConstructSignatures(): Signature[]; getStringIndexType(): Type; @@ -213,6 +214,9 @@ module ts { getProperties(): Symbol[] { return this.checker.getPropertiesOfType(this); } + getApparentProperties(): Symbol[]{ + return this.checker.getAugmentedPropertiesOfApparentType(this); + } getCallSignatures(): Signature[] { return this.checker.getSignaturesOfType(this, SignatureKind.Call); } diff --git a/src/services/typescriptServices.ts b/src/services/typescriptServices.ts index 9c79c2db5b0..21ae5f6a6fa 100644 --- a/src/services/typescriptServices.ts +++ b/src/services/typescriptServices.ts @@ -34,6 +34,8 @@ /// /// /// +/// +/// /// From 212c18460281cac5b5be5239d45f7d04212f62d8 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 23 Jul 2014 16:52:43 -0700 Subject: [PATCH 10/59] use Map instead of StringHashTable --- src/services/compiler/hashTable.ts | 224 ++++++++++++++-------------- src/services/pullLanguageService.ts | 57 +++---- 2 files changed, 143 insertions(+), 138 deletions(-) diff --git a/src/services/compiler/hashTable.ts b/src/services/compiler/hashTable.ts index e1bae0cd8df..0e05a05b52e 100644 --- a/src/services/compiler/hashTable.ts +++ b/src/services/compiler/hashTable.ts @@ -43,145 +43,145 @@ module TypeScript { return new BlockIntrinsics(); } - export interface IHashTable { - getAllKeys(): string[]; - add(key: string, data: T): boolean; - addOrUpdate(key: string, data: T): boolean; - map(fn: (k: string, value: T, context: any) => void , context: any): void; - every(fn: (k: string, value: T, context: any) => void , context: any): boolean; - some(fn: (k: string, value: T, context: any) => void , context: any): boolean; - count(): number; - lookup(key: string): T; - } + //export interface IHashTable { + // getAllKeys(): string[]; + // add(key: string, data: T): boolean; + // addOrUpdate(key: string, data: T): boolean; + // map(fn: (k: string, value: T, context: any) => void , context: any): void; + // every(fn: (k: string, value: T, context: any) => void , context: any): boolean; + // some(fn: (k: string, value: T, context: any) => void , context: any): boolean; + // count(): number; + // lookup(key: string): T; + //} - export class StringHashTable implements IHashTable { - private itemCount = 0; - private table: IIndexable = createIntrinsicsObject(); + //export class StringHashTable implements IHashTable { + // private itemCount = 0; + // private table: IIndexable = createIntrinsicsObject(); - public getAllKeys(): string[] { - var result: string[] = []; + // public getAllKeys(): string[] { + // var result: string[] = []; - for (var k in this.table) { - if (this.table[k] !== undefined) { - result.push(k); - } - } + // for (var k in this.table) { + // if (this.table[k] !== undefined) { + // result.push(k); + // } + // } - return result; - } + // return result; + // } - public add(key: string, data: T): boolean { - if (this.table[key] !== undefined) { - return false; - } + // public add(key: string, data: T): boolean { + // if (this.table[key] !== undefined) { + // return false; + // } - this.table[key] = data; - this.itemCount++; - return true; - } + // this.table[key] = data; + // this.itemCount++; + // return true; + // } - public addOrUpdate(key: string, data: T): boolean { - if (this.table[key] !== undefined) { - this.table[key] = data; - return false; - } + // public addOrUpdate(key: string, data: T): boolean { + // if (this.table[key] !== undefined) { + // this.table[key] = data; + // return false; + // } - this.table[key] = data; - this.itemCount++; - return true; - } + // this.table[key] = data; + // this.itemCount++; + // return true; + // } - public map(fn: (k: string, value: T, context: any) => void , context: any) { - for (var k in this.table) { - var data = this.table[k]; + // public map(fn: (k: string, value: T, context: any) => void , context: any) { + // for (var k in this.table) { + // var data = this.table[k]; - if (data !== undefined) { - fn(k, this.table[k], context); - } - } - } + // if (data !== undefined) { + // fn(k, this.table[k], context); + // } + // } + // } - public every(fn: (k: string, value: T, context: any) => void , context: any) { - for (var k in this.table) { - var data = this.table[k]; + // public every(fn: (k: string, value: T, context: any) => void , context: any) { + // for (var k in this.table) { + // var data = this.table[k]; - if (data !== undefined) { - if (!fn(k, this.table[k], context)) { - return false; - } - } - } + // if (data !== undefined) { + // if (!fn(k, this.table[k], context)) { + // return false; + // } + // } + // } - return true; - } + // return true; + // } - public some(fn: (k: string, value: T, context: any) => void , context: any) { - for (var k in this.table) { - var data = this.table[k]; + // public some(fn: (k: string, value: T, context: any) => void , context: any) { + // for (var k in this.table) { + // var data = this.table[k]; - if (data !== undefined) { - if (fn(k, this.table[k], context)) { - return true; - } - } - } + // if (data !== undefined) { + // if (fn(k, this.table[k], context)) { + // return true; + // } + // } + // } - return false; - } + // return false; + // } - public count(): number { - return this.itemCount; - } + // public count(): number { + // return this.itemCount; + // } - public lookup(key: string) : T { - var data = this.table[key]; - return data === undefined ? null : data; - } + // public lookup(key: string) : T { + // var data = this.table[key]; + // return data === undefined ? null : data; + // } - public remove(key: string): void { - if (this.table[key] !== undefined) { - this.table[key] = undefined; - this.itemCount--; - } - } - } + // public remove(key: string): void { + // if (this.table[key] !== undefined) { + // this.table[key] = undefined; + // this.itemCount--; + // } + // } + //} - export class IdentiferNameHashTable extends StringHashTable { - public getAllKeys(): string[]{ - var result: string[] = []; + //export class IdentiferNameHashTable extends StringHashTable { + // public getAllKeys(): string[]{ + // var result: string[] = []; - super.map((k, v, c) => { - if (v !== undefined) { - result.push(k.substring(1)); - } - }, null); + // super.map((k, v, c) => { + // if (v !== undefined) { + // result.push(k.substring(1)); + // } + // }, null); - return result; - } + // return result; + // } - public add(key: string, data: T): boolean { - return super.add("#" + key, data); - } + // public add(key: string, data: T): boolean { + // return super.add("#" + key, data); + // } - public addOrUpdate(key: string, data: T): boolean { - return super.addOrUpdate("#" + key, data); - } + // public addOrUpdate(key: string, data: T): boolean { + // return super.addOrUpdate("#" + key, data); + // } - public map(fn: (k: string, value: T, context: any) => void , context: any) { - return super.map((k, v, c) => fn(k.substring(1), v, c), context); - } + // public map(fn: (k: string, value: T, context: any) => void , context: any) { + // return super.map((k, v, c) => fn(k.substring(1), v, c), context); + // } - public every(fn: (k: string, value: T, context: any) => void , context: any) { - return super.every((k, v, c) => fn(k.substring(1), v, c), context); - } + // public every(fn: (k: string, value: T, context: any) => void , context: any) { + // return super.every((k, v, c) => fn(k.substring(1), v, c), context); + // } - public some(fn: (k: string, value: any, context: any) => void , context: any) { - return super.some((k, v, c) => fn(k.substring(1), v, c), context); - } + // public some(fn: (k: string, value: any, context: any) => void , context: any) { + // return super.some((k, v, c) => fn(k.substring(1), v, c), context); + // } - public lookup(key: string): T { - return super.lookup("#" + key); - } - } + // public lookup(key: string): T { + // return super.lookup("#" + key); + // } + //} } \ No newline at end of file diff --git a/src/services/pullLanguageService.ts b/src/services/pullLanguageService.ts index 7b97c1a9d63..fa1169b02cb 100644 --- a/src/services/pullLanguageService.ts +++ b/src/services/pullLanguageService.ts @@ -50,18 +50,18 @@ module TypeScript.Services { // at each language service public entry point, since we don't know when // set of scripts handled by the host changes. class HostCache { - private _filenameToEntry: TypeScript.StringHashTable; + private _filenameToEntry: ts.Map; private _compilationSettings: ts.CompilerOptions; constructor(host: ILanguageServiceHost) { // script id => script index - this._filenameToEntry = new TypeScript.StringHashTable(); + this._filenameToEntry = {}; var filenames = host.getScriptFileNames(); for (var i = 0, n = filenames.length; i < n; i++) { var filename = filenames[i]; - this._filenameToEntry.add(TypeScript.switchToForwardSlashes(filename), new HostFileInformation( - filename, host, host.getScriptVersion(filename), host.getScriptIsOpen(filename), host.getScriptByteOrderMark(filename))); + this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)] = new HostFileInformation( + filename, host, host.getScriptVersion(filename), host.getScriptIsOpen(filename), host.getScriptByteOrderMark(filename)); } this._compilationSettings = host.getCompilationSettings() || getDefaultCompilerOptions(); @@ -72,35 +72,39 @@ module TypeScript.Services { } public contains(filename: string): boolean { - return this._filenameToEntry.lookup(TypeScript.switchToForwardSlashes(filename)) !== null; + return !!this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)]; } public getHostfilename(filename: string) { - var hostCacheEntry = this._filenameToEntry.lookup(TypeScript.switchToForwardSlashes(filename)); + var hostCacheEntry = this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)]; if (hostCacheEntry) { return hostCacheEntry.filename; } return filename; } - public getfilenames(): string[] { - return this._filenameToEntry.getAllKeys(); + public getfilenames(): string[]{ + var fileNames: string[] = []; + for (var id in this._filenameToEntry) { + fileNames.push(id); + } + return fileNames; } public getVersion(filename: string): number { - return this._filenameToEntry.lookup(TypeScript.switchToForwardSlashes(filename)).version; + return this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)].version; } public isOpen(filename: string): boolean { - return this._filenameToEntry.lookup(TypeScript.switchToForwardSlashes(filename)).isOpen; + return this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)].isOpen; } public getByteOrderMark(filename: string): TypeScript.ByteOrderMark { - return this._filenameToEntry.lookup(TypeScript.switchToForwardSlashes(filename)).byteOrderMark; + return this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)].byteOrderMark; } public getScriptSnapshot(filename: string): TypeScript.IScriptSnapshot { - return this._filenameToEntry.lookup(TypeScript.switchToForwardSlashes(filename)).getScriptSnapshot(); + return this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)].getScriptSnapshot(); } public getScriptTextChangeRangeSinceVersion(filename: string, lastKnownVersion: number): TypeScript.TextChangeRange { @@ -325,17 +329,17 @@ module TypeScript.Services { } export class DocumentRegistry implements IDocumentRegistry { - private buckets: IIndexable> = {}; + private buckets: ts.Map> = {}; private getKeyFromCompilationSettings(settings: ts.CompilerOptions): string { return "_" + ts.ScriptTarget[settings.target]; // + "|" + settings.propagateEnumConstants.toString() } - private getBucketForCompilationSettings(settings: ts.CompilerOptions, createIfMissing: boolean): StringHashTable { + private getBucketForCompilationSettings(settings: ts.CompilerOptions, createIfMissing: boolean): ts.Map { var key = this.getKeyFromCompilationSettings(settings); var bucket = this.buckets[key]; if (!bucket && createIfMissing) { - this.buckets[key] = bucket = new StringHashTable(); + this.buckets[key] = bucket = {}; } return bucket; } @@ -343,14 +347,15 @@ module TypeScript.Services { public reportStats() { var bucketInfoArray = Object.keys(this.buckets).filter(name => name && name.charAt(0) === '_').map(name => { var entries = this.buckets[name]; - var documents = entries.getAllKeys().map((name) => { - var entry = entries.lookup(name); - return { - name: name, + var documents = []; + for (var i in entries) { + var entry = entries[i]; + documents.push({ + name: i, refCount: entry.refCount, references: entry.owners.slice(0) - }; - }); + }); + } documents.sort((x, y) => y.refCount - x.refCount); return { bucket: name, documents: documents } }); @@ -367,12 +372,12 @@ module TypeScript.Services { referencedFiles: string[]= []): TypeScript.Document { var bucket = this.getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ true); - var entry = bucket.lookup(filename); + var entry = bucket[filename]; if (!entry) { var document = Document.create(compilationSettings, filename, scriptSnapshot, byteOrderMark, version, isOpen, referencedFiles); entry = new DocumentRegistryEntry(document); - bucket.add(filename, entry); + bucket[filename] = entry; } entry.refCount++; @@ -391,7 +396,7 @@ module TypeScript.Services { var bucket = this.getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ false); Debug.assert(bucket); - var entry = bucket.lookup(filename); + var entry = bucket[filename]; Debug.assert(entry); if (entry.document.isOpen === isOpen && entry.document.version === version) { @@ -406,12 +411,12 @@ module TypeScript.Services { var bucket = this.getBucketForCompilationSettings(compilationSettings, false); Debug.assert(bucket); - var entry = bucket.lookup(filename); + var entry = bucket[filename]; entry.refCount--; Debug.assert(entry.refCount >= 0); if (entry.refCount === 0) { - bucket.remove(filename); + delete bucket[filename]; } } } From 3bfc294123906580668547541d3081a6c0b8126f Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 23 Jul 2014 17:31:44 -0700 Subject: [PATCH 11/59] Switch some more classes to interfaces --- src/services/pullLanguageService.ts | 56 +++++++++++++---------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/src/services/pullLanguageService.ts b/src/services/pullLanguageService.ts index fa1169b02cb..bd112a97fd3 100644 --- a/src/services/pullLanguageService.ts +++ b/src/services/pullLanguageService.ts @@ -17,25 +17,12 @@ module TypeScript.Services { } // Information about a specific host file. - class HostFileInformation { - private _sourceText: TypeScript.IScriptSnapshot; - - constructor( - public filename: string, - private host: ILanguageServiceHost, - public version: number, - public isOpen: boolean, - public byteOrderMark: TypeScript.ByteOrderMark) { - this._sourceText = null; - } - - public getScriptSnapshot(): TypeScript.IScriptSnapshot { - if (this._sourceText === null) { - this._sourceText = this.host.getScriptSnapshot(this.filename); - } - - return this._sourceText; - } + interface HostFileInformation { + filename: string; + version: number; + isOpen: boolean; + byteOrderMark: TypeScript.ByteOrderMark; + _sourceText?: TypeScript.IScriptSnapshot; } export function getDefaultCompilerOptions(): ts.CompilerOptions { @@ -53,15 +40,19 @@ module TypeScript.Services { private _filenameToEntry: ts.Map; private _compilationSettings: ts.CompilerOptions; - constructor(host: ILanguageServiceHost) { + constructor(private host: ILanguageServiceHost) { // script id => script index this._filenameToEntry = {}; var filenames = host.getScriptFileNames(); for (var i = 0, n = filenames.length; i < n; i++) { var filename = filenames[i]; - this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)] = new HostFileInformation( - filename, host, host.getScriptVersion(filename), host.getScriptIsOpen(filename), host.getScriptByteOrderMark(filename)); + this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)] = { + filename: filename, + version: host.getScriptVersion(filename), + isOpen: host.getScriptIsOpen(filename), + byteOrderMark: host.getScriptByteOrderMark(filename) + }; } this._compilationSettings = host.getCompilationSettings() || getDefaultCompilerOptions(); @@ -83,7 +74,7 @@ module TypeScript.Services { return filename; } - public getfilenames(): string[]{ + public getfilenames(): string[] { var fileNames: string[] = []; for (var id in this._filenameToEntry) { fileNames.push(id); @@ -104,7 +95,11 @@ module TypeScript.Services { } public getScriptSnapshot(filename: string): TypeScript.IScriptSnapshot { - return this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)].getScriptSnapshot(); + var file = this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)]; + if (!file._sourceText) { + file._sourceText = this.host.getScriptSnapshot(file.filename); + } + return file._sourceText; } public getScriptTextChangeRangeSinceVersion(filename: string, lastKnownVersion: number): TypeScript.TextChangeRange { @@ -256,14 +251,11 @@ module TypeScript.Services { } } - class FormattingOptions { - constructor(public useTabs: boolean, - public spacesPerTab: number, - public indentSpaces: number, - public newLineCharacter: string) { - } - - public static defaultOptions = new FormattingOptions(/*useTabs:*/ false, /*spacesPerTab:*/ 4, /*indentSpaces:*/ 4, /*newLineCharacter*/ "\r\n"); + interface FormattingOptions { + useTabs: boolean; + spacesPerTab: number; + indentSpaces: number; + newLineCharacter: string; } class DocumentRegistryEntry { From e5d810384cd64e194a29f4b73dc43d8335dbad2c Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 23 Jul 2014 17:41:37 -0700 Subject: [PATCH 12/59] remove dependency on settings --- src/services/pullLanguageService.ts | 8 +++++++- src/services/typescriptServices.ts | 1 - 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/services/pullLanguageService.ts b/src/services/pullLanguageService.ts index bd112a97fd3..c8926cd4a5f 100644 --- a/src/services/pullLanguageService.ts +++ b/src/services/pullLanguageService.ts @@ -480,8 +480,14 @@ module TypeScript.Services { var oldProgram = this.program; if (oldProgram) { var oldSettings = this.program.getCompilerOptions(); + + // If the language version changed, then that affects what types of things we parse. So + // we have to dump all syntax trees. + // TODO: handle propagateEnumConstants + var settingsChangeAffectsSyntax = oldSettings.target !== compilationSettings.target; + var changesInCompilationSettingsAffectSyntax = - oldSettings && compilationSettings && !compareDataObjects(oldSettings, compilationSettings) && settingsChangeAffectsSyntax(oldSettings, compilationSettings); + oldSettings && compilationSettings && !compareDataObjects(oldSettings, compilationSettings) && settingsChangeAffectsSyntax; var oldSourceFiles = this.program.getSourceFiles(); for (var i = 0, n = oldSourceFiles.length; i < n; i++) { diff --git a/src/services/typescriptServices.ts b/src/services/typescriptServices.ts index 21ae5f6a6fa..4e272126874 100644 --- a/src/services/typescriptServices.ts +++ b/src/services/typescriptServices.ts @@ -46,7 +46,6 @@ /// /// /// -/// /// /// /// From e23ff87f5ae13c6c1bb5a09c59048ab82d15caa8 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 23 Jul 2014 18:39:37 -0700 Subject: [PATCH 13/59] use Map instead of IIndexable --- src/services/compiler/bloomFilter.ts | 2 +- src/services/compiler/hashTable.ts | 2 +- src/services/compiler/referenceResolution.ts | 4 ++++ src/services/compiler/referenceResolver.ts | 2 +- src/services/core/diagnosticCore.ts | 4 ++-- src/services/formatting/rules.ts | 2 +- src/services/getScriptLexicalStructureWalker.ts | 4 ++-- src/services/resources/diagnosticInformationMap.generated.ts | 2 +- 8 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/services/compiler/bloomFilter.ts b/src/services/compiler/bloomFilter.ts index fe841b6f7a3..8b0e3674e09 100644 --- a/src/services/compiler/bloomFilter.ts +++ b/src/services/compiler/bloomFilter.ts @@ -81,7 +81,7 @@ module TypeScript { return Hash.computeMurmur2StringHashCode(key, seed); } - public addKeys(keys: IIndexable) { + public addKeys(keys: ts.Map) { for (var name in keys) { if (keys[name]) { this.add(name); diff --git a/src/services/compiler/hashTable.ts b/src/services/compiler/hashTable.ts index 0e05a05b52e..89c7551a571 100644 --- a/src/services/compiler/hashTable.ts +++ b/src/services/compiler/hashTable.ts @@ -39,7 +39,7 @@ module TypeScript { } } - export function createIntrinsicsObject(): IIndexable { + export function createIntrinsicsObject(): ts.Map { return new BlockIntrinsics(); } diff --git a/src/services/compiler/referenceResolution.ts b/src/services/compiler/referenceResolution.ts index 315c72d98f5..528347a6ea8 100644 --- a/src/services/compiler/referenceResolution.ts +++ b/src/services/compiler/referenceResolution.ts @@ -16,6 +16,10 @@ /// module TypeScript { + export interface ILineAndCharacter { + line: number; + character: number; + } // Note: This is being using by the host (VS) and is marshaled back and forth. When changing this make sure the changes // are reflected in the managed side as well. diff --git a/src/services/compiler/referenceResolver.ts b/src/services/compiler/referenceResolver.ts index d1b264d0818..7991be64a89 100644 --- a/src/services/compiler/referenceResolver.ts +++ b/src/services/compiler/referenceResolver.ts @@ -44,7 +44,7 @@ module TypeScript { export class ReferenceResolver { private inputFileNames: string[]; private host: IReferenceResolverHost; - private visited: IIndexable; + private visited: ts.Map; constructor(inputFileNames: string[], host: IReferenceResolverHost, private useCaseSensitiveFileResolution: boolean) { this.inputFileNames = inputFileNames; diff --git a/src/services/core/diagnosticCore.ts b/src/services/core/diagnosticCore.ts index 0a796a6770f..8485052af8f 100644 --- a/src/services/core/diagnosticCore.ts +++ b/src/services/core/diagnosticCore.ts @@ -1,7 +1,7 @@ /// module TypeScript { - export var LocalizedDiagnosticMessages: IIndexable = null; + export var LocalizedDiagnosticMessages: ts.Map = null; export class Location { private _fileName: string; @@ -120,7 +120,7 @@ module TypeScript { // TODO: We need to expose an extensibility point on our hosts to have them tell us what // they want the newline string to be. That way we can get the correct result regardless // of which host we use - return Environment ? Environment.newLine : "\r\n"; + return sys.newLine ? sys.newLine : "\r\n"; } function getLargestIndex(diagnostic: string): number { diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index 2a297efc371..ade1dc6b217 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -18,7 +18,7 @@ module TypeScript.Services.Formatting { export class Rules { public getRuleName(rule: Rule) { - var o: IIndexable = this; + var o: ts.Map = this; for (var name in o) { if (o[name] === rule) { return name; diff --git a/src/services/getScriptLexicalStructureWalker.ts b/src/services/getScriptLexicalStructureWalker.ts index 66d930784dd..a9a179e51b7 100644 --- a/src/services/getScriptLexicalStructureWalker.ts +++ b/src/services/getScriptLexicalStructureWalker.ts @@ -2,9 +2,9 @@ /// module TypeScript.Services { interface LexicalScope { - items: TypeScript.IIndexable; + items: ts.Map; itemNames: string[]; - childScopes: TypeScript.IIndexable; + childScopes: ts.Map; childScopeNames: string[]; } diff --git a/src/services/resources/diagnosticInformationMap.generated.ts b/src/services/resources/diagnosticInformationMap.generated.ts index ed594be6985..8d3bc73486e 100644 --- a/src/services/resources/diagnosticInformationMap.generated.ts +++ b/src/services/resources/diagnosticInformationMap.generated.ts @@ -1,7 +1,7 @@ // /// module TypeScript { - export var diagnosticInformationMap: IIndexable = { + export var diagnosticInformationMap: ts.Map = { "error TS{0}: {1}": { "code": 0, "category": DiagnosticCategory.NoPrefix }, "warning TS{0}: {1}": { "code": 1, "category": DiagnosticCategory.NoPrefix }, "Unrecognized escape sequence.": { "code": 1000, "category": DiagnosticCategory.Error }, From 5777320d27cfd87c6bcb75a89578dc7ff1608edb Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 23 Jul 2014 18:45:36 -0700 Subject: [PATCH 14/59] remove unused files --- src/services/core/references.ts | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/services/core/references.ts b/src/services/core/references.ts index a03523834ca..fcfd10126ec 100644 --- a/src/services/core/references.ts +++ b/src/services/core/references.ts @@ -1,24 +1,13 @@ -/// - /// /// -/// -/// -/// /// /// /// /// /// /// -/// -/// /// -/// -/// /// /// -// /// -/// -/// \ No newline at end of file +/// \ No newline at end of file From 87763db4090ad4169211c747f2de031360202d73 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 23 Jul 2014 18:46:11 -0700 Subject: [PATCH 15/59] Move ByteOrderMark to services --- src/services/typescriptServices.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/services/typescriptServices.ts b/src/services/typescriptServices.ts index 4e272126874..2dcd1e75678 100644 --- a/src/services/typescriptServices.ts +++ b/src/services/typescriptServices.ts @@ -80,6 +80,13 @@ module TypeScript { Declaration } + export enum ByteOrderMark { + None = 0, + Utf8 = 1, + Utf16BigEndian = 2, + Utf16LittleEndian = 3, + } + export class OutputFile { constructor(public name: string, public writeByteOrderMark: boolean, From 38771693c6b7692bdc0a449c2548d6ca3d6fd496 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 24 Jul 2014 10:51:16 -0700 Subject: [PATCH 16/59] Delete unused files --- src/services/compiler/settings.ts | 15 - src/services/compilerState.ts | 472 ------------- src/services/completionSession.ts | 68 -- src/services/core/bitMatrix.ts | 82 --- src/services/core/bitVector.ts | 210 ------ src/services/core/cancellationToken.ts | 3 - src/services/core/cancellationTokenSource.ts | 7 - src/services/core/constants.ts | 9 - src/services/core/environment.ts | 505 ------------- src/services/core/indexable.ts | 7 - src/services/core/iterator.ts | 8 - src/services/core/lineAndCharacter.ts | 8 - src/services/core/require.ts | 5 - src/services/diagnosticsParser.ts | 363 ---------- src/services/es5compat.ts | 354 ---------- src/services/indenter.ts | 207 ------ src/services/languageServiceCopy.ts | 342 --------- src/services/syntaxRewriter.generated.ts | 708 ------------------- src/services/syntaxUtilities.generated.ts | 395 ----------- 19 files changed, 3768 deletions(-) delete mode 100644 src/services/compiler/settings.ts delete mode 100644 src/services/compilerState.ts delete mode 100644 src/services/completionSession.ts delete mode 100644 src/services/core/bitMatrix.ts delete mode 100644 src/services/core/bitVector.ts delete mode 100644 src/services/core/cancellationToken.ts delete mode 100644 src/services/core/cancellationTokenSource.ts delete mode 100644 src/services/core/constants.ts delete mode 100644 src/services/core/environment.ts delete mode 100644 src/services/core/indexable.ts delete mode 100644 src/services/core/iterator.ts delete mode 100644 src/services/core/lineAndCharacter.ts delete mode 100644 src/services/core/require.ts delete mode 100644 src/services/diagnosticsParser.ts delete mode 100644 src/services/es5compat.ts delete mode 100644 src/services/indenter.ts delete mode 100644 src/services/languageServiceCopy.ts delete mode 100644 src/services/syntaxRewriter.generated.ts delete mode 100644 src/services/syntaxUtilities.generated.ts diff --git a/src/services/compiler/settings.ts b/src/services/compiler/settings.ts deleted file mode 100644 index 11b58fb0e41..00000000000 --- a/src/services/compiler/settings.ts +++ /dev/null @@ -1,15 +0,0 @@ -/// - -module TypeScript { - export function settingsChangeAffectsSyntax(before: ts.CompilerOptions, after: ts.CompilerOptions): boolean { - // If the automatic semicolon insertion option has changed, then we have to dump all - // syntax trees in order to reparse them with the new option. - // - // If the language version changed, then that affects what types of things we parse. So - // we have to dump all syntax trees. - // - // If propagateEnumConstants changes, then that affects the constant value data we've - // stored in the ISyntaxElement. - return before.module !== after.module || before.target !== after.target; - } -} \ No newline at end of file diff --git a/src/services/compilerState.ts b/src/services/compilerState.ts deleted file mode 100644 index a4d31494af7..00000000000 --- a/src/services/compilerState.ts +++ /dev/null @@ -1,472 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -/// - -module TypeScript.Services { - // Information about a specific host file. - class HostFileInformation { - private _sourceText: TypeScript.IScriptSnapshot; - - constructor( - public fileName: string, - private host: ILanguageServiceHost, - public version: number, - public isOpen: boolean, - public byteOrderMark: TypeScript.ByteOrderMark) { - this._sourceText = null; - } - - public getScriptSnapshot(): TypeScript.IScriptSnapshot { - if (this._sourceText === null) { - this._sourceText = this.host.getScriptSnapshot(this.fileName); - } - - return this._sourceText; - } - } - - // Cache host information about scripts. Should be refreshed - // at each language service public entry point, since we don't know when - // set of scripts handled by the host changes. - class HostCache { - private _fileNameToEntry: TypeScript.StringHashTable; - private _compilationSettings: TypeScript.ImmutableCompilationSettings; - - constructor(host: ILanguageServiceHost) { - // script id => script index - this._fileNameToEntry = new TypeScript.StringHashTable(); - - var fileNames = host.getScriptFileNames(); - for (var i = 0, n = fileNames.length; i < n; i++) { - var fileName = fileNames[i]; - this._fileNameToEntry.add(TypeScript.switchToForwardSlashes(fileName), new HostFileInformation( - fileName, host, host.getScriptVersion(fileName), host.getScriptIsOpen(fileName), host.getScriptByteOrderMark(fileName))); - } - - var settings = host.getCompilationSettings(); - if (!settings) { - // Set "ES5" target by default for language service - settings = new TypeScript.CompilationSettings(); - settings.codeGenTarget = TypeScript.LanguageVersion.EcmaScript5; - } - - this._compilationSettings = TypeScript.ImmutableCompilationSettings.fromCompilationSettings(settings); - } - - public compilationSettings() { - return this._compilationSettings; - } - - public contains(fileName: string): boolean { - return this._fileNameToEntry.lookup(TypeScript.switchToForwardSlashes(fileName)) !== null; - } - - public getHostFileName(fileName: string) { - var hostCacheEntry = this._fileNameToEntry.lookup(TypeScript.switchToForwardSlashes(fileName)); - if (hostCacheEntry) { - return hostCacheEntry.fileName; - } - return fileName; - } - - public getFileNames(): string[]{ - return this._fileNameToEntry.getAllKeys(); - } - - public getVersion(fileName: string): number { - return this._fileNameToEntry.lookup(TypeScript.switchToForwardSlashes(fileName)).version; - } - - public isOpen(fileName: string): boolean { - return this._fileNameToEntry.lookup(TypeScript.switchToForwardSlashes(fileName)).isOpen; - } - - public getByteOrderMark(fileName: string): TypeScript.ByteOrderMark { - return this._fileNameToEntry.lookup(TypeScript.switchToForwardSlashes(fileName)).byteOrderMark; - } - - public getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot { - return this._fileNameToEntry.lookup(TypeScript.switchToForwardSlashes(fileName)).getScriptSnapshot(); - } - - public getScriptTextChangeRangeSinceVersion(fileName: string, lastKnownVersion: number): TypeScript.TextChangeRange { - var currentVersion = this.getVersion(fileName); - if (lastKnownVersion === currentVersion) { - return TypeScript.TextChangeRange.unchanged; // "No changes" - } - - var scriptSnapshot = this.getScriptSnapshot(fileName); - return scriptSnapshot.getTextChangeRangeSinceVersion(lastKnownVersion); - } - } - - export class SyntaxTreeCache { - private _hostCache: HostCache; - - // For our syntactic only features, we also keep a cache of the syntax tree for the - // currently edited file. - private _currentFileName: string = ""; - private _currentFileVersion: number = -1; - private _currentFileSyntaxTree: TypeScript.SyntaxTree = null; - private _currentFileScriptSnapshot: TypeScript.IScriptSnapshot = null; - - constructor(private _host: ILanguageServiceHost) { - this._hostCache = new HostCache(_host); - } - - public getCurrentFileSyntaxTree(fileName: string): TypeScript.SyntaxTree { - this._hostCache = new HostCache(this._host); - - var version = this._hostCache.getVersion(fileName); - var syntaxTree: TypeScript.SyntaxTree = null; - - if (this._currentFileSyntaxTree === null || this._currentFileName !== fileName) { - var scriptSnapshot = this._hostCache.getScriptSnapshot(fileName); - syntaxTree = this.createSyntaxTree(fileName, scriptSnapshot); - } - else if (this._currentFileVersion !== version) { - var scriptSnapshot = this._hostCache.getScriptSnapshot(fileName); - syntaxTree = this.updateSyntaxTree(fileName, scriptSnapshot, this._currentFileSyntaxTree, this._currentFileVersion); - } - - if (syntaxTree !== null) { - // All done, ensure state is up to date - this._currentFileScriptSnapshot = scriptSnapshot; - this._currentFileVersion = version; - this._currentFileName = fileName; - this._currentFileSyntaxTree = syntaxTree; - } - - return this._currentFileSyntaxTree; - } - - private createSyntaxTree(fileName: string, scriptSnapshot: TypeScript.IScriptSnapshot): TypeScript.SyntaxTree { - var text = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot); - - // For the purposes of features that use this syntax tree, we can just use the default - // compilation settings. The features only use the syntax (and not the diagnostics), - // and the syntax isn't affected by the compilation settings. - var syntaxTree = TypeScript.Parser.parse(fileName, text, - TypeScript.ImmutableCompilationSettings.defaultSettings().codeGenTarget(), TypeScript.isDTSFile(fileName)); - - return syntaxTree; - } - - private updateSyntaxTree(fileName: string, scriptSnapshot: TypeScript.IScriptSnapshot, previousSyntaxTree: TypeScript.SyntaxTree, previousFileVersion: number): TypeScript.SyntaxTree { - var editRange = this._hostCache.getScriptTextChangeRangeSinceVersion(fileName, previousFileVersion); - - // Debug.assert(newLength >= 0); - - // The host considers the entire buffer changed. So parse a completely new tree. - if (editRange === null) { - return this.createSyntaxTree(fileName, scriptSnapshot); - } - - var nextSyntaxTree = IncrementalParser.parse( - previousSyntaxTree, editRange, SimpleText.fromScriptSnapshot(scriptSnapshot)); - - this.ensureInvariants(fileName, editRange, nextSyntaxTree, this._currentFileScriptSnapshot, scriptSnapshot); - - return nextSyntaxTree; - } - - private ensureInvariants(fileName: string, editRange: TypeScript.TextChangeRange, incrementalTree: TypeScript.SyntaxTree, oldScriptSnapshot: TypeScript.IScriptSnapshot, newScriptSnapshot: TypeScript.IScriptSnapshot) { - // First, verify that the edit range and the script snapshots make sense. - - // If this fires, then the edit range is completely bogus. Somehow the lengths of the - // old snapshot, the change range and the new snapshot aren't in sync. This is very - // bad. - var expectedNewLength = oldScriptSnapshot.getLength() - editRange.span().length() + editRange.newLength(); - var actualNewLength = newScriptSnapshot.getLength(); - - function provideMoreDebugInfo() { - - var debugInformation = ["expected length:", expectedNewLength, "and actual length:", actualNewLength, "are not equal\r\n"]; - - var oldSpan = editRange.span(); - - function prettyPrintString(s: string): string { - return '"' + s.replace(/\r/g, '\\r').replace(/\n/g, '\\n') + '"'; - } - - debugInformation.push('Edit range (old text) (start: ' + oldSpan.start() + ', end: ' + oldSpan.end() + ') \r\n'); - debugInformation.push('Old text edit range contents: ' + prettyPrintString(oldScriptSnapshot.getText(oldSpan.start(), oldSpan.end()))); - - var newSpan = editRange.newSpan(); - - debugInformation.push('Edit range (new text) (start: ' + newSpan.start() + ', end: ' + newSpan.end() + ') \r\n'); - debugInformation.push('New text edit range contents: ' + prettyPrintString(newScriptSnapshot.getText(newSpan.start(), newSpan.end()))); - - return debugInformation.join(' '); - } - - Debug.assert( - expectedNewLength === actualNewLength, - "Expected length is different from actual!", - provideMoreDebugInfo); - - if (Debug.shouldAssert(AssertionLevel.VeryAggressive)) { - // If this fires, the text change range is bogus. It says the change starts at point - // 'X', but we can see a text difference *before* that point. - var oldPrefixText = oldScriptSnapshot.getText(0, editRange.span().start()); - var newPrefixText = newScriptSnapshot.getText(0, editRange.span().start()); - Debug.assert(oldPrefixText === newPrefixText, 'Expected equal prefix texts!'); - - // If this fires, the text change range is bogus. It says the change goes only up to - // point 'X', but we can see a text difference *after* that point. - var oldSuffixText = oldScriptSnapshot.getText(editRange.span().end(), oldScriptSnapshot.getLength()); - var newSuffixText = newScriptSnapshot.getText(editRange.newSpan().end(), newScriptSnapshot.getLength()); - Debug.assert(oldSuffixText === newSuffixText, 'Expected equal suffix texts!'); - - // Ok, text change range and script snapshots look ok. Let's verify that our - // incremental parsing worked properly. - //var normalTree = this.createSyntaxTree(fileName, newScriptSnapshot); - //Debug.assert(normalTree.structuralEquals(incrementalTree), 'Expected equal incremental and normal trees'); - - // Ok, the trees looked good. So at least our incremental parser agrees with the - // normal parser. Now, verify that the incremental tree matches the contents of the - // script snapshot. - var incrementalTreeText = fullText(incrementalTree.sourceUnit()); - var actualSnapshotText = newScriptSnapshot.getText(0, newScriptSnapshot.getLength()); - Debug.assert(incrementalTreeText === actualSnapshotText, 'Expected full texts to be equal'); - } - } - } - - export class LanguageServiceCompiler { - private logger: TypeScript.ILogger; - - // The underlying typescript compiler we defer most operations to. - private compiler: TypeScript.TypeScriptCompiler = null; - - // A cache of all the information about the files on the host side. - private hostCache: HostCache = null; - - constructor(private host: ILanguageServiceHost, private documentRegistry: IDocumentRegistry, private cancellationToken: CancellationToken) { - this.logger = this.host; - } - - private synchronizeHostData(): void { - TypeScript.timeFunction(this.logger, "synchronizeHostData()", () => { - this.synchronizeHostDataWorker(); - }); - } - - private synchronizeHostDataWorker(): void { - // Reset the cache at start of every refresh - this.hostCache = new HostCache(this.host); - - var compilationSettings = this.hostCache.compilationSettings(); - - // If we don't have a compiler, then create a new one. - if (this.compiler === null) { - this.compiler = new TypeScript.TypeScriptCompiler(this.logger, compilationSettings); - } - - var oldSettings = this.compiler.compilationSettings(); - - var changesInCompilationSettingsAffectSyntax = - oldSettings && compilationSettings && !compareDataObjects(oldSettings, compilationSettings) && settingsChangeAffectsSyntax(oldSettings, compilationSettings); - - // let the compiler know about the current compilation settings. - this.compiler.setCompilationSettings(compilationSettings); - - // Now, remove any files from the compiler that are no longer in the host. - var compilerFileNames = this.compiler.fileNames(); - - for (var i = 0, n = compilerFileNames.length; i < n; i++) { - - this.cancellationToken.throwIfCancellationRequested(); - - var fileName = compilerFileNames[i]; - - if (!this.hostCache.contains(fileName) || changesInCompilationSettingsAffectSyntax) { - this.compiler.removeFile(fileName); - this.documentRegistry.releaseDocument(fileName, oldSettings); - } - } - - // Now, for every file the host knows about, either add the file (if the compiler - // doesn't know about it.). Or notify the compiler about any changes (if it does - // know about it.) - var hostFileNames = this.hostCache.getFileNames(); - - for (var i = 0, n = hostFileNames.length; i < n; i++) { - var fileName = hostFileNames[i]; - - var version = this.hostCache.getVersion(fileName); - var isOpen = this.hostCache.isOpen(fileName); - var scriptSnapshot = this.hostCache.getScriptSnapshot(fileName); - - var document: Document = this.compiler.getDocument(fileName) - if (document) { - // - // If the document is the same, assume no update - // - if (document.version === version && document.isOpen === isOpen) { - continue; - } - - // Only perform incremental parsing on open files that are being edited. If a file was - // open, but is now closed, we want to reparse entirely so we don't have any tokens that - // are holding onto expensive script snapshot instances on the host. Similarly, if a - // file was closed, then we always want to reparse. This is so our tree doesn't keep - // the old buffer alive that represented the file on disk (as the host has moved to a - // new text buffer). - var textChangeRange: TextChangeRange = null; - if (document.isOpen && isOpen) { - textChangeRange = this.hostCache.getScriptTextChangeRangeSinceVersion(fileName, document.version); - } - - document = this.documentRegistry.updateDocument(document, fileName, compilationSettings, scriptSnapshot, version, isOpen, textChangeRange); - } - else { - document = this.documentRegistry.acquireDocument(fileName, compilationSettings, scriptSnapshot, this.hostCache.getByteOrderMark(fileName), version, isOpen, []); - } - - this.compiler.addOrUpdateFile(document); - } - } - - // Methods that defer to the host cache to get the result. - - public getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot { - this.synchronizeHostData(); - return this.hostCache.getScriptSnapshot(fileName); - } - - // Methods that does not require updating the host cache information - public getCachedHostFileName(fileName: string) { - if (!this.hostCache) { - this.synchronizeHostData(); - } - - return this.hostCache.getHostFileName(fileName); - } - - public getCachedTopLevelDeclaration(fileName: string) { - if (!this.hostCache) { - this.synchronizeHostData(); - } - - return this.compiler.topLevelDeclaration(fileName); - } - - // Methods that defer to the compiler to get the result. - - public compilationSettings(): TypeScript.ImmutableCompilationSettings { - this.synchronizeHostData(); - return this.compiler.compilationSettings(); - } - - public fileNames(): string[] { - this.synchronizeHostData(); - return this.compiler.fileNames(); - } - - public cleanupSemanticCache(): void { - this.compiler.cleanupSemanticCache(); - } - - public getDocument(fileName: string): TypeScript.Document { - this.synchronizeHostData(); - return this.compiler.getDocument(fileName); - } - - public getSemanticInfoChain(): SemanticInfoChain { - this.synchronizeHostData(); - return this.compiler.getSemanticInfoChain(); - } - - public getSyntacticDiagnostics(fileName: string): TypeScript.Diagnostic[] { - this.synchronizeHostData(); - return this.compiler.getSyntacticDiagnostics(fileName); - } - - public getSemanticDiagnostics(fileName: string): TypeScript.Diagnostic[] { - this.synchronizeHostData(); - return this.compiler.getSemanticDiagnostics(fileName); - } - - public getCompilerOptionsDiagnostics(resolvePath: (path: string) => string): TypeScript.Diagnostic[] { - this.synchronizeHostData(); - return this.compiler.getCompilerOptionsDiagnostics(resolvePath); - } - - public getSymbolInformationFromAST(ast: TypeScript.ISyntaxElement, document: TypeScript.Document) { - this.synchronizeHostData(); - return this.compiler.pullGetSymbolInformationFromAST(ast, document); - } - - public getCallInformationFromAST(ast: TypeScript.ISyntaxElement, document: TypeScript.Document) { - this.synchronizeHostData(); - return this.compiler.pullGetCallInformationFromAST(ast, document); - } - - public getVisibleMemberSymbolsFromAST(ast: TypeScript.ISyntaxElement, document: TypeScript.Document) { - this.synchronizeHostData(); - return this.compiler.pullGetVisibleMemberSymbolsFromAST(ast, document); - } - - public getVisibleDeclsFromAST(ast: TypeScript.ISyntaxElement, document: TypeScript.Document) { - this.synchronizeHostData(); - return this.compiler.pullGetVisibleDeclsFromAST(ast, document); - } - - public getContextualMembersFromAST(ast: TypeScript.ISyntaxElement, document: TypeScript.Document) { - this.synchronizeHostData(); - return this.compiler.pullGetContextualMembersFromAST(ast, document); - } - - public pullGetDeclInformation(decl: TypeScript.PullDecl, ast: TypeScript.ISyntaxElement, document: TypeScript.Document) { - this.synchronizeHostData(); - return this.compiler.pullGetDeclInformation(decl, ast, document); - } - - public topLevelDeclaration(fileName: string) { - this.synchronizeHostData(); - return this.compiler.topLevelDeclaration(fileName); - } - - public getDeclForAST(ast: TypeScript.ISyntaxElement): TypeScript.PullDecl { - this.synchronizeHostData(); - return this.compiler.getDeclForAST(ast); - } - - public emit(fileName: string, resolvePath: (path: string) => string): TypeScript.EmitOutput { - this.synchronizeHostData(); - return this.compiler.emit(fileName, resolvePath); - } - - public emitDeclarations(fileName: string, resolvePath: (path: string) => string): TypeScript.EmitOutput { - this.synchronizeHostData(); - return this.compiler.emitDeclarations(fileName, resolvePath); - } - - public canEmitDeclarations(fileName: string) { - this.synchronizeHostData(); - return this.compiler.canEmitDeclarations(fileName); - } - - public dispose(): void { - if (this.compiler) { - var fileNames = this.compiler.fileNames(); - for (var i = 0; i < fileNames.length; ++i) { - this.documentRegistry.releaseDocument(fileNames[i], this.compiler.compilationSettings()); - } - } - } - } -} diff --git a/src/services/completionSession.ts b/src/services/completionSession.ts deleted file mode 100644 index 6cc985fa658..00000000000 --- a/src/services/completionSession.ts +++ /dev/null @@ -1,68 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -/// - -module TypeScript.Services { - - export interface CachedCompletionEntryDetails extends CompletionEntryDetails{ - isResolved(): boolean; - } - - export class ResolvedCompletionEntry implements CachedCompletionEntryDetails { - constructor(public name: string, - public kind: string, - public kindModifiers: string, - public type: string, - public fullSymbolName: string, - public docComment: string) { - } - - public isResolved(): boolean { - return true; - } - } - - export class DeclReferenceCompletionEntry implements CachedCompletionEntryDetails { - public type: string = null; - public fullSymbolName: string = null; - public docComment: string = null; - - private hasBeenResolved = false; - - constructor(public name: string, - public kind: string, - public kindModifiers: string, - public decl: TypeScript.PullDecl) { - } - - public isResolved(): boolean { - return this.hasBeenResolved; - } - - public resolve(type: string, fullSymbolName: string, docComments: string) { - this.type = type; - this.fullSymbolName = fullSymbolName; - this.docComment = docComments; - this.hasBeenResolved = true; - } - } - - export class CompletionSession { - constructor(public fileName: string, - public position: number, - public entries: TypeScript.IdentiferNameHashTable) { - } - } -} \ No newline at end of file diff --git a/src/services/core/bitMatrix.ts b/src/services/core/bitMatrix.ts deleted file mode 100644 index 4c2fbce4112..00000000000 --- a/src/services/core/bitMatrix.ts +++ /dev/null @@ -1,82 +0,0 @@ -/// - -module TypeScript { - export interface IBitMatrix { - // Returns true if the bit at the specified indices is set. False otherwise. - valueAt(x: number, y: number): boolean; - - // Sets the value at this specified indices. - setValueAt(x: number, y: number, value: boolean): void; - - // Releases the bit matrix, allowing its resources to be used by another matrix. - // This instance cannot be used after it is released. - release(): void; - } - - export module BitMatrix { - var pool: BitMatrixImpl[] = []; - - class BitMatrixImpl implements IBitMatrix { - public isReleased = false; - private vectors: IBitVector[] = []; - - constructor(public allowUndefinedValues: boolean) { - } - - public valueAt(x: number, y: number): boolean { - Debug.assert(!this.isReleased, "Should not use a released bitvector"); - var vector = this.vectors[x]; - if (!vector) { - return this.allowUndefinedValues ? undefined : false; - } - - return vector.valueAt(y); - } - - public setValueAt(x: number, y: number, value: boolean): void { - Debug.assert(!this.isReleased, "Should not use a released bitvector"); - var vector = this.vectors[x]; - if (!vector) { - if (value === undefined) { - // If they're storing an undefined value, and we don't even have a vector, - // then we can short circuit early here. - return; - } - - vector = BitVector.getBitVector(this.allowUndefinedValues); - this.vectors[x] = vector; - } - - vector.setValueAt(y, value); - } - - public release() { - Debug.assert(!this.isReleased, "Should not use a released bitvector"); - this.isReleased = true; - - // Release all the vectors back. - for (var name in this.vectors) { - if (this.vectors.hasOwnProperty(name)) { - var vector = this.vectors[name]; - vector.release(); - } - } - - this.vectors.length = 0; - pool.push(this); - } - } - - export function getBitMatrix(allowUndefinedValues: boolean): IBitMatrix { - if (pool.length === 0) { - return new BitMatrixImpl(allowUndefinedValues); - } - - var matrix = pool.pop(); - matrix.isReleased = false; - matrix.allowUndefinedValues = allowUndefinedValues; - - return matrix; - } - } -} \ No newline at end of file diff --git a/src/services/core/bitVector.ts b/src/services/core/bitVector.ts deleted file mode 100644 index 6845d88182f..00000000000 --- a/src/services/core/bitVector.ts +++ /dev/null @@ -1,210 +0,0 @@ -/// - -module TypeScript { - export interface IBitVector { - // Returns the value at the specified index. If this is a bi-state vector, then the result - // will only be 'true' or 'false'. If this is a tri-state vector, then the result can be - // 'true', 'false', or 'undefined'. - valueAt(index: number): boolean; - - // Sets the value at this specified bit. For a bi-state vector the value must be 'true' or - // 'false'. For a tri-state vector, it can be 'true', 'false', or 'undefined'. - setValueAt(index: number, value: boolean): void; - - // Releases the bit vector, allowing its resources to be used by another BitVector. - // This instance cannot be used after it is released. - release(): void; - } - - export module BitVector { - var pool: BitVectorImpl[] = []; - enum Constants { - // We only use up to 30 bits in a number. That way the encoded value can always fit - // within an int so that the underlying engine doesn't use a 64bit float here. - MaxBitsPerEncodedNumber = 30, - BitsPerEncodedBiStateValue = 1, - - // For a tri state vector we need 2 bits per encoded value. 00 for 'undefined', - // '01' for 'false' and '10' for true. - BitsPerEncodedTriStateValue = 2, - - BiStateEncodedTrue = 1, // 1 - BiStateClearBitsMask = 1, // 1 - - TriStateEncodedFalse = 1, // 01 - TriStateEncodedTrue = 2, // 10 - TriStateClearBitsMask = 3, // 11 - } - - class BitVectorImpl implements IBitVector { - public isReleased = false; - private bits: number[] = []; - - constructor(public allowUndefinedValues: boolean) { - } - - private computeTriStateArrayIndex(index: number): number { - // The number of values that can be encoded in a single number. - var encodedValuesPerNumber = Constants.MaxBitsPerEncodedNumber / Constants.BitsPerEncodedTriStateValue; - - return (index / encodedValuesPerNumber) >>> 0; - } - - private computeBiStateArrayIndex(index: number): number { - // The number of values that can be encoded in a single number. - var encodedValuesPerNumber = Constants.MaxBitsPerEncodedNumber / Constants.BitsPerEncodedBiStateValue; - - return (index / encodedValuesPerNumber) >>> 0; - } - - private computeTriStateEncodedValueIndex(index: number): number { - // The number of values that can be encoded in a single number. - var encodedValuesPerNumber = Constants.MaxBitsPerEncodedNumber / Constants.BitsPerEncodedTriStateValue; - - return (index % encodedValuesPerNumber) * Constants.BitsPerEncodedTriStateValue; - } - - private computeBiStateEncodedValueIndex(index: number): number { - // The number of values that can be encoded in a single number. - var encodedValuesPerNumber = Constants.MaxBitsPerEncodedNumber / Constants.BitsPerEncodedBiStateValue; - - return (index % encodedValuesPerNumber) * Constants.BitsPerEncodedBiStateValue; - } - - public valueAt(index: number): boolean { - Debug.assert(!this.isReleased, "Should not use a released bitvector"); - if (this.allowUndefinedValues) { - // tri-state bit vector. 2 bits per value. - - var arrayIndex = this.computeTriStateArrayIndex(index); - var encoded = this.bits[arrayIndex]; - if (encoded === undefined) { - // We don't even have an encoded value at this array position. That's - // equivalent to 'undefined' for a tri-state vector. - return undefined; - } - - var bitIndex = this.computeTriStateEncodedValueIndex(index); - if (encoded & (Constants.TriStateEncodedTrue << bitIndex)) { - return true; - } - else if (encoded & (Constants.TriStateEncodedFalse << bitIndex)) { - return false; - } - else { - return undefined; - } - } - else { - // Normal bitvector. One bit per value stored. - - var arrayIndex = this.computeBiStateArrayIndex(index); - var encoded = this.bits[arrayIndex]; - if (encoded === undefined) { - // We don't even have an encoded value at this array position. That's - // equivalent to 'false' for a bi-state vector. - return false; - } - - // If we don't support undefined values, then we use one bit per value. Just - // index to that bit and see if it's set or not. - var bitIndex = this.computeBiStateEncodedValueIndex(index); - if (encoded & (Constants.BiStateEncodedTrue << bitIndex)) { - return true; - } - else { - return false; - } - } - } - - public setValueAt(index: number, value: boolean): void { - Debug.assert(!this.isReleased, "Should not use a released bitvector"); - if (this.allowUndefinedValues) { - Debug.assert(value === true || value === false || value === undefined, "value must only be true, false or undefined."); - - var arrayIndex = this.computeTriStateArrayIndex(index); - var encoded = this.bits[arrayIndex]; - if (encoded === undefined) { - if (value === undefined) { - // They're trying to set a bit to undefined that we don't even have an entry - // for. We can bail out quickly here. - return; - } - - encoded = 0; - } - - // First, we clear out any bits set at the appropriate index. - var bitIndex = this.computeTriStateEncodedValueIndex(index); - - // Create a mask similar to: 11111111100111111 - // i.e. all 1's except for 2 zeroes in the appropriate place. - var clearMask = ~(Constants.TriStateClearBitsMask << bitIndex) - encoded = encoded & clearMask; - - if (value === true) { - encoded = encoded | (Constants.TriStateEncodedTrue << bitIndex); - } - else if (value === false) { - encoded = encoded | (Constants.TriStateEncodedFalse << bitIndex); - } - // else { - // They're setting the value to 'undefined'. We already cleared the value - // so there's nothing we need to do here. - // } - - this.bits[arrayIndex] = encoded; - } - else { - Debug.assert(value === true || value === false, "value must only be true or false."); - - var arrayIndex = this.computeBiStateArrayIndex(index); - var encoded = this.bits[arrayIndex]; - if (encoded === undefined) { - if (value === false) { - // They're trying to set a bit to false that we don't even have an entry - // for. We can bail out quickly here. - return; - } - - encoded = 0; - } - - var bitIndex = this.computeBiStateEncodedValueIndex(index); - // First, clear out the bit at this location. - encoded = encoded & ~(Constants.BiStateClearBitsMask << bitIndex); - - if (value) { - encoded = encoded | (Constants.BiStateEncodedTrue << bitIndex); - } - // else { - // They're setting the value to 'false'. We already cleared the value - // so there's nothing we need to do here. - // } - - this.bits[arrayIndex] = encoded; - } - } - - public release() { - Debug.assert(!this.isReleased, "Should not use a released bitvector"); - this.isReleased = true; - this.bits.length = 0; - pool.push(this); - } - } - - export function getBitVector(allowUndefinedValues: boolean): IBitVector { - if (pool.length === 0) { - return new BitVectorImpl(allowUndefinedValues); - } - - var vector = pool.pop(); - vector.isReleased = false; - vector.allowUndefinedValues = allowUndefinedValues; - - return vector; - } - } -} \ No newline at end of file diff --git a/src/services/core/cancellationToken.ts b/src/services/core/cancellationToken.ts deleted file mode 100644 index f479e4d7011..00000000000 --- a/src/services/core/cancellationToken.ts +++ /dev/null @@ -1,3 +0,0 @@ -interface ICancellationToken { - isCancellationRequested(): boolean; -} \ No newline at end of file diff --git a/src/services/core/cancellationTokenSource.ts b/src/services/core/cancellationTokenSource.ts deleted file mode 100644 index 684bf235cb7..00000000000 --- a/src/services/core/cancellationTokenSource.ts +++ /dev/null @@ -1,7 +0,0 @@ -/// - -interface ICancellationTokenSource { - token(): ICancellationToken; - - cancel(): void; -} \ No newline at end of file diff --git a/src/services/core/constants.ts b/src/services/core/constants.ts deleted file mode 100644 index 9a980359313..00000000000 --- a/src/services/core/constants.ts +++ /dev/null @@ -1,9 +0,0 @@ -/// - -module TypeScript { - export enum Constants { - // 2^30-1 - Max31BitInteger = 1073741823, - Min31BitInteger = -1073741824, - } -} \ No newline at end of file diff --git a/src/services/core/environment.ts b/src/services/core/environment.ts deleted file mode 100644 index ab1b351aed1..00000000000 --- a/src/services/core/environment.ts +++ /dev/null @@ -1,505 +0,0 @@ -/// -/// -/// - -declare var Buffer: { - new (str: string, encoding?: string): any; -} - -module TypeScript { - export var nodeMakeDirectoryTime = 0; - export var nodeCreateBufferTime = 0; - export var nodeWriteFileSyncTime = 0; - - export enum ByteOrderMark { - None = 0, - Utf8 = 1, - Utf16BigEndian = 2, - Utf16LittleEndian = 3, - } - - export class FileInformation { - constructor(public contents: string, public byteOrderMark: ByteOrderMark) { - } - } - - export interface IFileWatcher { - close(): void; - } - - export interface IEnvironment { - supportsCodePage(): boolean; - readFile(path: string, codepage: number): FileInformation; - writeFile(path: string, contents: string, writeByteOrderMark: boolean): void; - deleteFile(path: string): void; - fileExists(path: string): boolean; - directoryExists(path: string): boolean; - directoryName(path: string): string; - createDirectory(path: string): void; - absolutePath(path: string): string; - listFiles(path: string, re?: RegExp, options?: { recursive?: boolean; }): string[]; - - arguments: string[]; - standardOut: ITextWriter; - standardError: ITextWriter; - - executingFilePath(): string; - currentDirectory(): string; - newLine: string; - - watchFile(fileName: string, callback: (x: string) => void): IFileWatcher; - quit(exitCode?: number): void; - } - - function throwIOError(message: string, error: Error) { - var errorMessage = message; - if (error && error.message) { - errorMessage += (" " + error.message); - } - throw new Error(errorMessage); - } - - export var Environment: IEnvironment = (function () { - // Create an IO object for use inside WindowsScriptHost hosts - // Depends on WSCript and FileSystemObject - function getWindowsScriptHostEnvironment(): IEnvironment { - try { - var fso = new ActiveXObject("Scripting.FileSystemObject"); - } catch (e) { - return null; - } - - var streamObjectPool: any[] = []; - - function getStreamObject(): any { - if (streamObjectPool.length > 0) { - return streamObjectPool.pop(); - } - else { - return new ActiveXObject("ADODB.Stream"); - } - } - - function releaseStreamObject(obj: any) { - streamObjectPool.push(obj); - } - - var args: string[] = []; - for (var i = 0; i < WScript.Arguments.length; i++) { - args[i] = WScript.Arguments.Item(i); - } - - return { - // On windows, the newline sequence is always "\r\n"; - newLine: "\r\n", - - currentDirectory: () => (WScript).CreateObject("WScript.Shell").CurrentDirectory, - - supportsCodePage: () => (WScript).ReadFile, - - absolutePath: path => fso.GetAbsolutePathName(path), - - readFile: function (path, codepage) { - try { - // If a codepage is requested, defer to our host to do the reading. If it - // fails, fall back to our normal BOM/utf8 logic. - if (codepage !== null && this.supportsCodePage()) { - try { - var contents = (WScript).ReadFile(path, codepage); - return new FileInformation(contents, ByteOrderMark.None); - } - catch (e) { - // We couldn't read it with that code page. Fall back to the normal - // BOM/utf8 logic below. - } - } - - // Initially just read the first two bytes of the file to see if there's a bom. - var streamObj = getStreamObject(); - streamObj.Open(); - streamObj.Type = 2; // Text data - - // Start reading individual chars without any interpretation. That way we can check for a bom. - streamObj.Charset = 'x-ansi'; - - streamObj.LoadFromFile(path); - var bomChar = streamObj.ReadText(2); // Read the BOM char - - // Position has to be at 0 before changing the encoding - streamObj.Position = 0; - - var byteOrderMark = ByteOrderMark.None; - - if (bomChar.charCodeAt(0) === 0xFE && bomChar.charCodeAt(1) === 0xFF) { - streamObj.Charset = 'unicode'; - byteOrderMark = ByteOrderMark.Utf16BigEndian; - } - else if (bomChar.charCodeAt(0) === 0xFF && bomChar.charCodeAt(1) === 0xFE) { - streamObj.Charset = 'unicode'; - byteOrderMark = ByteOrderMark.Utf16LittleEndian; - } - else if (bomChar.charCodeAt(0) === 0xEF && bomChar.charCodeAt(1) === 0xBB) { - streamObj.Charset = 'utf-8'; - byteOrderMark = ByteOrderMark.Utf8; - } - else { - // Always read a file as utf8 if it has no bom. - streamObj.Charset = 'utf-8'; - } - - // Read the whole file - var contents = streamObj.ReadText(-1 /* read from the current position to EOS */); - streamObj.Close(); - releaseStreamObject(streamObj); - return new FileInformation(contents, byteOrderMark); - } - catch (err) { - // -2147024809 is the javascript value for 0x80070057 which is the HRESULT for - // "the parameter is incorrect". - var message: string; - if (err.number === -2147024809) { - message = TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.Unsupported_file_encoding, null); - } - else { - message = TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.Cannot_read_file_0_1, [path, err.message]); - } - - throw new Error(message); - } - }, - - writeFile: (path, contents, writeByteOrderMark) => { - // First, convert the text contents passed in to binary in UTF8 format. - var textStream = getStreamObject(); - textStream.Charset = 'utf-8'; - textStream.Open(); - textStream.WriteText(contents, 0 /*do not add newline*/); - - // If they don't want the BOM, then skip it (it will be added automatically - // when we write the utf8 bytes out above). - if (!writeByteOrderMark) { - textStream.Position = 3; - } - else { - textStream.Position = 0; - } - - // Now, write all those bytes out to a file. - var fileStream = getStreamObject(); - fileStream.Type = 1; //binary data. - fileStream.Open(); - - textStream.CopyTo(fileStream); - - // Flush and save the file. - fileStream.Flush(); - fileStream.SaveToFile(path, 2 /*overwrite*/); - fileStream.Close(); - - textStream.Flush(); - textStream.Close(); - }, - - fileExists: path => fso.FileExists(path), - - deleteFile: path => { - if (fso.FileExists(path)) { - fso.DeleteFile(path, true); // true: delete read-only files - } - }, - - directoryExists: path => fso.FolderExists(path), - - directoryName: path => fso.GetParentFolderName(path), - - createDirectory: function (path) { - try { - if (!this.directoryExists(path)) { - fso.CreateFolder(path); - } - } catch (e) { - throwIOError(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.Could_not_create_directory_0, [path]), e); - } - }, - - listFiles: (path, spec?, options?) => { - options = options || <{ recursive?: boolean; }>{}; - function filesInFolder(folder: any, root: string): string[] { - var paths: string[] = []; - var fc: Enumerator; - - if (options.recursive) { - fc = new Enumerator(folder.subfolders); - - for (; !fc.atEnd(); fc.moveNext()) { - paths = paths.concat(filesInFolder(fc.item(), root + "\\" + fc.item().Name)); - } - } - - fc = new Enumerator(folder.files); - - for (; !fc.atEnd(); fc.moveNext()) { - if (!spec || fc.item().Name.match(spec)) { - paths.push(root + "\\" + fc.item().Name); - } - } - - return paths; - } - - var folder: any = fso.GetFolder(path); - var paths: string[] = []; - - return filesInFolder(folder, path); - }, - - arguments: args, - - standardOut: WScript.StdOut, - standardError: WScript.StdErr, - - executingFilePath: () => WScript.ScriptFullName, - - quit: (exitCode = 0) => { - try { - WScript.Quit(exitCode); - } catch (e) { - } - }, - - watchFile: null, - }; - }; - - function getNodeEnvironment(): IEnvironment { - var _fs = require('fs'); - var _path = require('path'); - var _module = require('module'); - var _os = require('os'); - - return { - // On node pick up the newline character from the OS - newLine: _os.EOL, - - currentDirectory: () => (process).cwd(), - - supportsCodePage: () => false, - - absolutePath: path => _path.resolve(path), - - readFile: (file, codepage) => { - if (codepage !== null) { - throw new Error(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.codepage_option_not_supported_on_current_platform, null)); - } - - var buffer = _fs.readFileSync(file); - switch (buffer[0]) { - case 0xFE: - if (buffer[1] === 0xFF) { - // utf16-be. Reading the buffer as big endian is not supported, so convert it to - // Little Endian first - var i = 0; - while ((i + 1) < buffer.length) { - var temp = buffer[i]; - buffer[i] = buffer[i + 1]; - buffer[i + 1] = temp; - i += 2; - } - return new FileInformation(buffer.toString("ucs2", 2), ByteOrderMark.Utf16BigEndian); - } - break; - case 0xFF: - if (buffer[1] === 0xFE) { - // utf16-le - return new FileInformation(buffer.toString("ucs2", 2), ByteOrderMark.Utf16LittleEndian); - } - break; - case 0xEF: - if (buffer[1] === 0xBB) { - // utf-8 - return new FileInformation(buffer.toString("utf8", 3), ByteOrderMark.Utf8); - } - } - - // Default behaviour - return new FileInformation(buffer.toString("utf8", 0), ByteOrderMark.None); - }, - - writeFile: (path, contents, writeByteOrderMark) => { - function mkdirRecursiveSync(path: string) { - var stats = _fs.statSync(path); - if (stats.isFile()) { - throw "\"" + path + "\" exists but isn't a directory."; - } - else if (stats.isDirectory()) { - return; - } - else { - mkdirRecursiveSync(_path.dirname(path)); - _fs.mkdirSync(path, 509 /*775 in octal*/); - } - } - var start = new Date().getTime(); - mkdirRecursiveSync(_path.dirname(path)); - TypeScript.nodeMakeDirectoryTime += new Date().getTime() - start; - - if (writeByteOrderMark) { - contents = '\uFEFF' + contents; - } - - var start = new Date().getTime(); - - var chunkLength = 4 * 1024; - var fileDescriptor = _fs.openSync(path, "w"); - try { - for (var index = 0; index < contents.length; index += chunkLength) { - var bufferStart = new Date().getTime(); - var buffer = new Buffer(contents.substr(index, chunkLength), "utf8"); - TypeScript.nodeCreateBufferTime += new Date().getTime() - bufferStart; - - _fs.writeSync(fileDescriptor, buffer, 0, buffer.length, null); - } - } - finally { - _fs.closeSync(fileDescriptor); - } - - TypeScript.nodeWriteFileSyncTime += new Date().getTime() - start; - }, - - fileExists: path => _fs.existsSync(path), - - deleteFile: path => { - try { - _fs.unlinkSync(path); - } catch (e) { - } - }, - - directoryExists: path => - _fs.existsSync(path) && _fs.statSync(path).isDirectory(), - - directoryName: path => { - var dirPath = _path.dirname(path); - - // Node will just continue to repeat the root path, rather than return null - if (dirPath === path) { - dirPath = null; - } - - return dirPath; - }, - - createDirectory: function (path) { - try { - if (!this.directoryExists(path)) { - _fs.mkdirSync(path); - } - } catch (e) { - throwIOError(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.Could_not_create_directory_0, [path]), e); - } - }, - - listFiles: (path, spec?, options?) => { - options = options || <{ recursive?: boolean; }>{}; - - function filesInFolder(folder: string): string[] { - var paths: string[] = []; - - var files = _fs.readdirSync(folder); - for (var i = 0; i < files.length; i++) { - var pathToFile = _path.join(folder, files[i]); - var stat = _fs.statSync(pathToFile); - if (options.recursive && stat.isDirectory()) { - paths = paths.concat(filesInFolder(pathToFile)); - } - else if (stat.isFile() && (!spec || files[i].match(spec))) { - paths.push(pathToFile); - } - } - - return paths; - } - - return filesInFolder(path); - }, - - arguments: process.argv.slice(2), - - standardOut: { - Write: str => process.stdout.write(str), - WriteLine: str => process.stdout.write(str + '\n'), - Close() { } - }, - - standardError: { - Write: str => process.stderr.write(str), - WriteLine: str => process.stderr.write(str + '\n'), - Close() { } - }, - - executingFilePath: () => process.mainModule.filename, - - quit: code => { - var stderrFlushed = process.stderr.write(''); - var stdoutFlushed = process.stdout.write(''); - process.stderr.on('drain', function () { - stderrFlushed = true; - if (stdoutFlushed) { - process.exit(code); - } - }); - process.stdout.on('drain', function () { - stdoutFlushed = true; - if (stderrFlushed) { - process.exit(code); - } - }); - setTimeout(function () { - process.exit(code); - }, 5); - }, - - watchFile: (fileName, callback) => { - var firstRun = true; - var processingChange = false; - - var fileChanged: any = function (curr: any, prev: any) { - if (!firstRun) { - if (curr.mtime < prev.mtime) { - return; - } - - _fs.unwatchFile(fileName, fileChanged); - if (!processingChange) { - processingChange = true; - callback(fileName); - setTimeout(function () { processingChange = false; }, 100); - } - } - firstRun = false; - _fs.watchFile(fileName, { persistent: true, interval: 500 }, fileChanged); - }; - - fileChanged(); - return { - fileName: fileName, - close: function () { - _fs.unwatchFile(fileName, fileChanged); - } - }; - }, - }; - }; - - if (typeof WScript !== "undefined" && typeof ActiveXObject === "function") { - return getWindowsScriptHostEnvironment(); - } - else if (typeof module !== 'undefined' && module.exports) { - return getNodeEnvironment(); - } - else { - return null; // Unsupported host - } - })(); -} diff --git a/src/services/core/indexable.ts b/src/services/core/indexable.ts deleted file mode 100644 index c879b38cc75..00000000000 --- a/src/services/core/indexable.ts +++ /dev/null @@ -1,7 +0,0 @@ -/// - -module TypeScript { - export interface IIndexable { - [s: string]: T; - } -} \ No newline at end of file diff --git a/src/services/core/iterator.ts b/src/services/core/iterator.ts deleted file mode 100644 index a2c31746bb5..00000000000 --- a/src/services/core/iterator.ts +++ /dev/null @@ -1,8 +0,0 @@ -/// - -module TypeScript { - export interface Iterator { - moveNext(): boolean; - current(): T; - } -} \ No newline at end of file diff --git a/src/services/core/lineAndCharacter.ts b/src/services/core/lineAndCharacter.ts deleted file mode 100644 index 8af46296d34..00000000000 --- a/src/services/core/lineAndCharacter.ts +++ /dev/null @@ -1,8 +0,0 @@ -/// - -module TypeScript { - export interface ILineAndCharacter { - line: number; - character: number; - } -} \ No newline at end of file diff --git a/src/services/core/require.ts b/src/services/core/require.ts deleted file mode 100644 index fcd5a5cbda9..00000000000 --- a/src/services/core/require.ts +++ /dev/null @@ -1,5 +0,0 @@ -/// - -// Forward declarations of the variables we use from 'node'. -declare var require: any; -declare var module: any; \ No newline at end of file diff --git a/src/services/diagnosticsParser.ts b/src/services/diagnosticsParser.ts deleted file mode 100644 index 9ea7096bb65..00000000000 --- a/src/services/diagnosticsParser.ts +++ /dev/null @@ -1,363 +0,0 @@ -/// -/// -/// - -module DiagnosticsParser { - - class FourSlashGenerator { - - private fsFiles: { [s: string]: IFourSlashFile; }; - - constructor(private diagnosticsFile: string) { - this.fsFiles = {}; - } - - public generate(args: string[]): void { - - if (IO.fileExists(this.diagnosticsFile)) { - - this.parseDiagnostics(args); - - if (args !== undefined) { - for (var i = 0; i < args.length; i++) { - for (var fsFile in this.fsFiles) { - var strippedScriptId = fsFile.replace(/.+\\/, ''); - if (strippedScriptId === args[i]) { - this.writeFile(fsFile); - } - } - } - } else { - for (var fsFile in this.fsFiles) { - this.writeFile(fsFile); - } - } - - } - } - - private parseDiagnostics(args: string[]) { - - var file: string = IO.readFile(this.diagnosticsFile); - var lines: string[] = file.split('\r\n'); - - var updateMode: boolean; - var scriptId: string; - - var editBlock: string; - var editRange: TypeScript.ScriptEditRange; - - var startPosition: number; - var caretPosition: number; - var collapsingBlock: string; - - var openEditTag = /^.*/; - var closeEditTag = /.*/; - - // Loops through the lines of the diagnostics file - for (var i = 0; i < lines.length; i++) { - - // Indicates the user opening a file - if (lines[i].match(/\/\/=New=\\\\/)) { - - updateMode = false; - - // Indicates the user making updates to an opened file - } else if (lines[i].match(/\/\/=Update=\\\\/)) { - - updateMode = true; - - // Record the filePath of the opened/modified file - } else if (lines[i].match(/^scriptId: /)) { - - var newScriptId = lines[i].replace(/^scriptId: /, ''); - if (scriptId !== undefined && newScriptId !== scriptId && collapsingBlock !== undefined) { - this.fsFiles[scriptId].insertAt(startPosition, caretPosition, collapsingBlock); - - startPosition = undefined; - caretPosition = undefined; - collapsingBlock = undefined - } - scriptId = newScriptId; - - // Records the editRange (minChar, limChar, deltaOfCaret) - } else if (lines[i].match(/^editRange\(/)) { - - //Capture numbers in editRange(minChar=###, limChar=###, delta=###) - var match = /editRange\(minChar=([0-9]+), limChar=([0-9]+), delta=(-?[0-9]+)\)/.exec(lines[i]); - if (match !== null) { - editRange = new TypeScript.ScriptEditRange(parseInt(match[1], 10), parseInt(match[2], 10), parseInt(match[3], 10)); - } - - // Indicates the beginning of added text and records - } else if (lines[i].match(openEditTag)) { - - var editLines: string[] = []; - - lines[i] = lines[i].replace(openEditTag, ''); - while (lines[i].match(closeEditTag) === null) { - editLines.push(lines[i]); - i++; - } - - editLines.push(lines[i].replace(closeEditTag, '')); - editBlock = editLines.join('\r\n'); - - // Indicates the end of the edit block, and then adds the text to the relevant file - } else if (lines[i].match(/\\\\=====\/\//) && editRange !== null) { - - if (updateMode) { - - var range: number = editRange.limChar - editRange.minChar; - var deleting: boolean = (range !== 0); - - if (deleting) { - - if (collapsingBlock !== undefined) { - this.fsFiles[scriptId].insertAt(startPosition, caretPosition, collapsingBlock); - } - - caretPosition = editRange.minChar + (editBlock !== undefined ? editBlock.length : 0); - - this.fsFiles[scriptId].deleteAt(editRange.limChar, caretPosition, range, editBlock); - - startPosition = undefined; - caretPosition = undefined; - collapsingBlock = undefined; - - } else { - if (editRange.minChar === caretPosition) { - collapsingBlock += editBlock; - } else { - if (collapsingBlock !== undefined) { - this.fsFiles[scriptId].insertAt(startPosition, caretPosition, collapsingBlock); - } - startPosition = editRange.minChar; - collapsingBlock = editBlock; - } - caretPosition = editRange.minChar + editRange.delta; - } - } else { - this.fsFiles[scriptId] = new FourSlashFile(scriptId, editBlock); - } - editBlock = undefined; - } - } - - // Add any text that hasn't been stored to its relevant file - if (collapsingBlock !== undefined) { - this.fsFiles[scriptId].insertAt(startPosition, caretPosition, collapsingBlock); - } - } - - private writeFile(scriptId: string): void { - if (this.fsFiles[scriptId] !== undefined) { - var fsFileName = this.fsFiles[scriptId].getFsFileName(); - IO.writeFile(fsFileName, this.fsFiles[scriptId].getFile()); - } - } - - } - - interface IFourSlashFile { - getFile(): string; - getFsFileName(): string; - getOriginalScriptId(): string; - updateInternalFile(minChar: number, limChar: number, content: string): void; - insertAt(position: number, caretPosition: number, content: string): void; - deleteAt(position: number, caretPosition: number, amount: number, content?: string): void; - addInternalState(caretPosition: number): void; - } - - interface IFourSlashNode { - getNode(): string; - } - - class FourSlashFile implements IFourSlashFile { - - private static header = "/// " + '\r\n' + '\r\n'; - - private fsScriptId: string; - - private commands: IFourSlashNode[]; - - private internalState: string; - - constructor(private originalScriptId: string, private startingContent: string) { - - this.fsScriptId = 'tests\\cases\\fourslash\\' + originalScriptId.replace(/.+\\(.+).ts/, '$1_generated.ts'); - this.commands = []; - this.internalState = startingContent; - - } - - public getFile(): string { - var file: string; - - //Split on \r\n and add //// - var rnlines = this.startingContent.split('\r\n'); - rnlines.forEach((line, index, array) => { array[index] = '////' + line }); - var rnfile = rnlines.join('\r\n'); - - //Repeat for \n - var nlines = rnfile.split(/([^\r]\n|\r[^\n])/); - nlines.forEach((line, index, array) => { if (line.indexOf('////') !== 0) { array[index] = '////' + line } }); - var nfile = nlines.join('\n'); - - file = FourSlashFile.header + nfile + '\r\n' + '\r\n'; - this.commands.forEach((command, index, array) => { file += command.getNode() }); - - return file; - } - - private getWithWhitespace(text: string) { - return text.replace(/ /g, '\u00B7').replace(/\r/g, '\u00B6').replace(/\n/g, '\u2193\n').replace(/\t/g, '\u2192\ '); - } - - public getFsFileName(): string { - return this.fsScriptId; - } - - public getOriginalScriptId(): string { - return this.originalScriptId; - } - - public updateInternalFile(minChar: number, limChar: number, content: string): void { - this.internalState = this.internalState.substring(0, minChar) + content + this.internalState.substr(limChar); - } - - public insertAt(position: number, caretPosition: number, content: string): void { - var posOffset = this.getInsertOffset(position); - var insertNode = new FourSlashInsert(position - posOffset, content.replace(/(\r\n|\r|\n)/g, '\n')); - this.commands.push(insertNode); - this.updateInternalFile(position, position, content); - this.addInternalState(caretPosition); - } - - public deleteAt(position: number, caretPosition: number, amount: number, content?: string): void { - var posOffset = this.getInsertOffset(position); - var amountOffset = this.getDeleteOffset(position, amount); - var deleteNode = new FourSlashDelete(position - posOffset, amount - amountOffset, (content !== undefined ? content.replace(/(\r\n|\r|\n)/g, '\n') : undefined)); - this.commands.push(deleteNode); - this.updateInternalFile(position - amount, position, content); - this.addInternalState(caretPosition); - } - - public addInternalState(caretPosition: number): void { - var caretedState = this.internalState.substr(0, caretPosition) + '|' + this.internalState.substr(caretPosition); - var internalState = new FourSlashStateComment(caretedState); - this.commands.push(internalState); - } - - private getInsertOffset(position: number) { - var offset: number = 0; - var match = this.internalState.substring(0, position).match(/\r\n/g); - if (match !== null) { - offset = match.length; - } - offset = (match !== null ? match.length : 0); - return offset; - } - - private getDeleteOffset(position: number, amount: number) { - var offset: number = 0; - var match = this.internalState.substring(position - amount, position).match(/\r\n/g); - if (match !== null) { - offset = match.length; - } - return offset; - } - - } - - class FourSlashInsert implements IFourSlashNode { - - constructor(private position: number, private content: string) { - this.content = this.content.replace(/([\/\\"'])/g, '\\$1'); - this.content = this.content.replace(/\r\n/g, '\\r\\n'); - this.content = this.content.replace(/(\r|\n)/g, '\\n'); - } - - public getNode(): string { - var insertNode: string = "goTo.position(" + this.position.toString() + ");" + "\n" + - "edit.insert(\'" + this.content + "\');" + "\n"; - return insertNode; - } - - } - - class FourSlashDelete implements IFourSlashNode { - - constructor(private position: number, private deletionAmount: number, private content: string) { - if (this.content !== undefined) { - this.content = this.content.replace(/([\/\\"'])/g, '\\$1'); - this.content = this.content.replace(/\r\n/g, '\\r\\n'); - this.content = this.content.replace(/(\r|\n)/g, '\\n'); - } - } - - public getNode(): string { - var deleteNode: string = "goTo.position(" + this.position.toString() + ");" + "\n" + - "edit.backspace(" + this.deletionAmount + ");" + "\n"; - if (this.content !== undefined && this.content !== "") { - deleteNode += "edit.insert(\'" + this.content + "\');" + "\n"; - } - return deleteNode; - } - - } - - class FourSlashStateComment implements IFourSlashNode { - - constructor(private state: string) { } - - public getNode(): string { - - var lines = this.state.replace(/\r\n|\r|\n/g, '\r\n').split('\n'); - lines.forEach((line, index, array) => { array[index] = '//-' + line; }); - var stateNode = lines.join('\n'); - - return stateNode + '\n' + '\n'; - - } - - } - - class DiagnosticsLocator { - - private diagnosticsFile: string = 'diagnostics.txt'; - - public find(): string { - return this.findDiagnosticsInFolder("C:/Users"); - } - - private findDiagnosticsInFolder(path: string): string { - if (IO.directoryExists(path)) { - var diagnosticsPath = undefined; - var dir: string[] = IO.dir(path, undefined, { recursive: true }); - for (var i = 0; i < dir.length; i++) { - if (dir[i].indexOf(this.diagnosticsFile) !== -1) { - diagnosticsPath = dir[i]; - } - } - return diagnosticsPath; - } - } - - } - - var diagnosticsFile: string = undefined; - var diagnosticArgs: string[] = undefined - if (process.argv.length > 2) { - if (IO.fileExists(process.argv[2])) { - diagnosticsFile = process.argv[2]; - } - //Grab remaining arguments - diagnosticArgs = process.argv.slice(3, process.argv.length - 1); - } - - if (diagnosticsFile !== undefined) { - new FourSlashGenerator(diagnosticsFile).generate(diagnosticArgs); - } - -} \ No newline at end of file diff --git a/src/services/es5compat.ts b/src/services/es5compat.ts deleted file mode 100644 index 1cd6a50905a..00000000000 --- a/src/services/es5compat.ts +++ /dev/null @@ -1,354 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -/*----------------- ThirdPartyNotices ------------------------------------------------------- - -This file is based on or incorporates material from the projects listed below -(collectively "Third Party Code"). Microsoft is not the original author of the -Third Party Code. The original copyright notice and the license, under which -Microsoft received such Third Party Code, are set forth below. Such license and -notices are provided for informational purposes only. Microsoft licenses the Third -Party Code to you under the terms of the Apache 2.0 License. - --- -Array filter Compatibility Method, -Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter - -Array forEach Compatibility Method, -Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach - -Array indexOf Compatibility Method, -Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf - -Array map Compatibility Method, -Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map - -Array Reduce Compatibility Method, -Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/Reduce - -Array some Compatibility Method, -Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/some - -String Trim Compatibility Method, -Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/Trim - -Date now Compatibility Method, -Available at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/now - -Copyright (c) 2007 - 2012 Mozilla Developer Network and individual contributors - -Licensed by Microsoft under the Apache License, Version 2.0 (the "License"); you -may not use this file except in compliance with the License. You may obtain a copy -of the License at http://www.apache.org/licenses/LICENSE-2.0 - -THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR -CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. - -See the Apache Version 2.0 License for specific language governing permissions and -limitations under the License. - --- -Original License provided for Informational Purposes Only -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -------------- End of ThirdPartyNotices --------------------------------------------------- */ - - -// Compatibility with non ES5 compliant engines -if (!String.prototype.trim) { - String.prototype.trim = function() { - return this.replace(/^\s+|\s+$/g, ''); - }; -} - -// Compatibility with non ES5 compliant engines -if (!Array.prototype.indexOf) { - Array.prototype.indexOf = function (searchElement: any, fromIndex?: any) { - "use strict"; - if (this == null) { - throw new TypeError(); - } - var t = Object(this); - var len: any = t.length >>> 0; - if (len === 0) { - return -1; - } - var n: any = 0; - if (arguments.length > 0) { - n = Number(arguments[1]); - if (n != n) { // shortcut for verifying if it's NaN - n = 0; - } - else if (n != 0 && n != Infinity && n != -Infinity) { - n = (n > 0 || -1) * Math.floor(Math.abs(n)); - } - } - if (n >= len) { - return -1; - } - var k: any = n >= 0 ? n : Math.max(len - Math.abs(n), 0); - for (; k < len; k++) { - if (k in t && t[k] === searchElement) { - return k; - } - } - return -1; - } -} - -if (!Array.prototype.filter) -{ - Array.prototype.filter = function(fun: any, thisp?: any) - { - "use strict"; - - if (this == null) - throw new TypeError(); - - var t = Object(this); - var len = t.length >>> 0; - if (typeof fun != "function") - throw new TypeError(); - - var res: any[] = []; - for (var i = 0; i < len; i++) - { - if (i in t) - { - var val = t[i]; // in case fun mutates this - if (fun.call(thisp, val, i, t)) - res.push(val); - } - } - - return res; - }; -} - -// Production steps of ECMA-262, Edition 5, 15.4.4.19 -// Reference: http://es5.github.com/#x15.4.4.19 -if (!Array.prototype.map) { - Array.prototype.map = function(callback: any, thisArg?: any) { - - var T: any = undefined, A: any, k: any; - - if (this == null) { - throw new TypeError(" this is null or not defined"); - } - - // 1. Let O be the result of calling ToObject passing the |this| value as the argument. - var O = Object(this); - - // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". - // 3. Let len be ToUint32(lenValue). - var len = O.length >>> 0; - - // 4. If IsCallable(callback) is false, throw a TypeError exception. - // See: http://es5.github.com/#x9.11 - if ({}.toString.call(callback) != "[object Function]") { - throw new TypeError(callback + " is not a function"); - } - - // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. - if (thisArg) { - T = thisArg; - } - - // 6. Let A be a new array created as if by the expression new Array(len) where Array is - // the standard built-in constructor with that name and len is the value of len. - A = new Array(len); - - // 7. Let k be 0 - k = 0; - - // 8. Repeat, while k < len - while(k < len) { - - var kValue: any, mappedValue: any; - - // a. Let Pk be ToString(k). - // This is implicit for LHS operands of the in operator - // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. - // This step can be combined with c - // c. If kPresent is true, then - if (k in O) { - - // i. Let kValue be the result of calling the Get internal method of O with argument Pk. - kValue = O[ k ]; - - // ii. Let mappedValue be the result of calling the Call internal method of callback - // with T as the this value and argument list containing kValue, k, and O. - mappedValue = callback.call(T, kValue, k, O); - - // iii. Call the DefineOwnProperty internal method of A with arguments - // Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true}, - // and false. - - // In browsers that support Object.defineProperty, use the following: - // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true }); - - // For best browser support, use the following: - A[ k ] = mappedValue; - } - // d. Increase k by 1. - k++; - } - - // 9. return A - return A; - }; -} - -if (!Array.prototype.reduce) { - Array.prototype.reduce = function reduce(accumulator: any){ - if (this===null || this===undefined) throw new TypeError("Object is null or undefined"); - var i = 0, l = this.length >> 0, curr: any; - - if(typeof accumulator !== "function") // ES5 : "If IsCallable(callbackfn) is false, throw a TypeError exception." - throw new TypeError("First argument is not callable"); - - if(arguments.length < 2) { - if (l === 0) throw new TypeError("Array length is 0 and no second argument"); - curr = this[0]; - i = 1; // start accumulating at the second element - } - else - curr = arguments[1]; - - while (i < l) { - if(i in this) curr = accumulator.call(undefined, curr, this[i], i, this); - ++i; - } - - return curr; - }; -} - -// Compatibility with non ES5 compliant engines -// Production steps of ECMA-262, Edition 5, 15.4.4.18 -// Reference: http://es5.github.com/#x15.4.4.18 -if (!Array.prototype.forEach) { - Array.prototype.forEach = function(callback: any, thisArg?: any) { - - var T: any, k: any; - - if (this == null) { - throw new TypeError(" this is null or not defined"); - } - - // 1. Let O be the result of calling ToObject passing the |this| value as the argument. - var O = Object(this); - - // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". - // 3. Let len be ToUint32(lenValue). - var len = O.length >>> 0; // Hack to convert O.length to a UInt32 - - // 4. If IsCallable(callback) is false, throw a TypeError exception. - // See: http://es5.github.com/#x9.11 - if ({ }.toString.call(callback) != "[object Function]") { - throw new TypeError(callback + " is not a function"); - } - - // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. - if (thisArg) { - T = thisArg; - } - else { - T = undefined; // added to stop definite assignment error - } - - // 6. Let k be 0 - k = 0; - - // 7. Repeat, while k < len - while (k < len) { - - var kValue: any; - - // a. Let Pk be ToString(k). - // This is implicit for LHS operands of the in operator - // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. - // This step can be combined with c - // c. If kPresent is true, then - if (k in O) { - - // i. Let kValue be the result of calling the Get internal method of O with argument Pk. - kValue = O[k]; - - // ii. Call the Call internal method of callback with T as the this value and - // argument list containing kValue, k, and O. - callback.call(T, kValue, k, O); - } - // d. Increase k by 1. - k++; - } - // 8. return undefined - }; -} - -// Compatibility with non ES5 compliant engines -if (!Date.now) { - Date.now = function() { - return (new Date()).getTime(); - }; -} - -// Compatibility with non ES5 compliant engines -// Production steps of ECMA-262, Edition 5.1, 15.4.4.17 -if (!Array.prototype.some) -{ - Array.prototype.some = function(fun: any /*, thisp */) - { - "use strict"; - - if (this == null) - throw new TypeError(); - - var t = Object(this); - var len = t.length >>> 0; - if (typeof fun != "function") - throw new TypeError(); - - var thisp = arguments[1]; - for (var i = 0; i < len; i++) - { - var idx = i.toString(); // REVIEW: this line is not from the Mozilla page, necessary to avoid our compile time checks against non-string/any types in an in expression - if (idx in t && fun.call(thisp, t[i], i, t)) - return true; - } - - return false; - }; -} \ No newline at end of file diff --git a/src/services/indenter.ts b/src/services/indenter.ts deleted file mode 100644 index f082a3fe024..00000000000 --- a/src/services/indenter.ts +++ /dev/null @@ -1,207 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -/// - -module TypeScript.Services { - export class Indenter { - public static getIndentation(node: TypeScript.SourceUnitSyntax, soruceText: TypeScript.IScriptSnapshot, position: number, editorOptions: TypeScript.Services.EditorOptions): number { - var indentation = 0; - var currentToken = TypeScript.findToken(node, position); - var currentNode: TypeScript.ISyntaxElement = currentToken; - - if (currentToken.kind() === TypeScript.SyntaxKind.EndOfFileToken) { - // Ignore EOF tokens, pick the one before it - currentNode = previousToken(currentToken); - } - else if (Indenter.belongsToBracket(soruceText, currentToken, position)) { - // Let braces and brackets take the indentation of thier parents - currentNode = currentToken.parent; - } - - if (currentNode === null) { - return indentation; - } - - // Check if this is a valid node to provide indentation - if (currentNode.kind() === TypeScript.SyntaxKind.StringLiteral || - currentNode.kind() === TypeScript.SyntaxKind.RegularExpressionLiteral) { - return indentation; - } - - var currentElement = currentNode; - var parent = currentNode.parent; - - while (parent !== null) { - // Skip nodes that start at the position, these will have the indentation level of thier parent - if (fullStart(parent) !== fullStart(currentNode)) { - if (Indenter.isInContainerNode(parent, currentElement)) { - indentation += editorOptions.IndentSize; - } - else { - var listIndentation = Indenter.getCustomListIndentation(parent, currentElement); - if (listIndentation !== -1) { - // Found a list node with special indentation, If the list items span multiple lines, we want - // to use the user-specified indentation; return. - return indentation + listIndentation; - } - } - } - currentNode = parent; - currentElement = parent; - parent = parent.parent; - } - - return indentation; - } - - private static belongsToBracket(sourceText: TypeScript.IScriptSnapshot, token: TypeScript.ISyntaxToken, position: number): boolean { - switch (token.kind()) { - case TypeScript.SyntaxKind.OpenBraceToken: - case TypeScript.SyntaxKind.CloseBraceToken: - case TypeScript.SyntaxKind.OpenParenToken: - case TypeScript.SyntaxKind.CloseParenToken: - case TypeScript.SyntaxKind.OpenBracketToken: - case TypeScript.SyntaxKind.CloseBracketToken: - // the current token is a bracket, check if the current position is separated from it by a new line - if (position < start(token)) { - var text = sourceText.getText(position, start(token)); - for(var i = 0; i< text.length; i++){ - if (TypeScript.CharacterInfo.isLineTerminator(text.charCodeAt(i))) { - return false; - } - } - } - return true; - } - return false; - } - - private static isInContainerNode(parent: TypeScript.ISyntaxElement, element: TypeScript.ISyntaxElement): boolean { - switch (parent.kind()) { - case TypeScript.SyntaxKind.ClassDeclaration: - case TypeScript.SyntaxKind.ModuleDeclaration: - case TypeScript.SyntaxKind.EnumDeclaration: - case TypeScript.SyntaxKind.ImportDeclaration: - case TypeScript.SyntaxKind.Block: - case TypeScript.SyntaxKind.SwitchStatement: - case TypeScript.SyntaxKind.CaseSwitchClause: - case TypeScript.SyntaxKind.DefaultSwitchClause: - return true; - - case TypeScript.SyntaxKind.ObjectType: - return true; - - case TypeScript.SyntaxKind.InterfaceDeclaration: - return element.kind() !== TypeScript.SyntaxKind.ObjectType; - - case TypeScript.SyntaxKind.FunctionDeclaration: - case TypeScript.SyntaxKind.MemberFunctionDeclaration: - case TypeScript.SyntaxKind.GetAccessor: - case TypeScript.SyntaxKind.SetAccessor: - case TypeScript.SyntaxKind.FunctionExpression: - case TypeScript.SyntaxKind.CatchClause: - case TypeScript.SyntaxKind.FinallyClause: - case TypeScript.SyntaxKind.FunctionDeclaration: - case TypeScript.SyntaxKind.ConstructorDeclaration: - case TypeScript.SyntaxKind.ForStatement: - case TypeScript.SyntaxKind.ForInStatement: - case TypeScript.SyntaxKind.WhileStatement: - case TypeScript.SyntaxKind.DoStatement: - case TypeScript.SyntaxKind.WithStatement: - case TypeScript.SyntaxKind.IfStatement: - case TypeScript.SyntaxKind.ElseClause: - // The block has already been conted before, ignore the container node - return element.kind() !== TypeScript.SyntaxKind.Block; - - case TypeScript.SyntaxKind.TryStatement: - // If inside the try body, the block element will take care of the indentation - // If not, we do not want to indent, as the next token would probally be catch or finally - // and we want these on the same indentation level. - return false; - default: - return isNode(parent) && SyntaxUtilities.isStatement(parent); - } - } - - private static getCustomListIndentation(list: TypeScript.ISyntaxElement, element: TypeScript.ISyntaxElement): number { - switch (list.kind()) { - case TypeScript.SyntaxKind.SeparatedList: - // If it is the first in the list, let it have its parents indentation; no custom indentation here. - for (var i = 0, n = childCount(list); i < n ; i++) { - var child = childAt(list, i); - if (child !== null && child === element) - return Indenter.getListItemIndentation(list, i - 1); - } - break; - - case TypeScript.SyntaxKind.ArgumentList: - // The separated list has been handled in the previous case, this is just if we are after - // the last element of the list, we want to get the indentation of the last element of the list - var argumentList = list; - var _arguments = argumentList.arguments; - if (_arguments !== null && argumentList.closeParenToken === element) { - return Indenter.getListItemIndentation(_arguments, childCount(_arguments) - 1); - } - break; - - case TypeScript.SyntaxKind.ParameterList: - // The separated list has been handled in the previous case, this is just if we are after - // the last element of the list, we want to get the indentation of the last element of the list - var parameterList = list; - var parameters = parameterList.parameters; - if (parameters !== null && parameterList.closeParenToken === element) { - return Indenter.getListItemIndentation(parameters, childCount(parameters) - 1); - } - break; - - case TypeScript.SyntaxKind.TypeArgumentList: - // The separated list has been handled in the previous case, this is just if we are after - // the last element of the list, we want to get the indentation of the last element of the list - var typeArgumentList = list; - var typeArguments = typeArgumentList.typeArguments; - if (typeArguments !== null && typeArgumentList.greaterThanToken === element) { - return Indenter.getListItemIndentation(typeArguments, childCount(typeArguments) - 1); - } - break; - - case TypeScript.SyntaxKind.TypeParameterList: - // The separated list has been handled in the previous case, this is just if we are after - // the last element of the list, we want to get the indentation of the last element of the list - var typeParameterList = list; - var typeParameters = typeParameterList.typeParameters; - if (typeParameters !== null && typeParameterList.greaterThanToken === element) { - return Indenter.getListItemIndentation(typeParameters, childCount(typeParameters) - 1); - } - break; - } - return -1; - } - - private static getListItemIndentation(list: TypeScript.ISyntaxElement, elementIndex: number): number { - for (var i = elementIndex; i > 0 ; i--) { - var child = childAt(list, i); - var previousChild = childAt(list, i - 1); - if ((child !== null && firstToken(child).leadingTrivia().hasNewLine()) || - (previousChild !== null && lastToken(previousChild).trailingTrivia().hasNewLine())) { - - // TODO: get the trivia after new line - return leadingTriviaWidth(child); - } - } - return -1; - } - } -} diff --git a/src/services/languageServiceCopy.ts b/src/services/languageServiceCopy.ts deleted file mode 100644 index 912006eea0c..00000000000 --- a/src/services/languageServiceCopy.ts +++ /dev/null @@ -1,342 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -/// -/// - -module TypeScript.Services { - - // - // Public interface of the host of a language service instance. - // - export interface ILanguageServiceHost extends TypeScript.ILogger, TypeScript.IReferenceResolverHost { - getCompilationSettings(): TypeScript.CompilationSettings; - - getScriptFileNames(): string[]; - getScriptVersion(fileName: string): number; - getScriptIsOpen(fileName: string): boolean; - getScriptByteOrderMark(fileName: string): TypeScript.ByteOrderMark; - getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot; - getDiagnosticsObject(): TypeScript.Services.ILanguageServicesDiagnostics; - getLocalizedDiagnosticMessages(): any; - } - - // - // Public services of a language service instance associated - // with a language service host instance - // - export interface ILanguageService { - // Note: refresh is a no-op now. It is only around for back compat purposes. - refresh(): void; - - cleanupSemanticCache(): void; - - getSyntacticDiagnostics(fileName: string): TypeScript.Diagnostic[]; - getSemanticDiagnostics(fileName: string): TypeScript.Diagnostic[]; - getCompilerOptionsDiagnostics(): TypeScript.Diagnostic[]; - - getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean): CompletionInfo; - getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails; - - getTypeAtPosition(fileName: string, position: number): TypeInfo; - - getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): SpanInfo; - - getBreakpointStatementAtPosition(fileName: string, position: number): SpanInfo; - - getSignatureAtPosition(fileName: string, position: number): SignatureInfo; - - getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; - getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[]; - getOccurrencesAtPosition(fileName: string, position: number): ReferenceEntry[]; - getImplementorsAtPosition(fileName: string, position: number): ReferenceEntry[]; - - getNavigateToItems(searchValue: string): NavigateToItem[]; - getScriptLexicalStructure(fileName: string): NavigateToItem[]; - - getOutliningRegions(fileName: string): TypeScript.TextSpan[]; - getBraceMatchingAtPosition(fileName: string, position: number): TypeScript.TextSpan[]; - getIndentationAtPosition(fileName: string, position: number, options: TypeScript.Services.EditorOptions): number; - - getFormattingEditsForRange(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[]; - getFormattingEditsForDocument(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[]; - getFormattingEditsOnPaste(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[]; - getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions): TextEdit[]; - - getEmitOutput(fileName: string): TypeScript.EmitOutput; - - getSyntaxTree(fileName: string): TypeScript.SyntaxTree; - } - - export function logInternalError(logger: TypeScript.ILogger, err: Error) { - logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message); - } - - export class ReferenceEntry { - public fileName: string = "" - public minChar: number = -1; - public limChar: number = -1; - public isWriteAccess: boolean = false; - - constructor(fileName: string, minChar: number, limChar: number, isWriteAccess: boolean) { - this.fileName = fileName; - this.minChar = minChar; - this.limChar = limChar; - this.isWriteAccess = isWriteAccess; - } - } - - export class NavigateToItem { - public name: string = ""; - public kind: string = ""; // see ScriptElementKind - public kindModifiers: string = ""; // see ScriptElementKindModifier, comma separated - public matchKind: string = ""; - public fileName: string = ""; - public minChar: number = -1; - public limChar: number = -1; - public additionalSpans: SpanInfo[] = null; - public containerName: string = ""; - public containerKind: string = ""; // see ScriptElementKind - } - - export class TextEdit { - constructor(public minChar: number, public limChar: number, public text: string) { - } - - static createInsert(pos: number, text: string): TextEdit { - return new TextEdit(pos, pos, text); - } - static createDelete(minChar: number, limChar: number): TextEdit { - return new TextEdit(minChar, limChar, ""); - } - static createReplace(minChar: number, limChar: number, text: string): TextEdit { - return new TextEdit(minChar, limChar, text); - } - } - - export class EditorOptions { - public IndentSize: number = 4; - public TabSize: number = 4; - public NewLineCharacter: string = "\r\n"; - public ConvertTabsToSpaces: boolean = true; - - public static clone(objectToClone: EditorOptions): EditorOptions { - var editorOptions = new EditorOptions(); - editorOptions.IndentSize = objectToClone.IndentSize; - editorOptions.TabSize = objectToClone.TabSize; - editorOptions.NewLineCharacter = objectToClone.NewLineCharacter; - editorOptions.ConvertTabsToSpaces = objectToClone.ConvertTabsToSpaces; - return editorOptions; - } - } - - export class FormatCodeOptions extends EditorOptions { - public InsertSpaceAfterCommaDelimiter: boolean = true; - public InsertSpaceAfterSemicolonInForStatements: boolean = true; - public InsertSpaceBeforeAndAfterBinaryOperators: boolean = true; - public InsertSpaceAfterKeywordsInControlFlowStatements: boolean = true; - public InsertSpaceAfterFunctionKeywordForAnonymousFunctions: boolean = false; - public InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: boolean = false; - public PlaceOpenBraceOnNewLineForFunctions: boolean = false; - public PlaceOpenBraceOnNewLineForControlBlocks: boolean = false; - - public static clone(objectToClone: FormatCodeOptions ): FormatCodeOptions { - var formatCodeOptions = EditorOptions.clone(objectToClone); - formatCodeOptions.InsertSpaceAfterCommaDelimiter = objectToClone.InsertSpaceAfterCommaDelimiter; - formatCodeOptions.InsertSpaceAfterSemicolonInForStatements = objectToClone.InsertSpaceAfterSemicolonInForStatements; - formatCodeOptions.InsertSpaceBeforeAndAfterBinaryOperators = objectToClone.InsertSpaceBeforeAndAfterBinaryOperators; - formatCodeOptions.InsertSpaceAfterKeywordsInControlFlowStatements = objectToClone.InsertSpaceAfterKeywordsInControlFlowStatements; - formatCodeOptions.InsertSpaceAfterFunctionKeywordForAnonymousFunctions = objectToClone.InsertSpaceAfterFunctionKeywordForAnonymousFunctions; - formatCodeOptions.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis = objectToClone.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis; - formatCodeOptions.PlaceOpenBraceOnNewLineForFunctions = objectToClone.PlaceOpenBraceOnNewLineForFunctions; - formatCodeOptions.PlaceOpenBraceOnNewLineForControlBlocks = objectToClone.PlaceOpenBraceOnNewLineForControlBlocks; - return formatCodeOptions; - } - } - - export class DefinitionInfo { - constructor( - public fileName: string, - public minChar: number, - public limChar: number, - public kind: string, - public name: string, - public containerKind: string, - public containerName: string) { - } - } - - export class TypeInfo { - constructor( - public memberName: TypeScript.MemberName, - public docComment: string, - public fullSymbolName: string, - public kind: string, - public minChar: number, - public limChar: number) { - } - } - - export class SpanInfo { - constructor(public minChar: number, public limChar: number, public text: string = null) { - } - } - - export class SignatureInfo { - public actual: ActualSignatureInfo; - public formal: FormalSignatureItemInfo[] = []; // Formal signatures - public activeFormal: number; // Index of the "best match" formal signature - } - - export class FormalSignatureItemInfo { - public signatureInfo: string; - public typeParameters: FormalTypeParameterInfo[] = []; - public parameters: FormalParameterInfo[] = []; // Array of parameters - public docComment: string; // Help for the signature - } - - export class FormalTypeParameterInfo { - public name: string; // Type parameter name - public docComment: string; // Comments that contain help for the parameter - public minChar: number; // minChar for parameter info in the formal signature info string - public limChar: number; // lim char for parameter info in the formal signature info string - } - - export class FormalParameterInfo { - public name: string; // Parameter name - public isVariable: boolean; // true if parameter is var args - public docComment: string; // Comments that contain help for the parameter - public minChar: number; // minChar for parameter info in the formal signature info string - public limChar: number; // lim char for parameter info in the formal signature info string - } - - export class ActualSignatureInfo { - public parameterMinChar: number; - public parameterLimChar: number; - public currentParameterIsTypeParameter: boolean; // current parameter is a type argument or a normal argument - public currentParameter: number; // Index of active parameter in "parameters" or "typeParamters" array - } - - export class CompletionInfo { - public maybeInaccurate = false; - public isMemberCompletion = false; - public entries: CompletionEntry[] = []; - } - - export interface CompletionEntry { - name: string; - kind: string; // see ScriptElementKind - kindModifiers: string; // see ScriptElementKindModifier, comma separated - } - - export interface CompletionEntryDetails { - name: string; - kind: string; // see ScriptElementKind - kindModifiers: string; // see ScriptElementKindModifier, comma separated - type: string; - fullSymbolName: string; - docComment: string; - } - - - export class ScriptElementKind { - static unknown = ""; - - // predefined type (void) or keyword (class) - static keyword = "keyword"; - - // top level script node - static scriptElement = "script"; - - // module foo {} - static moduleElement = "module"; - - // class X {} - static classElement = "class"; - - // interface Y {} - static interfaceElement = "interface"; - - // enum E - static enumElement = "enum"; - - // Inside module and script only - // var v = .. - static variableElement = "var"; - - // Inside function - static localVariableElement = "local var"; - - // Inside module and script only - // function f() { } - static functionElement = "function"; - - // Inside function - static localFunctionElement = "local function"; - - // class X { [public|private]* foo() {} } - static memberFunctionElement = "method"; - - // class X { [public|private]* [get|set] foo:number; } - static memberGetAccessorElement = "getter"; - static memberSetAccessorElement = "setter"; - - // class X { [public|private]* foo:number; } - // interface Y { foo:number; } - static memberVariableElement = "property"; - - // class X { constructor() { } } - static constructorImplementationElement = "constructor"; - - // interface Y { ():number; } - static callSignatureElement = "call"; - - // interface Y { []:number; } - static indexSignatureElement = "index"; - - // interface Y { new():Y; } - static constructSignatureElement = "construct"; - - // function foo(*Y*: string) - static parameterElement = "parameter"; - - static typeParameterElement = "type parameter"; - - static primitiveType = "primitive type"; - } - - export class ScriptElementKindModifier { - static none = ""; - static publicMemberModifier = "public"; - static privateMemberModifier = "private"; - static exportedModifier = "export"; - static ambientModifier = "declare"; - static staticModifier = "static"; - } - - export class MatchKind { - static none: string = null; - static exact = "exact"; - static subString = "substring"; - static prefix = "prefix"; - } - - export class DiagnosticCategory { - static none = ""; - static error = "error"; - static warning = "warning"; - static message = "message"; - } -} diff --git a/src/services/syntaxRewriter.generated.ts b/src/services/syntaxRewriter.generated.ts deleted file mode 100644 index 110fdb22c2a..00000000000 --- a/src/services/syntaxRewriter.generated.ts +++ /dev/null @@ -1,708 +0,0 @@ -/// - -module TypeScript { - export class SyntaxRewriter implements ISyntaxVisitor { - public visitToken(token: ISyntaxToken): ISyntaxToken { - return token; - } - - public visitNode(node: ISyntaxNode): ISyntaxNode { - return visitNodeOrToken(this, node); - } - - public visitNodeOrToken(node: ISyntaxNodeOrToken): ISyntaxNodeOrToken { - return isToken(node) ? this.visitToken(node) : this.visitNode(node); - } - - public visitList(list: T[]): T[] { - var newItems: T[] = null; - - for (var i = 0, n = list.length; i < n; i++) { - var item = list[i]; - var newItem = this.visitNodeOrToken(item); - - if (item !== newItem && newItems === null) { - newItems = []; - for (var j = 0; j < i; j++) { - newItems.push(list[j]); - } - } - - if (newItems) { - newItems.push(newItem); - } - } - - // Debug.assert(newItems === null || newItems.length === childCount(list)); - return newItems === null ? list : Syntax.list(newItems); - } - - public visitSeparatedList(list: T[]): T[] { - var newItems: ISyntaxNodeOrToken[] = null; - - for (var i = 0, n = childCount(list); i < n; i++) { - var item = childAt(list, i); - var newItem = isToken(item) ? this.visitToken(item) : this.visitNode(item); - - if (item !== newItem && newItems === null) { - newItems = []; - for (var j = 0; j < i; j++) { - newItems.push(childAt(list, j)); - } - } - - if (newItems) { - newItems.push(newItem); - } - } - - // Debug.assert(newItems === null || newItems.length === childCount(list)); - return newItems === null ? list : Syntax.separatedList(newItems); - } - - public visitSourceUnit(node: SourceUnitSyntax): any { - return node.update( - this.visitList(node.moduleElements), - this.visitToken(node.endOfFileToken)); - } - - public visitQualifiedName(node: QualifiedNameSyntax): any { - return node.update( - this.visitNodeOrToken(node.left), - this.visitToken(node.dotToken), - this.visitToken(node.right)); - } - - public visitObjectType(node: ObjectTypeSyntax): any { - return node.update( - this.visitToken(node.openBraceToken), - this.visitSeparatedList(node.typeMembers), - this.visitToken(node.closeBraceToken)); - } - - public visitFunctionType(node: FunctionTypeSyntax): any { - return node.update( - node.typeParameterList === null ? null : this.visitNode(node.typeParameterList), - this.visitNode(node.parameterList), - this.visitToken(node.equalsGreaterThanToken), - this.visitNodeOrToken(node.type)); - } - - public visitArrayType(node: ArrayTypeSyntax): any { - return node.update( - this.visitNodeOrToken(node.type), - this.visitToken(node.openBracketToken), - this.visitToken(node.closeBracketToken)); - } - - public visitConstructorType(node: ConstructorTypeSyntax): any { - return node.update( - this.visitToken(node.newKeyword), - node.typeParameterList === null ? null : this.visitNode(node.typeParameterList), - this.visitNode(node.parameterList), - this.visitToken(node.equalsGreaterThanToken), - this.visitNodeOrToken(node.type)); - } - - public visitGenericType(node: GenericTypeSyntax): any { - return node.update( - this.visitNodeOrToken(node.name), - this.visitNode(node.typeArgumentList)); - } - - public visitTypeQuery(node: TypeQuerySyntax): any { - return node.update( - this.visitToken(node.typeOfKeyword), - this.visitNodeOrToken(node.name)); - } - - public visitInterfaceDeclaration(node: InterfaceDeclarationSyntax): any { - return node.update( - this.visitList(node.modifiers), - this.visitToken(node.interfaceKeyword), - this.visitToken(node.identifier), - node.typeParameterList === null ? null : this.visitNode(node.typeParameterList), - this.visitList(node.heritageClauses), - this.visitNode(node.body)); - } - - public visitFunctionDeclaration(node: FunctionDeclarationSyntax): any { - return node.update( - this.visitList(node.modifiers), - this.visitToken(node.functionKeyword), - this.visitToken(node.identifier), - this.visitNode(node.callSignature), - node.block === null ? null : this.visitNode(node.block), - node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); - } - - public visitModuleDeclaration(node: ModuleDeclarationSyntax): any { - return node.update( - this.visitList(node.modifiers), - this.visitToken(node.moduleKeyword), - node.name === null ? null : this.visitNodeOrToken(node.name), - node.stringLiteral === null ? null : this.visitToken(node.stringLiteral), - this.visitToken(node.openBraceToken), - this.visitList(node.moduleElements), - this.visitToken(node.closeBraceToken)); - } - - public visitClassDeclaration(node: ClassDeclarationSyntax): any { - return node.update( - this.visitList(node.modifiers), - this.visitToken(node.classKeyword), - this.visitToken(node.identifier), - node.typeParameterList === null ? null : this.visitNode(node.typeParameterList), - this.visitList(node.heritageClauses), - this.visitToken(node.openBraceToken), - this.visitList(node.classElements), - this.visitToken(node.closeBraceToken)); - } - - public visitEnumDeclaration(node: EnumDeclarationSyntax): any { - return node.update( - this.visitList(node.modifiers), - this.visitToken(node.enumKeyword), - this.visitToken(node.identifier), - this.visitToken(node.openBraceToken), - this.visitSeparatedList(node.enumElements), - this.visitToken(node.closeBraceToken)); - } - - public visitImportDeclaration(node: ImportDeclarationSyntax): any { - return node.update( - this.visitList(node.modifiers), - this.visitToken(node.importKeyword), - this.visitToken(node.identifier), - this.visitToken(node.equalsToken), - this.visitNodeOrToken(node.moduleReference), - node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); - } - - public visitExportAssignment(node: ExportAssignmentSyntax): any { - return node.update( - this.visitToken(node.exportKeyword), - this.visitToken(node.equalsToken), - this.visitToken(node.identifier), - node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); - } - - public visitMemberFunctionDeclaration(node: MemberFunctionDeclarationSyntax): any { - return node.update( - this.visitList(node.modifiers), - this.visitToken(node.propertyName), - this.visitNode(node.callSignature), - node.block === null ? null : this.visitNode(node.block), - node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); - } - - public visitMemberVariableDeclaration(node: MemberVariableDeclarationSyntax): any { - return node.update( - this.visitList(node.modifiers), - this.visitNode(node.variableDeclarator), - node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); - } - - public visitConstructorDeclaration(node: ConstructorDeclarationSyntax): any { - return node.update( - this.visitList(node.modifiers), - this.visitToken(node.constructorKeyword), - this.visitNode(node.callSignature), - node.block === null ? null : this.visitNode(node.block), - node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); - } - - public visitIndexMemberDeclaration(node: IndexMemberDeclarationSyntax): any { - return node.update( - this.visitList(node.modifiers), - this.visitNode(node.indexSignature), - node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); - } - - public visitGetAccessor(node: GetAccessorSyntax): any { - return node.update( - this.visitList(node.modifiers), - this.visitToken(node.getKeyword), - this.visitToken(node.propertyName), - this.visitNode(node.callSignature), - this.visitNode(node.block)); - } - - public visitSetAccessor(node: SetAccessorSyntax): any { - return node.update( - this.visitList(node.modifiers), - this.visitToken(node.setKeyword), - this.visitToken(node.propertyName), - this.visitNode(node.callSignature), - this.visitNode(node.block)); - } - - public visitPropertySignature(node: PropertySignatureSyntax): any { - return node.update( - this.visitToken(node.propertyName), - node.questionToken === null ? null : this.visitToken(node.questionToken), - node.typeAnnotation === null ? null : this.visitNode(node.typeAnnotation)); - } - - public visitCallSignature(node: CallSignatureSyntax): any { - return node.update( - node.typeParameterList === null ? null : this.visitNode(node.typeParameterList), - this.visitNode(node.parameterList), - node.typeAnnotation === null ? null : this.visitNode(node.typeAnnotation)); - } - - public visitConstructSignature(node: ConstructSignatureSyntax): any { - return node.update( - this.visitToken(node.newKeyword), - this.visitNode(node.callSignature)); - } - - public visitIndexSignature(node: IndexSignatureSyntax): any { - return node.update( - this.visitToken(node.openBracketToken), - this.visitSeparatedList(node.parameters), - this.visitToken(node.closeBracketToken), - node.typeAnnotation === null ? null : this.visitNode(node.typeAnnotation)); - } - - public visitMethodSignature(node: MethodSignatureSyntax): any { - return node.update( - this.visitToken(node.propertyName), - node.questionToken === null ? null : this.visitToken(node.questionToken), - this.visitNode(node.callSignature)); - } - - public visitBlock(node: BlockSyntax): any { - return node.update( - this.visitToken(node.openBraceToken), - this.visitList(node.statements), - this.visitToken(node.closeBraceToken)); - } - - public visitIfStatement(node: IfStatementSyntax): any { - return node.update( - this.visitToken(node.ifKeyword), - this.visitToken(node.openParenToken), - this.visitNodeOrToken(node.condition), - this.visitToken(node.closeParenToken), - this.visitNodeOrToken(node.statement), - node.elseClause === null ? null : this.visitNode(node.elseClause)); - } - - public visitVariableStatement(node: VariableStatementSyntax): any { - return node.update( - this.visitList(node.modifiers), - this.visitNode(node.variableDeclaration), - node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); - } - - public visitExpressionStatement(node: ExpressionStatementSyntax): any { - return node.update( - this.visitNodeOrToken(node.expression), - node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); - } - - public visitReturnStatement(node: ReturnStatementSyntax): any { - return node.update( - this.visitToken(node.returnKeyword), - node.expression === null ? null : this.visitNodeOrToken(node.expression), - node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); - } - - public visitSwitchStatement(node: SwitchStatementSyntax): any { - return node.update( - this.visitToken(node.switchKeyword), - this.visitToken(node.openParenToken), - this.visitNodeOrToken(node.expression), - this.visitToken(node.closeParenToken), - this.visitToken(node.openBraceToken), - this.visitList(node.switchClauses), - this.visitToken(node.closeBraceToken)); - } - - public visitBreakStatement(node: BreakStatementSyntax): any { - return node.update( - this.visitToken(node.breakKeyword), - node.identifier === null ? null : this.visitToken(node.identifier), - node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); - } - - public visitContinueStatement(node: ContinueStatementSyntax): any { - return node.update( - this.visitToken(node.continueKeyword), - node.identifier === null ? null : this.visitToken(node.identifier), - node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); - } - - public visitForStatement(node: ForStatementSyntax): any { - return node.update( - this.visitToken(node.forKeyword), - this.visitToken(node.openParenToken), - node.variableDeclaration === null ? null : this.visitNode(node.variableDeclaration), - node.initializer === null ? null : this.visitNodeOrToken(node.initializer), - this.visitToken(node.firstSemicolonToken), - node.condition === null ? null : this.visitNodeOrToken(node.condition), - this.visitToken(node.secondSemicolonToken), - node.incrementor === null ? null : this.visitNodeOrToken(node.incrementor), - this.visitToken(node.closeParenToken), - this.visitNodeOrToken(node.statement)); - } - - public visitForInStatement(node: ForInStatementSyntax): any { - return node.update( - this.visitToken(node.forKeyword), - this.visitToken(node.openParenToken), - node.variableDeclaration === null ? null : this.visitNode(node.variableDeclaration), - node.left === null ? null : this.visitNodeOrToken(node.left), - this.visitToken(node.inKeyword), - this.visitNodeOrToken(node.expression), - this.visitToken(node.closeParenToken), - this.visitNodeOrToken(node.statement)); - } - - public visitEmptyStatement(node: EmptyStatementSyntax): any { - return node.update( - this.visitToken(node.semicolonToken)); - } - - public visitThrowStatement(node: ThrowStatementSyntax): any { - return node.update( - this.visitToken(node.throwKeyword), - this.visitNodeOrToken(node.expression), - node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); - } - - public visitWhileStatement(node: WhileStatementSyntax): any { - return node.update( - this.visitToken(node.whileKeyword), - this.visitToken(node.openParenToken), - this.visitNodeOrToken(node.condition), - this.visitToken(node.closeParenToken), - this.visitNodeOrToken(node.statement)); - } - - public visitTryStatement(node: TryStatementSyntax): any { - return node.update( - this.visitToken(node.tryKeyword), - this.visitNode(node.block), - node.catchClause === null ? null : this.visitNode(node.catchClause), - node.finallyClause === null ? null : this.visitNode(node.finallyClause)); - } - - public visitLabeledStatement(node: LabeledStatementSyntax): any { - return node.update( - this.visitToken(node.identifier), - this.visitToken(node.colonToken), - this.visitNodeOrToken(node.statement)); - } - - public visitDoStatement(node: DoStatementSyntax): any { - return node.update( - this.visitToken(node.doKeyword), - this.visitNodeOrToken(node.statement), - this.visitToken(node.whileKeyword), - this.visitToken(node.openParenToken), - this.visitNodeOrToken(node.condition), - this.visitToken(node.closeParenToken), - node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); - } - - public visitDebuggerStatement(node: DebuggerStatementSyntax): any { - return node.update( - this.visitToken(node.debuggerKeyword), - node.semicolonToken === null ? null : this.visitToken(node.semicolonToken)); - } - - public visitWithStatement(node: WithStatementSyntax): any { - return node.update( - this.visitToken(node.withKeyword), - this.visitToken(node.openParenToken), - this.visitNodeOrToken(node.condition), - this.visitToken(node.closeParenToken), - this.visitNodeOrToken(node.statement)); - } - - public visitPrefixUnaryExpression(node: PrefixUnaryExpressionSyntax): any { - return node.update( - this.visitToken(node.operatorToken), - this.visitNodeOrToken(node.operand)); - } - - public visitDeleteExpression(node: DeleteExpressionSyntax): any { - return node.update( - this.visitToken(node.deleteKeyword), - this.visitNodeOrToken(node.expression)); - } - - public visitTypeOfExpression(node: TypeOfExpressionSyntax): any { - return node.update( - this.visitToken(node.typeOfKeyword), - this.visitNodeOrToken(node.expression)); - } - - public visitVoidExpression(node: VoidExpressionSyntax): any { - return node.update( - this.visitToken(node.voidKeyword), - this.visitNodeOrToken(node.expression)); - } - - public visitConditionalExpression(node: ConditionalExpressionSyntax): any { - return node.update( - this.visitNodeOrToken(node.condition), - this.visitToken(node.questionToken), - this.visitNodeOrToken(node.whenTrue), - this.visitToken(node.colonToken), - this.visitNodeOrToken(node.whenFalse)); - } - - public visitBinaryExpression(node: BinaryExpressionSyntax): any { - return node.update( - this.visitNodeOrToken(node.left), - this.visitToken(node.operatorToken), - this.visitNodeOrToken(node.right)); - } - - public visitPostfixUnaryExpression(node: PostfixUnaryExpressionSyntax): any { - return node.update( - this.visitNodeOrToken(node.operand), - this.visitToken(node.operatorToken)); - } - - public visitMemberAccessExpression(node: MemberAccessExpressionSyntax): any { - return node.update( - this.visitNodeOrToken(node.expression), - this.visitToken(node.dotToken), - this.visitToken(node.name)); - } - - public visitInvocationExpression(node: InvocationExpressionSyntax): any { - return node.update( - this.visitNodeOrToken(node.expression), - this.visitNode(node.argumentList)); - } - - public visitArrayLiteralExpression(node: ArrayLiteralExpressionSyntax): any { - return node.update( - this.visitToken(node.openBracketToken), - this.visitSeparatedList(node.expressions), - this.visitToken(node.closeBracketToken)); - } - - public visitObjectLiteralExpression(node: ObjectLiteralExpressionSyntax): any { - return node.update( - this.visitToken(node.openBraceToken), - this.visitSeparatedList(node.propertyAssignments), - this.visitToken(node.closeBraceToken)); - } - - public visitObjectCreationExpression(node: ObjectCreationExpressionSyntax): any { - return node.update( - this.visitToken(node.newKeyword), - this.visitNodeOrToken(node.expression), - node.argumentList === null ? null : this.visitNode(node.argumentList)); - } - - public visitParenthesizedExpression(node: ParenthesizedExpressionSyntax): any { - return node.update( - this.visitToken(node.openParenToken), - this.visitNodeOrToken(node.expression), - this.visitToken(node.closeParenToken)); - } - - public visitParenthesizedArrowFunctionExpression(node: ParenthesizedArrowFunctionExpressionSyntax): any { - return node.update( - this.visitNode(node.callSignature), - this.visitToken(node.equalsGreaterThanToken), - node.block === null ? null : this.visitNode(node.block), - node.expression === null ? null : this.visitNodeOrToken(node.expression)); - } - - public visitSimpleArrowFunctionExpression(node: SimpleArrowFunctionExpressionSyntax): any { - return node.update( - this.visitNode(node.parameter), - this.visitToken(node.equalsGreaterThanToken), - node.block === null ? null : this.visitNode(node.block), - node.expression === null ? null : this.visitNodeOrToken(node.expression)); - } - - public visitCastExpression(node: CastExpressionSyntax): any { - return node.update( - this.visitToken(node.lessThanToken), - this.visitNodeOrToken(node.type), - this.visitToken(node.greaterThanToken), - this.visitNodeOrToken(node.expression)); - } - - public visitElementAccessExpression(node: ElementAccessExpressionSyntax): any { - return node.update( - this.visitNodeOrToken(node.expression), - this.visitToken(node.openBracketToken), - this.visitNodeOrToken(node.argumentExpression), - this.visitToken(node.closeBracketToken)); - } - - public visitFunctionExpression(node: FunctionExpressionSyntax): any { - return node.update( - this.visitToken(node.functionKeyword), - node.identifier === null ? null : this.visitToken(node.identifier), - this.visitNode(node.callSignature), - this.visitNode(node.block)); - } - - public visitOmittedExpression(node: OmittedExpressionSyntax): any { - return node; - } - - public visitVariableDeclaration(node: VariableDeclarationSyntax): any { - return node.update( - this.visitToken(node.varKeyword), - this.visitSeparatedList(node.variableDeclarators)); - } - - public visitVariableDeclarator(node: VariableDeclaratorSyntax): any { - return node.update( - this.visitToken(node.propertyName), - node.typeAnnotation === null ? null : this.visitNode(node.typeAnnotation), - node.equalsValueClause === null ? null : this.visitNode(node.equalsValueClause)); - } - - public visitArgumentList(node: ArgumentListSyntax): any { - return node.update( - node.typeArgumentList === null ? null : this.visitNode(node.typeArgumentList), - this.visitToken(node.openParenToken), - this.visitSeparatedList(node.arguments), - this.visitToken(node.closeParenToken)); - } - - public visitParameterList(node: ParameterListSyntax): any { - return node.update( - this.visitToken(node.openParenToken), - this.visitSeparatedList(node.parameters), - this.visitToken(node.closeParenToken)); - } - - public visitTypeArgumentList(node: TypeArgumentListSyntax): any { - return node.update( - this.visitToken(node.lessThanToken), - this.visitSeparatedList(node.typeArguments), - this.visitToken(node.greaterThanToken)); - } - - public visitTypeParameterList(node: TypeParameterListSyntax): any { - return node.update( - this.visitToken(node.lessThanToken), - this.visitSeparatedList(node.typeParameters), - this.visitToken(node.greaterThanToken)); - } - - public visitHeritageClause(node: HeritageClauseSyntax): any { - return node.update( - this.visitToken(node.extendsOrImplementsKeyword), - this.visitSeparatedList(node.typeNames)); - } - - public visitEqualsValueClause(node: EqualsValueClauseSyntax): any { - return node.update( - this.visitToken(node.equalsToken), - this.visitNodeOrToken(node.value)); - } - - public visitCaseSwitchClause(node: CaseSwitchClauseSyntax): any { - return node.update( - this.visitToken(node.caseKeyword), - this.visitNodeOrToken(node.expression), - this.visitToken(node.colonToken), - this.visitList(node.statements)); - } - - public visitDefaultSwitchClause(node: DefaultSwitchClauseSyntax): any { - return node.update( - this.visitToken(node.defaultKeyword), - this.visitToken(node.colonToken), - this.visitList(node.statements)); - } - - public visitElseClause(node: ElseClauseSyntax): any { - return node.update( - this.visitToken(node.elseKeyword), - this.visitNodeOrToken(node.statement)); - } - - public visitCatchClause(node: CatchClauseSyntax): any { - return node.update( - this.visitToken(node.catchKeyword), - this.visitToken(node.openParenToken), - this.visitToken(node.identifier), - node.typeAnnotation === null ? null : this.visitNode(node.typeAnnotation), - this.visitToken(node.closeParenToken), - this.visitNode(node.block)); - } - - public visitFinallyClause(node: FinallyClauseSyntax): any { - return node.update( - this.visitToken(node.finallyKeyword), - this.visitNode(node.block)); - } - - public visitTypeParameter(node: TypeParameterSyntax): any { - return node.update( - this.visitToken(node.identifier), - node.constraint === null ? null : this.visitNode(node.constraint)); - } - - public visitConstraint(node: ConstraintSyntax): any { - return node.update( - this.visitToken(node.extendsKeyword), - this.visitNodeOrToken(node.typeOrExpression)); - } - - public visitSimplePropertyAssignment(node: SimplePropertyAssignmentSyntax): any { - return node.update( - this.visitToken(node.propertyName), - this.visitToken(node.colonToken), - this.visitNodeOrToken(node.expression)); - } - - public visitFunctionPropertyAssignment(node: FunctionPropertyAssignmentSyntax): any { - return node.update( - this.visitToken(node.propertyName), - this.visitNode(node.callSignature), - this.visitNode(node.block)); - } - - public visitParameter(node: ParameterSyntax): any { - return node.update( - node.dotDotDotToken === null ? null : this.visitToken(node.dotDotDotToken), - this.visitList(node.modifiers), - this.visitToken(node.identifier), - node.questionToken === null ? null : this.visitToken(node.questionToken), - node.typeAnnotation === null ? null : this.visitNode(node.typeAnnotation), - node.equalsValueClause === null ? null : this.visitNode(node.equalsValueClause)); - } - - public visitEnumElement(node: EnumElementSyntax): any { - return node.update( - this.visitToken(node.propertyName), - node.equalsValueClause === null ? null : this.visitNode(node.equalsValueClause)); - } - - public visitTypeAnnotation(node: TypeAnnotationSyntax): any { - return node.update( - this.visitToken(node.colonToken), - this.visitNodeOrToken(node.type)); - } - - public visitExternalModuleReference(node: ExternalModuleReferenceSyntax): any { - return node.update( - this.visitToken(node.requireKeyword), - this.visitToken(node.openParenToken), - this.visitToken(node.stringLiteral), - this.visitToken(node.closeParenToken)); - } - - public visitModuleNameModuleReference(node: ModuleNameModuleReferenceSyntax): any { - return node.update( - this.visitNodeOrToken(node.moduleName)); - } - } -} \ No newline at end of file diff --git a/src/services/syntaxUtilities.generated.ts b/src/services/syntaxUtilities.generated.ts deleted file mode 100644 index 9ec244141fc..00000000000 --- a/src/services/syntaxUtilities.generated.ts +++ /dev/null @@ -1,395 +0,0 @@ -module TypeScript { - function isSeparatedListTypeScriptSpecific(list: ISyntaxNodeOrToken[]): boolean { - for (var i = 0, n = childCount(list); i < n; i++) { - if (isTypeScriptSpecific(childAt(list, i))) { - return true; - } - } - - return false; - } - - function isListTypeScriptSpecific(list: ISyntaxNodeOrToken[]): boolean { - for (var i = 0, n = list.length; i < n; i++) { - if (isTypeScriptSpecific(list[i])) { - return true; - } - } - - return false; - } - - export function isTypeScriptSpecific(element: ISyntaxElement): boolean { - if (element === null) { return false; } - if (isToken(element)) { return false; } - if (isList(element)) { return isListTypeScriptSpecific(element); } - if (isSeparatedList(element)) { return isSeparatedListTypeScriptSpecific(element); } - - switch (element.kind()) { - case SyntaxKind.QualifiedName: - case SyntaxKind.ObjectType: - case SyntaxKind.FunctionType: - case SyntaxKind.ArrayType: - case SyntaxKind.ConstructorType: - case SyntaxKind.GenericType: - case SyntaxKind.TypeQuery: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.ModuleDeclaration: - case SyntaxKind.ClassDeclaration: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.ImportDeclaration: - case SyntaxKind.ExportAssignment: - case SyntaxKind.MemberFunctionDeclaration: - case SyntaxKind.MemberVariableDeclaration: - case SyntaxKind.ConstructorDeclaration: - case SyntaxKind.IndexMemberDeclaration: - case SyntaxKind.SetAccessor: - case SyntaxKind.PropertySignature: - case SyntaxKind.ConstructSignature: - case SyntaxKind.IndexSignature: - case SyntaxKind.ParenthesizedArrowFunctionExpression: - case SyntaxKind.SimpleArrowFunctionExpression: - case SyntaxKind.CastExpression: - case SyntaxKind.TypeArgumentList: - case SyntaxKind.TypeParameterList: - case SyntaxKind.ExtendsHeritageClause: - case SyntaxKind.ImplementsHeritageClause: - case SyntaxKind.TypeParameter: - case SyntaxKind.Constraint: - case SyntaxKind.TypeAnnotation: - case SyntaxKind.ExternalModuleReference: - case SyntaxKind.ModuleNameModuleReference: - return true; - case SyntaxKind.BreakStatement: - case SyntaxKind.ContinueStatement: - case SyntaxKind.EmptyStatement: - case SyntaxKind.DebuggerStatement: - case SyntaxKind.OmittedExpression: - return false; - case SyntaxKind.SourceUnit: - return isSourceUnitTypeScriptSpecific(element); - case SyntaxKind.FunctionDeclaration: - return isFunctionDeclarationTypeScriptSpecific(element); - case SyntaxKind.GetAccessor: - return isGetAccessorTypeScriptSpecific(element); - case SyntaxKind.CallSignature: - return isCallSignatureTypeScriptSpecific(element); - case SyntaxKind.MethodSignature: - return isMethodSignatureTypeScriptSpecific(element); - case SyntaxKind.Block: - return isBlockTypeScriptSpecific(element); - case SyntaxKind.IfStatement: - return isIfStatementTypeScriptSpecific(element); - case SyntaxKind.VariableStatement: - return isVariableStatementTypeScriptSpecific(element); - case SyntaxKind.ExpressionStatement: - return isExpressionStatementTypeScriptSpecific(element); - case SyntaxKind.ReturnStatement: - return isReturnStatementTypeScriptSpecific(element); - case SyntaxKind.SwitchStatement: - return isSwitchStatementTypeScriptSpecific(element); - case SyntaxKind.ForStatement: - return isForStatementTypeScriptSpecific(element); - case SyntaxKind.ForInStatement: - return isForInStatementTypeScriptSpecific(element); - case SyntaxKind.ThrowStatement: - return isThrowStatementTypeScriptSpecific(element); - case SyntaxKind.WhileStatement: - return isWhileStatementTypeScriptSpecific(element); - case SyntaxKind.TryStatement: - return isTryStatementTypeScriptSpecific(element); - case SyntaxKind.LabeledStatement: - return isLabeledStatementTypeScriptSpecific(element); - case SyntaxKind.DoStatement: - return isDoStatementTypeScriptSpecific(element); - case SyntaxKind.WithStatement: - return isWithStatementTypeScriptSpecific(element); - case SyntaxKind.PreIncrementExpression: case SyntaxKind.PreDecrementExpression: case SyntaxKind.PlusExpression: case SyntaxKind.NegateExpression: case SyntaxKind.BitwiseNotExpression: case SyntaxKind.LogicalNotExpression: - return isPrefixUnaryExpressionTypeScriptSpecific(element); - case SyntaxKind.DeleteExpression: - return isDeleteExpressionTypeScriptSpecific(element); - case SyntaxKind.TypeOfExpression: - return isTypeOfExpressionTypeScriptSpecific(element); - case SyntaxKind.VoidExpression: - return isVoidExpressionTypeScriptSpecific(element); - case SyntaxKind.ConditionalExpression: - return isConditionalExpressionTypeScriptSpecific(element); - case SyntaxKind.MultiplyExpression: case SyntaxKind.DivideExpression: case SyntaxKind.ModuloExpression: case SyntaxKind.AddExpression: case SyntaxKind.SubtractExpression: case SyntaxKind.LeftShiftExpression: case SyntaxKind.SignedRightShiftExpression: case SyntaxKind.UnsignedRightShiftExpression: case SyntaxKind.LessThanExpression: case SyntaxKind.GreaterThanExpression: case SyntaxKind.LessThanOrEqualExpression: case SyntaxKind.GreaterThanOrEqualExpression: case SyntaxKind.InstanceOfExpression: case SyntaxKind.InExpression: case SyntaxKind.EqualsWithTypeConversionExpression: case SyntaxKind.NotEqualsWithTypeConversionExpression: case SyntaxKind.EqualsExpression: case SyntaxKind.NotEqualsExpression: case SyntaxKind.BitwiseAndExpression: case SyntaxKind.BitwiseExclusiveOrExpression: case SyntaxKind.BitwiseOrExpression: case SyntaxKind.LogicalAndExpression: case SyntaxKind.LogicalOrExpression: case SyntaxKind.OrAssignmentExpression: case SyntaxKind.AndAssignmentExpression: case SyntaxKind.ExclusiveOrAssignmentExpression: case SyntaxKind.LeftShiftAssignmentExpression: case SyntaxKind.SignedRightShiftAssignmentExpression: case SyntaxKind.UnsignedRightShiftAssignmentExpression: case SyntaxKind.AddAssignmentExpression: case SyntaxKind.SubtractAssignmentExpression: case SyntaxKind.MultiplyAssignmentExpression: case SyntaxKind.DivideAssignmentExpression: case SyntaxKind.ModuloAssignmentExpression: case SyntaxKind.AssignmentExpression: case SyntaxKind.CommaExpression: - return isBinaryExpressionTypeScriptSpecific(element); - case SyntaxKind.PostIncrementExpression: case SyntaxKind.PostDecrementExpression: - return isPostfixUnaryExpressionTypeScriptSpecific(element); - case SyntaxKind.MemberAccessExpression: - return isMemberAccessExpressionTypeScriptSpecific(element); - case SyntaxKind.InvocationExpression: - return isInvocationExpressionTypeScriptSpecific(element); - case SyntaxKind.ArrayLiteralExpression: - return isArrayLiteralExpressionTypeScriptSpecific(element); - case SyntaxKind.ObjectLiteralExpression: - return isObjectLiteralExpressionTypeScriptSpecific(element); - case SyntaxKind.ObjectCreationExpression: - return isObjectCreationExpressionTypeScriptSpecific(element); - case SyntaxKind.ParenthesizedExpression: - return isParenthesizedExpressionTypeScriptSpecific(element); - case SyntaxKind.ElementAccessExpression: - return isElementAccessExpressionTypeScriptSpecific(element); - case SyntaxKind.FunctionExpression: - return isFunctionExpressionTypeScriptSpecific(element); - case SyntaxKind.VariableDeclaration: - return isVariableDeclarationTypeScriptSpecific(element); - case SyntaxKind.VariableDeclarator: - return isVariableDeclaratorTypeScriptSpecific(element); - case SyntaxKind.ArgumentList: - return isArgumentListTypeScriptSpecific(element); - case SyntaxKind.ParameterList: - return isParameterListTypeScriptSpecific(element); - case SyntaxKind.EqualsValueClause: - return isEqualsValueClauseTypeScriptSpecific(element); - case SyntaxKind.CaseSwitchClause: - return isCaseSwitchClauseTypeScriptSpecific(element); - case SyntaxKind.DefaultSwitchClause: - return isDefaultSwitchClauseTypeScriptSpecific(element); - case SyntaxKind.ElseClause: - return isElseClauseTypeScriptSpecific(element); - case SyntaxKind.CatchClause: - return isCatchClauseTypeScriptSpecific(element); - case SyntaxKind.FinallyClause: - return isFinallyClauseTypeScriptSpecific(element); - case SyntaxKind.SimplePropertyAssignment: - return isSimplePropertyAssignmentTypeScriptSpecific(element); - case SyntaxKind.FunctionPropertyAssignment: - return isFunctionPropertyAssignmentTypeScriptSpecific(element); - case SyntaxKind.Parameter: - return isParameterTypeScriptSpecific(element); - case SyntaxKind.EnumElement: - return isEnumElementTypeScriptSpecific(element); - } - } - - function isSourceUnitTypeScriptSpecific(node: SourceUnitSyntax): boolean { - return isTypeScriptSpecific(node.moduleElements); - } - - function isFunctionDeclarationTypeScriptSpecific(node: FunctionDeclarationSyntax): boolean { - return node.modifiers.length > 0 || - isTypeScriptSpecific(node.callSignature) || - isTypeScriptSpecific(node.block); - } - - function isGetAccessorTypeScriptSpecific(node: GetAccessorSyntax): boolean { - return node.modifiers.length > 0 || - isTypeScriptSpecific(node.callSignature) || - isTypeScriptSpecific(node.block); - } - - function isCallSignatureTypeScriptSpecific(node: CallSignatureSyntax): boolean { - return node.typeParameterList !== null || - isTypeScriptSpecific(node.parameterList) || - node.typeAnnotation !== null; - } - - function isMethodSignatureTypeScriptSpecific(node: MethodSignatureSyntax): boolean { - return isTypeScriptSpecific(node.callSignature); - } - - function isBlockTypeScriptSpecific(node: BlockSyntax): boolean { - return isTypeScriptSpecific(node.statements); - } - - function isIfStatementTypeScriptSpecific(node: IfStatementSyntax): boolean { - return isTypeScriptSpecific(node.condition) || - isTypeScriptSpecific(node.statement) || - isTypeScriptSpecific(node.elseClause); - } - - function isVariableStatementTypeScriptSpecific(node: VariableStatementSyntax): boolean { - return node.modifiers.length > 0 || - isTypeScriptSpecific(node.variableDeclaration); - } - - function isExpressionStatementTypeScriptSpecific(node: ExpressionStatementSyntax): boolean { - return isTypeScriptSpecific(node.expression); - } - - function isReturnStatementTypeScriptSpecific(node: ReturnStatementSyntax): boolean { - return isTypeScriptSpecific(node.expression); - } - - function isSwitchStatementTypeScriptSpecific(node: SwitchStatementSyntax): boolean { - return isTypeScriptSpecific(node.expression) || - isTypeScriptSpecific(node.switchClauses); - } - - function isForStatementTypeScriptSpecific(node: ForStatementSyntax): boolean { - return isTypeScriptSpecific(node.variableDeclaration) || - isTypeScriptSpecific(node.initializer) || - isTypeScriptSpecific(node.condition) || - isTypeScriptSpecific(node.incrementor) || - isTypeScriptSpecific(node.statement); - } - - function isForInStatementTypeScriptSpecific(node: ForInStatementSyntax): boolean { - return isTypeScriptSpecific(node.variableDeclaration) || - isTypeScriptSpecific(node.left) || - isTypeScriptSpecific(node.expression) || - isTypeScriptSpecific(node.statement); - } - - function isThrowStatementTypeScriptSpecific(node: ThrowStatementSyntax): boolean { - return isTypeScriptSpecific(node.expression); - } - - function isWhileStatementTypeScriptSpecific(node: WhileStatementSyntax): boolean { - return isTypeScriptSpecific(node.condition) || - isTypeScriptSpecific(node.statement); - } - - function isTryStatementTypeScriptSpecific(node: TryStatementSyntax): boolean { - return isTypeScriptSpecific(node.block) || - isTypeScriptSpecific(node.catchClause) || - isTypeScriptSpecific(node.finallyClause); - } - - function isLabeledStatementTypeScriptSpecific(node: LabeledStatementSyntax): boolean { - return isTypeScriptSpecific(node.statement); - } - - function isDoStatementTypeScriptSpecific(node: DoStatementSyntax): boolean { - return isTypeScriptSpecific(node.statement) || - isTypeScriptSpecific(node.condition); - } - - function isWithStatementTypeScriptSpecific(node: WithStatementSyntax): boolean { - return isTypeScriptSpecific(node.condition) || - isTypeScriptSpecific(node.statement); - } - - function isPrefixUnaryExpressionTypeScriptSpecific(node: PrefixUnaryExpressionSyntax): boolean { - return isTypeScriptSpecific(node.operand); - } - - function isDeleteExpressionTypeScriptSpecific(node: DeleteExpressionSyntax): boolean { - return isTypeScriptSpecific(node.expression); - } - - function isTypeOfExpressionTypeScriptSpecific(node: TypeOfExpressionSyntax): boolean { - return isTypeScriptSpecific(node.expression); - } - - function isVoidExpressionTypeScriptSpecific(node: VoidExpressionSyntax): boolean { - return isTypeScriptSpecific(node.expression); - } - - function isConditionalExpressionTypeScriptSpecific(node: ConditionalExpressionSyntax): boolean { - return isTypeScriptSpecific(node.condition) || - isTypeScriptSpecific(node.whenTrue) || - isTypeScriptSpecific(node.whenFalse); - } - - function isBinaryExpressionTypeScriptSpecific(node: BinaryExpressionSyntax): boolean { - return isTypeScriptSpecific(node.left) || - isTypeScriptSpecific(node.right); - } - - function isPostfixUnaryExpressionTypeScriptSpecific(node: PostfixUnaryExpressionSyntax): boolean { - return isTypeScriptSpecific(node.operand); - } - - function isMemberAccessExpressionTypeScriptSpecific(node: MemberAccessExpressionSyntax): boolean { - return isTypeScriptSpecific(node.expression); - } - - function isInvocationExpressionTypeScriptSpecific(node: InvocationExpressionSyntax): boolean { - return isTypeScriptSpecific(node.expression) || - isTypeScriptSpecific(node.argumentList); - } - - function isArrayLiteralExpressionTypeScriptSpecific(node: ArrayLiteralExpressionSyntax): boolean { - return isTypeScriptSpecific(node.expressions); - } - - function isObjectLiteralExpressionTypeScriptSpecific(node: ObjectLiteralExpressionSyntax): boolean { - return isTypeScriptSpecific(node.propertyAssignments); - } - - function isObjectCreationExpressionTypeScriptSpecific(node: ObjectCreationExpressionSyntax): boolean { - return isTypeScriptSpecific(node.expression) || - isTypeScriptSpecific(node.argumentList); - } - - function isParenthesizedExpressionTypeScriptSpecific(node: ParenthesizedExpressionSyntax): boolean { - return isTypeScriptSpecific(node.expression); - } - - function isElementAccessExpressionTypeScriptSpecific(node: ElementAccessExpressionSyntax): boolean { - return isTypeScriptSpecific(node.expression) || - isTypeScriptSpecific(node.argumentExpression); - } - - function isFunctionExpressionTypeScriptSpecific(node: FunctionExpressionSyntax): boolean { - return isTypeScriptSpecific(node.callSignature) || - isTypeScriptSpecific(node.block); - } - - function isVariableDeclarationTypeScriptSpecific(node: VariableDeclarationSyntax): boolean { - return isTypeScriptSpecific(node.variableDeclarators); - } - - function isVariableDeclaratorTypeScriptSpecific(node: VariableDeclaratorSyntax): boolean { - return node.typeAnnotation !== null || - isTypeScriptSpecific(node.equalsValueClause); - } - - function isArgumentListTypeScriptSpecific(node: ArgumentListSyntax): boolean { - return isTypeScriptSpecific(node.typeArgumentList) || - isTypeScriptSpecific(node.arguments); - } - - function isParameterListTypeScriptSpecific(node: ParameterListSyntax): boolean { - return isTypeScriptSpecific(node.parameters); - } - - function isEqualsValueClauseTypeScriptSpecific(node: EqualsValueClauseSyntax): boolean { - return isTypeScriptSpecific(node.value); - } - - function isCaseSwitchClauseTypeScriptSpecific(node: CaseSwitchClauseSyntax): boolean { - return isTypeScriptSpecific(node.expression) || - isTypeScriptSpecific(node.statements); - } - - function isDefaultSwitchClauseTypeScriptSpecific(node: DefaultSwitchClauseSyntax): boolean { - return isTypeScriptSpecific(node.statements); - } - - function isElseClauseTypeScriptSpecific(node: ElseClauseSyntax): boolean { - return isTypeScriptSpecific(node.statement); - } - - function isCatchClauseTypeScriptSpecific(node: CatchClauseSyntax): boolean { - return isTypeScriptSpecific(node.typeAnnotation) || - isTypeScriptSpecific(node.block); - } - - function isFinallyClauseTypeScriptSpecific(node: FinallyClauseSyntax): boolean { - return isTypeScriptSpecific(node.block); - } - - function isSimplePropertyAssignmentTypeScriptSpecific(node: SimplePropertyAssignmentSyntax): boolean { - return isTypeScriptSpecific(node.expression); - } - - function isFunctionPropertyAssignmentTypeScriptSpecific(node: FunctionPropertyAssignmentSyntax): boolean { - return isTypeScriptSpecific(node.callSignature) || - isTypeScriptSpecific(node.block); - } - - function isParameterTypeScriptSpecific(node: ParameterSyntax): boolean { - return isTypeScriptSpecific(node.modifiers) || - node.typeAnnotation !== null || - node.equalsValueClause !== null; - } - - function isEnumElementTypeScriptSpecific(node: EnumElementSyntax): boolean { - return isTypeScriptSpecific(node.equalsValueClause); - } -} \ No newline at end of file From b4d5b984edb24216bfdc58f812602f209800a490 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 24 Jul 2014 10:57:20 -0700 Subject: [PATCH 17/59] Remove unused type --- src/services/pullLanguageService.ts | 34 +---------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/src/services/pullLanguageService.ts b/src/services/pullLanguageService.ts index c8926cd4a5f..97ea7cacd1d 100644 --- a/src/services/pullLanguageService.ts +++ b/src/services/pullLanguageService.ts @@ -113,7 +113,7 @@ module TypeScript.Services { } } - export class SyntaxTreeCache { + class SyntaxTreeCache { private _hostCache: HostCache; // For our syntactic only features, we also keep a cache of the syntax tree for the @@ -288,38 +288,6 @@ module TypeScript.Services { releaseDocument(filename: string, compilationSettings: ts.CompilerOptions): void } - export class NonCachingDocumentRegistry implements IDocumentRegistry { - - public static Instance: IDocumentRegistry = new NonCachingDocumentRegistry(); - - public acquireDocument( - filename: string, - compilationSettings: ts.CompilerOptions, - scriptSnapshot: IScriptSnapshot, - byteOrderMark: ByteOrderMark, - version: number, - isOpen: boolean, - referencedFiles: string[]= []): TypeScript.Document { - return Document.create(compilationSettings, filename, scriptSnapshot, byteOrderMark, version, isOpen, referencedFiles); - } - - public updateDocument( - document: Document, - filename: string, - compilationSettings: ts.CompilerOptions, - scriptSnapshot: IScriptSnapshot, - version: number, - isOpen: boolean, - textChangeRange: TextChangeRange - ): TypeScript.Document { - return document.update(scriptSnapshot, version, isOpen, textChangeRange); - } - - public releaseDocument(filename: string, compilationSettings: ts.CompilerOptions): void { - // no op since this class doesn't cache anything - } - } - export class DocumentRegistry implements IDocumentRegistry { private buckets: ts.Map> = {}; From 52688af1486136db57bad45f87cb9ef156119411 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 24 Jul 2014 11:24:09 -0700 Subject: [PATCH 18/59] Switch LanguageService from a class to a function --- src/services/pullLanguageService.ts | 440 ++++++++++++++-------------- src/services/typescriptServices.ts | 2 +- 2 files changed, 228 insertions(+), 214 deletions(-) diff --git a/src/services/pullLanguageService.ts b/src/services/pullLanguageService.ts index 97ea7cacd1d..dd4243a4ea1 100644 --- a/src/services/pullLanguageService.ts +++ b/src/services/pullLanguageService.ts @@ -381,46 +381,37 @@ module TypeScript.Services { } } - export class LanguageService implements ILanguageService { - private logger: TypeScript.ILogger; - private _syntaxTreeCache: SyntaxTreeCache; - private formattingRulesProvider: Formatting.RulesProvider; + export function createLanguageService(host: ILanguageServiceHost, documentRegistry: IDocumentRegistry) :ILanguageService{ + var logger: TypeScript.ILogger = host; + var _syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host); + var formattingRulesProvider: Formatting.RulesProvider; + var hostCache: HostCache; // A cache of all the information about the files on the host side. + var program: ts.Program; + var typeChecker: ts.TypeChecker; + var useCaseSensitivefilenames = false; + var documentsByName: ts.Map = {}; + var documentRegistry = documentRegistry; + var cancellationToken = new CancellationToken(host.getCancellationToken()); + var activeCompletionSession: CompletionSession; - // A cache of all the information about the files on the host side. - private hostCache: HostCache = null; - private program: ts.Program; - private typeChecker: ts.TypeChecker; - private useCaseSensitivefilenames = false; - private documentsByName: ts.Map = {}; - private documentRegistry: IDocumentRegistry - private cancellationToken: CancellationToken; - private activeCompletionSession: CompletionSession; - - constructor(public host: ILanguageServiceHost, documentRegistry: IDocumentRegistry) { - this.logger = this.host; - this.cancellationToken = new CancellationToken(this.host.getCancellationToken()); - this.documentRegistry = documentRegistry; - this._syntaxTreeCache = new SyntaxTreeCache(this.host); - - // Check if the localized messages json is set, otherwise query the host for it - if (!TypeScript.LocalizedDiagnosticMessages) { - TypeScript.LocalizedDiagnosticMessages = this.host.getLocalizedDiagnosticMessages(); - } + // Check if the localized messages json is set, otherwise query the host for it + if (!TypeScript.LocalizedDiagnosticMessages) { + TypeScript.LocalizedDiagnosticMessages = host.getLocalizedDiagnosticMessages(); } - private createCompilerHost(): ts.CompilerHost { + function createCompilerHost(): ts.CompilerHost { return { getSourceFile: (filename, languageVersion) => { - var document = this.documentsByName[filename]; + var document = documentsByName[filename]; Debug.assert(!!document, "document can not be undefined"); return document.sourceFile(); }, - getCancellationToken: () => this.cancellationToken, - getCanonicalFileName: (filename) => this.useCaseSensitivefilenames ? filename : filename.toLowerCase(), - useCaseSensitiveFileNames: () => this.useCaseSensitivefilenames, - getNewLine: ()=> "\n", + getCancellationToken: () => cancellationToken, + getCanonicalFileName: (filename) => useCaseSensitivefilenames ? filename : filename.toLowerCase(), + useCaseSensitiveFileNames: () => useCaseSensitivefilenames, + getNewLine: () => "\n", // Need something that doesn't depend on sys.ts here getDefaultLibFilename: (): string => { throw Error("TOD:: getDefaultLibfilename"); @@ -434,20 +425,20 @@ module TypeScript.Services { }; } - private synchronizeHostData(): void { + function synchronizeHostData(): void { // Reset the cache at start of every refresh - this.hostCache = new HostCache(this.host); + hostCache = new HostCache(host); - var compilationSettings = this.hostCache.compilationSettings(); + var compilationSettings = hostCache.compilationSettings(); // TODO: check if we need to create a new compiler to start with // 1. files are identical // 2. compilation settings are identical // Now, remove any files from the compiler that are no longer in the host. - var oldProgram = this.program; + var oldProgram = program; if (oldProgram) { - var oldSettings = this.program.getCompilerOptions(); + var oldSettings = program.getCompilerOptions(); // If the language version changed, then that affects what types of things we parse. So // we have to dump all syntax trees. @@ -456,14 +447,14 @@ module TypeScript.Services { var changesInCompilationSettingsAffectSyntax = oldSettings && compilationSettings && !compareDataObjects(oldSettings, compilationSettings) && settingsChangeAffectsSyntax; - var oldSourceFiles = this.program.getSourceFiles(); + var oldSourceFiles = program.getSourceFiles(); for (var i = 0, n = oldSourceFiles.length; i < n; i++) { - this.cancellationToken.throwIfCancellationRequested(); + cancellationToken.throwIfCancellationRequested(); var filename = oldSourceFiles[i].filename; - if (!this.hostCache.contains(filename) || changesInCompilationSettingsAffectSyntax) { - this.documentRegistry.releaseDocument(filename, oldSettings); - delete this.documentsByName[filename]; + if (!hostCache.contains(filename) || changesInCompilationSettingsAffectSyntax) { + documentRegistry.releaseDocument(filename, oldSettings); + delete documentsByName[filename]; } } } @@ -471,16 +462,16 @@ module TypeScript.Services { // Now, for every file the host knows about, either add the file (if the compiler // doesn't know about it.). Or notify the compiler about any changes (if it does // know about it.) - var hostfilenames = this.hostCache.getfilenames(); + var hostfilenames = hostCache.getfilenames(); for (var i = 0, n = hostfilenames.length; i < n; i++) { var filename = hostfilenames[i]; - var version = this.hostCache.getVersion(filename); - var isOpen = this.hostCache.isOpen(filename); - var scriptSnapshot = this.hostCache.getScriptSnapshot(filename); + var version = hostCache.getVersion(filename); + var isOpen = hostCache.isOpen(filename); + var scriptSnapshot = hostCache.getScriptSnapshot(filename); - var document: Document = this.documentsByName[filename]; + var document: Document = documentsByName[filename]; if (document) { // // If the document is the same, assume no update @@ -497,64 +488,53 @@ module TypeScript.Services { // new text buffer). var textChangeRange: TextChangeRange = null; if (document.isOpen && isOpen) { - textChangeRange = this.hostCache.getScriptTextChangeRangeSinceVersion(filename, document.version); + textChangeRange = hostCache.getScriptTextChangeRangeSinceVersion(filename, document.version); } - document = this.documentRegistry.updateDocument(document, filename, compilationSettings, scriptSnapshot, version, isOpen, textChangeRange); + document = documentRegistry.updateDocument(document, filename, compilationSettings, scriptSnapshot, version, isOpen, textChangeRange); } else { - document = this.documentRegistry.acquireDocument(filename, compilationSettings, scriptSnapshot, this.hostCache.getByteOrderMark(filename), version, isOpen, []); + document = documentRegistry.acquireDocument(filename, compilationSettings, scriptSnapshot, hostCache.getByteOrderMark(filename), version, isOpen, []); } // Remeber the new document - this.documentsByName[filename] = document; + documentsByName[filename] = document; } // Now create a new compiler - this.program = ts.createProgram(hostfilenames, compilationSettings, this.createCompilerHost()); - this.typeChecker = this.program.getTypeChecker(); + program = ts.createProgram(hostfilenames, compilationSettings, createCompilerHost()); + typeChecker = program.getTypeChecker(); } - dispose(): void { - if (this.program) { - ts.forEach(this.program.getSourceFiles(), - (f) => this.documentRegistry.releaseDocument(f.filename, this.program.getCompilerOptions())); + function dispose(): void { + if (program) { + ts.forEach(program.getSourceFiles(), + (f) => documentRegistry.releaseDocument(f.filename, program.getCompilerOptions())); } } - refresh() { - // No-op. Only kept around for compatability with the interface we shipped. - } - cleanupSemanticCache() { } - - getSyntacticDiagnostics(filename: string) { - this.synchronizeHostData(); - return this.program.getDiagnostics(this.program.getSourceFile(filename)); - } - getSemanticDiagnostics(filename: string) { - this.synchronizeHostData(); - return this.typeChecker.getDiagnostics(this.program.getSourceFile(filename)); - } - getCompilerOptionsDiagnostics() { - this.synchronizeHostData(); - return this.program.getGlobalDiagnostics(); + /// Diagnostics + function getSyntacticDiagnostics(filename: string) { + synchronizeHostData(); + return program.getDiagnostics(program.getSourceFile(filename)); } - private getCompletionEntriesFromSymbols(symbols: ts.Symbol[], session:CompletionSession): void { - ts.forEach(symbols, (symbol) => { - var entry = this.createCompletionEntry(symbol); - if (entry) { - session.entries.push(entry); - session.symbols[entry.name] = symbol; - } - }); + function getSemanticDiagnostics(filename: string) { + synchronizeHostData(); + return typeChecker.getDiagnostics(program.getSourceFile(filename)); } - private createCompletionEntry(symbol: ts.Symbol): CompletionEntry { + function getCompilerOptionsDiagnostics() { + synchronizeHostData(); + return program.getGlobalDiagnostics(); + } + + /// Completion + function createCompletionEntry(symbol: ts.Symbol): CompletionEntry { // Try to get a valid display name for this symbol, if we could not find one, then ignore it. // We would like to only show things that can be added after a dot, so for instance numeric properties can // not be accessed with a dot (a.1 <- invalid) - var displayName = CompletionHelpers.getValidCompletionEntryDisplayName(symbol.getName(), this.program.getCompilerOptions().target); + var displayName = CompletionHelpers.getValidCompletionEntryDisplayName(symbol.getName(), program.getCompilerOptions().target); if (!displayName) { return undefined; } @@ -563,21 +543,31 @@ module TypeScript.Services { var firstDeclaration = [0]; return { name: displayName, - kind: this.getSymbolKind(symbol), - kindModifiers: declarations ? this.getNodeModifiers(declarations[0]) : ScriptElementKindModifier.none + kind: getSymbolKind(symbol), + kindModifiers: declarations ? getNodeModifiers(declarations[0]) : ScriptElementKindModifier.none }; } - getCompletionsAtPosition(filename: string, position: number, isMemberCompletion: boolean) { - this.synchronizeHostData(); + function getCompletionsAtPosition(filename: string, position: number, isMemberCompletion: boolean) { + function getCompletionEntriesFromSymbols(symbols: ts.Symbol[], session: CompletionSession): void { + ts.forEach(symbols, (symbol) => { + var entry = createCompletionEntry(symbol); + if (entry) { + session.entries.push(entry); + session.symbols[entry.name] = symbol; + } + }); + } + + synchronizeHostData(); filename = TypeScript.switchToForwardSlashes(filename); - var document = this.documentsByName[filename]; + var document = documentsByName[filename]; var sourceUnit = document.sourceUnit(); if (CompletionHelpers.isCompletionListBlocker(document.syntaxTree().sourceUnit(), position)) { - this.logger.log("Returning an empty list because completion was blocked."); + logger.log("Returning an empty list because completion was blocked."); return null; } @@ -622,30 +612,30 @@ module TypeScript.Services { } // TODO: this is a hack for now, we need a proper walking mechanism to verify that we have the correct node - var mappedNode = this.getNodeAtPosition(document.sourceFile(), end(node) - 1); + var mappedNode = getNodeAtPosition(document.sourceFile(), end(node) - 1); Debug.assert(mappedNode, "Could not map a Fidelity node to an AST node"); // Get the completions - this.activeCompletionSession = { + activeCompletionSession = { filename: filename, position: position, entries: [], symbols: {}, location: mappedNode, - typeChecker: this.typeChecker + typeChecker: typeChecker }; // Right of dot member completion list if (isRightOfDot) { - var type: ts.Type = this.typeChecker.getTypeOfExpression(mappedNode); + var type: ts.Type = typeChecker.getTypeOfExpression(mappedNode); if (!type) { return undefined; } var symbols = type.getApparentProperties(); isMemberCompletion = true; - this.getCompletionEntriesFromSymbols(symbols, this.activeCompletionSession); + getCompletionEntriesFromSymbols(symbols, activeCompletionSession); } else { var containingObjectLiteral = CompletionHelpers.getContainingObjectLiteralApplicableForCompletion(document.syntaxTree().sourceUnit(), position); @@ -669,13 +659,13 @@ module TypeScript.Services { isMemberCompletion = true; //// Try to get the object members form contextual typing - //var contextualMembers = this.compiler.getContextualMembersFromAST(node, document); + //var contextualMembers = compiler.getContextualMembersFromAST(node, document); //if (contextualMembers && contextualMembers.symbols && contextualMembers.symbols.length > 0) { // // get existing members - // var existingMembers = this.compiler.getVisibleMemberSymbolsFromAST(node, document); + // var existingMembers = compiler.getVisibleMemberSymbolsFromAST(node, document); // // Add filtterd items to the completion list - // this.getCompletionEntriesFromSymbols({ + // getCompletionEntriesFromSymbols({ // symbols: CompletionHelpers.filterContextualMembersList(contextualMembers.symbols, existingMembers, filename, position), // enclosingScopeSymbol: contextualMembers.enclosingScopeSymbol // }, entries); @@ -686,45 +676,46 @@ module TypeScript.Services { isMemberCompletion = false; /// TODO filter meaning based on the current context var symbolMeanings = ts.SymbolFlags.Type | ts.SymbolFlags.Value | ts.SymbolFlags.Namespace; - var symbols = this.typeChecker.getSymbolsInScope(mappedNode, symbolMeanings); + var symbols = typeChecker.getSymbolsInScope(mappedNode, symbolMeanings); - this.getCompletionEntriesFromSymbols(symbols, this.activeCompletionSession); + getCompletionEntriesFromSymbols(symbols, activeCompletionSession); } } // Add keywords if this is not a member completion list if (!isMemberCompletion) { - Array.prototype.push.apply(this.activeCompletionSession.entries, KeywordCompletions.getKeywordCompltions()); + Array.prototype.push.apply(activeCompletionSession.entries, KeywordCompletions.getKeywordCompltions()); } return { isMemberCompletion: isMemberCompletion, - entries: this.activeCompletionSession.entries + entries: activeCompletionSession.entries }; } - getCompletionEntryDetails(filename: string, position: number, entryName: string) { + + function getCompletionEntryDetails(filename: string, position: number, entryName: string) { // Note: No need to call synchronizeHostData, as we have captured all the data we need // in the getCompletionsAtPosition erlier filename = TypeScript.switchToForwardSlashes(filename); - var session = this.activeCompletionSession; + var session = activeCompletionSession; // Ensure that the current active completion session is still valid for this request if (!session || session.filename !== filename || session.position !== position) { return undefined; } - var symbol = this.activeCompletionSession.symbols[entryName]; + var symbol = activeCompletionSession.symbols[entryName]; if (symbol) { var type = session.typeChecker.getTypeOfSymbol(symbol); Debug.assert(type, "Could not find type for symbol"); - var completionEntry = this.createCompletionEntry(symbol); + var completionEntry = createCompletionEntry(symbol); return { name: entryName, kind: completionEntry.kind, kindModifiers: completionEntry.kindModifiers, type: session.typeChecker.typeToString(type, session.location), - fullSymbolName: this.typeChecker.symbolToString(symbol, session.location), + fullSymbolName: typeChecker.symbolToString(symbol, session.location), docComment: "" }; } @@ -741,7 +732,7 @@ module TypeScript.Services { } } - private getNodeAtPosition(sourceFile: ts.SourceFile, position: number) { + function getNodeAtPosition(sourceFile: ts.SourceFile, position: number) { var current: ts.Node = sourceFile; outer: while (true) { // find the child that has this @@ -757,7 +748,7 @@ module TypeScript.Services { } } - private getEnclosingDeclaration(node: ts.Node): ts.Node { + function getEnclosingDeclaration(node: ts.Node): ts.Node { while (true) { node = node.parent; if (!node) { @@ -778,7 +769,7 @@ module TypeScript.Services { } } - getSymbolKind(symbol: ts.Symbol): string { + function getSymbolKind(symbol: ts.Symbol): string { var flags = symbol.getFlags(); if (flags & ts.SymbolFlags.Module) return ScriptElementKind.moduleElement; @@ -801,7 +792,7 @@ module TypeScript.Services { return ScriptElementKind.unknown; } - getTypeKind(type: ts.Type): string { + function getTypeKind(type: ts.Type): string { var flags = type.getFlags(); if (flags & ts.TypeFlags.Enum) return ScriptElementKind.enumElement; @@ -814,7 +805,7 @@ module TypeScript.Services { return ScriptElementKind.unknown; } - getNodeModifiers(node: ts.Node): string { + function getNodeModifiers(node: ts.Node): string { var flags = node.flags; var result: string[] = []; @@ -827,12 +818,13 @@ module TypeScript.Services { return result.length > 0 ? result.join(',') : ScriptElementKindModifier.none; } - getTypeAtPosition(filename: string, position: number): TypeInfo { - this.synchronizeHostData(); + /// QuickInfo + function getTypeAtPosition(filename: string, position: number): TypeInfo { + synchronizeHostData(); filename = TypeScript.switchToForwardSlashes(filename); - var document = this.documentsByName[filename]; - var node = this.getNodeAtPosition(document.sourceFile(), position); + var document = documentsByName[filename]; + var node = getNodeAtPosition(document.sourceFile(), position); if (!node) return undefined; switch (node.kind) { @@ -842,15 +834,15 @@ module TypeScript.Services { // TODO: handle new and call expressions } - var symbol = this.typeChecker. getSymbolOfIdentifier(node); + var symbol = typeChecker. getSymbolOfIdentifier(node); Debug.assert(symbol, "getTypeAtPosition: Could not find symbol for node"); - var type = this.typeChecker.getTypeOfSymbol(symbol); + var type = typeChecker.getTypeOfSymbol(symbol); return { - memberName: new MemberNameString(this.typeChecker.typeToString(type)), + memberName: new MemberNameString(typeChecker.typeToString(type)), docComment: "", - fullSymbolName: this.typeChecker.symbolToString(symbol, this.getEnclosingDeclaration(node)), - kind: this.getSymbolKind(symbol), + fullSymbolName: typeChecker.symbolToString(symbol, getEnclosingDeclaration(node)), + kind: getSymbolKind(symbol), minChar: node.pos, limChar: node.end }; @@ -860,79 +852,65 @@ module TypeScript.Services { case ts.SyntaxKind.QualifiedName: case ts.SyntaxKind.SuperKeyword: case ts.SyntaxKind.StringLiteral: - var type = this.typeChecker.getTypeOfExpression(node); + var type = typeChecker.getTypeOfExpression(node); Debug.assert(type, "getTypeAtPosition: Could not find type for node"); return { memberName: new MemberNameString(""), docComment: "", - fullSymbolName: this.typeChecker.typeToString(type, this.getEnclosingDeclaration(node)), - kind: this.getTypeKind(type), + fullSymbolName: typeChecker.typeToString(type, getEnclosingDeclaration(node)), + kind: getTypeKind(type), minChar: node.pos, limChar: node.end }; break; } } - getSignatureAtPosition(filename: string, position: number) { - return undefined; - } - getDefinitionAtPosition(filename: string, position: number) { - return []; - } - getReferencesAtPosition(filename: string, position: number) { - return []; - } - getOccurrencesAtPosition(filename: string, position: number) { - return []; - } - getImplementorsAtPosition(filename: string, position: number) { - return []; - } - getNavigateToItems(searchValue: string) { - return []; - } - getEmitOutput(filename: string) { - return undefined; + + /// Syntactic features + function getSyntaxTree(filename: string): TypeScript.SyntaxTree { + filename = TypeScript.switchToForwardSlashes(filename); + return _syntaxTreeCache.getCurrentFileSyntaxTree(filename); } - private getTypeInfoEligiblePath(filename: string, position: number, isConstructorValidPosition: boolean) { - var sourceUnit = this._syntaxTreeCache.getCurrentFileSyntaxTree(filename).sourceUnit(); + function getNameOrDottedNameSpan(filename: string, startPos: number, endPos: number): SpanInfo { + function getTypeInfoEligiblePath(filename: string, position: number, isConstructorValidPosition: boolean) { + var sourceUnit = _syntaxTreeCache.getCurrentFileSyntaxTree(filename).sourceUnit(); - var ast = TypeScript.ASTHelpers.getAstAtPosition(sourceUnit, position, /*useTrailingTriviaAsLimChar*/ false, /*forceInclusive*/ true); - if (ast === null) { - return null; - } - - if (ast.kind() === SyntaxKind.ParameterList && ast.parent.kind() === SyntaxKind.CallSignature && ast.parent.parent.kind() === SyntaxKind.ConstructorDeclaration) { - ast = ast.parent.parent; - } - - switch (ast.kind()) { - default: + var ast = TypeScript.ASTHelpers.getAstAtPosition(sourceUnit, position, /*useTrailingTriviaAsLimChar*/ false, /*forceInclusive*/ true); + if (ast === null) { return null; - case TypeScript.SyntaxKind.ConstructorDeclaration: - var constructorAST = ast; - if (!isConstructorValidPosition || !(position >= start(constructorAST) && position <= start(constructorAST) + "constructor".length)) { + } + + if (ast.kind() === SyntaxKind.ParameterList && ast.parent.kind() === SyntaxKind.CallSignature && ast.parent.parent.kind() === SyntaxKind.ConstructorDeclaration) { + ast = ast.parent.parent; + } + + switch (ast.kind()) { + default: return null; - } - else { + case TypeScript.SyntaxKind.ConstructorDeclaration: + var constructorAST = ast; + if (!isConstructorValidPosition || !(position >= start(constructorAST) && position <= start(constructorAST) + "constructor".length)) { + return null; + } + else { + return ast; + } + case TypeScript.SyntaxKind.FunctionDeclaration: + return null; + case TypeScript.SyntaxKind.MemberAccessExpression: + case TypeScript.SyntaxKind.QualifiedName: + case TypeScript.SyntaxKind.SuperKeyword: + case TypeScript.SyntaxKind.StringLiteral: + case TypeScript.SyntaxKind.ThisKeyword: + case TypeScript.SyntaxKind.IdentifierName: return ast; - } - case TypeScript.SyntaxKind.FunctionDeclaration: - return null; - case TypeScript.SyntaxKind.MemberAccessExpression: - case TypeScript.SyntaxKind.QualifiedName: - case TypeScript.SyntaxKind.SuperKeyword: - case TypeScript.SyntaxKind.StringLiteral: - case TypeScript.SyntaxKind.ThisKeyword: - case TypeScript.SyntaxKind.IdentifierName: - return ast; + } } - } - getNameOrDottedNameSpan(filename: string, startPos: number, endPos: number): SpanInfo { + filename = TypeScript.switchToForwardSlashes(filename); - var node = this.getTypeInfoEligiblePath(filename, startPos, false); + var node = getTypeInfoEligiblePath(filename, startPos, false); if (!node) return null; while (node) { @@ -950,93 +928,129 @@ module TypeScript.Services { limChar: end(node) }; } - getBreakpointStatementAtPosition(filename: string, position: number) { + + function getBreakpointStatementAtPosition(filename: string, position: number) { // doesn't use compiler - no need to synchronize with host filename = TypeScript.switchToForwardSlashes(filename); - var syntaxtree = this.getSyntaxTree(filename); + var syntaxtree = getSyntaxTree(filename); return TypeScript.Services.Breakpoints.getBreakpointLocation(syntaxtree, position); } - getScriptLexicalStructure(filename: string) { + + function getScriptLexicalStructure(filename: string) { filename = TypeScript.switchToForwardSlashes(filename); - var syntaxTree = this.getSyntaxTree(filename); + var syntaxTree = getSyntaxTree(filename); var items: NavigateToItem[] = []; GetScriptLexicalStructureWalker.getListsOfAllScriptLexicalStructure(items, filename, syntaxTree.sourceUnit()); return items; } - getOutliningRegions(filename: string) { + + function getOutliningRegions(filename: string) { // doesn't use compiler - no need to synchronize with host filename = TypeScript.switchToForwardSlashes(filename); - var syntaxTree = this.getSyntaxTree(filename); + var syntaxTree = getSyntaxTree(filename); return OutliningElementsCollector.collectElements(syntaxTree.sourceUnit()); } - getBraceMatchingAtPosition(filename: string, position: number) { + + function getBraceMatchingAtPosition(filename: string, position: number) { filename = TypeScript.switchToForwardSlashes(filename); - var syntaxTree = this.getSyntaxTree(filename); + var syntaxTree = getSyntaxTree(filename); return BraceMatcher.getMatchSpans(syntaxTree, position); } - getIndentationAtPosition(filename: string, position: number, editorOptions: EditorOptions) { + + function getIndentationAtPosition(filename: string, position: number, editorOptions: EditorOptions) { filename = TypeScript.switchToForwardSlashes(filename); - var syntaxTree = this.getSyntaxTree(filename); + var syntaxTree = getSyntaxTree(filename); - var scriptSnapshot = this._syntaxTreeCache.getCurrentScriptSnapshot(filename); + var scriptSnapshot = _syntaxTreeCache.getCurrentScriptSnapshot(filename); var scriptText = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot); var textSnapshot = new TypeScript.Services.Formatting.TextSnapshot(scriptText); var options = new FormattingOptions(!editorOptions.ConvertTabsToSpaces, editorOptions.TabSize, editorOptions.IndentSize, editorOptions.NewLineCharacter) return TypeScript.Services.Formatting.SingleTokenIndenter.getIndentationAmount(position, syntaxTree.sourceUnit(), textSnapshot, options); } - getFormattingEditsForRange(filename: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[] { + + function getFormattingManager(filename: string, options: FormatCodeOptions) { + // Ensure rules are initialized and up to date wrt to formatting options + if (formattingRulesProvider == null) { + formattingRulesProvider = new TypeScript.Services.Formatting.RulesProvider(logger); + } + + formattingRulesProvider.ensureUpToDate(options); + + // Get the Syntax Tree + var syntaxTree = getSyntaxTree(filename); + + // Convert IScriptSnapshot to ITextSnapshot + var scriptSnapshot = _syntaxTreeCache.getCurrentScriptSnapshot(filename); + var scriptText = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot); + var textSnapshot = new TypeScript.Services.Formatting.TextSnapshot(scriptText); + + var manager = new TypeScript.Services.Formatting.FormattingManager(syntaxTree, textSnapshot, formattingRulesProvider, options); + + return manager; + } + + function getFormattingEditsForRange(filename: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[] { filename = TypeScript.switchToForwardSlashes(filename); - var manager = this.getFormattingManager(filename, options); + var manager = getFormattingManager(filename, options); return manager.formatSelection(minChar, limChar); } - getFormattingEditsForDocument(filename: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[] { + + function getFormattingEditsForDocument(filename: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[] { filename = TypeScript.switchToForwardSlashes(filename); - var manager = this.getFormattingManager(filename, options); + var manager = getFormattingManager(filename, options); return manager.formatDocument(minChar, limChar); } - getFormattingEditsOnPaste(filename: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[] { + + function getFormattingEditsOnPaste(filename: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[] { filename = TypeScript.switchToForwardSlashes(filename); - var manager = this.getFormattingManager(filename, options); + var manager = getFormattingManager(filename, options); return manager.formatOnPaste(minChar, limChar); } - getFormattingEditsAfterKeystroke(filename: string, position: number, key: string, options: FormatCodeOptions): TextEdit[] { + + function getFormattingEditsAfterKeystroke(filename: string, position: number, key: string, options: FormatCodeOptions): TextEdit[] { filename = TypeScript.switchToForwardSlashes(filename); - var manager = this.getFormattingManager(filename, options); + var manager = getFormattingManager(filename, options); if (key === "}") return manager.formatOnClosingCurlyBrace(position); else if (key === ";") return manager.formatOnSemicolon(position); else if (key === "\n") return manager.formatOnEnter(position); else return []; } - private getFormattingManager(filename: string, options: FormatCodeOptions) { - // Ensure rules are initialized and up to date wrt to formatting options - if (this.formattingRulesProvider == null) { - this.formattingRulesProvider = new TypeScript.Services.Formatting.RulesProvider(this.logger); - } - this.formattingRulesProvider.ensureUpToDate(options); - // Get the Syntax Tree - var syntaxTree = this.getSyntaxTree(filename); - - // Convert IScriptSnapshot to ITextSnapshot - var scriptSnapshot = this._syntaxTreeCache.getCurrentScriptSnapshot(filename); - var scriptText = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot); - var textSnapshot = new TypeScript.Services.Formatting.TextSnapshot(scriptText); - - var manager = new TypeScript.Services.Formatting.FormattingManager(syntaxTree, textSnapshot, this.formattingRulesProvider, options); - - return manager; - } - getSyntaxTree(filename: string): TypeScript.SyntaxTree { - filename = TypeScript.switchToForwardSlashes(filename); - return this._syntaxTreeCache.getCurrentFileSyntaxTree(filename); - } + return { + dispose: dispose, + refresh: () => { }, + cleanupSemanticCache: () => { }, + getSyntacticDiagnostics: getSyntacticDiagnostics, + getSemanticDiagnostics: getSemanticDiagnostics, + getCompilerOptionsDiagnostics: getCompilerOptionsDiagnostics, + getCompletionsAtPosition: getCompletionsAtPosition, + getCompletionEntryDetails: getCompletionEntryDetails, + getTypeAtPosition: getTypeAtPosition, + getSignatureAtPosition: (filename, position) => undefined, + getDefinitionAtPosition: (filename, position) => [], + getReferencesAtPosition: (filename, position) => [], + getOccurrencesAtPosition: (filename, position) => [], + getImplementorsAtPosition: (filename, position) => [], + getNameOrDottedNameSpan: getNameOrDottedNameSpan, + getBreakpointStatementAtPosition: getBreakpointStatementAtPosition, + getNavigateToItems: (searchValue) => [], + getScriptLexicalStructure: getScriptLexicalStructure, + getOutliningRegions: getOutliningRegions, + getBraceMatchingAtPosition: getBraceMatchingAtPosition, + getIndentationAtPosition: getIndentationAtPosition, + getFormattingEditsForRange: getFormattingEditsForRange, + getFormattingEditsForDocument: getFormattingEditsForDocument, + getFormattingEditsOnPaste: getFormattingEditsOnPaste, + getFormattingEditsAfterKeystroke: getFormattingEditsAfterKeystroke, + getEmitOutput: (filename) => undefined, + }; } } \ No newline at end of file diff --git a/src/services/typescriptServices.ts b/src/services/typescriptServices.ts index 2dcd1e75678..505fd9b6ac5 100644 --- a/src/services/typescriptServices.ts +++ b/src/services/typescriptServices.ts @@ -162,7 +162,7 @@ module TypeScript.Services { public createPullLanguageService(host: TypeScript.Services.ILanguageServiceHost): TypeScript.Services.ILanguageService { try { - return new TypeScript.Services.LanguageService(host, this.documentRegistry); + return TypeScript.Services.createLanguageService(host, this.documentRegistry); } catch (err) { TypeScript.Services.logInternalError(host, err); From 410a657b1c10b6e7121aa64e2260a7dffa0d47bf Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 24 Jul 2014 11:26:43 -0700 Subject: [PATCH 19/59] Remove the "I" prefix from interface names --- src/services/classifier.ts | 2 +- src/services/compiler/diagnostics.ts | 6 +++--- src/services/coreServices.ts | 2 +- src/services/formatting/rulesProvider.ts | 2 +- src/services/languageService.ts | 6 +++--- src/services/pullLanguageService.ts | 8 ++++---- src/services/shims.ts | 16 ++++++++-------- src/services/typescriptServices.ts | 2 +- 8 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/services/classifier.ts b/src/services/classifier.ts index e5e68f06296..7e69e55c317 100644 --- a/src/services/classifier.ts +++ b/src/services/classifier.ts @@ -176,7 +176,7 @@ module TypeScript.Services { } } - export interface IClassifierHost extends TypeScript.ILogger { + export interface IClassifierHost extends TypeScript.Logger { } export class ClassificationResult { diff --git a/src/services/compiler/diagnostics.ts b/src/services/compiler/diagnostics.ts index 75d7bfd5a78..d759c8bf014 100644 --- a/src/services/compiler/diagnostics.ts +++ b/src/services/compiler/diagnostics.ts @@ -16,7 +16,7 @@ /// module TypeScript { - export interface ILogger { + export interface Logger { information(): boolean; debug(): boolean; warning(): boolean; @@ -25,7 +25,7 @@ module TypeScript { log(s: string): void; } - export class NullLogger implements ILogger { + export class NullLogger implements Logger { public information(): boolean { return false; } public debug(): boolean { return false; } public warning(): boolean { return false; } @@ -35,7 +35,7 @@ module TypeScript { } } - export function timeFunction(logger: ILogger, funcDescription: string, func: () => any): any { + export function timeFunction(logger: Logger, funcDescription: string, func: () => any): any { var start = (new Date()).getTime(); var result = func(); var end = (new Date()).getTime(); diff --git a/src/services/coreServices.ts b/src/services/coreServices.ts index 2e34f646649..0f725d3d6be 100644 --- a/src/services/coreServices.ts +++ b/src/services/coreServices.ts @@ -23,7 +23,7 @@ var debugObjectHost = (this); module TypeScript.Services { export interface ICoreServicesHost { - logger: TypeScript.ILogger; + logger: TypeScript.Logger; } export class CoreServices { diff --git a/src/services/formatting/rulesProvider.ts b/src/services/formatting/rulesProvider.ts index 0b100500f2d..2ff436d123d 100644 --- a/src/services/formatting/rulesProvider.ts +++ b/src/services/formatting/rulesProvider.ts @@ -22,7 +22,7 @@ module TypeScript.Services.Formatting { private activeRules: Rule[]; private rulesMap: RulesMap; - constructor(private logger: TypeScript.ILogger) { + constructor(private logger: TypeScript.Logger) { this.globalRules = new Rules(); } diff --git a/src/services/languageService.ts b/src/services/languageService.ts index de526c9ee6b..8c656a53f84 100644 --- a/src/services/languageService.ts +++ b/src/services/languageService.ts @@ -21,7 +21,7 @@ module TypeScript.Services { // // Public interface of the host of a language service instance. // - export interface ILanguageServiceHost extends TypeScript.ILogger, TypeScript.IReferenceResolverHost { + export interface LanguageServiceHost extends TypeScript.Logger, TypeScript.IReferenceResolverHost { getCompilationSettings(): ts.CompilerOptions; getScriptFileNames(): string[]; @@ -38,7 +38,7 @@ module TypeScript.Services { // Public services of a language service instance associated // with a language service host instance // - export interface ILanguageService { + export interface LanguageService { // Note: refresh is a no-op now. It is only around for back compat purposes. refresh(): void; @@ -83,7 +83,7 @@ module TypeScript.Services { dispose(): void; } - export function logInternalError(logger: TypeScript.ILogger, err: Error) { + export function logInternalError(logger: TypeScript.Logger, err: Error) { logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message); } diff --git a/src/services/pullLanguageService.ts b/src/services/pullLanguageService.ts index dd4243a4ea1..88aeccf81d7 100644 --- a/src/services/pullLanguageService.ts +++ b/src/services/pullLanguageService.ts @@ -40,7 +40,7 @@ module TypeScript.Services { private _filenameToEntry: ts.Map; private _compilationSettings: ts.CompilerOptions; - constructor(private host: ILanguageServiceHost) { + constructor(private host: LanguageServiceHost) { // script id => script index this._filenameToEntry = {}; @@ -123,7 +123,7 @@ module TypeScript.Services { private _currentFileSyntaxTree: TypeScript.SyntaxTree = null; private _currentFileScriptSnapshot: TypeScript.IScriptSnapshot = null; - constructor(private _host: ILanguageServiceHost) { + constructor(private _host: LanguageServiceHost) { this._hostCache = new HostCache(_host); } @@ -381,8 +381,8 @@ module TypeScript.Services { } } - export function createLanguageService(host: ILanguageServiceHost, documentRegistry: IDocumentRegistry) :ILanguageService{ - var logger: TypeScript.ILogger = host; + export function createLanguageService(host: LanguageServiceHost, documentRegistry: IDocumentRegistry) :LanguageService{ + var logger: TypeScript.Logger = host; var _syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host); var formattingRulesProvider: Formatting.RulesProvider; var hostCache: HostCache; // A cache of all the information about the files on the host side. diff --git a/src/services/shims.ts b/src/services/shims.ts index 53e44b262e7..ddab3b75fe2 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -38,7 +38,7 @@ module TypeScript.Services { // // Public interface of the host of a language service shim instance. // - export interface ILanguageServiceShimHost extends TypeScript.ILogger { + export interface ILanguageServiceShimHost extends TypeScript.Logger { getCompilationSettings(): string; // Returns a JSON encoded value of the type: @@ -79,7 +79,7 @@ module TypeScript.Services { } export interface ILanguageServiceShim extends IShim { - languageService: TypeScript.Services.ILanguageService; + languageService: TypeScript.Services.LanguageService; dispose(dummy: any): void; @@ -283,7 +283,7 @@ module TypeScript.Services { } } - export class LanguageServiceShimHostAdapter implements TypeScript.Services.ILanguageServiceHost { + export class LanguageServiceShimHostAdapter implements TypeScript.Services.LanguageServiceHost { constructor(private shimHost: ILanguageServiceShimHost) { } @@ -389,7 +389,7 @@ module TypeScript.Services { } } - export function simpleForwardCall(logger: TypeScript.ILogger, actionDescription: string, action: () =>any): any { + export function simpleForwardCall(logger: TypeScript.Logger, actionDescription: string, action: () =>any): any { logger.log(actionDescription); var start = Date.now(); var result = action(); @@ -405,7 +405,7 @@ module TypeScript.Services { return result; } - export function forwardJSONCall(logger: TypeScript.ILogger, actionDescription: string, action: () =>any): string { + export function forwardJSONCall(logger: TypeScript.Logger, actionDescription: string, action: () =>any): string { try { var result = simpleForwardCall(logger, actionDescription, action); return JSON.stringify({ result: result }); @@ -421,11 +421,11 @@ module TypeScript.Services { } export class LanguageServiceShim extends ShimBase implements ILanguageServiceShim { - private logger: TypeScript.ILogger; + private logger: TypeScript.Logger; constructor(factory: IShimFactory, private host: ILanguageServiceShimHost, - public languageService: TypeScript.Services.ILanguageService) { + public languageService: TypeScript.Services.LanguageService) { super(factory); this.logger = this.host; } @@ -802,7 +802,7 @@ module TypeScript.Services { } export class CoreServicesShim extends ShimBase { - public logger: TypeScript.ILogger; + public logger: TypeScript.Logger; public services: TypeScript.Services.CoreServices; constructor(factory: IShimFactory, public host: TypeScript.Services.ICoreServicesHost) { diff --git a/src/services/typescriptServices.ts b/src/services/typescriptServices.ts index 505fd9b6ac5..04617b00725 100644 --- a/src/services/typescriptServices.ts +++ b/src/services/typescriptServices.ts @@ -160,7 +160,7 @@ module TypeScript.Services { private _shims: IShim[] = []; private documentRegistry: DocumentRegistry = new DocumentRegistry(); - public createPullLanguageService(host: TypeScript.Services.ILanguageServiceHost): TypeScript.Services.ILanguageService { + public createPullLanguageService(host: TypeScript.Services.LanguageServiceHost): TypeScript.Services.LanguageService { try { return TypeScript.Services.createLanguageService(host, this.documentRegistry); } From cb3f8c1d74ccf30bf7ffd48ff680b09c56022c60 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 24 Jul 2014 11:31:02 -0700 Subject: [PATCH 20/59] switch some more classes to interfaces --- src/services/typescriptServices.ts | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/services/typescriptServices.ts b/src/services/typescriptServices.ts index 04617b00725..00b13b1b05b 100644 --- a/src/services/typescriptServices.ts +++ b/src/services/typescriptServices.ts @@ -66,12 +66,9 @@ module TypeScript { FailedToGenerateDeclarationsBecauseOfSemanticErrors } - export class EmitOutput { - public outputFiles: OutputFile[] = []; - public emitOutputResult: EmitOutputResult; - constructor(emitOutputResult = EmitOutputResult.Succeeded) { - this.emitOutputResult = emitOutputResult; - } + export interface EmitOutput { + outputFiles: OutputFile[]; + emitOutputResult: EmitOutputResult; } export enum OutputFileType { @@ -87,13 +84,12 @@ module TypeScript { Utf16LittleEndian = 3, } - export class OutputFile { - constructor(public name: string, - public writeByteOrderMark: boolean, - public text: string, - public fileType: OutputFileType, - public sourceMapOutput: any = null) { - } + export interface OutputFile { + name: string; + writeByteOrderMark: boolean; + text: string; + fileType: OutputFileType; + sourceMapOutput: any; } export interface ICancellationToken { From 580eaebad34772bea45fc1ec269b369d3f616954 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 24 Jul 2014 11:38:46 -0700 Subject: [PATCH 21/59] some more cleanup --- src/services/compiler/precompile.ts | 2 +- src/services/compiler/referenceResolver.ts | 4 ++-- src/services/typescriptServices.ts | 19 ------------------- 3 files changed, 3 insertions(+), 22 deletions(-) diff --git a/src/services/compiler/precompile.ts b/src/services/compiler/precompile.ts index 61ba930a055..5c03b1f0a06 100644 --- a/src/services/compiler/precompile.ts +++ b/src/services/compiler/precompile.ts @@ -127,7 +127,7 @@ module TypeScript { } var totalTime = new Date().getTime() - start; - TypeScript.fileResolutionScanImportsTime += totalTime; + //TypeScript.fileResolutionScanImportsTime += totalTime; } function processTripleSlashDirectives(fileName: string, text: ISimpleText, firstToken: ISyntaxToken): ITripleSlashDirectiveProperties { diff --git a/src/services/compiler/referenceResolver.ts b/src/services/compiler/referenceResolver.ts index 7991be64a89..b67d65ead6d 100644 --- a/src/services/compiler/referenceResolver.ts +++ b/src/services/compiler/referenceResolver.ts @@ -156,7 +156,7 @@ module TypeScript { } while (parentDirectory); - TypeScript.fileResolutionImportFileSearchTime += new Date().getTime() - start; + //TypeScript.fileResolutionImportFileSearchTime += new Date().getTime() - start; if (!searchFilePath) { // Cannot find file import, do not reprot an error, the typeChecker will report it later on @@ -179,7 +179,7 @@ module TypeScript { var start = new Date().getTime(); var scriptSnapshot = this.host.getScriptSnapshot(normalizedPath); var totalTime = new Date().getTime() - start; - TypeScript.fileResolutionIOTime += totalTime; + //TypeScript.fileResolutionIOTime += totalTime; var lineMap = LineMap1.fromScriptSnapshot(scriptSnapshot); var preprocessedFileInformation = TypeScript.preProcessFile(normalizedPath, scriptSnapshot); diff --git a/src/services/typescriptServices.ts b/src/services/typescriptServices.ts index 00b13b1b05b..6df7b3bbc45 100644 --- a/src/services/typescriptServices.ts +++ b/src/services/typescriptServices.ts @@ -129,29 +129,10 @@ module TypeScript { } return true; } - - export var version = "1.0.3.0"; - export var fileResolutionTime = 0; - export var fileResolutionIOTime = 0; - export var fileResolutionScanImportsTime = 0; - export var fileResolutionImportFileSearchTime = 0; - export var fileResolutionGetDefaultLibraryTime = 0; } module TypeScript.Services { - export function copyDataObject(dst: any, src: any): any { - for (var e in dst) { - if (typeof dst[e] == "object") { - copyDataObject(dst[e], src[e]); - } - else if (typeof dst[e] != "function") { - dst[e] = src[e]; - } - } - return dst; - } - export class TypeScriptServicesFactory implements IShimFactory { private _shims: IShim[] = []; private documentRegistry: DocumentRegistry = new DocumentRegistry(); From 02fa159d7c94facfb2bc27b1cc322ee71aa79401 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 24 Jul 2014 11:42:55 -0700 Subject: [PATCH 22/59] move TypeScriptServicesFactory to shims.ts --- src/services/shims.ts | 113 ++++++++++++++++++++++++++--- src/services/typescriptServices.ts | 97 ------------------------- 2 files changed, 104 insertions(+), 106 deletions(-) diff --git a/src/services/shims.ts b/src/services/shims.ts index ddab3b75fe2..f16bf9afec6 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -263,7 +263,7 @@ module TypeScript.Services { return this.scriptSnapshotShim.getLength(); } - public getLineStartPositions(): number[]{ + public getLineStartPositions(): number[] { if (this.lineStartPositions == null) { this.lineStartPositions = JSON.parse(this.scriptSnapshotShim.getLineStartPositions()); } @@ -389,7 +389,7 @@ module TypeScript.Services { } } - export function simpleForwardCall(logger: TypeScript.Logger, actionDescription: string, action: () =>any): any { + export function simpleForwardCall(logger: TypeScript.Logger, actionDescription: string, action: () => any): any { logger.log(actionDescription); var start = Date.now(); var result = action(); @@ -405,7 +405,7 @@ module TypeScript.Services { return result; } - export function forwardJSONCall(logger: TypeScript.Logger, actionDescription: string, action: () =>any): string { + export function forwardJSONCall(logger: TypeScript.Logger, actionDescription: string, action: () => any): string { try { var result = simpleForwardCall(logger, actionDescription, action); return JSON.stringify({ result: result }); @@ -424,13 +424,13 @@ module TypeScript.Services { private logger: TypeScript.Logger; constructor(factory: IShimFactory, - private host: ILanguageServiceShimHost, - public languageService: TypeScript.Services.LanguageService) { + private host: ILanguageServiceShimHost, + public languageService: TypeScript.Services.LanguageService) { super(factory); this.logger = this.host; } - public forwardJSONCall(actionDescription: string, action: () =>any): string { + public forwardJSONCall(actionDescription: string, action: () => any): string { return TypeScript.Services.forwardJSONCall(this.logger, actionDescription, action); } @@ -487,7 +487,7 @@ module TypeScript.Services { private realizeDiagnosticWithFileName(diagnostic: ts.Diagnostic): { fileName: string; message: string; start: number; length: number; category: string; } { return { - fileName:diagnostic.file.filename, + fileName: diagnostic.file.filename, message: diagnostic.messageText, start: diagnostic.start, length: diagnostic.length, @@ -540,7 +540,7 @@ module TypeScript.Services { // in the active file. public getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): string { return this.forwardJSONCall( - "getNameOrDottedNameSpan(\"" + fileName + "\", " + startPos + ", " + endPos + ")", + "getNameOrDottedNameSpan(\"" + fileName + "\", " + startPos + ", " + endPos + ")", () => { var spanInfo = this.languageService.getNameOrDottedNameSpan(fileName, startPos, endPos); return spanInfo; @@ -811,7 +811,7 @@ module TypeScript.Services { this.services = new TypeScript.Services.CoreServices(this.host); } - private forwardJSONCall(actionDescription: string, action: () =>any): any { + private forwardJSONCall(actionDescription: string, action: () => any): any { return TypeScript.Services.forwardJSONCall(this.logger, actionDescription, action); } @@ -838,4 +838,99 @@ module TypeScript.Services { }); } } + + export class TypeScriptServicesFactory implements IShimFactory { + private _shims: IShim[] = []; + private documentRegistry: DocumentRegistry = new DocumentRegistry(); + + public createPullLanguageService(host: TypeScript.Services.LanguageServiceHost): TypeScript.Services.LanguageService { + try { + return TypeScript.Services.createLanguageService(host, this.documentRegistry); + } + catch (err) { + TypeScript.Services.logInternalError(host, err); + throw err; + } + } + + public createLanguageServiceShim(host: ILanguageServiceShimHost): ILanguageServiceShim { + try { + var hostAdapter = new LanguageServiceShimHostAdapter(host); + var pullLanguageService = this.createPullLanguageService(hostAdapter); + return new LanguageServiceShim(this, host, pullLanguageService); + } + catch (err) { + TypeScript.Services.logInternalError(host, err); + throw err; + } + } + + public createClassifier(host: TypeScript.Services.IClassifierHost): TypeScript.Services.Classifier { + try { + return new TypeScript.Services.Classifier(host); + } + catch (err) { + TypeScript.Services.logInternalError(host, err); + throw err; + } + } + + public createClassifierShim(host: TypeScript.Services.IClassifierHost): ClassifierShim { + try { + return new ClassifierShim(this, host); + } + catch (err) { + TypeScript.Services.logInternalError(host, err); + throw err; + } + } + + public createCoreServices(host: TypeScript.Services.ICoreServicesHost): TypeScript.Services.CoreServices { + try { + return new TypeScript.Services.CoreServices(host); + } + catch (err) { + TypeScript.Services.logInternalError(host.logger, err); + throw err; + } + } + + public createCoreServicesShim(host: TypeScript.Services.ICoreServicesHost): CoreServicesShim { + try { + return new CoreServicesShim(this, host); + } + catch (err) { + TypeScript.Services.logInternalError(host.logger, err); + throw err; + } + } + + public close(): void { + // Forget all the registered shims + this._shims = []; + this.documentRegistry = new DocumentRegistry(); + } + + public registerShim(shim: IShim): void { + this._shims.push(shim); + } + + public unregisterShim(shim: IShim): void { + for (var i = 0, n = this._shims.length; i < n; i++) { + if (this._shims[i] === shim) { + delete this._shims[i]; + return; + } + } + + throw TypeScript.Errors.invalidOperation(); + } + } } + + +/// TODO: this is used by VS, clean this up on both sides of the interfrace +module Services { + export var TypeScriptServicesFactory = TypeScript.Services.TypeScriptServicesFactory; +} + diff --git a/src/services/typescriptServices.ts b/src/services/typescriptServices.ts index 6df7b3bbc45..a899c96a07a 100644 --- a/src/services/typescriptServices.ts +++ b/src/services/typescriptServices.ts @@ -130,100 +130,3 @@ module TypeScript { return true; } } - - -module TypeScript.Services { - export class TypeScriptServicesFactory implements IShimFactory { - private _shims: IShim[] = []; - private documentRegistry: DocumentRegistry = new DocumentRegistry(); - - public createPullLanguageService(host: TypeScript.Services.LanguageServiceHost): TypeScript.Services.LanguageService { - try { - return TypeScript.Services.createLanguageService(host, this.documentRegistry); - } - catch (err) { - TypeScript.Services.logInternalError(host, err); - throw err; - } - } - - public createLanguageServiceShim(host: ILanguageServiceShimHost): ILanguageServiceShim { - try { - var hostAdapter = new LanguageServiceShimHostAdapter(host); - var pullLanguageService = this.createPullLanguageService(hostAdapter); - return new LanguageServiceShim(this, host, pullLanguageService); - } - catch (err) { - TypeScript.Services.logInternalError(host, err); - throw err; - } - } - - public createClassifier(host: TypeScript.Services.IClassifierHost): TypeScript.Services.Classifier { - try { - return new TypeScript.Services.Classifier(host); - } - catch (err) { - TypeScript.Services.logInternalError(host, err); - throw err; - } - } - - public createClassifierShim(host: TypeScript.Services.IClassifierHost): ClassifierShim { - try { - return new ClassifierShim(this, host); - } - catch (err) { - TypeScript.Services.logInternalError(host, err); - throw err; - } - } - - public createCoreServices(host: TypeScript.Services.ICoreServicesHost): TypeScript.Services.CoreServices { - try { - return new TypeScript.Services.CoreServices(host); - } - catch (err) { - TypeScript.Services.logInternalError(host.logger, err); - throw err; - } - } - - public createCoreServicesShim(host: TypeScript.Services.ICoreServicesHost): CoreServicesShim { - try { - return new CoreServicesShim(this, host); - } - catch (err) { - TypeScript.Services.logInternalError(host.logger, err); - throw err; - } - } - - public close(): void { - // Forget all the registered shims - this._shims = []; - this.documentRegistry = new DocumentRegistry(); - } - - public registerShim(shim: IShim): void { - this._shims.push(shim); - } - - public unregisterShim(shim: IShim): void { - for(var i =0, n = this._shims.length; i Date: Thu, 24 Jul 2014 11:57:18 -0700 Subject: [PATCH 23/59] only expose needed types --- src/services/shims.ts | 106 +++++++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 49 deletions(-) diff --git a/src/services/shims.ts b/src/services/shims.ts index f16bf9afec6..f2d293ebf66 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -52,7 +52,7 @@ module TypeScript.Services { fileExists(path: string): boolean; directoryExists(path: string): boolean; getParentDirectory(path: string): string; - getDiagnosticsObject(): TypeScript.Services.ILanguageServicesDiagnostics; + getDiagnosticsObject(): ILanguageServicesDiagnostics; getLocalizedDiagnosticMessages(): string; getCancellationToken(): TypeScript.ICancellationToken } @@ -69,17 +69,8 @@ module TypeScript.Services { dispose(dummy: any): void; } - export class ShimBase implements IShim { - constructor(private factory: IShimFactory) { - factory.registerShim(this); - } - public dispose(dummy: any): void { - this.factory.unregisterShim(this); - } - } - export interface ILanguageServiceShim extends IShim { - languageService: TypeScript.Services.LanguageService; + languageService: LanguageService; dispose(dummy: any): void; @@ -140,8 +131,16 @@ module TypeScript.Services { getEmitOutput(fileName: string): string; } - /// TODO: delete this, it is only needed untill the VS interface is updated + export interface IClassifierShim extends IShim { + getClassificationsForLine(text: string, lexState: EndOfLineState): string; + } + export interface ICoreServicesShim extends IShim { + getPreProcessedFileInfo(fileName: string, sourceText: TypeScript.IScriptSnapshot): string; + getDefaultCompilationSettings(): string; + } + + /// TODO: delete this, it is only needed untill the VS interface is updated enum LanguageVersion { EcmaScript3 = 0, EcmaScript5 = 1, @@ -283,7 +282,7 @@ module TypeScript.Services { } } - export class LanguageServiceShimHostAdapter implements TypeScript.Services.LanguageServiceHost { + class LanguageServiceShimHostAdapter implements LanguageServiceHost { constructor(private shimHost: ILanguageServiceShimHost) { } @@ -389,7 +388,7 @@ module TypeScript.Services { } } - export function simpleForwardCall(logger: TypeScript.Logger, actionDescription: string, action: () => any): any { + function simpleForwardCall(logger: TypeScript.Logger, actionDescription: string, action: () => any): any { logger.log(actionDescription); var start = Date.now(); var result = action(); @@ -405,7 +404,7 @@ module TypeScript.Services { return result; } - export function forwardJSONCall(logger: TypeScript.Logger, actionDescription: string, action: () => any): string { + function forwardJSONCall(logger: TypeScript.Logger, actionDescription: string, action: () => any): string { try { var result = simpleForwardCall(logger, actionDescription, action); return JSON.stringify({ result: result }); @@ -414,24 +413,33 @@ module TypeScript.Services { if (err instanceof OperationCanceledException) { return JSON.stringify({ canceled: true }); } - TypeScript.Services.logInternalError(logger, err); + logInternalError(logger, err); err.description = actionDescription; return JSON.stringify({ error: err }); } } - export class LanguageServiceShim extends ShimBase implements ILanguageServiceShim { + class ShimBase implements IShim { + constructor(private factory: IShimFactory) { + factory.registerShim(this); + } + public dispose(dummy: any): void { + this.factory.unregisterShim(this); + } + } + + class LanguageServiceShim extends ShimBase implements ILanguageServiceShim { private logger: TypeScript.Logger; constructor(factory: IShimFactory, private host: ILanguageServiceShimHost, - public languageService: TypeScript.Services.LanguageService) { + public languageService: LanguageService) { super(factory); this.logger = this.host; } public forwardJSONCall(actionDescription: string, action: () => any): string { - return TypeScript.Services.forwardJSONCall(this.logger, actionDescription, action); + return forwardJSONCall(this.logger, actionDescription, action); } // DISPOSE @@ -596,7 +604,7 @@ module TypeScript.Services { return this.forwardJSONCall( "getIndentationAtPosition(\"" + fileName + "\", " + position + ")", () => { - var localOptions: TypeScript.Services.EditorOptions = JSON.parse(options); + var localOptions: EditorOptions = JSON.parse(options); var columnOffset = this.languageService.getIndentationAtPosition(fileName, position, localOptions); return { value: columnOffset }; }); @@ -660,7 +668,7 @@ module TypeScript.Services { return this.forwardJSONCall( "getFormattingEditsForRange(\"" + fileName + "\", " + minChar + ", " + limChar + ")", () => { - var localOptions: TypeScript.Services.FormatCodeOptions = JSON.parse(options); + var localOptions: FormatCodeOptions = JSON.parse(options); var edits = this.languageService.getFormattingEditsForRange(fileName, minChar, limChar, localOptions); return edits; }); @@ -671,7 +679,7 @@ module TypeScript.Services { return this.forwardJSONCall( "getFormattingEditsForDocument(\"" + fileName + "\", " + minChar + ", " + limChar + ")", () => { - var localOptions: TypeScript.Services.FormatCodeOptions = JSON.parse(options); + var localOptions: FormatCodeOptions = JSON.parse(options); var edits = this.languageService.getFormattingEditsForDocument(fileName, minChar, limChar, localOptions); return edits; }); @@ -682,7 +690,7 @@ module TypeScript.Services { return this.forwardJSONCall( "getFormattingEditsOnPaste(\"" + fileName + "\", " + minChar + ", " + limChar + ")", () => { - var localOptions: TypeScript.Services.FormatCodeOptions = JSON.parse(options); + var localOptions: FormatCodeOptions = JSON.parse(options); var edits = this.languageService.getFormattingEditsOnPaste(fileName, minChar, limChar, localOptions); return edits; }); @@ -693,7 +701,7 @@ module TypeScript.Services { return this.forwardJSONCall( "getFormattingEditsAfterKeystroke(\"" + fileName + "\", " + position + ", \"" + key + "\")", () => { - var localOptions: TypeScript.Services.FormatCodeOptions = JSON.parse(options); + var localOptions: FormatCodeOptions = JSON.parse(options); var edits = this.languageService.getFormattingEditsAfterKeystroke(fileName, position, key, localOptions); return edits; }); @@ -744,7 +752,7 @@ module TypeScript.Services { }); } - private _navigateToItemsToString(items: TypeScript.Services.NavigateToItem[]): any { + private _navigateToItemsToString(items: NavigateToItem[]): any { var result: { name: string; kind: string; @@ -779,12 +787,12 @@ module TypeScript.Services { } } - export class ClassifierShim extends ShimBase { - public classifier: TypeScript.Services.Classifier; + class ClassifierShim extends ShimBase implements IClassifierShim { + public classifier: Classifier; - constructor(factory: IShimFactory, public host: TypeScript.Services.IClassifierHost) { + constructor(factory: IShimFactory, public host: IClassifierHost) { super(factory); - this.classifier = new TypeScript.Services.Classifier(this.host); + this.classifier = new Classifier(this.host); } /// COLORIZATION @@ -801,18 +809,18 @@ module TypeScript.Services { } } - export class CoreServicesShim extends ShimBase { + class CoreServicesShim extends ShimBase implements ICoreServicesShim { public logger: TypeScript.Logger; - public services: TypeScript.Services.CoreServices; + public services: CoreServices; - constructor(factory: IShimFactory, public host: TypeScript.Services.ICoreServicesHost) { + constructor(factory: IShimFactory, public host: ICoreServicesHost) { super(factory); this.logger = this.host.logger; - this.services = new TypeScript.Services.CoreServices(this.host); + this.services = new CoreServices(this.host); } private forwardJSONCall(actionDescription: string, action: () => any): any { - return TypeScript.Services.forwardJSONCall(this.logger, actionDescription, action); + return forwardJSONCall(this.logger, actionDescription, action); } /// @@ -843,12 +851,12 @@ module TypeScript.Services { private _shims: IShim[] = []; private documentRegistry: DocumentRegistry = new DocumentRegistry(); - public createPullLanguageService(host: TypeScript.Services.LanguageServiceHost): TypeScript.Services.LanguageService { + public createPullLanguageService(host: LanguageServiceHost): LanguageService { try { - return TypeScript.Services.createLanguageService(host, this.documentRegistry); + return createLanguageService(host, this.documentRegistry); } catch (err) { - TypeScript.Services.logInternalError(host, err); + logInternalError(host, err); throw err; } } @@ -860,47 +868,47 @@ module TypeScript.Services { return new LanguageServiceShim(this, host, pullLanguageService); } catch (err) { - TypeScript.Services.logInternalError(host, err); + logInternalError(host, err); throw err; } } - public createClassifier(host: TypeScript.Services.IClassifierHost): TypeScript.Services.Classifier { + public createClassifier(host: IClassifierHost): Classifier { try { - return new TypeScript.Services.Classifier(host); + return new Classifier(host); } catch (err) { - TypeScript.Services.logInternalError(host, err); + logInternalError(host, err); throw err; } } - public createClassifierShim(host: TypeScript.Services.IClassifierHost): ClassifierShim { + public createClassifierShim(host: IClassifierHost): IClassifierShim { try { return new ClassifierShim(this, host); } catch (err) { - TypeScript.Services.logInternalError(host, err); + logInternalError(host, err); throw err; } } - public createCoreServices(host: TypeScript.Services.ICoreServicesHost): TypeScript.Services.CoreServices { + public createCoreServices(host: ICoreServicesHost): CoreServices { try { - return new TypeScript.Services.CoreServices(host); + return new CoreServices(host); } catch (err) { - TypeScript.Services.logInternalError(host.logger, err); + logInternalError(host.logger, err); throw err; } } - public createCoreServicesShim(host: TypeScript.Services.ICoreServicesHost): CoreServicesShim { + public createCoreServicesShim(host: ICoreServicesHost): ICoreServicesShim { try { return new CoreServicesShim(this, host); } catch (err) { - TypeScript.Services.logInternalError(host.logger, err); + logInternalError(host.logger, err); throw err; } } @@ -931,6 +939,6 @@ module TypeScript.Services { /// TODO: this is used by VS, clean this up on both sides of the interfrace module Services { - export var TypeScriptServicesFactory = TypeScript.Services.TypeScriptServicesFactory; + export var TypeScriptServicesFactory = TypeScriptServicesFactory; } From 247504924b0e56545ca65669f0e002effa90fb16 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 24 Jul 2014 12:00:45 -0700 Subject: [PATCH 24/59] remove the 'I' prefix from interface names --- src/services/shims.ts | 60 +++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/services/shims.ts b/src/services/shims.ts index f2d293ebf66..1422f98655c 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -38,7 +38,7 @@ module TypeScript.Services { // // Public interface of the host of a language service shim instance. // - export interface ILanguageServiceShimHost extends TypeScript.Logger { + export interface LanguageServiceShimHost extends TypeScript.Logger { getCompilationSettings(): string; // Returns a JSON encoded value of the type: @@ -60,16 +60,16 @@ module TypeScript.Services { // // Public interface of of a language service instance shim. // - export interface IShimFactory { - registerShim(shim: IShim): void; - unregisterShim(shim: IShim): void; + export interface ShimFactory { + registerShim(shim: Shim): void; + unregisterShim(shim: Shim): void; } - export interface IShim { + export interface Shim { dispose(dummy: any): void; } - export interface ILanguageServiceShim extends IShim { + export interface LanguageServiceShim extends Shim { languageService: LanguageService; dispose(dummy: any): void; @@ -131,11 +131,11 @@ module TypeScript.Services { getEmitOutput(fileName: string): string; } - export interface IClassifierShim extends IShim { + export interface ClassifierShim extends Shim { getClassificationsForLine(text: string, lexState: EndOfLineState): string; } - export interface ICoreServicesShim extends IShim { + export interface CoreServicesShim extends Shim { getPreProcessedFileInfo(fileName: string, sourceText: TypeScript.IScriptSnapshot): string; getDefaultCompilationSettings(): string; } @@ -283,7 +283,7 @@ module TypeScript.Services { } class LanguageServiceShimHostAdapter implements LanguageServiceHost { - constructor(private shimHost: ILanguageServiceShimHost) { + constructor(private shimHost: LanguageServiceShimHost) { } public information(): boolean { @@ -419,8 +419,8 @@ module TypeScript.Services { } } - class ShimBase implements IShim { - constructor(private factory: IShimFactory) { + class ShimBase implements Shim { + constructor(private factory: ShimFactory) { factory.registerShim(this); } public dispose(dummy: any): void { @@ -428,11 +428,11 @@ module TypeScript.Services { } } - class LanguageServiceShim extends ShimBase implements ILanguageServiceShim { + class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim { private logger: TypeScript.Logger; - constructor(factory: IShimFactory, - private host: ILanguageServiceShimHost, + constructor(factory: ShimFactory, + private host: LanguageServiceShimHost, public languageService: LanguageService) { super(factory); this.logger = this.host; @@ -509,7 +509,7 @@ module TypeScript.Services { "getSyntacticDiagnostics(\"" + fileName + "\")", () => { var errors = this.languageService.getSyntacticDiagnostics(fileName); - return errors.map(LanguageServiceShim.realizeDiagnostic); + return errors.map(LanguageServiceShimObject.realizeDiagnostic); }); } @@ -518,7 +518,7 @@ module TypeScript.Services { "getSemanticDiagnostics(\"" + fileName + "\")", () => { var errors = this.languageService.getSemanticDiagnostics(fileName); - return errors.map(LanguageServiceShim.realizeDiagnostic); + return errors.map(LanguageServiceShimObject.realizeDiagnostic); }); } @@ -787,10 +787,10 @@ module TypeScript.Services { } } - class ClassifierShim extends ShimBase implements IClassifierShim { + class ClassifierShimObject extends ShimBase implements ClassifierShim { public classifier: Classifier; - constructor(factory: IShimFactory, public host: IClassifierHost) { + constructor(factory: ShimFactory, public host: IClassifierHost) { super(factory); this.classifier = new Classifier(this.host); } @@ -809,11 +809,11 @@ module TypeScript.Services { } } - class CoreServicesShim extends ShimBase implements ICoreServicesShim { + class CoreServicesShimObject extends ShimBase implements CoreServicesShim { public logger: TypeScript.Logger; public services: CoreServices; - constructor(factory: IShimFactory, public host: ICoreServicesHost) { + constructor(factory: ShimFactory, public host: ICoreServicesHost) { super(factory); this.logger = this.host.logger; this.services = new CoreServices(this.host); @@ -847,8 +847,8 @@ module TypeScript.Services { } } - export class TypeScriptServicesFactory implements IShimFactory { - private _shims: IShim[] = []; + export class TypeScriptServicesFactory implements ShimFactory { + private _shims: Shim[] = []; private documentRegistry: DocumentRegistry = new DocumentRegistry(); public createPullLanguageService(host: LanguageServiceHost): LanguageService { @@ -861,11 +861,11 @@ module TypeScript.Services { } } - public createLanguageServiceShim(host: ILanguageServiceShimHost): ILanguageServiceShim { + public createLanguageServiceShim(host: LanguageServiceShimHost): LanguageServiceShim { try { var hostAdapter = new LanguageServiceShimHostAdapter(host); var pullLanguageService = this.createPullLanguageService(hostAdapter); - return new LanguageServiceShim(this, host, pullLanguageService); + return new LanguageServiceShimObject(this, host, pullLanguageService); } catch (err) { logInternalError(host, err); @@ -883,9 +883,9 @@ module TypeScript.Services { } } - public createClassifierShim(host: IClassifierHost): IClassifierShim { + public createClassifierShim(host: IClassifierHost): ClassifierShim { try { - return new ClassifierShim(this, host); + return new ClassifierShimObject(this, host); } catch (err) { logInternalError(host, err); @@ -903,9 +903,9 @@ module TypeScript.Services { } } - public createCoreServicesShim(host: ICoreServicesHost): ICoreServicesShim { + public createCoreServicesShim(host: ICoreServicesHost): CoreServicesShim { try { - return new CoreServicesShim(this, host); + return new CoreServicesShimObject(this, host); } catch (err) { logInternalError(host.logger, err); @@ -919,11 +919,11 @@ module TypeScript.Services { this.documentRegistry = new DocumentRegistry(); } - public registerShim(shim: IShim): void { + public registerShim(shim: Shim): void { this._shims.push(shim); } - public unregisterShim(shim: IShim): void { + public unregisterShim(shim: Shim): void { for (var i = 0, n = this._shims.length; i < n; i++) { if (this._shims[i] === shim) { delete this._shims[i]; From 41826986ac3a14713f71496c5e8dc32a7272b7ad Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 24 Jul 2014 12:10:59 -0700 Subject: [PATCH 25/59] Clean up code and types in typeScriptServices.ts --- src/compiler/types.ts | 7 +++ src/services/compiler/astHelpers.ts | 4 ++ src/services/compiler/document.ts | 4 +- src/services/formatting/rulesProvider.ts | 2 +- src/services/languageService.ts | 32 ++++++++-- src/services/pullLanguageService.ts | 42 +++++++++++-- src/services/shims.ts | 6 +- src/services/typescriptServices.ts | 75 ------------------------ 8 files changed, 83 insertions(+), 89 deletions(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 71d1c9d1e84..05e2ce641c0 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1111,4 +1111,11 @@ module ts { useCaseSensitiveFileNames(): boolean; getNewLine(): string; } + + export enum ByteOrderMark { + None = 0, + Utf8 = 1, + Utf16BigEndian = 2, + Utf16LittleEndian = 3, + } } diff --git a/src/services/compiler/astHelpers.ts b/src/services/compiler/astHelpers.ts index 589e4fad503..51d7f5e87fd 100644 --- a/src/services/compiler/astHelpers.ts +++ b/src/services/compiler/astHelpers.ts @@ -16,6 +16,10 @@ /// module TypeScript.ASTHelpers { + + + var sentinelEmptyArray = []; + //export function scriptIsElided(sourceUnit: SourceUnitSyntax): boolean { // return isDTSFile(sourceUnit.syntaxTree.fileName()) || moduleMembersAreElided(sourceUnit.moduleElements); //} diff --git a/src/services/compiler/document.ts b/src/services/compiler/document.ts index e8a2f89df68..6da1b143f91 100644 --- a/src/services/compiler/document.ts +++ b/src/services/compiler/document.ts @@ -18,7 +18,7 @@ module TypeScript { public filename: string, public referencedFiles: string[], private _scriptSnapshot: IScriptSnapshot, - public byteOrderMark: ByteOrderMark, + public byteOrderMark: ts.ByteOrderMark, public version: number, public isOpen: boolean, private _syntaxTree: SyntaxTree, @@ -144,7 +144,7 @@ module TypeScript { return new Document(this.compilationSettings, this.filename, this.referencedFiles, scriptSnapshot, this.byteOrderMark, version, isOpen, newSyntaxTree, /*soruceFile*/ null); } - public static create(compilationSettings: ts.CompilerOptions, fileName: string, scriptSnapshot: IScriptSnapshot, byteOrderMark: ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]): Document { + public static create(compilationSettings: ts.CompilerOptions, fileName: string, scriptSnapshot: IScriptSnapshot, byteOrderMark: ts.ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]): Document { return new Document(compilationSettings, fileName, referencedFiles, scriptSnapshot, byteOrderMark, version, isOpen, /*syntaxTree:*/ null, /*soruceFile*/ null); } } diff --git a/src/services/formatting/rulesProvider.ts b/src/services/formatting/rulesProvider.ts index 2ff436d123d..1b55676c7df 100644 --- a/src/services/formatting/rulesProvider.ts +++ b/src/services/formatting/rulesProvider.ts @@ -39,7 +39,7 @@ module TypeScript.Services.Formatting { } public ensureUpToDate(options: TypeScript.Services.FormatCodeOptions) { - if (this.options == null || !TypeScript.compareDataObjects(this.options, options)) { + if (this.options == null || !compareDataObjects(this.options, options)) { var activeRules: Rule[] = TypeScript.timeFunction(this.logger, "RulesProvider: createActiveRules()", () => { return this.createActiveRules(options); }); var rulesMap: RulesMap = TypeScript.timeFunction(this.logger, "RulesProvider: RulesMap.create()", () => { return RulesMap.create(activeRules); }); diff --git a/src/services/languageService.ts b/src/services/languageService.ts index 8c656a53f84..894d1a83b94 100644 --- a/src/services/languageService.ts +++ b/src/services/languageService.ts @@ -23,15 +23,14 @@ module TypeScript.Services { // export interface LanguageServiceHost extends TypeScript.Logger, TypeScript.IReferenceResolverHost { getCompilationSettings(): ts.CompilerOptions; - getScriptFileNames(): string[]; getScriptVersion(fileName: string): number; getScriptIsOpen(fileName: string): boolean; - getScriptByteOrderMark(fileName: string): TypeScript.ByteOrderMark; + getScriptByteOrderMark(fileName: string): ts.ByteOrderMark; getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot; getDiagnosticsObject(): TypeScript.Services.ILanguageServicesDiagnostics; getLocalizedDiagnosticMessages(): any; - getCancellationToken(): ICancellationToken; + getCancellationToken(): ts.CancellationToken; } // @@ -76,7 +75,7 @@ module TypeScript.Services { getFormattingEditsOnPaste(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[]; getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions): TextEdit[]; - getEmitOutput(fileName: string): TypeScript.EmitOutput; + getEmitOutput(fileName: string): EmitOutput; //getSyntaxTree(fileName: string): TypeScript.SyntaxTree; @@ -242,6 +241,31 @@ module TypeScript.Services { docComment: string; } + export enum EmitOutputResult { + Succeeded, + FailedBecauseOfSyntaxErrors, + FailedBecauseOfCompilerOptionsErrors, + FailedToGenerateDeclarationsBecauseOfSemanticErrors + } + + export interface EmitOutput { + outputFiles: OutputFile[]; + emitOutputResult: EmitOutputResult; + } + + export enum OutputFileType { + JavaScript, + SourceMap, + Declaration + } + + export interface OutputFile { + name: string; + writeByteOrderMark: boolean; + text: string; + fileType: OutputFileType; + sourceMapOutput: any; + } // TODO: move these to enums export class ScriptElementKind { diff --git a/src/services/pullLanguageService.ts b/src/services/pullLanguageService.ts index 88aeccf81d7..0155eed384d 100644 --- a/src/services/pullLanguageService.ts +++ b/src/services/pullLanguageService.ts @@ -21,7 +21,7 @@ module TypeScript.Services { filename: string; version: number; isOpen: boolean; - byteOrderMark: TypeScript.ByteOrderMark; + byteOrderMark: ts.ByteOrderMark; _sourceText?: TypeScript.IScriptSnapshot; } @@ -33,6 +33,40 @@ module TypeScript.Services { }; } + export function compareDataObjects(dst: any, src: any): boolean { + for (var e in dst) { + if (typeof dst[e] === "object") { + if (!compareDataObjects(dst[e], src[e])) + return false; + } + else if (typeof dst[e] !== "function") { + if (dst[e] !== src[e]) + return false; + } + } + return true; + } + + export class OperationCanceledException { } + + class CancellationToken { + + public static None: CancellationToken = new CancellationToken(null) + + constructor(private cancellationToken: ts.CancellationToken) { + } + + public isCancellationRequested() { + return this.cancellationToken && this.cancellationToken.isCancellationRequested(); + } + + public throwIfCancellationRequested(): void { + if (this.isCancellationRequested()) { + throw new OperationCanceledException(); + } + } + } + // Cache host information about scripts. Should be refreshed // at each language service public entry point, since we don't know when // set of scripts handled by the host changes. @@ -90,7 +124,7 @@ module TypeScript.Services { return this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)].isOpen; } - public getByteOrderMark(filename: string): TypeScript.ByteOrderMark { + public getByteOrderMark(filename: string): ts.ByteOrderMark { return this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)].byteOrderMark; } @@ -270,7 +304,7 @@ module TypeScript.Services { filename: string, compilationSettings: ts.CompilerOptions, scriptSnapshot: IScriptSnapshot, - byteOrderMark: ByteOrderMark, + byteOrderMark: ts.ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]): TypeScript.Document; @@ -326,7 +360,7 @@ module TypeScript.Services { filename: string, compilationSettings: ts.CompilerOptions, scriptSnapshot: IScriptSnapshot, - byteOrderMark: ByteOrderMark, + byteOrderMark: ts.ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]= []): TypeScript.Document { diff --git a/src/services/shims.ts b/src/services/shims.ts index 1422f98655c..ec577c78c4a 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -54,7 +54,7 @@ module TypeScript.Services { getParentDirectory(path: string): string; getDiagnosticsObject(): ILanguageServicesDiagnostics; getLocalizedDiagnosticMessages(): string; - getCancellationToken(): TypeScript.ICancellationToken + getCancellationToken(): ts.CancellationToken; } // @@ -344,7 +344,7 @@ module TypeScript.Services { return this.shimHost.getScriptIsOpen(fileName); } - public getScriptByteOrderMark(fileName: string): TypeScript.ByteOrderMark { + public getScriptByteOrderMark(fileName: string): ts.ByteOrderMark { return this.shimHost.getScriptByteOrderMark(fileName); } @@ -366,7 +366,7 @@ module TypeScript.Services { } } - public getCancellationToken(): ICancellationToken { + public getCancellationToken(): ts.CancellationToken { return this.shimHost.getCancellationToken(); } diff --git a/src/services/typescriptServices.ts b/src/services/typescriptServices.ts index a899c96a07a..27f17723e13 100644 --- a/src/services/typescriptServices.ts +++ b/src/services/typescriptServices.ts @@ -55,78 +55,3 @@ /// -module TypeScript { - - export var sentinelEmptyArray = []; - - export enum EmitOutputResult { - Succeeded, - FailedBecauseOfSyntaxErrors, - FailedBecauseOfCompilerOptionsErrors, - FailedToGenerateDeclarationsBecauseOfSemanticErrors - } - - export interface EmitOutput { - outputFiles: OutputFile[]; - emitOutputResult: EmitOutputResult; - } - - export enum OutputFileType { - JavaScript, - SourceMap, - Declaration - } - - export enum ByteOrderMark { - None = 0, - Utf8 = 1, - Utf16BigEndian = 2, - Utf16LittleEndian = 3, - } - - export interface OutputFile { - name: string; - writeByteOrderMark: boolean; - text: string; - fileType: OutputFileType; - sourceMapOutput: any; - } - - export interface ICancellationToken { - isCancellationRequested(): boolean; - } - - export class OperationCanceledException { } - - export class CancellationToken { - - public static None: CancellationToken = new CancellationToken(null) - - constructor(private cancellationToken: ICancellationToken) { - } - - public isCancellationRequested() { - return this.cancellationToken && this.cancellationToken.isCancellationRequested(); - } - - public throwIfCancellationRequested(): void { - if (this.isCancellationRequested()) { - throw new OperationCanceledException(); - } - } - } - - export function compareDataObjects(dst: any, src: any): boolean { - for (var e in dst) { - if (typeof dst[e] === "object") { - if (!compareDataObjects(dst[e], src[e])) - return false; - } - else if (typeof dst[e] !== "function") { - if (dst[e] !== src[e]) - return false; - } - } - return true; - } -} From 742197077bcd3cddad3b8a9e465c2488c6cddd67 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 24 Jul 2014 14:08:10 -0700 Subject: [PATCH 26/59] remove unused diagnostics interfaces --- src/services/diagnosticServices.ts | 7 ------- src/services/languageService.ts | 2 -- src/services/shims.ts | 5 ----- 3 files changed, 14 deletions(-) delete mode 100644 src/services/diagnosticServices.ts diff --git a/src/services/diagnosticServices.ts b/src/services/diagnosticServices.ts deleted file mode 100644 index 885170a8131..00000000000 --- a/src/services/diagnosticServices.ts +++ /dev/null @@ -1,7 +0,0 @@ -/// - -module TypeScript.Services { - export interface ILanguageServicesDiagnostics { - log(content: string): void; - } -} diff --git a/src/services/languageService.ts b/src/services/languageService.ts index 894d1a83b94..8b2708856fe 100644 --- a/src/services/languageService.ts +++ b/src/services/languageService.ts @@ -14,7 +14,6 @@ // /// -/// module TypeScript.Services { @@ -28,7 +27,6 @@ module TypeScript.Services { getScriptIsOpen(fileName: string): boolean; getScriptByteOrderMark(fileName: string): ts.ByteOrderMark; getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot; - getDiagnosticsObject(): TypeScript.Services.ILanguageServicesDiagnostics; getLocalizedDiagnosticMessages(): any; getCancellationToken(): ts.CancellationToken; } diff --git a/src/services/shims.ts b/src/services/shims.ts index ec577c78c4a..ad6068f9743 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -52,7 +52,6 @@ module TypeScript.Services { fileExists(path: string): boolean; directoryExists(path: string): boolean; getParentDirectory(path: string): string; - getDiagnosticsObject(): ILanguageServicesDiagnostics; getLocalizedDiagnosticMessages(): string; getCancellationToken(): ts.CancellationToken; } @@ -348,10 +347,6 @@ module TypeScript.Services { return this.shimHost.getScriptByteOrderMark(fileName); } - public getDiagnosticsObject(): ILanguageServicesDiagnostics { - return this.shimHost.getDiagnosticsObject(); - } - public getLocalizedDiagnosticMessages(): any { var diagnosticMessagesJson = this.shimHost.getLocalizedDiagnosticMessages(); if (diagnosticMessagesJson == null || diagnosticMessagesJson == "") { From 6ed29c236736f9839935d3539cd599a7793dd4e1 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 24 Jul 2014 14:26:29 -0700 Subject: [PATCH 27/59] Switch classifer to a function --- src/services/classifier.ts | 115 +++++++++++++++++++------------------ src/services/shims.ts | 38 ++---------- 2 files changed, 64 insertions(+), 89 deletions(-) diff --git a/src/services/classifier.ts b/src/services/classifier.ts index 7e69e55c317..412d96b6eba 100644 --- a/src/services/classifier.ts +++ b/src/services/classifier.ts @@ -35,32 +35,45 @@ module TypeScript.Services { RegExpLiteral, } - var noRegexTable: boolean[] = []; - noRegexTable[TypeScript.SyntaxKind.IdentifierName] = true; - noRegexTable[TypeScript.SyntaxKind.StringLiteral] = true; - noRegexTable[TypeScript.SyntaxKind.NumericLiteral] = true; - noRegexTable[TypeScript.SyntaxKind.RegularExpressionLiteral] = true; - noRegexTable[TypeScript.SyntaxKind.ThisKeyword] = true; - noRegexTable[TypeScript.SyntaxKind.PlusPlusToken] = true; - noRegexTable[TypeScript.SyntaxKind.MinusMinusToken] = true; - noRegexTable[TypeScript.SyntaxKind.CloseParenToken] = true; - noRegexTable[TypeScript.SyntaxKind.CloseBracketToken] = true; - noRegexTable[TypeScript.SyntaxKind.CloseBraceToken] = true; - noRegexTable[TypeScript.SyntaxKind.TrueKeyword] = true; - noRegexTable[TypeScript.SyntaxKind.FalseKeyword] = true; + export interface ClassificationResult { + finalLexState: EndOfLineState; + entries: ClassificationInfo[]; + } - export class Classifier { - private scanner: TypeScript.Scanner.IScanner; - private lastDiagnosticKey: string = null; - private reportDiagnostic = (position: number, fullWidth: number, key: string, args: any[]) => { - this.lastDiagnosticKey = key; + export interface ClassificationInfo { + length: number; + classification: TokenClass; + } + + export interface Classifier { + getClassificationsForLine(text: string, lexState: EndOfLineState): ClassificationResult; + } + + export function createClassifier(host: Logger): Classifier { + var scanner: TypeScript.Scanner.IScanner; + var lastDiagnosticKey: string = null; + var noRegexTable: boolean[]; + var reportDiagnostic = (position: number, fullWidth: number, key: string, args: any[]) => { + lastDiagnosticKey = key; }; - constructor(public host: IClassifierHost) { + if (!noRegexTable) { + noRegexTable= []; + noRegexTable[TypeScript.SyntaxKind.IdentifierName] = true; + noRegexTable[TypeScript.SyntaxKind.StringLiteral] = true; + noRegexTable[TypeScript.SyntaxKind.NumericLiteral] = true; + noRegexTable[TypeScript.SyntaxKind.RegularExpressionLiteral] = true; + noRegexTable[TypeScript.SyntaxKind.ThisKeyword] = true; + noRegexTable[TypeScript.SyntaxKind.PlusPlusToken] = true; + noRegexTable[TypeScript.SyntaxKind.MinusMinusToken] = true; + noRegexTable[TypeScript.SyntaxKind.CloseParenToken] = true; + noRegexTable[TypeScript.SyntaxKind.CloseBracketToken] = true; + noRegexTable[TypeScript.SyntaxKind.CloseBraceToken] = true; + noRegexTable[TypeScript.SyntaxKind.TrueKeyword] = true; + noRegexTable[TypeScript.SyntaxKind.FalseKeyword] = true; } - /// COLORIZATION - public getClassificationsForLine(text: string, lexState: EndOfLineState): ClassificationResult { + function getClassificationsForLine(text: string, lexState: EndOfLineState): ClassificationResult { var offset = 0; if (lexState !== EndOfLineState.Start) { // If we're in a string literal, then prepend: "\ @@ -81,34 +94,38 @@ module TypeScript.Services { offset = 3; } - var result = new ClassificationResult(); + var result = { + finalLexState: EndOfLineState.Start, + entries: [] + }; + var simpleText = TypeScript.SimpleText.fromString(text); - this.scanner = Scanner.createScanner(ts.ScriptTarget.ES5, simpleText, this.reportDiagnostic); + scanner = Scanner.createScanner(ts.ScriptTarget.ES5, simpleText, reportDiagnostic); var lastTokenKind = TypeScript.SyntaxKind.None; var token: ISyntaxToken = null; do { - this.lastDiagnosticKey = null; + lastDiagnosticKey = null; - token = this.scanner.scan(!noRegexTable[lastTokenKind]); + token = scanner.scan(!noRegexTable[lastTokenKind]); lastTokenKind = token.kind(); - this.processToken(text, simpleText, offset, token, result); + processToken(text, simpleText, offset, token, result); } while (token.kind() !== SyntaxKind.EndOfFileToken); - this.lastDiagnosticKey = null; + lastDiagnosticKey = null; return result; } - private processToken(text: string, simpleText: ISimpleText, offset: number, token: TypeScript.ISyntaxToken, result: ClassificationResult): void { - this.processTriviaList(text, offset, token.leadingTrivia(simpleText), result); - this.addResult(text, offset, result, width(token), token.kind()); - this.processTriviaList(text, offset, token.trailingTrivia(simpleText), result); + function processToken(text: string, simpleText: ISimpleText, offset: number, token: TypeScript.ISyntaxToken, result: ClassificationResult): void { + processTriviaList(text, offset, token.leadingTrivia(simpleText), result); + addResult(text, offset, result, width(token), token.kind()); + processTriviaList(text, offset, token.trailingTrivia(simpleText), result); if (fullEnd(token) >= text.length) { // We're at the end. - if (this.lastDiagnosticKey === TypeScript.DiagnosticCode.AsteriskSlash_expected) { + if (lastDiagnosticKey === TypeScript.DiagnosticCode.AsteriskSlash_expected) { result.finalLexState = EndOfLineState.InMultiLineCommentTrivia; return; } @@ -118,22 +135,22 @@ module TypeScript.Services { if (tokenText.length > 0 && tokenText.charCodeAt(tokenText.length - 1) === TypeScript.CharacterCodes.backslash) { var quoteChar = tokenText.charCodeAt(0); result.finalLexState = quoteChar === TypeScript.CharacterCodes.doubleQuote - ? EndOfLineState.InDoubleQuoteStringLiteral - : EndOfLineState.InSingleQuoteStringLiteral; + ? EndOfLineState.InDoubleQuoteStringLiteral + : EndOfLineState.InSingleQuoteStringLiteral; return; } } } } - private processTriviaList(text: string, offset: number, triviaList: TypeScript.ISyntaxTriviaList, result: ClassificationResult): void { + function processTriviaList(text: string, offset: number, triviaList: TypeScript.ISyntaxTriviaList, result: ClassificationResult): void { for (var i = 0, n = triviaList.count(); i < n; i++) { var trivia = triviaList.syntaxTriviaAt(i); - this.addResult(text, offset, result, trivia.fullWidth(), trivia.kind()); + addResult(text, offset, result, trivia.fullWidth(), trivia.kind()); } } - private addResult(text: string, offset: number, result: ClassificationResult, length: number, kind: TypeScript.SyntaxKind): void { + function addResult(text: string, offset: number, result: ClassificationResult, length: number, kind: TypeScript.SyntaxKind): void { if (length > 0) { // If this is the first classification we're adding to the list, then remove any // offset we have if we were continuing a construct from the previous line. @@ -141,16 +158,16 @@ module TypeScript.Services { length -= offset; } - result.entries.push(new ClassificationInfo(length, this.classFromKind(kind))); + result.entries.push({ length: length, classification: classFromKind(kind) }); } } - private classFromKind(kind: TypeScript.SyntaxKind) { + function classFromKind(kind: TypeScript.SyntaxKind) { if (TypeScript.SyntaxFacts.isAnyKeyword(kind)) { return TokenClass.Keyword; } else if (TypeScript.SyntaxFacts.isBinaryExpressionOperatorToken(kind) || - TypeScript.SyntaxFacts.isPrefixUnaryExpressionOperatorToken(kind)) { + TypeScript.SyntaxFacts.isPrefixUnaryExpressionOperatorToken(kind)) { return TokenClass.Operator; } else if (TypeScript.SyntaxFacts.isAnyPunctuation(kind)) { @@ -174,21 +191,9 @@ module TypeScript.Services { return TokenClass.Identifier; } } - } - export interface IClassifierHost extends TypeScript.Logger { - } - - export class ClassificationResult { - public finalLexState: EndOfLineState = EndOfLineState.Start; - public entries: ClassificationInfo[] = []; - - constructor() { - } - } - - export class ClassificationInfo { - constructor(public length: number, public classification: TokenClass) { - } + return { + getClassificationsForLine: getClassificationsForLine + }; } } diff --git a/src/services/shims.ts b/src/services/shims.ts index ad6068f9743..6efbceecc52 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -785,9 +785,9 @@ module TypeScript.Services { class ClassifierShimObject extends ShimBase implements ClassifierShim { public classifier: Classifier; - constructor(factory: ShimFactory, public host: IClassifierHost) { + constructor(factory: ShimFactory, public host: Logger) { super(factory); - this.classifier = new Classifier(this.host); + this.classifier = createClassifier(this.host); } /// COLORIZATION @@ -846,20 +846,10 @@ module TypeScript.Services { private _shims: Shim[] = []; private documentRegistry: DocumentRegistry = new DocumentRegistry(); - public createPullLanguageService(host: LanguageServiceHost): LanguageService { - try { - return createLanguageService(host, this.documentRegistry); - } - catch (err) { - logInternalError(host, err); - throw err; - } - } - public createLanguageServiceShim(host: LanguageServiceShimHost): LanguageServiceShim { try { var hostAdapter = new LanguageServiceShimHostAdapter(host); - var pullLanguageService = this.createPullLanguageService(hostAdapter); + var pullLanguageService = createLanguageService(hostAdapter, this.documentRegistry); return new LanguageServiceShimObject(this, host, pullLanguageService); } catch (err) { @@ -868,17 +858,7 @@ module TypeScript.Services { } } - public createClassifier(host: IClassifierHost): Classifier { - try { - return new Classifier(host); - } - catch (err) { - logInternalError(host, err); - throw err; - } - } - - public createClassifierShim(host: IClassifierHost): ClassifierShim { + public createClassifierShim(host: Logger): ClassifierShim { try { return new ClassifierShimObject(this, host); } @@ -888,16 +868,6 @@ module TypeScript.Services { } } - public createCoreServices(host: ICoreServicesHost): CoreServices { - try { - return new CoreServices(host); - } - catch (err) { - logInternalError(host.logger, err); - throw err; - } - } - public createCoreServicesShim(host: ICoreServicesHost): CoreServicesShim { try { return new CoreServicesShimObject(this, host); From 4a4c74958da9f8645ef78e613117aaebec0c6f0a Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 24 Jul 2014 14:36:23 -0700 Subject: [PATCH 28/59] clean up coreServices --- src/services/coreServices.ts | 49 ------------------------------ src/services/shims.ts | 20 +++++------- src/services/typescriptServices.ts | 1 - 3 files changed, 7 insertions(+), 63 deletions(-) delete mode 100644 src/services/coreServices.ts diff --git a/src/services/coreServices.ts b/src/services/coreServices.ts deleted file mode 100644 index 0f725d3d6be..00000000000 --- a/src/services/coreServices.ts +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -/// -/// -/// - -// Access to "Debug" object -var debugObjectHost = (this); - -module TypeScript.Services { - - export interface ICoreServicesHost { - logger: TypeScript.Logger; - } - - export class CoreServices { - constructor (public host: ICoreServicesHost) { - } - - public getPreProcessedFileInfo(fileName: string, sourceText: TypeScript.IScriptSnapshot): TypeScript.IPreProcessedFileInfo { - return TypeScript.preProcessFile(fileName, sourceText); - } - - public getDefaultCompilationSettings(): ts.CompilerOptions { - return getDefaultCompilerOptions(); - } - - public collectGarbage(): void { - if (!debugObjectHost || !debugObjectHost.CollectGarbage) { - throw new Error(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.This_version_of_the_Javascript_runtime_does_not_support_the_0_function, ['collectGarbage()'])); - } - - debugObjectHost.CollectGarbage(); - } - } -} diff --git a/src/services/shims.ts b/src/services/shims.ts index 6efbceecc52..de49c57687f 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -14,9 +14,8 @@ // /// - + var debugObjectHost = (this); module TypeScript.Services { - export interface IScriptSnapshotShim { // Get's a portion of the script snapshot specified by [start, end). getText(start: number, end: number): string; @@ -805,17 +804,12 @@ module TypeScript.Services { } class CoreServicesShimObject extends ShimBase implements CoreServicesShim { - public logger: TypeScript.Logger; - public services: CoreServices; - - constructor(factory: ShimFactory, public host: ICoreServicesHost) { + constructor(factory: ShimFactory, public host: Logger) { super(factory); - this.logger = this.host.logger; - this.services = new CoreServices(this.host); } private forwardJSONCall(actionDescription: string, action: () => any): any { - return forwardJSONCall(this.logger, actionDescription, action); + return forwardJSONCall(this.host, actionDescription, action); } /// @@ -825,7 +819,7 @@ module TypeScript.Services { return this.forwardJSONCall( "getPreProcessedFileInfo(\"" + fileName + "\")", () => { - var result = this.services.getPreProcessedFileInfo(fileName, sourceText); + var result = TypeScript.preProcessFile(fileName, sourceText); return result; }); } @@ -837,7 +831,7 @@ module TypeScript.Services { return this.forwardJSONCall( "getDefaultCompilationSettings()", () => { - return compilerOptionsToCompilationSettings(this.services.getDefaultCompilationSettings()); + return compilerOptionsToCompilationSettings(getDefaultCompilerOptions()); }); } } @@ -868,12 +862,12 @@ module TypeScript.Services { } } - public createCoreServicesShim(host: ICoreServicesHost): CoreServicesShim { + public createCoreServicesShim(host: Logger): CoreServicesShim { try { return new CoreServicesShimObject(this, host); } catch (err) { - logInternalError(host.logger, err); + logInternalError(host, err); throw err; } } diff --git a/src/services/typescriptServices.ts b/src/services/typescriptServices.ts index 27f17723e13..d4af024bd31 100644 --- a/src/services/typescriptServices.ts +++ b/src/services/typescriptServices.ts @@ -22,7 +22,6 @@ /// -/// /// /// /// From 2dfd63eb5fba528a24ee976e958a24c79c84642b Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 24 Jul 2014 14:51:14 -0700 Subject: [PATCH 29/59] consolidate all services in one file: services.ts --- src/services/classifier.ts | 199 --- src/services/compiler/base64.ts | 96 -- src/services/compiler/document.ts | 151 --- src/services/compiler/flags.ts | 0 src/services/document.ts | 6 - src/services/languageService.ts | 357 ------ src/services/pullLanguageService.ts | 1090 ---------------- src/services/services.ts | 1772 +++++++++++++++++++++++++++ src/services/typescriptServices.ts | 18 - 9 files changed, 1772 insertions(+), 1917 deletions(-) delete mode 100644 src/services/classifier.ts delete mode 100644 src/services/compiler/base64.ts delete mode 100644 src/services/compiler/document.ts delete mode 100644 src/services/compiler/flags.ts delete mode 100644 src/services/document.ts delete mode 100644 src/services/languageService.ts delete mode 100644 src/services/pullLanguageService.ts diff --git a/src/services/classifier.ts b/src/services/classifier.ts deleted file mode 100644 index 412d96b6eba..00000000000 --- a/src/services/classifier.ts +++ /dev/null @@ -1,199 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -/// - -module TypeScript.Services { - export enum EndOfLineState { - Start, - InMultiLineCommentTrivia, - InSingleQuoteStringLiteral, - InDoubleQuoteStringLiteral, - } - - export enum TokenClass { - Punctuation, - Keyword, - Operator, - Comment, - Whitespace, - Identifier, - NumberLiteral, - StringLiteral, - RegExpLiteral, - } - - export interface ClassificationResult { - finalLexState: EndOfLineState; - entries: ClassificationInfo[]; - } - - export interface ClassificationInfo { - length: number; - classification: TokenClass; - } - - export interface Classifier { - getClassificationsForLine(text: string, lexState: EndOfLineState): ClassificationResult; - } - - export function createClassifier(host: Logger): Classifier { - var scanner: TypeScript.Scanner.IScanner; - var lastDiagnosticKey: string = null; - var noRegexTable: boolean[]; - var reportDiagnostic = (position: number, fullWidth: number, key: string, args: any[]) => { - lastDiagnosticKey = key; - }; - - if (!noRegexTable) { - noRegexTable= []; - noRegexTable[TypeScript.SyntaxKind.IdentifierName] = true; - noRegexTable[TypeScript.SyntaxKind.StringLiteral] = true; - noRegexTable[TypeScript.SyntaxKind.NumericLiteral] = true; - noRegexTable[TypeScript.SyntaxKind.RegularExpressionLiteral] = true; - noRegexTable[TypeScript.SyntaxKind.ThisKeyword] = true; - noRegexTable[TypeScript.SyntaxKind.PlusPlusToken] = true; - noRegexTable[TypeScript.SyntaxKind.MinusMinusToken] = true; - noRegexTable[TypeScript.SyntaxKind.CloseParenToken] = true; - noRegexTable[TypeScript.SyntaxKind.CloseBracketToken] = true; - noRegexTable[TypeScript.SyntaxKind.CloseBraceToken] = true; - noRegexTable[TypeScript.SyntaxKind.TrueKeyword] = true; - noRegexTable[TypeScript.SyntaxKind.FalseKeyword] = true; - } - - function getClassificationsForLine(text: string, lexState: EndOfLineState): ClassificationResult { - var offset = 0; - if (lexState !== EndOfLineState.Start) { - // If we're in a string literal, then prepend: "\ - // (and a newline). That way when we lex we'll think we're still in a string literal. - // - // If we're in a multiline comment, then prepend: /* - // (and a newline). That way when we lex we'll think we're still in a multiline comment. - if (lexState === EndOfLineState.InDoubleQuoteStringLiteral) { - text = '"\\\n' + text; - } - else if (lexState === EndOfLineState.InSingleQuoteStringLiteral) { - text = "'\\\n" + text; - } - else if (lexState === EndOfLineState.InMultiLineCommentTrivia) { - text = "/*\n" + text; - } - - offset = 3; - } - - var result = { - finalLexState: EndOfLineState.Start, - entries: [] - }; - - var simpleText = TypeScript.SimpleText.fromString(text); - scanner = Scanner.createScanner(ts.ScriptTarget.ES5, simpleText, reportDiagnostic); - - var lastTokenKind = TypeScript.SyntaxKind.None; - var token: ISyntaxToken = null; - do { - lastDiagnosticKey = null; - - token = scanner.scan(!noRegexTable[lastTokenKind]); - lastTokenKind = token.kind(); - - processToken(text, simpleText, offset, token, result); - } - while (token.kind() !== SyntaxKind.EndOfFileToken); - - lastDiagnosticKey = null; - return result; - } - - function processToken(text: string, simpleText: ISimpleText, offset: number, token: TypeScript.ISyntaxToken, result: ClassificationResult): void { - processTriviaList(text, offset, token.leadingTrivia(simpleText), result); - addResult(text, offset, result, width(token), token.kind()); - processTriviaList(text, offset, token.trailingTrivia(simpleText), result); - - if (fullEnd(token) >= text.length) { - // We're at the end. - if (lastDiagnosticKey === TypeScript.DiagnosticCode.AsteriskSlash_expected) { - result.finalLexState = EndOfLineState.InMultiLineCommentTrivia; - return; - } - - if (token.kind() === TypeScript.SyntaxKind.StringLiteral) { - var tokenText = token.text(); - if (tokenText.length > 0 && tokenText.charCodeAt(tokenText.length - 1) === TypeScript.CharacterCodes.backslash) { - var quoteChar = tokenText.charCodeAt(0); - result.finalLexState = quoteChar === TypeScript.CharacterCodes.doubleQuote - ? EndOfLineState.InDoubleQuoteStringLiteral - : EndOfLineState.InSingleQuoteStringLiteral; - return; - } - } - } - } - - function processTriviaList(text: string, offset: number, triviaList: TypeScript.ISyntaxTriviaList, result: ClassificationResult): void { - for (var i = 0, n = triviaList.count(); i < n; i++) { - var trivia = triviaList.syntaxTriviaAt(i); - addResult(text, offset, result, trivia.fullWidth(), trivia.kind()); - } - } - - function addResult(text: string, offset: number, result: ClassificationResult, length: number, kind: TypeScript.SyntaxKind): void { - if (length > 0) { - // If this is the first classification we're adding to the list, then remove any - // offset we have if we were continuing a construct from the previous line. - if (result.entries.length === 0) { - length -= offset; - } - - result.entries.push({ length: length, classification: classFromKind(kind) }); - } - } - - function classFromKind(kind: TypeScript.SyntaxKind) { - if (TypeScript.SyntaxFacts.isAnyKeyword(kind)) { - return TokenClass.Keyword; - } - else if (TypeScript.SyntaxFacts.isBinaryExpressionOperatorToken(kind) || - TypeScript.SyntaxFacts.isPrefixUnaryExpressionOperatorToken(kind)) { - return TokenClass.Operator; - } - else if (TypeScript.SyntaxFacts.isAnyPunctuation(kind)) { - return TokenClass.Punctuation; - } - - switch (kind) { - case TypeScript.SyntaxKind.WhitespaceTrivia: - return TokenClass.Whitespace; - case TypeScript.SyntaxKind.MultiLineCommentTrivia: - case TypeScript.SyntaxKind.SingleLineCommentTrivia: - return TokenClass.Comment; - case TypeScript.SyntaxKind.NumericLiteral: - return TokenClass.NumberLiteral; - case TypeScript.SyntaxKind.StringLiteral: - return TokenClass.StringLiteral; - case TypeScript.SyntaxKind.RegularExpressionLiteral: - return TokenClass.RegExpLiteral; - case TypeScript.SyntaxKind.IdentifierName: - default: - return TokenClass.Identifier; - } - } - - return { - getClassificationsForLine: getClassificationsForLine - }; - } -} diff --git a/src/services/compiler/base64.ts b/src/services/compiler/base64.ts deleted file mode 100644 index 06eac4f4b74..00000000000 --- a/src/services/compiler/base64.ts +++ /dev/null @@ -1,96 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -module TypeScript { - class Base64Format { - static encodedValues = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - static encode(inValue: number) { - if (inValue < 64) { - return Base64Format.encodedValues.charAt(inValue); - } - throw TypeError(inValue + ": not a 64 based value"); - } - - static decodeChar(inChar: string) { - if (inChar.length === 1) { - return Base64Format.encodedValues.indexOf(inChar); - } - else { - throw TypeError('"' + inChar + '" must have length 1'); - } - } - } - - export class Base64VLQFormat { - static encode(inValue: number) { - // Add a new least significant bit that has the sign of the value. - // if negative number the least significant bit that gets added to the number has value 1 - // else least significant bit value that gets added is 0 - // eg. -1 changes to binary : 01 [1] => 3 - // +1 changes to binary : 01 [0] => 2 - if (inValue < 0) { - inValue = ((-inValue) << 1) + 1; - } - else { - inValue = inValue << 1; - } - - // Encode 5 bits at a time starting from least significant bits - var encodedStr = ""; - do { - var currentDigit = inValue & 31; // 11111 - inValue = inValue >> 5; - if (inValue > 0) { - // There are still more digits to decode, set the msb (6th bit) - currentDigit = currentDigit | 32; - } - encodedStr = encodedStr + Base64Format.encode(currentDigit); - } while (inValue > 0); - - return encodedStr; - } - - static decode(inString: string) { - var result = 0; - var negative = false; - - var shift = 0; - for (var i = 0; i < inString.length; i++) { - var byte = Base64Format.decodeChar(inString[i]); - if (i === 0) { - // Sign bit appears in the LSBit of the first value - if ((byte & 1) === 1) { - negative = true; - } - result = (byte >> 1) & 15; // 1111x - } - else { - result = result | ((byte & 31) << shift); // 11111 - } - - shift += (i === 0) ? 4 : 5; - - if ((byte & 32) === 32) { - // Continue - } - else { - return { value: negative ? -(result) : result, rest: inString.substr(i + 1) }; - } - } - - throw new Error(getDiagnosticMessage(DiagnosticCode.Base64_value_0_finished_with_a_continuation_bit, [inString])); - } - } -} diff --git a/src/services/compiler/document.ts b/src/services/compiler/document.ts deleted file mode 100644 index 6da1b143f91..00000000000 --- a/src/services/compiler/document.ts +++ /dev/null @@ -1,151 +0,0 @@ -/// - -module TypeScript { - export interface IncrementalParse { - (oldSyntaxTree: SyntaxTree, textChangeRange: TextChangeRange, newText: ISimpleText): SyntaxTree - } - - - export class Document { - private _bloomFilter: BloomFilter = null; - - // By default, our Document class doesn't support incremental update of its contents. - // However, we enable other layers (like teh services layer) to inject the capability - // into us by setting this function. - public static incrementalParse: IncrementalParse = null; - - constructor(private compilationSettings: ts.CompilerOptions, - public filename: string, - public referencedFiles: string[], - private _scriptSnapshot: IScriptSnapshot, - public byteOrderMark: ts.ByteOrderMark, - public version: number, - public isOpen: boolean, - private _syntaxTree: SyntaxTree, - private _soruceFile: ts.SourceFile) { - } - - public isDeclareFile(): boolean { - return isDTSFile(this.filename); - } - - public sourceUnit(): SourceUnitSyntax { - // If we don't have a script, create one from our parse tree. - return this.syntaxTree().sourceUnit(); - } - - public diagnostics(): Diagnostic[] { - return this.syntaxTree().diagnostics(); - } - - public lineMap(): LineMap { - return this.syntaxTree().lineMap(); - } - - public syntaxTree(): SyntaxTree { - if (!this._syntaxTree) { - var start = new Date().getTime(); - - this._syntaxTree = Parser.parse( - this.filename, SimpleText.fromScriptSnapshot(this._scriptSnapshot), this.compilationSettings.target, this.isDeclareFile()); - - var time = new Date().getTime() - start; - - //TypeScript.syntaxTreeParseTime += time; - } - - return this._syntaxTree; - } - - public sourceFile(): ts.SourceFile { - if (!this._soruceFile) { - var start = new Date().getTime(); - - this._soruceFile = ts.createSourceFile(this.filename, this._scriptSnapshot.getText(0, this._scriptSnapshot.getLength()), this.compilationSettings.target); - - var time = new Date().getTime() - start; - - //TypeScript.astParseTime += time; - } - - return this._soruceFile; - } - - public bloomFilter(): BloomFilter { - if (!this._bloomFilter) { - var identifiers = createIntrinsicsObject(); - var pre = function (cur: TypeScript.ISyntaxElement) { - if (ASTHelpers.isValidAstNode(cur)) { - if (cur.kind() === SyntaxKind.IdentifierName) { - var nodeText = tokenValueText((cur)); - - identifiers[nodeText] = true; - } - } - }; - - TypeScript.getAstWalkerFactory().simpleWalk(this.sourceUnit(), pre, null, identifiers); - - var identifierCount = 0; - for (var name in identifiers) { - if (identifiers[name]) { - identifierCount++; - } - } - - this._bloomFilter = new BloomFilter(identifierCount); - this._bloomFilter.addKeys(identifiers); - } - return this._bloomFilter; - } - - // Returns true if this file should get emitted into its own unique output file. - // Otherwise, it should be written into a single output file along with the rest of hte - // documents in the compilation. - public emitToOwnOutputFile(): boolean { - // If we haven't specified an output file in our settings, then we're definitely - // emitting to our own file. Also, if we're an external module, then we're - // definitely emitting to our own file. - return !this.compilationSettings.out || this.syntaxTree().isExternalModule(); - } - - public update(scriptSnapshot: IScriptSnapshot, version: number, isOpen: boolean, textChangeRange: TextChangeRange): Document { - // See if we are currently holding onto a syntax tree. We may not be because we're - // either a closed file, or we've just been lazy and haven't had to create the syntax - // tree yet. Access the field instead of the method so we don't accidently realize - // the old syntax tree. - var oldSyntaxTree = this._syntaxTree; - - if (textChangeRange !== null && Debug.shouldAssert(AssertionLevel.Normal)) { - var oldText = this._scriptSnapshot; - var newText = scriptSnapshot; - - TypeScript.Debug.assert((oldText.getLength() - textChangeRange.span().length() + textChangeRange.newLength()) === newText.getLength()); - - if (Debug.shouldAssert(AssertionLevel.VeryAggressive)) { - var oldTextPrefix = oldText.getText(0, textChangeRange.span().start()); - var newTextPrefix = newText.getText(0, textChangeRange.span().start()); - TypeScript.Debug.assert(oldTextPrefix === newTextPrefix); - - var oldTextSuffix = oldText.getText(textChangeRange.span().end(), oldText.getLength()); - var newTextSuffix = newText.getText(textChangeRange.newSpan().end(), newText.getLength()); - TypeScript.Debug.assert(oldTextSuffix === newTextSuffix); - } - } - - var text = SimpleText.fromScriptSnapshot(scriptSnapshot); - - // If we don't have a text change, or we don't have an old syntax tree, then do a full - // parse. Otherwise, do an incremental parse. - var newSyntaxTree = textChangeRange === null || oldSyntaxTree === null || Document.incrementalParse === null - ? TypeScript.Parser.parse(this.filename, text, this.compilationSettings.target, TypeScript.isDTSFile(this.filename)) - : Document.incrementalParse(oldSyntaxTree, textChangeRange, text); - - return new Document(this.compilationSettings, this.filename, this.referencedFiles, scriptSnapshot, this.byteOrderMark, version, isOpen, newSyntaxTree, /*soruceFile*/ null); - } - - public static create(compilationSettings: ts.CompilerOptions, fileName: string, scriptSnapshot: IScriptSnapshot, byteOrderMark: ts.ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]): Document { - return new Document(compilationSettings, fileName, referencedFiles, scriptSnapshot, byteOrderMark, version, isOpen, /*syntaxTree:*/ null, /*soruceFile*/ null); - } - } -} \ No newline at end of file diff --git a/src/services/compiler/flags.ts b/src/services/compiler/flags.ts deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/services/document.ts b/src/services/document.ts deleted file mode 100644 index 44c97e6aa20..00000000000 --- a/src/services/document.ts +++ /dev/null @@ -1,6 +0,0 @@ -/// - -module TypeScript.Services { - // Inject support for incremental parsing to the core compiler Document class. - Document.incrementalParse = IncrementalParser.parse; -} \ No newline at end of file diff --git a/src/services/languageService.ts b/src/services/languageService.ts deleted file mode 100644 index 8b2708856fe..00000000000 --- a/src/services/languageService.ts +++ /dev/null @@ -1,357 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -/// - -module TypeScript.Services { - - // - // Public interface of the host of a language service instance. - // - export interface LanguageServiceHost extends TypeScript.Logger, TypeScript.IReferenceResolverHost { - getCompilationSettings(): ts.CompilerOptions; - getScriptFileNames(): string[]; - getScriptVersion(fileName: string): number; - getScriptIsOpen(fileName: string): boolean; - getScriptByteOrderMark(fileName: string): ts.ByteOrderMark; - getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot; - getLocalizedDiagnosticMessages(): any; - getCancellationToken(): ts.CancellationToken; - } - - // - // Public services of a language service instance associated - // with a language service host instance - // - export interface LanguageService { - // Note: refresh is a no-op now. It is only around for back compat purposes. - refresh(): void; - - cleanupSemanticCache(): void; - - getSyntacticDiagnostics(fileName: string): ts.Diagnostic[]; - getSemanticDiagnostics(fileName: string): ts.Diagnostic[]; - getCompilerOptionsDiagnostics(): ts.Diagnostic[]; - - getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean): CompletionInfo; - getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails; - - getTypeAtPosition(fileName: string, position: number): TypeInfo; - - getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): SpanInfo; - - getBreakpointStatementAtPosition(fileName: string, position: number): SpanInfo; - - getSignatureAtPosition(fileName: string, position: number): SignatureInfo; - - getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; - getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[]; - getOccurrencesAtPosition(fileName: string, position: number): ReferenceEntry[]; - getImplementorsAtPosition(fileName: string, position: number): ReferenceEntry[]; - - getNavigateToItems(searchValue: string): NavigateToItem[]; - getScriptLexicalStructure(fileName: string): NavigateToItem[]; - - getOutliningRegions(fileName: string): TypeScript.TextSpan[]; - getBraceMatchingAtPosition(fileName: string, position: number): TypeScript.TextSpan[]; - getIndentationAtPosition(fileName: string, position: number, options: TypeScript.Services.EditorOptions): number; - - getFormattingEditsForRange(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[]; - getFormattingEditsForDocument(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[]; - getFormattingEditsOnPaste(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[]; - getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions): TextEdit[]; - - getEmitOutput(fileName: string): EmitOutput; - - //getSyntaxTree(fileName: string): TypeScript.SyntaxTree; - - dispose(): void; - } - - export function logInternalError(logger: TypeScript.Logger, err: Error) { - logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message); - } - - export interface ReferenceEntry { - fileName: string; - minChar: number; - limChar: number; - isWriteAccess: boolean; - } - - export interface NavigateToItem { - name: string; - kind: string; // see ScriptElementKind - kindModifiers: string; // see ScriptElementKindModifier, comma separated - matchKind: string; - fileName: string; - minChar: number; - limChar: number; - additionalSpans?: SpanInfo[]; - containerName: string; - containerKind: string; // see ScriptElementKind - } - - export class TextEdit { - constructor(public minChar: number, public limChar: number, public text: string) { - } - - static createInsert(pos: number, text: string): TextEdit { - return new TextEdit(pos, pos, text); - } - static createDelete(minChar: number, limChar: number): TextEdit { - return new TextEdit(minChar, limChar, ""); - } - static createReplace(minChar: number, limChar: number, text: string): TextEdit { - return new TextEdit(minChar, limChar, text); - } - } - - export class EditorOptions { - public IndentSize: number = 4; - public TabSize: number = 4; - public NewLineCharacter: string = "\r\n"; - public ConvertTabsToSpaces: boolean = true; - - public static clone(objectToClone: EditorOptions): EditorOptions { - var editorOptions = new EditorOptions(); - editorOptions.IndentSize = objectToClone.IndentSize; - editorOptions.TabSize = objectToClone.TabSize; - editorOptions.NewLineCharacter = objectToClone.NewLineCharacter; - editorOptions.ConvertTabsToSpaces = objectToClone.ConvertTabsToSpaces; - return editorOptions; - } - } - - export class FormatCodeOptions extends EditorOptions { - public InsertSpaceAfterCommaDelimiter: boolean = true; - public InsertSpaceAfterSemicolonInForStatements: boolean = true; - public InsertSpaceBeforeAndAfterBinaryOperators: boolean = true; - public InsertSpaceAfterKeywordsInControlFlowStatements: boolean = true; - public InsertSpaceAfterFunctionKeywordForAnonymousFunctions: boolean = false; - public InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: boolean = false; - public PlaceOpenBraceOnNewLineForFunctions: boolean = false; - public PlaceOpenBraceOnNewLineForControlBlocks: boolean = false; - - public static clone(objectToClone: FormatCodeOptions ): FormatCodeOptions { - var formatCodeOptions = EditorOptions.clone(objectToClone); - formatCodeOptions.InsertSpaceAfterCommaDelimiter = objectToClone.InsertSpaceAfterCommaDelimiter; - formatCodeOptions.InsertSpaceAfterSemicolonInForStatements = objectToClone.InsertSpaceAfterSemicolonInForStatements; - formatCodeOptions.InsertSpaceBeforeAndAfterBinaryOperators = objectToClone.InsertSpaceBeforeAndAfterBinaryOperators; - formatCodeOptions.InsertSpaceAfterKeywordsInControlFlowStatements = objectToClone.InsertSpaceAfterKeywordsInControlFlowStatements; - formatCodeOptions.InsertSpaceAfterFunctionKeywordForAnonymousFunctions = objectToClone.InsertSpaceAfterFunctionKeywordForAnonymousFunctions; - formatCodeOptions.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis = objectToClone.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis; - formatCodeOptions.PlaceOpenBraceOnNewLineForFunctions = objectToClone.PlaceOpenBraceOnNewLineForFunctions; - formatCodeOptions.PlaceOpenBraceOnNewLineForControlBlocks = objectToClone.PlaceOpenBraceOnNewLineForControlBlocks; - return formatCodeOptions; - } - } - - export interface DefinitionInfo { - fileName: string; - minChar: number; - limChar: number; - kind: string; - name: string; - containerKind: string; - containerName: string; - } - - export interface TypeInfo { - memberName: TypeScript.MemberName; - docComment: string; - fullSymbolName: string; - kind: string; - minChar: number; - limChar: number; - } - - export interface SpanInfo { - minChar: number; - limChar: number; - // text?: string; - } - - export interface SignatureInfo { - actual: ActualSignatureInfo; - formal: FormalSignatureItemInfo[]; // Formal signatures - activeFormal: number; // Index of the "best match" formal signature - } - - export interface FormalSignatureItemInfo { - signatureInfo: string; - typeParameters: FormalTypeParameterInfo[]; - parameters: FormalParameterInfo[]; // Array of parameters - docComment: string; // Help for the signature - } - - export interface FormalTypeParameterInfo { - name: string; // Type parameter name - docComment: string; // Comments that contain help for the parameter - minChar: number; // minChar for parameter info in the formal signature info string - limChar: number; // lim char for parameter info in the formal signature info string - } - - export interface FormalParameterInfo { - name: string; // Parameter name - isVariable: boolean; // true if parameter is var args - docComment: string; // Comments that contain help for the parameter - minChar: number; // minChar for parameter info in the formal signature info string - limChar: number; // lim char for parameter info in the formal signature info string - } - - export interface ActualSignatureInfo { - parameterMinChar: number; - parameterLimChar: number; - currentParameterIsTypeParameter: boolean; // current parameter is a type argument or a normal argument - currentParameter: number; // Index of active parameter in "parameters" or "typeParamters" array - } - - export interface CompletionInfo { - isMemberCompletion: boolean; - entries: CompletionEntry[]; - } - - export interface CompletionEntry { - name: string; - kind: string; // see ScriptElementKind - kindModifiers: string; // see ScriptElementKindModifier, comma separated - } - - export interface CompletionEntryDetails { - name: string; - kind: string; // see ScriptElementKind - kindModifiers: string; // see ScriptElementKindModifier, comma separated - type: string; - fullSymbolName: string; - docComment: string; - } - - export enum EmitOutputResult { - Succeeded, - FailedBecauseOfSyntaxErrors, - FailedBecauseOfCompilerOptionsErrors, - FailedToGenerateDeclarationsBecauseOfSemanticErrors - } - - export interface EmitOutput { - outputFiles: OutputFile[]; - emitOutputResult: EmitOutputResult; - } - - export enum OutputFileType { - JavaScript, - SourceMap, - Declaration - } - - export interface OutputFile { - name: string; - writeByteOrderMark: boolean; - text: string; - fileType: OutputFileType; - sourceMapOutput: any; - } - - // TODO: move these to enums - export class ScriptElementKind { - static unknown = ""; - - // predefined type (void) or keyword (class) - static keyword = "keyword"; - - // top level script node - static scriptElement = "script"; - - // module foo {} - static moduleElement = "module"; - - // class X {} - static classElement = "class"; - - // interface Y {} - static interfaceElement = "interface"; - - // enum E - static enumElement = "enum"; - - // Inside module and script only - // var v = .. - static variableElement = "var"; - - // Inside function - static localVariableElement = "local var"; - - // Inside module and script only - // function f() { } - static functionElement = "function"; - - // Inside function - static localFunctionElement = "local function"; - - // class X { [public|private]* foo() {} } - static memberFunctionElement = "method"; - - // class X { [public|private]* [get|set] foo:number; } - static memberGetAccessorElement = "getter"; - static memberSetAccessorElement = "setter"; - - // class X { [public|private]* foo:number; } - // interface Y { foo:number; } - static memberVariableElement = "property"; - - // class X { constructor() { } } - static constructorImplementationElement = "constructor"; - - // interface Y { ():number; } - static callSignatureElement = "call"; - - // interface Y { []:number; } - static indexSignatureElement = "index"; - - // interface Y { new():Y; } - static constructSignatureElement = "construct"; - - // function foo(*Y*: string) - static parameterElement = "parameter"; - - static typeParameterElement = "type parameter"; - - static primitiveType = "primitive type"; - } - - export class ScriptElementKindModifier { - static none = ""; - static publicMemberModifier = "public"; - static privateMemberModifier = "private"; - static exportedModifier = "export"; - static ambientModifier = "declare"; - static staticModifier = "static"; - } - - export class MatchKind { - static none: string = null; - static exact = "exact"; - static subString = "substring"; - static prefix = "prefix"; - } - - export class DiagnosticCategory { - static none = ""; - static error = "error"; - static warning = "warning"; - static message = "message"; - } -} diff --git a/src/services/pullLanguageService.ts b/src/services/pullLanguageService.ts deleted file mode 100644 index 0155eed384d..00000000000 --- a/src/services/pullLanguageService.ts +++ /dev/null @@ -1,1090 +0,0 @@ -/// - -/// -/// -/// -/// -/// - -module TypeScript.Services { - interface CompletionSession { - filename: string; // the file where the completion was requested - position: number; // position in the file where the completion was requested - entries: CompletionEntry[]; // entries for this completion - symbols: ts.Map; // symbols by entry name map - location: ts.Node; // the node where the completion was requested - typeChecker: ts.TypeChecker;// the typeChecker used to generate this completion - } - - // Information about a specific host file. - interface HostFileInformation { - filename: string; - version: number; - isOpen: boolean; - byteOrderMark: ts.ByteOrderMark; - _sourceText?: TypeScript.IScriptSnapshot; - } - - export function getDefaultCompilerOptions(): ts.CompilerOptions { - // Set "ES5" target by default for language service - return { - target: ts.ScriptTarget.ES5, - module: ts.ModuleKind.None, - }; - } - - export function compareDataObjects(dst: any, src: any): boolean { - for (var e in dst) { - if (typeof dst[e] === "object") { - if (!compareDataObjects(dst[e], src[e])) - return false; - } - else if (typeof dst[e] !== "function") { - if (dst[e] !== src[e]) - return false; - } - } - return true; - } - - export class OperationCanceledException { } - - class CancellationToken { - - public static None: CancellationToken = new CancellationToken(null) - - constructor(private cancellationToken: ts.CancellationToken) { - } - - public isCancellationRequested() { - return this.cancellationToken && this.cancellationToken.isCancellationRequested(); - } - - public throwIfCancellationRequested(): void { - if (this.isCancellationRequested()) { - throw new OperationCanceledException(); - } - } - } - - // Cache host information about scripts. Should be refreshed - // at each language service public entry point, since we don't know when - // set of scripts handled by the host changes. - class HostCache { - private _filenameToEntry: ts.Map; - private _compilationSettings: ts.CompilerOptions; - - constructor(private host: LanguageServiceHost) { - // script id => script index - this._filenameToEntry = {}; - - var filenames = host.getScriptFileNames(); - for (var i = 0, n = filenames.length; i < n; i++) { - var filename = filenames[i]; - this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)] = { - filename: filename, - version: host.getScriptVersion(filename), - isOpen: host.getScriptIsOpen(filename), - byteOrderMark: host.getScriptByteOrderMark(filename) - }; - } - - this._compilationSettings = host.getCompilationSettings() || getDefaultCompilerOptions(); - } - - public compilationSettings() { - return this._compilationSettings; - } - - public contains(filename: string): boolean { - return !!this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)]; - } - - public getHostfilename(filename: string) { - var hostCacheEntry = this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)]; - if (hostCacheEntry) { - return hostCacheEntry.filename; - } - return filename; - } - - public getfilenames(): string[] { - var fileNames: string[] = []; - for (var id in this._filenameToEntry) { - fileNames.push(id); - } - return fileNames; - } - - public getVersion(filename: string): number { - return this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)].version; - } - - public isOpen(filename: string): boolean { - return this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)].isOpen; - } - - public getByteOrderMark(filename: string): ts.ByteOrderMark { - return this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)].byteOrderMark; - } - - public getScriptSnapshot(filename: string): TypeScript.IScriptSnapshot { - var file = this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)]; - if (!file._sourceText) { - file._sourceText = this.host.getScriptSnapshot(file.filename); - } - return file._sourceText; - } - - public getScriptTextChangeRangeSinceVersion(filename: string, lastKnownVersion: number): TypeScript.TextChangeRange { - var currentVersion = this.getVersion(filename); - if (lastKnownVersion === currentVersion) { - return TypeScript.TextChangeRange.unchanged; // "No changes" - } - - var scriptSnapshot = this.getScriptSnapshot(filename); - return scriptSnapshot.getTextChangeRangeSinceVersion(lastKnownVersion); - } - } - - class SyntaxTreeCache { - private _hostCache: HostCache; - - // For our syntactic only features, we also keep a cache of the syntax tree for the - // currently edited file. - private _currentfilename: string = ""; - private _currentFileVersion: number = -1; - private _currentFileSyntaxTree: TypeScript.SyntaxTree = null; - private _currentFileScriptSnapshot: TypeScript.IScriptSnapshot = null; - - constructor(private _host: LanguageServiceHost) { - this._hostCache = new HostCache(_host); - } - - public getCurrentFileSyntaxTree(filename: string): TypeScript.SyntaxTree { - this._hostCache = new HostCache(this._host); - - var version = this._hostCache.getVersion(filename); - var syntaxTree: TypeScript.SyntaxTree = null; - - if (this._currentFileSyntaxTree === null || this._currentfilename !== filename) { - var scriptSnapshot = this._hostCache.getScriptSnapshot(filename); - syntaxTree = this.createSyntaxTree(filename, scriptSnapshot); - } - else if (this._currentFileVersion !== version) { - var scriptSnapshot = this._hostCache.getScriptSnapshot(filename); - syntaxTree = this.updateSyntaxTree(filename, scriptSnapshot, this._currentFileSyntaxTree, this._currentFileVersion); - } - - if (syntaxTree !== null) { - // All done, ensure state is up to date - this._currentFileScriptSnapshot = scriptSnapshot; - this._currentFileVersion = version; - this._currentfilename = filename; - this._currentFileSyntaxTree = syntaxTree; - } - - return this._currentFileSyntaxTree; - } - - public getCurrentScriptSnapshot(filename: string): IScriptSnapshot { - // update _currentFileScriptSnapshot as a part of 'getCurrentFileSyntaxTree' call - this.getCurrentFileSyntaxTree(filename); - return this._currentFileScriptSnapshot; - } - - private createSyntaxTree(filename: string, scriptSnapshot: TypeScript.IScriptSnapshot): TypeScript.SyntaxTree { - var text = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot); - - // For the purposes of features that use this syntax tree, we can just use the default - // compilation settings. The features only use the syntax (and not the diagnostics), - // and the syntax isn't affected by the compilation settings. - var syntaxTree = TypeScript.Parser.parse(filename, text, getDefaultCompilerOptions().target, TypeScript.isDTSFile(filename)); - - return syntaxTree; - } - - private updateSyntaxTree(filename: string, scriptSnapshot: TypeScript.IScriptSnapshot, previousSyntaxTree: TypeScript.SyntaxTree, previousFileVersion: number): TypeScript.SyntaxTree { - var editRange = this._hostCache.getScriptTextChangeRangeSinceVersion(filename, previousFileVersion); - - // Debug.assert(newLength >= 0); - - // The host considers the entire buffer changed. So parse a completely new tree. - if (editRange === null) { - return this.createSyntaxTree(filename, scriptSnapshot); - } - - var nextSyntaxTree = IncrementalParser.parse( - previousSyntaxTree, editRange, SimpleText.fromScriptSnapshot(scriptSnapshot)); - - this.ensureInvariants(filename, editRange, nextSyntaxTree, this._currentFileScriptSnapshot, scriptSnapshot); - - return nextSyntaxTree; - } - - private ensureInvariants(filename: string, editRange: TypeScript.TextChangeRange, incrementalTree: TypeScript.SyntaxTree, oldScriptSnapshot: TypeScript.IScriptSnapshot, newScriptSnapshot: TypeScript.IScriptSnapshot) { - // First, verify that the edit range and the script snapshots make sense. - - // If this fires, then the edit range is completely bogus. Somehow the lengths of the - // old snapshot, the change range and the new snapshot aren't in sync. This is very - // bad. - var expectedNewLength = oldScriptSnapshot.getLength() - editRange.span().length() + editRange.newLength(); - var actualNewLength = newScriptSnapshot.getLength(); - - function provideMoreDebugInfo() { - - var debugInformation = ["expected length:", expectedNewLength, "and actual length:", actualNewLength, "are not equal\r\n"]; - - var oldSpan = editRange.span(); - - function prettyPrintString(s: string): string { - return '"' + s.replace(/\r/g, '\\r').replace(/\n/g, '\\n') + '"'; - } - - debugInformation.push('Edit range (old text) (start: ' + oldSpan.start() + ', end: ' + oldSpan.end() + ') \r\n'); - debugInformation.push('Old text edit range contents: ' + prettyPrintString(oldScriptSnapshot.getText(oldSpan.start(), oldSpan.end()))); - - var newSpan = editRange.newSpan(); - - debugInformation.push('Edit range (new text) (start: ' + newSpan.start() + ', end: ' + newSpan.end() + ') \r\n'); - debugInformation.push('New text edit range contents: ' + prettyPrintString(newScriptSnapshot.getText(newSpan.start(), newSpan.end()))); - - return debugInformation.join(' '); - } - - Debug.assert( - expectedNewLength === actualNewLength, - "Expected length is different from actual!", - provideMoreDebugInfo); - - if (Debug.shouldAssert(AssertionLevel.VeryAggressive)) { - // If this fires, the text change range is bogus. It says the change starts at point - // 'X', but we can see a text difference *before* that point. - var oldPrefixText = oldScriptSnapshot.getText(0, editRange.span().start()); - var newPrefixText = newScriptSnapshot.getText(0, editRange.span().start()); - Debug.assert(oldPrefixText === newPrefixText, 'Expected equal prefix texts!'); - - // If this fires, the text change range is bogus. It says the change goes only up to - // point 'X', but we can see a text difference *after* that point. - var oldSuffixText = oldScriptSnapshot.getText(editRange.span().end(), oldScriptSnapshot.getLength()); - var newSuffixText = newScriptSnapshot.getText(editRange.newSpan().end(), newScriptSnapshot.getLength()); - Debug.assert(oldSuffixText === newSuffixText, 'Expected equal suffix texts!'); - - // Ok, text change range and script snapshots look ok. Let's verify that our - // incremental parsing worked properly. - //var normalTree = this.createSyntaxTree(filename, newScriptSnapshot); - //Debug.assert(normalTree.structuralEquals(incrementalTree), 'Expected equal incremental and normal trees'); - - // Ok, the trees looked good. So at least our incremental parser agrees with the - // normal parser. Now, verify that the incremental tree matches the contents of the - // script snapshot. - var incrementalTreeText = fullText(incrementalTree.sourceUnit()); - var actualSnapshotText = newScriptSnapshot.getText(0, newScriptSnapshot.getLength()); - Debug.assert(incrementalTreeText === actualSnapshotText, 'Expected full texts to be equal'); - } - } - } - - interface FormattingOptions { - useTabs: boolean; - spacesPerTab: number; - indentSpaces: number; - newLineCharacter: string; - } - - class DocumentRegistryEntry { - public refCount: number = 0; - public owners: string[] = []; - constructor(public document: Document) { - } - } - - export interface IDocumentRegistry { - acquireDocument( - filename: string, - compilationSettings: ts.CompilerOptions, - scriptSnapshot: IScriptSnapshot, - byteOrderMark: ts.ByteOrderMark, - version: number, - isOpen: boolean, - referencedFiles: string[]): TypeScript.Document; - - updateDocument( - document: Document, - filename: string, - compilationSettings: ts.CompilerOptions, - scriptSnapshot: IScriptSnapshot, - version: number, - isOpen: boolean, - textChangeRange: TextChangeRange - ): TypeScript.Document; - - releaseDocument(filename: string, compilationSettings: ts.CompilerOptions): void - } - - export class DocumentRegistry implements IDocumentRegistry { - private buckets: ts.Map> = {}; - - private getKeyFromCompilationSettings(settings: ts.CompilerOptions): string { - return "_" + ts.ScriptTarget[settings.target]; // + "|" + settings.propagateEnumConstants.toString() - } - - private getBucketForCompilationSettings(settings: ts.CompilerOptions, createIfMissing: boolean): ts.Map { - var key = this.getKeyFromCompilationSettings(settings); - var bucket = this.buckets[key]; - if (!bucket && createIfMissing) { - this.buckets[key] = bucket = {}; - } - return bucket; - } - - public reportStats() { - var bucketInfoArray = Object.keys(this.buckets).filter(name => name && name.charAt(0) === '_').map(name => { - var entries = this.buckets[name]; - var documents = []; - for (var i in entries) { - var entry = entries[i]; - documents.push({ - name: i, - refCount: entry.refCount, - references: entry.owners.slice(0) - }); - } - documents.sort((x, y) => y.refCount - x.refCount); - return { bucket: name, documents: documents } - }); - return JSON.stringify(bucketInfoArray, null, 2); - } - - public acquireDocument( - filename: string, - compilationSettings: ts.CompilerOptions, - scriptSnapshot: IScriptSnapshot, - byteOrderMark: ts.ByteOrderMark, - version: number, - isOpen: boolean, - referencedFiles: string[]= []): TypeScript.Document { - - var bucket = this.getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ true); - var entry = bucket[filename]; - if (!entry) { - var document = Document.create(compilationSettings, filename, scriptSnapshot, byteOrderMark, version, isOpen, referencedFiles); - - entry = new DocumentRegistryEntry(document); - bucket[filename] = entry; - } - entry.refCount++; - - return entry.document; - } - - public updateDocument( - document: Document, - filename: string, - compilationSettings: ts.CompilerOptions, - scriptSnapshot: IScriptSnapshot, - version: number, - isOpen: boolean, - textChangeRange: TextChangeRange - ): TypeScript.Document { - - var bucket = this.getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ false); - Debug.assert(bucket); - var entry = bucket[filename]; - Debug.assert(entry); - - if (entry.document.isOpen === isOpen && entry.document.version === version) { - return entry.document; - } - - entry.document = entry.document.update(scriptSnapshot, version, isOpen, textChangeRange); - return entry.document; - } - - public releaseDocument(filename: string, compilationSettings: ts.CompilerOptions): void { - var bucket = this.getBucketForCompilationSettings(compilationSettings, false); - Debug.assert(bucket); - - var entry = bucket[filename]; - entry.refCount--; - - Debug.assert(entry.refCount >= 0); - if (entry.refCount === 0) { - delete bucket[filename]; - } - } - } - - export function createLanguageService(host: LanguageServiceHost, documentRegistry: IDocumentRegistry) :LanguageService{ - var logger: TypeScript.Logger = host; - var _syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host); - var formattingRulesProvider: Formatting.RulesProvider; - var hostCache: HostCache; // A cache of all the information about the files on the host side. - var program: ts.Program; - var typeChecker: ts.TypeChecker; - var useCaseSensitivefilenames = false; - var documentsByName: ts.Map = {}; - var documentRegistry = documentRegistry; - var cancellationToken = new CancellationToken(host.getCancellationToken()); - var activeCompletionSession: CompletionSession; - - // Check if the localized messages json is set, otherwise query the host for it - if (!TypeScript.LocalizedDiagnosticMessages) { - TypeScript.LocalizedDiagnosticMessages = host.getLocalizedDiagnosticMessages(); - } - - function createCompilerHost(): ts.CompilerHost { - return { - getSourceFile: (filename, languageVersion) => { - var document = documentsByName[filename]; - - Debug.assert(!!document, "document can not be undefined"); - - return document.sourceFile(); - }, - getCancellationToken: () => cancellationToken, - getCanonicalFileName: (filename) => useCaseSensitivefilenames ? filename : filename.toLowerCase(), - useCaseSensitiveFileNames: () => useCaseSensitivefilenames, - getNewLine: () => "\n", - // Need something that doesn't depend on sys.ts here - getDefaultLibFilename: (): string => { - throw Error("TOD:: getDefaultLibfilename"); - }, - writeFile: (filename, data) => { - throw Error("TODO: write file"); - }, - getCurrentDirectory: (): string => { - throw Error("TODO: getCurrentDirectory"); - } - }; - } - - function synchronizeHostData(): void { - // Reset the cache at start of every refresh - hostCache = new HostCache(host); - - var compilationSettings = hostCache.compilationSettings(); - - // TODO: check if we need to create a new compiler to start with - // 1. files are identical - // 2. compilation settings are identical - - // Now, remove any files from the compiler that are no longer in the host. - var oldProgram = program; - if (oldProgram) { - var oldSettings = program.getCompilerOptions(); - - // If the language version changed, then that affects what types of things we parse. So - // we have to dump all syntax trees. - // TODO: handle propagateEnumConstants - var settingsChangeAffectsSyntax = oldSettings.target !== compilationSettings.target; - - var changesInCompilationSettingsAffectSyntax = - oldSettings && compilationSettings && !compareDataObjects(oldSettings, compilationSettings) && settingsChangeAffectsSyntax; - var oldSourceFiles = program.getSourceFiles(); - - for (var i = 0, n = oldSourceFiles.length; i < n; i++) { - cancellationToken.throwIfCancellationRequested(); - var filename = oldSourceFiles[i].filename; - if (!hostCache.contains(filename) || changesInCompilationSettingsAffectSyntax) { - documentRegistry.releaseDocument(filename, oldSettings); - delete documentsByName[filename]; - } - } - } - - // Now, for every file the host knows about, either add the file (if the compiler - // doesn't know about it.). Or notify the compiler about any changes (if it does - // know about it.) - var hostfilenames = hostCache.getfilenames(); - - for (var i = 0, n = hostfilenames.length; i < n; i++) { - var filename = hostfilenames[i]; - - var version = hostCache.getVersion(filename); - var isOpen = hostCache.isOpen(filename); - var scriptSnapshot = hostCache.getScriptSnapshot(filename); - - var document: Document = documentsByName[filename]; - if (document) { - // - // If the document is the same, assume no update - // - if (document.version === version && document.isOpen === isOpen) { - continue; - } - - // Only perform incremental parsing on open files that are being edited. If a file was - // open, but is now closed, we want to reparse entirely so we don't have any tokens that - // are holding onto expensive script snapshot instances on the host. Similarly, if a - // file was closed, then we always want to reparse. This is so our tree doesn't keep - // the old buffer alive that represented the file on disk (as the host has moved to a - // new text buffer). - var textChangeRange: TextChangeRange = null; - if (document.isOpen && isOpen) { - textChangeRange = hostCache.getScriptTextChangeRangeSinceVersion(filename, document.version); - } - - document = documentRegistry.updateDocument(document, filename, compilationSettings, scriptSnapshot, version, isOpen, textChangeRange); - } - else { - document = documentRegistry.acquireDocument(filename, compilationSettings, scriptSnapshot, hostCache.getByteOrderMark(filename), version, isOpen, []); - } - - // Remeber the new document - documentsByName[filename] = document; - } - - // Now create a new compiler - program = ts.createProgram(hostfilenames, compilationSettings, createCompilerHost()); - typeChecker = program.getTypeChecker(); - } - - function dispose(): void { - if (program) { - ts.forEach(program.getSourceFiles(), - (f) => documentRegistry.releaseDocument(f.filename, program.getCompilerOptions())); - } - } - - /// Diagnostics - function getSyntacticDiagnostics(filename: string) { - synchronizeHostData(); - return program.getDiagnostics(program.getSourceFile(filename)); - } - - function getSemanticDiagnostics(filename: string) { - synchronizeHostData(); - return typeChecker.getDiagnostics(program.getSourceFile(filename)); - } - - function getCompilerOptionsDiagnostics() { - synchronizeHostData(); - return program.getGlobalDiagnostics(); - } - - /// Completion - function createCompletionEntry(symbol: ts.Symbol): CompletionEntry { - // Try to get a valid display name for this symbol, if we could not find one, then ignore it. - // We would like to only show things that can be added after a dot, so for instance numeric properties can - // not be accessed with a dot (a.1 <- invalid) - var displayName = CompletionHelpers.getValidCompletionEntryDisplayName(symbol.getName(), program.getCompilerOptions().target); - if (!displayName) { - return undefined; - } - - var declarations = symbol.getDeclarations(); - var firstDeclaration = [0]; - return { - name: displayName, - kind: getSymbolKind(symbol), - kindModifiers: declarations ? getNodeModifiers(declarations[0]) : ScriptElementKindModifier.none - }; - } - - function getCompletionsAtPosition(filename: string, position: number, isMemberCompletion: boolean) { - function getCompletionEntriesFromSymbols(symbols: ts.Symbol[], session: CompletionSession): void { - ts.forEach(symbols, (symbol) => { - var entry = createCompletionEntry(symbol); - if (entry) { - session.entries.push(entry); - session.symbols[entry.name] = symbol; - } - }); - } - - synchronizeHostData(); - - filename = TypeScript.switchToForwardSlashes(filename); - - var document = documentsByName[filename]; - var sourceUnit = document.sourceUnit(); - - if (CompletionHelpers.isCompletionListBlocker(document.syntaxTree().sourceUnit(), position)) { - logger.log("Returning an empty list because completion was blocked."); - return null; - } - - var node = TypeScript.ASTHelpers.getAstAtPosition(sourceUnit, position, /*useTrailingTriviaAsLimChar*/ true, /*forceInclusive*/ true); - - if (node && node.kind() === TypeScript.SyntaxKind.IdentifierName && - start(node) === end(node)) { - // Ignore missing name nodes - node = node.parent; - } - - var isRightOfDot = false; - if (node && - node.kind() === TypeScript.SyntaxKind.MemberAccessExpression && - end((node).expression) < position) { - - isRightOfDot = true; - node = (node).expression; - } - else if (node && - node.kind() === TypeScript.SyntaxKind.QualifiedName && - end((node).left) < position) { - - isRightOfDot = true; - node = (node).left; - } - else if (node && node.parent && - node.kind() === TypeScript.SyntaxKind.IdentifierName && - node.parent.kind() === TypeScript.SyntaxKind.MemberAccessExpression && - (node.parent).name === node) { - - isRightOfDot = true; - node = (node.parent).expression; - } - else if (node && node.parent && - node.kind() === TypeScript.SyntaxKind.IdentifierName && - node.parent.kind() === TypeScript.SyntaxKind.QualifiedName && - (node.parent).right === node) { - - isRightOfDot = true; - node = (node.parent).left; - } - - // TODO: this is a hack for now, we need a proper walking mechanism to verify that we have the correct node - var mappedNode = getNodeAtPosition(document.sourceFile(), end(node) - 1); - - Debug.assert(mappedNode, "Could not map a Fidelity node to an AST node"); - - // Get the completions - activeCompletionSession = { - filename: filename, - position: position, - entries: [], - symbols: {}, - location: mappedNode, - typeChecker: typeChecker - }; - - // Right of dot member completion list - if (isRightOfDot) { - var type: ts.Type = typeChecker.getTypeOfExpression(mappedNode); - if (!type) { - return undefined; - } - - var symbols = type.getApparentProperties(); - isMemberCompletion = true; - getCompletionEntriesFromSymbols(symbols, activeCompletionSession); - } - else { - var containingObjectLiteral = CompletionHelpers.getContainingObjectLiteralApplicableForCompletion(document.syntaxTree().sourceUnit(), position); - - // Object literal expression, look up possible property names from contextual type - if (containingObjectLiteral) { - var searchPosition = Math.min(position, end(containingObjectLiteral)); - var path = TypeScript.ASTHelpers.getAstAtPosition(sourceUnit, searchPosition); - // Get the object literal node - - while (node && node.kind() !== TypeScript.SyntaxKind.ObjectLiteralExpression) { - node = node.parent; - } - - if (!node || node.kind() !== TypeScript.SyntaxKind.ObjectLiteralExpression) { - // AST Path look up did not result in the same node as Fidelity Syntax Tree look up. - // Once we remove AST this will no longer be a problem. - return null; - } - - isMemberCompletion = true; - - //// Try to get the object members form contextual typing - //var contextualMembers = compiler.getContextualMembersFromAST(node, document); - //if (contextualMembers && contextualMembers.symbols && contextualMembers.symbols.length > 0) { - // // get existing members - // var existingMembers = compiler.getVisibleMemberSymbolsFromAST(node, document); - - // // Add filtterd items to the completion list - // getCompletionEntriesFromSymbols({ - // symbols: CompletionHelpers.filterContextualMembersList(contextualMembers.symbols, existingMembers, filename, position), - // enclosingScopeSymbol: contextualMembers.enclosingScopeSymbol - // }, entries); - //} - } - // Get scope memebers - else { - isMemberCompletion = false; - /// TODO filter meaning based on the current context - var symbolMeanings = ts.SymbolFlags.Type | ts.SymbolFlags.Value | ts.SymbolFlags.Namespace; - var symbols = typeChecker.getSymbolsInScope(mappedNode, symbolMeanings); - - getCompletionEntriesFromSymbols(symbols, activeCompletionSession); - } - } - - // Add keywords if this is not a member completion list - if (!isMemberCompletion) { - Array.prototype.push.apply(activeCompletionSession.entries, KeywordCompletions.getKeywordCompltions()); - } - - return { - isMemberCompletion: isMemberCompletion, - entries: activeCompletionSession.entries - }; - } - - function getCompletionEntryDetails(filename: string, position: number, entryName: string) { - // Note: No need to call synchronizeHostData, as we have captured all the data we need - // in the getCompletionsAtPosition erlier - filename = TypeScript.switchToForwardSlashes(filename); - - var session = activeCompletionSession; - - // Ensure that the current active completion session is still valid for this request - if (!session || session.filename !== filename || session.position !== position) { - return undefined; - } - - var symbol = activeCompletionSession.symbols[entryName]; - if (symbol) { - var type = session.typeChecker.getTypeOfSymbol(symbol); - Debug.assert(type, "Could not find type for symbol"); - var completionEntry = createCompletionEntry(symbol); - return { - name: entryName, - kind: completionEntry.kind, - kindModifiers: completionEntry.kindModifiers, - type: session.typeChecker.typeToString(type, session.location), - fullSymbolName: typeChecker.symbolToString(symbol, session.location), - docComment: "" - }; - } - else { - // No symbol, it is a keyword - return { - name: entryName, - kind: ScriptElementKind.keyword, - kindModifiers: ScriptElementKindModifier.none, - type: undefined, - fullSymbolName: entryName, - docComment: undefined - }; - } - } - - function getNodeAtPosition(sourceFile: ts.SourceFile, position: number) { - var current: ts.Node = sourceFile; - outer: while (true) { - // find the child that has this - for (var i = 0, n = current.getChildCount(); i < n; i++) { - var child = current.getChildAt(i); - if (ts.getTokenPosOfNode(child) <= position && position < child.end) { - current = child; - continue outer; - } - if (child.end > position) break; - } - return current; - } - } - - function getEnclosingDeclaration(node: ts.Node): ts.Node { - while (true) { - node = node.parent; - if (!node) { - return node; - } - switch (node.kind) { - case ts.SyntaxKind.Method: - case ts.SyntaxKind.FunctionDeclaration: - case ts.SyntaxKind.FunctionExpression: - case ts.SyntaxKind.GetAccessor: - case ts.SyntaxKind.SetAccessor: - case ts.SyntaxKind.ClassDeclaration: - case ts.SyntaxKind.InterfaceDeclaration: - case ts.SyntaxKind.EnumDeclaration: - case ts.SyntaxKind.ModuleDeclaration: - return node; - } - } - } - - function getSymbolKind(symbol: ts.Symbol): string { - var flags = symbol.getFlags(); - - if (flags & ts.SymbolFlags.Module) return ScriptElementKind.moduleElement; - if (flags & ts.SymbolFlags.Class) return ScriptElementKind.classElement; - if (flags & ts.SymbolFlags.Interface) return ScriptElementKind.interfaceElement; - if (flags & ts.SymbolFlags.Enum) return ScriptElementKind.enumElement; - if (flags & ts.SymbolFlags.Variable) return ScriptElementKind.variableElement; - if (flags & ts.SymbolFlags.Function) return ScriptElementKind.functionElement; - if (flags & ts.SymbolFlags.GetAccessor) return ScriptElementKind.memberGetAccessorElement; - if (flags & ts.SymbolFlags.SetAccessor) return ScriptElementKind.memberSetAccessorElement; - if (flags & ts.SymbolFlags.Method) return ScriptElementKind.memberFunctionElement; - if (flags & ts.SymbolFlags.Property) return ScriptElementKind.memberVariableElement; - if (flags & ts.SymbolFlags.IndexSignature) return ScriptElementKind.indexSignatureElement; - if (flags & ts.SymbolFlags.ConstructSignature) return ScriptElementKind.constructSignatureElement; - if (flags & ts.SymbolFlags.CallSignature) return ScriptElementKind.callSignatureElement; - if (flags & ts.SymbolFlags.Constructor) return ScriptElementKind.constructorImplementationElement; - if (flags & ts.SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; - if (flags & ts.SymbolFlags.EnumMember) return ScriptElementKind.variableElement; - - return ScriptElementKind.unknown; - } - - function getTypeKind(type: ts.Type): string { - var flags = type.getFlags(); - - if (flags & ts.TypeFlags.Enum) return ScriptElementKind.enumElement; - if (flags & ts.TypeFlags.Class) return ScriptElementKind.classElement; - if (flags & ts.TypeFlags.Interface) return ScriptElementKind.interfaceElement; - if (flags & ts.TypeFlags.TypeParameter) return ScriptElementKind.typeParameterElement; - if (flags & ts.TypeFlags.Intrinsic) return ScriptElementKind.primitiveType; - if (flags & ts.TypeFlags.StringLiteral) return ScriptElementKind.primitiveType; - - return ScriptElementKind.unknown; - } - - function getNodeModifiers(node: ts.Node): string { - var flags = node.flags; - var result: string[] = []; - - if (flags & ts.NodeFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier); - if (flags & ts.NodeFlags.Public) result.push(ScriptElementKindModifier.publicMemberModifier); - if (flags & ts.NodeFlags.Static) result.push(ScriptElementKindModifier.staticModifier); - if (flags & ts.NodeFlags.Export) result.push(ScriptElementKindModifier.exportedModifier); - if (ts.isInAmbientContext(node)) result.push(ScriptElementKindModifier.ambientModifier); - - return result.length > 0 ? result.join(',') : ScriptElementKindModifier.none; - } - - /// QuickInfo - function getTypeAtPosition(filename: string, position: number): TypeInfo { - synchronizeHostData(); - - filename = TypeScript.switchToForwardSlashes(filename); - var document = documentsByName[filename]; - var node = getNodeAtPosition(document.sourceFile(), position); - if (!node) return undefined; - - switch (node.kind) { - // A declaration - case ts.SyntaxKind.Identifier: - if (node.parent.kind === ts.SyntaxKind.CallExpression || node.parent.kind === ts.SyntaxKind.NewExpression) { - // TODO: handle new and call expressions - } - - var symbol = typeChecker. getSymbolOfIdentifier(node); - Debug.assert(symbol, "getTypeAtPosition: Could not find symbol for node"); - var type = typeChecker.getTypeOfSymbol(symbol); - - return { - memberName: new MemberNameString(typeChecker.typeToString(type)), - docComment: "", - fullSymbolName: typeChecker.symbolToString(symbol, getEnclosingDeclaration(node)), - kind: getSymbolKind(symbol), - minChar: node.pos, - limChar: node.end - }; - - // An Expression - case ts.SyntaxKind.ThisKeyword: - case ts.SyntaxKind.QualifiedName: - case ts.SyntaxKind.SuperKeyword: - case ts.SyntaxKind.StringLiteral: - var type = typeChecker.getTypeOfExpression(node); - Debug.assert(type, "getTypeAtPosition: Could not find type for node"); - return { - memberName: new MemberNameString(""), - docComment: "", - fullSymbolName: typeChecker.typeToString(type, getEnclosingDeclaration(node)), - kind: getTypeKind(type), - minChar: node.pos, - limChar: node.end - }; - break; - } - } - - /// Syntactic features - function getSyntaxTree(filename: string): TypeScript.SyntaxTree { - filename = TypeScript.switchToForwardSlashes(filename); - return _syntaxTreeCache.getCurrentFileSyntaxTree(filename); - } - - function getNameOrDottedNameSpan(filename: string, startPos: number, endPos: number): SpanInfo { - function getTypeInfoEligiblePath(filename: string, position: number, isConstructorValidPosition: boolean) { - var sourceUnit = _syntaxTreeCache.getCurrentFileSyntaxTree(filename).sourceUnit(); - - var ast = TypeScript.ASTHelpers.getAstAtPosition(sourceUnit, position, /*useTrailingTriviaAsLimChar*/ false, /*forceInclusive*/ true); - if (ast === null) { - return null; - } - - if (ast.kind() === SyntaxKind.ParameterList && ast.parent.kind() === SyntaxKind.CallSignature && ast.parent.parent.kind() === SyntaxKind.ConstructorDeclaration) { - ast = ast.parent.parent; - } - - switch (ast.kind()) { - default: - return null; - case TypeScript.SyntaxKind.ConstructorDeclaration: - var constructorAST = ast; - if (!isConstructorValidPosition || !(position >= start(constructorAST) && position <= start(constructorAST) + "constructor".length)) { - return null; - } - else { - return ast; - } - case TypeScript.SyntaxKind.FunctionDeclaration: - return null; - case TypeScript.SyntaxKind.MemberAccessExpression: - case TypeScript.SyntaxKind.QualifiedName: - case TypeScript.SyntaxKind.SuperKeyword: - case TypeScript.SyntaxKind.StringLiteral: - case TypeScript.SyntaxKind.ThisKeyword: - case TypeScript.SyntaxKind.IdentifierName: - return ast; - } - } - - filename = TypeScript.switchToForwardSlashes(filename); - - var node = getTypeInfoEligiblePath(filename, startPos, false); - if (!node) return null; - - while (node) { - if (TypeScript.ASTHelpers.isNameOfMemberAccessExpression(node) || - TypeScript.ASTHelpers.isRightSideOfQualifiedName(node)) { - node = node.parent; - } - else { - break; - } - } - - return { - minChar: start(node), - limChar: end(node) - }; - } - - function getBreakpointStatementAtPosition(filename: string, position: number) { - // doesn't use compiler - no need to synchronize with host - filename = TypeScript.switchToForwardSlashes(filename); - - var syntaxtree = getSyntaxTree(filename); - return TypeScript.Services.Breakpoints.getBreakpointLocation(syntaxtree, position); - } - - function getScriptLexicalStructure(filename: string) { - filename = TypeScript.switchToForwardSlashes(filename); - var syntaxTree = getSyntaxTree(filename); - var items: NavigateToItem[] = []; - GetScriptLexicalStructureWalker.getListsOfAllScriptLexicalStructure(items, filename, syntaxTree.sourceUnit()); - return items; - } - - function getOutliningRegions(filename: string) { - // doesn't use compiler - no need to synchronize with host - filename = TypeScript.switchToForwardSlashes(filename); - var syntaxTree = getSyntaxTree(filename); - return OutliningElementsCollector.collectElements(syntaxTree.sourceUnit()); - } - - function getBraceMatchingAtPosition(filename: string, position: number) { - filename = TypeScript.switchToForwardSlashes(filename); - var syntaxTree = getSyntaxTree(filename); - return BraceMatcher.getMatchSpans(syntaxTree, position); - } - - function getIndentationAtPosition(filename: string, position: number, editorOptions: EditorOptions) { - filename = TypeScript.switchToForwardSlashes(filename); - - var syntaxTree = getSyntaxTree(filename); - - var scriptSnapshot = _syntaxTreeCache.getCurrentScriptSnapshot(filename); - var scriptText = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot); - var textSnapshot = new TypeScript.Services.Formatting.TextSnapshot(scriptText); - var options = new FormattingOptions(!editorOptions.ConvertTabsToSpaces, editorOptions.TabSize, editorOptions.IndentSize, editorOptions.NewLineCharacter) - - return TypeScript.Services.Formatting.SingleTokenIndenter.getIndentationAmount(position, syntaxTree.sourceUnit(), textSnapshot, options); - } - - function getFormattingManager(filename: string, options: FormatCodeOptions) { - // Ensure rules are initialized and up to date wrt to formatting options - if (formattingRulesProvider == null) { - formattingRulesProvider = new TypeScript.Services.Formatting.RulesProvider(logger); - } - - formattingRulesProvider.ensureUpToDate(options); - - // Get the Syntax Tree - var syntaxTree = getSyntaxTree(filename); - - // Convert IScriptSnapshot to ITextSnapshot - var scriptSnapshot = _syntaxTreeCache.getCurrentScriptSnapshot(filename); - var scriptText = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot); - var textSnapshot = new TypeScript.Services.Formatting.TextSnapshot(scriptText); - - var manager = new TypeScript.Services.Formatting.FormattingManager(syntaxTree, textSnapshot, formattingRulesProvider, options); - - return manager; - } - - function getFormattingEditsForRange(filename: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[] { - filename = TypeScript.switchToForwardSlashes(filename); - - var manager = getFormattingManager(filename, options); - return manager.formatSelection(minChar, limChar); - } - - function getFormattingEditsForDocument(filename: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[] { - filename = TypeScript.switchToForwardSlashes(filename); - - var manager = getFormattingManager(filename, options); - return manager.formatDocument(minChar, limChar); - } - - function getFormattingEditsOnPaste(filename: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[] { - filename = TypeScript.switchToForwardSlashes(filename); - - var manager = getFormattingManager(filename, options); - return manager.formatOnPaste(minChar, limChar); - } - - function getFormattingEditsAfterKeystroke(filename: string, position: number, key: string, options: FormatCodeOptions): TextEdit[] { - filename = TypeScript.switchToForwardSlashes(filename); - - var manager = getFormattingManager(filename, options); - if (key === "}") return manager.formatOnClosingCurlyBrace(position); - else if (key === ";") return manager.formatOnSemicolon(position); - else if (key === "\n") return manager.formatOnEnter(position); - else return []; - } - - - return { - dispose: dispose, - refresh: () => { }, - cleanupSemanticCache: () => { }, - getSyntacticDiagnostics: getSyntacticDiagnostics, - getSemanticDiagnostics: getSemanticDiagnostics, - getCompilerOptionsDiagnostics: getCompilerOptionsDiagnostics, - getCompletionsAtPosition: getCompletionsAtPosition, - getCompletionEntryDetails: getCompletionEntryDetails, - getTypeAtPosition: getTypeAtPosition, - getSignatureAtPosition: (filename, position) => undefined, - getDefinitionAtPosition: (filename, position) => [], - getReferencesAtPosition: (filename, position) => [], - getOccurrencesAtPosition: (filename, position) => [], - getImplementorsAtPosition: (filename, position) => [], - getNameOrDottedNameSpan: getNameOrDottedNameSpan, - getBreakpointStatementAtPosition: getBreakpointStatementAtPosition, - getNavigateToItems: (searchValue) => [], - getScriptLexicalStructure: getScriptLexicalStructure, - getOutliningRegions: getOutliningRegions, - getBraceMatchingAtPosition: getBraceMatchingAtPosition, - getIndentationAtPosition: getIndentationAtPosition, - getFormattingEditsForRange: getFormattingEditsForRange, - getFormattingEditsForDocument: getFormattingEditsForDocument, - getFormattingEditsOnPaste: getFormattingEditsOnPaste, - getFormattingEditsAfterKeystroke: getFormattingEditsAfterKeystroke, - getEmitOutput: (filename) => undefined, - }; - } -} \ No newline at end of file diff --git a/src/services/services.ts b/src/services/services.ts index e8cd12002fd..4d6dbd1c058 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -4,6 +4,16 @@ /// /// +/// +/// +/// +/// +/// +/// +/// +/// +/// + module ts { export interface Node { @@ -279,3 +289,1765 @@ module ts { initializeServices(); } + +module TypeScript.Services { + export interface IncrementalParse { + (oldSyntaxTree: SyntaxTree, textChangeRange: TextChangeRange, newText: ISimpleText): SyntaxTree + } + + + export class Document { + private _bloomFilter: BloomFilter = null; + + // By default, our Document class doesn't support incremental update of its contents. + // However, we enable other layers (like teh services layer) to inject the capability + // into us by setting this function. + public static incrementalParse: IncrementalParse = null; + + constructor(private compilationSettings: ts.CompilerOptions, + public filename: string, + public referencedFiles: string[], + private _scriptSnapshot: IScriptSnapshot, + public byteOrderMark: ts.ByteOrderMark, + public version: number, + public isOpen: boolean, + private _syntaxTree: SyntaxTree, + private _soruceFile: ts.SourceFile) { + } + + public isDeclareFile(): boolean { + return isDTSFile(this.filename); + } + + public sourceUnit(): SourceUnitSyntax { + // If we don't have a script, create one from our parse tree. + return this.syntaxTree().sourceUnit(); + } + + public diagnostics(): Diagnostic[] { + return this.syntaxTree().diagnostics(); + } + + public lineMap(): LineMap { + return this.syntaxTree().lineMap(); + } + + public syntaxTree(): SyntaxTree { + if (!this._syntaxTree) { + var start = new Date().getTime(); + + this._syntaxTree = Parser.parse( + this.filename, SimpleText.fromScriptSnapshot(this._scriptSnapshot), this.compilationSettings.target, this.isDeclareFile()); + + var time = new Date().getTime() - start; + + //TypeScript.syntaxTreeParseTime += time; + } + + return this._syntaxTree; + } + + public sourceFile(): ts.SourceFile { + if (!this._soruceFile) { + var start = new Date().getTime(); + + this._soruceFile = ts.createSourceFile(this.filename, this._scriptSnapshot.getText(0, this._scriptSnapshot.getLength()), this.compilationSettings.target); + + var time = new Date().getTime() - start; + + //TypeScript.astParseTime += time; + } + + return this._soruceFile; + } + + public bloomFilter(): BloomFilter { + if (!this._bloomFilter) { + var identifiers = createIntrinsicsObject(); + var pre = function (cur: TypeScript.ISyntaxElement) { + if (ASTHelpers.isValidAstNode(cur)) { + if (cur.kind() === SyntaxKind.IdentifierName) { + var nodeText = tokenValueText((cur)); + + identifiers[nodeText] = true; + } + } + }; + + TypeScript.getAstWalkerFactory().simpleWalk(this.sourceUnit(), pre, null, identifiers); + + var identifierCount = 0; + for (var name in identifiers) { + if (identifiers[name]) { + identifierCount++; + } + } + + this._bloomFilter = new BloomFilter(identifierCount); + this._bloomFilter.addKeys(identifiers); + } + return this._bloomFilter; + } + + // Returns true if this file should get emitted into its own unique output file. + // Otherwise, it should be written into a single output file along with the rest of hte + // documents in the compilation. + public emitToOwnOutputFile(): boolean { + // If we haven't specified an output file in our settings, then we're definitely + // emitting to our own file. Also, if we're an external module, then we're + // definitely emitting to our own file. + return !this.compilationSettings.out || this.syntaxTree().isExternalModule(); + } + + public update(scriptSnapshot: IScriptSnapshot, version: number, isOpen: boolean, textChangeRange: TextChangeRange): Document { + // See if we are currently holding onto a syntax tree. We may not be because we're + // either a closed file, or we've just been lazy and haven't had to create the syntax + // tree yet. Access the field instead of the method so we don't accidently realize + // the old syntax tree. + var oldSyntaxTree = this._syntaxTree; + + if (textChangeRange !== null && Debug.shouldAssert(AssertionLevel.Normal)) { + var oldText = this._scriptSnapshot; + var newText = scriptSnapshot; + + TypeScript.Debug.assert((oldText.getLength() - textChangeRange.span().length() + textChangeRange.newLength()) === newText.getLength()); + + if (Debug.shouldAssert(AssertionLevel.VeryAggressive)) { + var oldTextPrefix = oldText.getText(0, textChangeRange.span().start()); + var newTextPrefix = newText.getText(0, textChangeRange.span().start()); + TypeScript.Debug.assert(oldTextPrefix === newTextPrefix); + + var oldTextSuffix = oldText.getText(textChangeRange.span().end(), oldText.getLength()); + var newTextSuffix = newText.getText(textChangeRange.newSpan().end(), newText.getLength()); + TypeScript.Debug.assert(oldTextSuffix === newTextSuffix); + } + } + + var text = SimpleText.fromScriptSnapshot(scriptSnapshot); + + // If we don't have a text change, or we don't have an old syntax tree, then do a full + // parse. Otherwise, do an incremental parse. + var newSyntaxTree = textChangeRange === null || oldSyntaxTree === null || Document.incrementalParse === null + ? TypeScript.Parser.parse(this.filename, text, this.compilationSettings.target, TypeScript.isDTSFile(this.filename)) + : Document.incrementalParse(oldSyntaxTree, textChangeRange, text); + + return new Document(this.compilationSettings, this.filename, this.referencedFiles, scriptSnapshot, this.byteOrderMark, version, isOpen, newSyntaxTree, /*soruceFile*/ null); + } + + public static create(compilationSettings: ts.CompilerOptions, fileName: string, scriptSnapshot: IScriptSnapshot, byteOrderMark: ts.ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]): Document { + return new Document(compilationSettings, fileName, referencedFiles, scriptSnapshot, byteOrderMark, version, isOpen, /*syntaxTree:*/ null, /*soruceFile*/ null); + } + } +} + +module TypeScript.Services { + // Inject support for incremental parsing to the core compiler Document class. + Document.incrementalParse = IncrementalParser.parse; +} + +module TypeScript.Services { + + // + // Public interface of the host of a language service instance. + // + export interface LanguageServiceHost extends TypeScript.Logger, TypeScript.IReferenceResolverHost { + getCompilationSettings(): ts.CompilerOptions; + getScriptFileNames(): string[]; + getScriptVersion(fileName: string): number; + getScriptIsOpen(fileName: string): boolean; + getScriptByteOrderMark(fileName: string): ts.ByteOrderMark; + getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot; + getLocalizedDiagnosticMessages(): any; + getCancellationToken(): ts.CancellationToken; + } + + // + // Public services of a language service instance associated + // with a language service host instance + // + export interface LanguageService { + // Note: refresh is a no-op now. It is only around for back compat purposes. + refresh(): void; + + cleanupSemanticCache(): void; + + getSyntacticDiagnostics(fileName: string): ts.Diagnostic[]; + getSemanticDiagnostics(fileName: string): ts.Diagnostic[]; + getCompilerOptionsDiagnostics(): ts.Diagnostic[]; + + getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean): CompletionInfo; + getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails; + + getTypeAtPosition(fileName: string, position: number): TypeInfo; + + getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): SpanInfo; + + getBreakpointStatementAtPosition(fileName: string, position: number): SpanInfo; + + getSignatureAtPosition(fileName: string, position: number): SignatureInfo; + + getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; + getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[]; + getOccurrencesAtPosition(fileName: string, position: number): ReferenceEntry[]; + getImplementorsAtPosition(fileName: string, position: number): ReferenceEntry[]; + + getNavigateToItems(searchValue: string): NavigateToItem[]; + getScriptLexicalStructure(fileName: string): NavigateToItem[]; + + getOutliningRegions(fileName: string): TypeScript.TextSpan[]; + getBraceMatchingAtPosition(fileName: string, position: number): TypeScript.TextSpan[]; + getIndentationAtPosition(fileName: string, position: number, options: TypeScript.Services.EditorOptions): number; + + getFormattingEditsForRange(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[]; + getFormattingEditsForDocument(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[]; + getFormattingEditsOnPaste(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[]; + getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions): TextEdit[]; + + getEmitOutput(fileName: string): EmitOutput; + + //getSyntaxTree(fileName: string): TypeScript.SyntaxTree; + + dispose(): void; + } + + export function logInternalError(logger: TypeScript.Logger, err: Error) { + logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message); + } + + export interface ReferenceEntry { + fileName: string; + minChar: number; + limChar: number; + isWriteAccess: boolean; + } + + export interface NavigateToItem { + name: string; + kind: string; // see ScriptElementKind + kindModifiers: string; // see ScriptElementKindModifier, comma separated + matchKind: string; + fileName: string; + minChar: number; + limChar: number; + additionalSpans?: SpanInfo[]; + containerName: string; + containerKind: string; // see ScriptElementKind + } + + export class TextEdit { + constructor(public minChar: number, public limChar: number, public text: string) { + } + + static createInsert(pos: number, text: string): TextEdit { + return new TextEdit(pos, pos, text); + } + static createDelete(minChar: number, limChar: number): TextEdit { + return new TextEdit(minChar, limChar, ""); + } + static createReplace(minChar: number, limChar: number, text: string): TextEdit { + return new TextEdit(minChar, limChar, text); + } + } + + export class EditorOptions { + public IndentSize: number = 4; + public TabSize: number = 4; + public NewLineCharacter: string = "\r\n"; + public ConvertTabsToSpaces: boolean = true; + + public static clone(objectToClone: EditorOptions): EditorOptions { + var editorOptions = new EditorOptions(); + editorOptions.IndentSize = objectToClone.IndentSize; + editorOptions.TabSize = objectToClone.TabSize; + editorOptions.NewLineCharacter = objectToClone.NewLineCharacter; + editorOptions.ConvertTabsToSpaces = objectToClone.ConvertTabsToSpaces; + return editorOptions; + } + } + + export class FormatCodeOptions extends EditorOptions { + public InsertSpaceAfterCommaDelimiter: boolean = true; + public InsertSpaceAfterSemicolonInForStatements: boolean = true; + public InsertSpaceBeforeAndAfterBinaryOperators: boolean = true; + public InsertSpaceAfterKeywordsInControlFlowStatements: boolean = true; + public InsertSpaceAfterFunctionKeywordForAnonymousFunctions: boolean = false; + public InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: boolean = false; + public PlaceOpenBraceOnNewLineForFunctions: boolean = false; + public PlaceOpenBraceOnNewLineForControlBlocks: boolean = false; + + public static clone(objectToClone: FormatCodeOptions): FormatCodeOptions { + var formatCodeOptions = EditorOptions.clone(objectToClone); + formatCodeOptions.InsertSpaceAfterCommaDelimiter = objectToClone.InsertSpaceAfterCommaDelimiter; + formatCodeOptions.InsertSpaceAfterSemicolonInForStatements = objectToClone.InsertSpaceAfterSemicolonInForStatements; + formatCodeOptions.InsertSpaceBeforeAndAfterBinaryOperators = objectToClone.InsertSpaceBeforeAndAfterBinaryOperators; + formatCodeOptions.InsertSpaceAfterKeywordsInControlFlowStatements = objectToClone.InsertSpaceAfterKeywordsInControlFlowStatements; + formatCodeOptions.InsertSpaceAfterFunctionKeywordForAnonymousFunctions = objectToClone.InsertSpaceAfterFunctionKeywordForAnonymousFunctions; + formatCodeOptions.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis = objectToClone.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis; + formatCodeOptions.PlaceOpenBraceOnNewLineForFunctions = objectToClone.PlaceOpenBraceOnNewLineForFunctions; + formatCodeOptions.PlaceOpenBraceOnNewLineForControlBlocks = objectToClone.PlaceOpenBraceOnNewLineForControlBlocks; + return formatCodeOptions; + } + } + + export interface DefinitionInfo { + fileName: string; + minChar: number; + limChar: number; + kind: string; + name: string; + containerKind: string; + containerName: string; + } + + export interface TypeInfo { + memberName: TypeScript.MemberName; + docComment: string; + fullSymbolName: string; + kind: string; + minChar: number; + limChar: number; + } + + export interface SpanInfo { + minChar: number; + limChar: number; + // text?: string; + } + + export interface SignatureInfo { + actual: ActualSignatureInfo; + formal: FormalSignatureItemInfo[]; // Formal signatures + activeFormal: number; // Index of the "best match" formal signature + } + + export interface FormalSignatureItemInfo { + signatureInfo: string; + typeParameters: FormalTypeParameterInfo[]; + parameters: FormalParameterInfo[]; // Array of parameters + docComment: string; // Help for the signature + } + + export interface FormalTypeParameterInfo { + name: string; // Type parameter name + docComment: string; // Comments that contain help for the parameter + minChar: number; // minChar for parameter info in the formal signature info string + limChar: number; // lim char for parameter info in the formal signature info string + } + + export interface FormalParameterInfo { + name: string; // Parameter name + isVariable: boolean; // true if parameter is var args + docComment: string; // Comments that contain help for the parameter + minChar: number; // minChar for parameter info in the formal signature info string + limChar: number; // lim char for parameter info in the formal signature info string + } + + export interface ActualSignatureInfo { + parameterMinChar: number; + parameterLimChar: number; + currentParameterIsTypeParameter: boolean; // current parameter is a type argument or a normal argument + currentParameter: number; // Index of active parameter in "parameters" or "typeParamters" array + } + + export interface CompletionInfo { + isMemberCompletion: boolean; + entries: CompletionEntry[]; + } + + export interface CompletionEntry { + name: string; + kind: string; // see ScriptElementKind + kindModifiers: string; // see ScriptElementKindModifier, comma separated + } + + export interface CompletionEntryDetails { + name: string; + kind: string; // see ScriptElementKind + kindModifiers: string; // see ScriptElementKindModifier, comma separated + type: string; + fullSymbolName: string; + docComment: string; + } + + export enum EmitOutputResult { + Succeeded, + FailedBecauseOfSyntaxErrors, + FailedBecauseOfCompilerOptionsErrors, + FailedToGenerateDeclarationsBecauseOfSemanticErrors + } + + export interface EmitOutput { + outputFiles: OutputFile[]; + emitOutputResult: EmitOutputResult; + } + + export enum OutputFileType { + JavaScript, + SourceMap, + Declaration + } + + export interface OutputFile { + name: string; + writeByteOrderMark: boolean; + text: string; + fileType: OutputFileType; + sourceMapOutput: any; + } + + // TODO: move these to enums + export class ScriptElementKind { + static unknown = ""; + + // predefined type (void) or keyword (class) + static keyword = "keyword"; + + // top level script node + static scriptElement = "script"; + + // module foo {} + static moduleElement = "module"; + + // class X {} + static classElement = "class"; + + // interface Y {} + static interfaceElement = "interface"; + + // enum E + static enumElement = "enum"; + + // Inside module and script only + // var v = .. + static variableElement = "var"; + + // Inside function + static localVariableElement = "local var"; + + // Inside module and script only + // function f() { } + static functionElement = "function"; + + // Inside function + static localFunctionElement = "local function"; + + // class X { [public|private]* foo() {} } + static memberFunctionElement = "method"; + + // class X { [public|private]* [get|set] foo:number; } + static memberGetAccessorElement = "getter"; + static memberSetAccessorElement = "setter"; + + // class X { [public|private]* foo:number; } + // interface Y { foo:number; } + static memberVariableElement = "property"; + + // class X { constructor() { } } + static constructorImplementationElement = "constructor"; + + // interface Y { ():number; } + static callSignatureElement = "call"; + + // interface Y { []:number; } + static indexSignatureElement = "index"; + + // interface Y { new():Y; } + static constructSignatureElement = "construct"; + + // function foo(*Y*: string) + static parameterElement = "parameter"; + + static typeParameterElement = "type parameter"; + + static primitiveType = "primitive type"; + } + + export class ScriptElementKindModifier { + static none = ""; + static publicMemberModifier = "public"; + static privateMemberModifier = "private"; + static exportedModifier = "export"; + static ambientModifier = "declare"; + static staticModifier = "static"; + } + + export class MatchKind { + static none: string = null; + static exact = "exact"; + static subString = "substring"; + static prefix = "prefix"; + } + + export class DiagnosticCategory { + static none = ""; + static error = "error"; + static warning = "warning"; + static message = "message"; + } +} + +module TypeScript.Services { + export enum EndOfLineState { + Start, + InMultiLineCommentTrivia, + InSingleQuoteStringLiteral, + InDoubleQuoteStringLiteral, + } + + export enum TokenClass { + Punctuation, + Keyword, + Operator, + Comment, + Whitespace, + Identifier, + NumberLiteral, + StringLiteral, + RegExpLiteral, + } + + export interface ClassificationResult { + finalLexState: EndOfLineState; + entries: ClassificationInfo[]; + } + + export interface ClassificationInfo { + length: number; + classification: TokenClass; + } + + export interface Classifier { + getClassificationsForLine(text: string, lexState: EndOfLineState): ClassificationResult; + } + + export function createClassifier(host: Logger): Classifier { + var scanner: TypeScript.Scanner.IScanner; + var lastDiagnosticKey: string = null; + var noRegexTable: boolean[]; + var reportDiagnostic = (position: number, fullWidth: number, key: string, args: any[]) => { + lastDiagnosticKey = key; + }; + + if (!noRegexTable) { + noRegexTable = []; + noRegexTable[TypeScript.SyntaxKind.IdentifierName] = true; + noRegexTable[TypeScript.SyntaxKind.StringLiteral] = true; + noRegexTable[TypeScript.SyntaxKind.NumericLiteral] = true; + noRegexTable[TypeScript.SyntaxKind.RegularExpressionLiteral] = true; + noRegexTable[TypeScript.SyntaxKind.ThisKeyword] = true; + noRegexTable[TypeScript.SyntaxKind.PlusPlusToken] = true; + noRegexTable[TypeScript.SyntaxKind.MinusMinusToken] = true; + noRegexTable[TypeScript.SyntaxKind.CloseParenToken] = true; + noRegexTable[TypeScript.SyntaxKind.CloseBracketToken] = true; + noRegexTable[TypeScript.SyntaxKind.CloseBraceToken] = true; + noRegexTable[TypeScript.SyntaxKind.TrueKeyword] = true; + noRegexTable[TypeScript.SyntaxKind.FalseKeyword] = true; + } + + function getClassificationsForLine(text: string, lexState: EndOfLineState): ClassificationResult { + var offset = 0; + if (lexState !== EndOfLineState.Start) { + // If we're in a string literal, then prepend: "\ + // (and a newline). That way when we lex we'll think we're still in a string literal. + // + // If we're in a multiline comment, then prepend: /* + // (and a newline). That way when we lex we'll think we're still in a multiline comment. + if (lexState === EndOfLineState.InDoubleQuoteStringLiteral) { + text = '"\\\n' + text; + } + else if (lexState === EndOfLineState.InSingleQuoteStringLiteral) { + text = "'\\\n" + text; + } + else if (lexState === EndOfLineState.InMultiLineCommentTrivia) { + text = "/*\n" + text; + } + + offset = 3; + } + + var result = { + finalLexState: EndOfLineState.Start, + entries: [] + }; + + var simpleText = TypeScript.SimpleText.fromString(text); + scanner = Scanner.createScanner(ts.ScriptTarget.ES5, simpleText, reportDiagnostic); + + var lastTokenKind = TypeScript.SyntaxKind.None; + var token: ISyntaxToken = null; + do { + lastDiagnosticKey = null; + + token = scanner.scan(!noRegexTable[lastTokenKind]); + lastTokenKind = token.kind(); + + processToken(text, simpleText, offset, token, result); + } + while (token.kind() !== SyntaxKind.EndOfFileToken); + + lastDiagnosticKey = null; + return result; + } + + function processToken(text: string, simpleText: ISimpleText, offset: number, token: TypeScript.ISyntaxToken, result: ClassificationResult): void { + processTriviaList(text, offset, token.leadingTrivia(simpleText), result); + addResult(text, offset, result, width(token), token.kind()); + processTriviaList(text, offset, token.trailingTrivia(simpleText), result); + + if (fullEnd(token) >= text.length) { + // We're at the end. + if (lastDiagnosticKey === TypeScript.DiagnosticCode.AsteriskSlash_expected) { + result.finalLexState = EndOfLineState.InMultiLineCommentTrivia; + return; + } + + if (token.kind() === TypeScript.SyntaxKind.StringLiteral) { + var tokenText = token.text(); + if (tokenText.length > 0 && tokenText.charCodeAt(tokenText.length - 1) === TypeScript.CharacterCodes.backslash) { + var quoteChar = tokenText.charCodeAt(0); + result.finalLexState = quoteChar === TypeScript.CharacterCodes.doubleQuote + ? EndOfLineState.InDoubleQuoteStringLiteral + : EndOfLineState.InSingleQuoteStringLiteral; + return; + } + } + } + } + + function processTriviaList(text: string, offset: number, triviaList: TypeScript.ISyntaxTriviaList, result: ClassificationResult): void { + for (var i = 0, n = triviaList.count(); i < n; i++) { + var trivia = triviaList.syntaxTriviaAt(i); + addResult(text, offset, result, trivia.fullWidth(), trivia.kind()); + } + } + + function addResult(text: string, offset: number, result: ClassificationResult, length: number, kind: TypeScript.SyntaxKind): void { + if (length > 0) { + // If this is the first classification we're adding to the list, then remove any + // offset we have if we were continuing a construct from the previous line. + if (result.entries.length === 0) { + length -= offset; + } + + result.entries.push({ length: length, classification: classFromKind(kind) }); + } + } + + function classFromKind(kind: TypeScript.SyntaxKind) { + if (TypeScript.SyntaxFacts.isAnyKeyword(kind)) { + return TokenClass.Keyword; + } + else if (TypeScript.SyntaxFacts.isBinaryExpressionOperatorToken(kind) || + TypeScript.SyntaxFacts.isPrefixUnaryExpressionOperatorToken(kind)) { + return TokenClass.Operator; + } + else if (TypeScript.SyntaxFacts.isAnyPunctuation(kind)) { + return TokenClass.Punctuation; + } + + switch (kind) { + case TypeScript.SyntaxKind.WhitespaceTrivia: + return TokenClass.Whitespace; + case TypeScript.SyntaxKind.MultiLineCommentTrivia: + case TypeScript.SyntaxKind.SingleLineCommentTrivia: + return TokenClass.Comment; + case TypeScript.SyntaxKind.NumericLiteral: + return TokenClass.NumberLiteral; + case TypeScript.SyntaxKind.StringLiteral: + return TokenClass.StringLiteral; + case TypeScript.SyntaxKind.RegularExpressionLiteral: + return TokenClass.RegExpLiteral; + case TypeScript.SyntaxKind.IdentifierName: + default: + return TokenClass.Identifier; + } + } + + return { + getClassificationsForLine: getClassificationsForLine + }; + } +} + +module TypeScript.Services { + interface CompletionSession { + filename: string; // the file where the completion was requested + position: number; // position in the file where the completion was requested + entries: CompletionEntry[]; // entries for this completion + symbols: ts.Map; // symbols by entry name map + location: ts.Node; // the node where the completion was requested + typeChecker: ts.TypeChecker;// the typeChecker used to generate this completion + } + + // Information about a specific host file. + interface HostFileInformation { + filename: string; + version: number; + isOpen: boolean; + byteOrderMark: ts.ByteOrderMark; + _sourceText?: TypeScript.IScriptSnapshot; + } + + export function getDefaultCompilerOptions(): ts.CompilerOptions { + // Set "ES5" target by default for language service + return { + target: ts.ScriptTarget.ES5, + module: ts.ModuleKind.None, + }; + } + + export function compareDataObjects(dst: any, src: any): boolean { + for (var e in dst) { + if (typeof dst[e] === "object") { + if (!compareDataObjects(dst[e], src[e])) + return false; + } + else if (typeof dst[e] !== "function") { + if (dst[e] !== src[e]) + return false; + } + } + return true; + } + + export class OperationCanceledException { } + + class CancellationToken { + + public static None: CancellationToken = new CancellationToken(null) + + constructor(private cancellationToken: ts.CancellationToken) { + } + + public isCancellationRequested() { + return this.cancellationToken && this.cancellationToken.isCancellationRequested(); + } + + public throwIfCancellationRequested(): void { + if (this.isCancellationRequested()) { + throw new OperationCanceledException(); + } + } + } + + // Cache host information about scripts. Should be refreshed + // at each language service public entry point, since we don't know when + // set of scripts handled by the host changes. + class HostCache { + private _filenameToEntry: ts.Map; + private _compilationSettings: ts.CompilerOptions; + + constructor(private host: LanguageServiceHost) { + // script id => script index + this._filenameToEntry = {}; + + var filenames = host.getScriptFileNames(); + for (var i = 0, n = filenames.length; i < n; i++) { + var filename = filenames[i]; + this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)] = { + filename: filename, + version: host.getScriptVersion(filename), + isOpen: host.getScriptIsOpen(filename), + byteOrderMark: host.getScriptByteOrderMark(filename) + }; + } + + this._compilationSettings = host.getCompilationSettings() || getDefaultCompilerOptions(); + } + + public compilationSettings() { + return this._compilationSettings; + } + + public contains(filename: string): boolean { + return !!this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)]; + } + + public getHostfilename(filename: string) { + var hostCacheEntry = this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)]; + if (hostCacheEntry) { + return hostCacheEntry.filename; + } + return filename; + } + + public getfilenames(): string[] { + var fileNames: string[] = []; + for (var id in this._filenameToEntry) { + fileNames.push(id); + } + return fileNames; + } + + public getVersion(filename: string): number { + return this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)].version; + } + + public isOpen(filename: string): boolean { + return this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)].isOpen; + } + + public getByteOrderMark(filename: string): ts.ByteOrderMark { + return this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)].byteOrderMark; + } + + public getScriptSnapshot(filename: string): TypeScript.IScriptSnapshot { + var file = this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)]; + if (!file._sourceText) { + file._sourceText = this.host.getScriptSnapshot(file.filename); + } + return file._sourceText; + } + + public getScriptTextChangeRangeSinceVersion(filename: string, lastKnownVersion: number): TypeScript.TextChangeRange { + var currentVersion = this.getVersion(filename); + if (lastKnownVersion === currentVersion) { + return TypeScript.TextChangeRange.unchanged; // "No changes" + } + + var scriptSnapshot = this.getScriptSnapshot(filename); + return scriptSnapshot.getTextChangeRangeSinceVersion(lastKnownVersion); + } + } + + class SyntaxTreeCache { + private _hostCache: HostCache; + + // For our syntactic only features, we also keep a cache of the syntax tree for the + // currently edited file. + private _currentfilename: string = ""; + private _currentFileVersion: number = -1; + private _currentFileSyntaxTree: TypeScript.SyntaxTree = null; + private _currentFileScriptSnapshot: TypeScript.IScriptSnapshot = null; + + constructor(private _host: LanguageServiceHost) { + this._hostCache = new HostCache(_host); + } + + public getCurrentFileSyntaxTree(filename: string): TypeScript.SyntaxTree { + this._hostCache = new HostCache(this._host); + + var version = this._hostCache.getVersion(filename); + var syntaxTree: TypeScript.SyntaxTree = null; + + if (this._currentFileSyntaxTree === null || this._currentfilename !== filename) { + var scriptSnapshot = this._hostCache.getScriptSnapshot(filename); + syntaxTree = this.createSyntaxTree(filename, scriptSnapshot); + } + else if (this._currentFileVersion !== version) { + var scriptSnapshot = this._hostCache.getScriptSnapshot(filename); + syntaxTree = this.updateSyntaxTree(filename, scriptSnapshot, this._currentFileSyntaxTree, this._currentFileVersion); + } + + if (syntaxTree !== null) { + // All done, ensure state is up to date + this._currentFileScriptSnapshot = scriptSnapshot; + this._currentFileVersion = version; + this._currentfilename = filename; + this._currentFileSyntaxTree = syntaxTree; + } + + return this._currentFileSyntaxTree; + } + + public getCurrentScriptSnapshot(filename: string): IScriptSnapshot { + // update _currentFileScriptSnapshot as a part of 'getCurrentFileSyntaxTree' call + this.getCurrentFileSyntaxTree(filename); + return this._currentFileScriptSnapshot; + } + + private createSyntaxTree(filename: string, scriptSnapshot: TypeScript.IScriptSnapshot): TypeScript.SyntaxTree { + var text = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot); + + // For the purposes of features that use this syntax tree, we can just use the default + // compilation settings. The features only use the syntax (and not the diagnostics), + // and the syntax isn't affected by the compilation settings. + var syntaxTree = TypeScript.Parser.parse(filename, text, getDefaultCompilerOptions().target, TypeScript.isDTSFile(filename)); + + return syntaxTree; + } + + private updateSyntaxTree(filename: string, scriptSnapshot: TypeScript.IScriptSnapshot, previousSyntaxTree: TypeScript.SyntaxTree, previousFileVersion: number): TypeScript.SyntaxTree { + var editRange = this._hostCache.getScriptTextChangeRangeSinceVersion(filename, previousFileVersion); + + // Debug.assert(newLength >= 0); + + // The host considers the entire buffer changed. So parse a completely new tree. + if (editRange === null) { + return this.createSyntaxTree(filename, scriptSnapshot); + } + + var nextSyntaxTree = IncrementalParser.parse( + previousSyntaxTree, editRange, SimpleText.fromScriptSnapshot(scriptSnapshot)); + + this.ensureInvariants(filename, editRange, nextSyntaxTree, this._currentFileScriptSnapshot, scriptSnapshot); + + return nextSyntaxTree; + } + + private ensureInvariants(filename: string, editRange: TypeScript.TextChangeRange, incrementalTree: TypeScript.SyntaxTree, oldScriptSnapshot: TypeScript.IScriptSnapshot, newScriptSnapshot: TypeScript.IScriptSnapshot) { + // First, verify that the edit range and the script snapshots make sense. + + // If this fires, then the edit range is completely bogus. Somehow the lengths of the + // old snapshot, the change range and the new snapshot aren't in sync. This is very + // bad. + var expectedNewLength = oldScriptSnapshot.getLength() - editRange.span().length() + editRange.newLength(); + var actualNewLength = newScriptSnapshot.getLength(); + + function provideMoreDebugInfo() { + + var debugInformation = ["expected length:", expectedNewLength, "and actual length:", actualNewLength, "are not equal\r\n"]; + + var oldSpan = editRange.span(); + + function prettyPrintString(s: string): string { + return '"' + s.replace(/\r/g, '\\r').replace(/\n/g, '\\n') + '"'; + } + + debugInformation.push('Edit range (old text) (start: ' + oldSpan.start() + ', end: ' + oldSpan.end() + ') \r\n'); + debugInformation.push('Old text edit range contents: ' + prettyPrintString(oldScriptSnapshot.getText(oldSpan.start(), oldSpan.end()))); + + var newSpan = editRange.newSpan(); + + debugInformation.push('Edit range (new text) (start: ' + newSpan.start() + ', end: ' + newSpan.end() + ') \r\n'); + debugInformation.push('New text edit range contents: ' + prettyPrintString(newScriptSnapshot.getText(newSpan.start(), newSpan.end()))); + + return debugInformation.join(' '); + } + + Debug.assert( + expectedNewLength === actualNewLength, + "Expected length is different from actual!", + provideMoreDebugInfo); + + if (Debug.shouldAssert(AssertionLevel.VeryAggressive)) { + // If this fires, the text change range is bogus. It says the change starts at point + // 'X', but we can see a text difference *before* that point. + var oldPrefixText = oldScriptSnapshot.getText(0, editRange.span().start()); + var newPrefixText = newScriptSnapshot.getText(0, editRange.span().start()); + Debug.assert(oldPrefixText === newPrefixText, 'Expected equal prefix texts!'); + + // If this fires, the text change range is bogus. It says the change goes only up to + // point 'X', but we can see a text difference *after* that point. + var oldSuffixText = oldScriptSnapshot.getText(editRange.span().end(), oldScriptSnapshot.getLength()); + var newSuffixText = newScriptSnapshot.getText(editRange.newSpan().end(), newScriptSnapshot.getLength()); + Debug.assert(oldSuffixText === newSuffixText, 'Expected equal suffix texts!'); + + // Ok, text change range and script snapshots look ok. Let's verify that our + // incremental parsing worked properly. + //var normalTree = this.createSyntaxTree(filename, newScriptSnapshot); + //Debug.assert(normalTree.structuralEquals(incrementalTree), 'Expected equal incremental and normal trees'); + + // Ok, the trees looked good. So at least our incremental parser agrees with the + // normal parser. Now, verify that the incremental tree matches the contents of the + // script snapshot. + var incrementalTreeText = fullText(incrementalTree.sourceUnit()); + var actualSnapshotText = newScriptSnapshot.getText(0, newScriptSnapshot.getLength()); + Debug.assert(incrementalTreeText === actualSnapshotText, 'Expected full texts to be equal'); + } + } + } + + interface FormattingOptions { + useTabs: boolean; + spacesPerTab: number; + indentSpaces: number; + newLineCharacter: string; + } + + class DocumentRegistryEntry { + public refCount: number = 0; + public owners: string[] = []; + constructor(public document: Document) { + } + } + + export interface IDocumentRegistry { + acquireDocument( + filename: string, + compilationSettings: ts.CompilerOptions, + scriptSnapshot: IScriptSnapshot, + byteOrderMark: ts.ByteOrderMark, + version: number, + isOpen: boolean, + referencedFiles: string[]): Document; + + updateDocument( + document: Document, + filename: string, + compilationSettings: ts.CompilerOptions, + scriptSnapshot: IScriptSnapshot, + version: number, + isOpen: boolean, + textChangeRange: TextChangeRange + ): Document; + + releaseDocument(filename: string, compilationSettings: ts.CompilerOptions): void + } + + export class DocumentRegistry implements IDocumentRegistry { + private buckets: ts.Map> = {}; + + private getKeyFromCompilationSettings(settings: ts.CompilerOptions): string { + return "_" + ts.ScriptTarget[settings.target]; // + "|" + settings.propagateEnumConstants.toString() + } + + private getBucketForCompilationSettings(settings: ts.CompilerOptions, createIfMissing: boolean): ts.Map { + var key = this.getKeyFromCompilationSettings(settings); + var bucket = this.buckets[key]; + if (!bucket && createIfMissing) { + this.buckets[key] = bucket = {}; + } + return bucket; + } + + public reportStats() { + var bucketInfoArray = Object.keys(this.buckets).filter(name => name && name.charAt(0) === '_').map(name => { + var entries = this.buckets[name]; + var documents = []; + for (var i in entries) { + var entry = entries[i]; + documents.push({ + name: i, + refCount: entry.refCount, + references: entry.owners.slice(0) + }); + } + documents.sort((x, y) => y.refCount - x.refCount); + return { bucket: name, documents: documents } + }); + return JSON.stringify(bucketInfoArray, null, 2); + } + + public acquireDocument( + filename: string, + compilationSettings: ts.CompilerOptions, + scriptSnapshot: IScriptSnapshot, + byteOrderMark: ts.ByteOrderMark, + version: number, + isOpen: boolean, + referencedFiles: string[]= []): Document { + + var bucket = this.getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ true); + var entry = bucket[filename]; + if (!entry) { + var document = Document.create(compilationSettings, filename, scriptSnapshot, byteOrderMark, version, isOpen, referencedFiles); + + entry = new DocumentRegistryEntry(document); + bucket[filename] = entry; + } + entry.refCount++; + + return entry.document; + } + + public updateDocument( + document: Document, + filename: string, + compilationSettings: ts.CompilerOptions, + scriptSnapshot: IScriptSnapshot, + version: number, + isOpen: boolean, + textChangeRange: TextChangeRange + ): Document { + + var bucket = this.getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ false); + Debug.assert(bucket); + var entry = bucket[filename]; + Debug.assert(entry); + + if (entry.document.isOpen === isOpen && entry.document.version === version) { + return entry.document; + } + + entry.document = entry.document.update(scriptSnapshot, version, isOpen, textChangeRange); + return entry.document; + } + + public releaseDocument(filename: string, compilationSettings: ts.CompilerOptions): void { + var bucket = this.getBucketForCompilationSettings(compilationSettings, false); + Debug.assert(bucket); + + var entry = bucket[filename]; + entry.refCount--; + + Debug.assert(entry.refCount >= 0); + if (entry.refCount === 0) { + delete bucket[filename]; + } + } + } + + export function createLanguageService(host: LanguageServiceHost, documentRegistry: IDocumentRegistry): LanguageService { + var logger: TypeScript.Logger = host; + var _syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host); + var formattingRulesProvider: Formatting.RulesProvider; + var hostCache: HostCache; // A cache of all the information about the files on the host side. + var program: ts.Program; + var typeChecker: ts.TypeChecker; + var useCaseSensitivefilenames = false; + var documentsByName: ts.Map = {}; + var documentRegistry = documentRegistry; + var cancellationToken = new CancellationToken(host.getCancellationToken()); + var activeCompletionSession: CompletionSession; + + // Check if the localized messages json is set, otherwise query the host for it + if (!TypeScript.LocalizedDiagnosticMessages) { + TypeScript.LocalizedDiagnosticMessages = host.getLocalizedDiagnosticMessages(); + } + + function createCompilerHost(): ts.CompilerHost { + return { + getSourceFile: (filename, languageVersion) => { + var document = documentsByName[filename]; + + Debug.assert(!!document, "document can not be undefined"); + + return document.sourceFile(); + }, + getCancellationToken: () => cancellationToken, + getCanonicalFileName: (filename) => useCaseSensitivefilenames ? filename : filename.toLowerCase(), + useCaseSensitiveFileNames: () => useCaseSensitivefilenames, + getNewLine: () => "\n", + // Need something that doesn't depend on sys.ts here + getDefaultLibFilename: (): string => { + throw Error("TOD:: getDefaultLibfilename"); + }, + writeFile: (filename, data) => { + throw Error("TODO: write file"); + }, + getCurrentDirectory: (): string => { + throw Error("TODO: getCurrentDirectory"); + } + }; + } + + function synchronizeHostData(): void { + // Reset the cache at start of every refresh + hostCache = new HostCache(host); + + var compilationSettings = hostCache.compilationSettings(); + + // TODO: check if we need to create a new compiler to start with + // 1. files are identical + // 2. compilation settings are identical + + // Now, remove any files from the compiler that are no longer in the host. + var oldProgram = program; + if (oldProgram) { + var oldSettings = program.getCompilerOptions(); + + // If the language version changed, then that affects what types of things we parse. So + // we have to dump all syntax trees. + // TODO: handle propagateEnumConstants + var settingsChangeAffectsSyntax = oldSettings.target !== compilationSettings.target; + + var changesInCompilationSettingsAffectSyntax = + oldSettings && compilationSettings && !compareDataObjects(oldSettings, compilationSettings) && settingsChangeAffectsSyntax; + var oldSourceFiles = program.getSourceFiles(); + + for (var i = 0, n = oldSourceFiles.length; i < n; i++) { + cancellationToken.throwIfCancellationRequested(); + var filename = oldSourceFiles[i].filename; + if (!hostCache.contains(filename) || changesInCompilationSettingsAffectSyntax) { + documentRegistry.releaseDocument(filename, oldSettings); + delete documentsByName[filename]; + } + } + } + + // Now, for every file the host knows about, either add the file (if the compiler + // doesn't know about it.). Or notify the compiler about any changes (if it does + // know about it.) + var hostfilenames = hostCache.getfilenames(); + + for (var i = 0, n = hostfilenames.length; i < n; i++) { + var filename = hostfilenames[i]; + + var version = hostCache.getVersion(filename); + var isOpen = hostCache.isOpen(filename); + var scriptSnapshot = hostCache.getScriptSnapshot(filename); + + var document: Document = documentsByName[filename]; + if (document) { + // + // If the document is the same, assume no update + // + if (document.version === version && document.isOpen === isOpen) { + continue; + } + + // Only perform incremental parsing on open files that are being edited. If a file was + // open, but is now closed, we want to reparse entirely so we don't have any tokens that + // are holding onto expensive script snapshot instances on the host. Similarly, if a + // file was closed, then we always want to reparse. This is so our tree doesn't keep + // the old buffer alive that represented the file on disk (as the host has moved to a + // new text buffer). + var textChangeRange: TextChangeRange = null; + if (document.isOpen && isOpen) { + textChangeRange = hostCache.getScriptTextChangeRangeSinceVersion(filename, document.version); + } + + document = documentRegistry.updateDocument(document, filename, compilationSettings, scriptSnapshot, version, isOpen, textChangeRange); + } + else { + document = documentRegistry.acquireDocument(filename, compilationSettings, scriptSnapshot, hostCache.getByteOrderMark(filename), version, isOpen, []); + } + + // Remeber the new document + documentsByName[filename] = document; + } + + // Now create a new compiler + program = ts.createProgram(hostfilenames, compilationSettings, createCompilerHost()); + typeChecker = program.getTypeChecker(); + } + + function dispose(): void { + if (program) { + ts.forEach(program.getSourceFiles(), + (f) => documentRegistry.releaseDocument(f.filename, program.getCompilerOptions())); + } + } + + /// Diagnostics + function getSyntacticDiagnostics(filename: string) { + synchronizeHostData(); + return program.getDiagnostics(program.getSourceFile(filename)); + } + + function getSemanticDiagnostics(filename: string) { + synchronizeHostData(); + return typeChecker.getDiagnostics(program.getSourceFile(filename)); + } + + function getCompilerOptionsDiagnostics() { + synchronizeHostData(); + return program.getGlobalDiagnostics(); + } + + /// Completion + function createCompletionEntry(symbol: ts.Symbol): CompletionEntry { + // Try to get a valid display name for this symbol, if we could not find one, then ignore it. + // We would like to only show things that can be added after a dot, so for instance numeric properties can + // not be accessed with a dot (a.1 <- invalid) + var displayName = CompletionHelpers.getValidCompletionEntryDisplayName(symbol.getName(), program.getCompilerOptions().target); + if (!displayName) { + return undefined; + } + + var declarations = symbol.getDeclarations(); + var firstDeclaration = [0]; + return { + name: displayName, + kind: getSymbolKind(symbol), + kindModifiers: declarations ? getNodeModifiers(declarations[0]) : ScriptElementKindModifier.none + }; + } + + function getCompletionsAtPosition(filename: string, position: number, isMemberCompletion: boolean) { + function getCompletionEntriesFromSymbols(symbols: ts.Symbol[], session: CompletionSession): void { + ts.forEach(symbols, (symbol) => { + var entry = createCompletionEntry(symbol); + if (entry) { + session.entries.push(entry); + session.symbols[entry.name] = symbol; + } + }); + } + + synchronizeHostData(); + + filename = TypeScript.switchToForwardSlashes(filename); + + var document = documentsByName[filename]; + var sourceUnit = document.sourceUnit(); + + if (CompletionHelpers.isCompletionListBlocker(document.syntaxTree().sourceUnit(), position)) { + logger.log("Returning an empty list because completion was blocked."); + return null; + } + + var node = TypeScript.ASTHelpers.getAstAtPosition(sourceUnit, position, /*useTrailingTriviaAsLimChar*/ true, /*forceInclusive*/ true); + + if (node && node.kind() === TypeScript.SyntaxKind.IdentifierName && + start(node) === end(node)) { + // Ignore missing name nodes + node = node.parent; + } + + var isRightOfDot = false; + if (node && + node.kind() === TypeScript.SyntaxKind.MemberAccessExpression && + end((node).expression) < position) { + + isRightOfDot = true; + node = (node).expression; + } + else if (node && + node.kind() === TypeScript.SyntaxKind.QualifiedName && + end((node).left) < position) { + + isRightOfDot = true; + node = (node).left; + } + else if (node && node.parent && + node.kind() === TypeScript.SyntaxKind.IdentifierName && + node.parent.kind() === TypeScript.SyntaxKind.MemberAccessExpression && + (node.parent).name === node) { + + isRightOfDot = true; + node = (node.parent).expression; + } + else if (node && node.parent && + node.kind() === TypeScript.SyntaxKind.IdentifierName && + node.parent.kind() === TypeScript.SyntaxKind.QualifiedName && + (node.parent).right === node) { + + isRightOfDot = true; + node = (node.parent).left; + } + + // TODO: this is a hack for now, we need a proper walking mechanism to verify that we have the correct node + var mappedNode = getNodeAtPosition(document.sourceFile(), end(node) - 1); + + Debug.assert(mappedNode, "Could not map a Fidelity node to an AST node"); + + // Get the completions + activeCompletionSession = { + filename: filename, + position: position, + entries: [], + symbols: {}, + location: mappedNode, + typeChecker: typeChecker + }; + + // Right of dot member completion list + if (isRightOfDot) { + var type: ts.Type = typeChecker.getTypeOfExpression(mappedNode); + if (!type) { + return undefined; + } + + var symbols = type.getApparentProperties(); + isMemberCompletion = true; + getCompletionEntriesFromSymbols(symbols, activeCompletionSession); + } + else { + var containingObjectLiteral = CompletionHelpers.getContainingObjectLiteralApplicableForCompletion(document.syntaxTree().sourceUnit(), position); + + // Object literal expression, look up possible property names from contextual type + if (containingObjectLiteral) { + var searchPosition = Math.min(position, end(containingObjectLiteral)); + var path = TypeScript.ASTHelpers.getAstAtPosition(sourceUnit, searchPosition); + // Get the object literal node + + while (node && node.kind() !== TypeScript.SyntaxKind.ObjectLiteralExpression) { + node = node.parent; + } + + if (!node || node.kind() !== TypeScript.SyntaxKind.ObjectLiteralExpression) { + // AST Path look up did not result in the same node as Fidelity Syntax Tree look up. + // Once we remove AST this will no longer be a problem. + return null; + } + + isMemberCompletion = true; + + //// Try to get the object members form contextual typing + //var contextualMembers = compiler.getContextualMembersFromAST(node, document); + //if (contextualMembers && contextualMembers.symbols && contextualMembers.symbols.length > 0) { + // // get existing members + // var existingMembers = compiler.getVisibleMemberSymbolsFromAST(node, document); + + // // Add filtterd items to the completion list + // getCompletionEntriesFromSymbols({ + // symbols: CompletionHelpers.filterContextualMembersList(contextualMembers.symbols, existingMembers, filename, position), + // enclosingScopeSymbol: contextualMembers.enclosingScopeSymbol + // }, entries); + //} + } + // Get scope memebers + else { + isMemberCompletion = false; + /// TODO filter meaning based on the current context + var symbolMeanings = ts.SymbolFlags.Type | ts.SymbolFlags.Value | ts.SymbolFlags.Namespace; + var symbols = typeChecker.getSymbolsInScope(mappedNode, symbolMeanings); + + getCompletionEntriesFromSymbols(symbols, activeCompletionSession); + } + } + + // Add keywords if this is not a member completion list + if (!isMemberCompletion) { + Array.prototype.push.apply(activeCompletionSession.entries, KeywordCompletions.getKeywordCompltions()); + } + + return { + isMemberCompletion: isMemberCompletion, + entries: activeCompletionSession.entries + }; + } + + function getCompletionEntryDetails(filename: string, position: number, entryName: string) { + // Note: No need to call synchronizeHostData, as we have captured all the data we need + // in the getCompletionsAtPosition erlier + filename = TypeScript.switchToForwardSlashes(filename); + + var session = activeCompletionSession; + + // Ensure that the current active completion session is still valid for this request + if (!session || session.filename !== filename || session.position !== position) { + return undefined; + } + + var symbol = activeCompletionSession.symbols[entryName]; + if (symbol) { + var type = session.typeChecker.getTypeOfSymbol(symbol); + Debug.assert(type, "Could not find type for symbol"); + var completionEntry = createCompletionEntry(symbol); + return { + name: entryName, + kind: completionEntry.kind, + kindModifiers: completionEntry.kindModifiers, + type: session.typeChecker.typeToString(type, session.location), + fullSymbolName: typeChecker.symbolToString(symbol, session.location), + docComment: "" + }; + } + else { + // No symbol, it is a keyword + return { + name: entryName, + kind: ScriptElementKind.keyword, + kindModifiers: ScriptElementKindModifier.none, + type: undefined, + fullSymbolName: entryName, + docComment: undefined + }; + } + } + + function getNodeAtPosition(sourceFile: ts.SourceFile, position: number) { + var current: ts.Node = sourceFile; + outer: while (true) { + // find the child that has this + for (var i = 0, n = current.getChildCount(); i < n; i++) { + var child = current.getChildAt(i); + if (ts.getTokenPosOfNode(child) <= position && position < child.end) { + current = child; + continue outer; + } + if (child.end > position) break; + } + return current; + } + } + + function getEnclosingDeclaration(node: ts.Node): ts.Node { + while (true) { + node = node.parent; + if (!node) { + return node; + } + switch (node.kind) { + case ts.SyntaxKind.Method: + case ts.SyntaxKind.FunctionDeclaration: + case ts.SyntaxKind.FunctionExpression: + case ts.SyntaxKind.GetAccessor: + case ts.SyntaxKind.SetAccessor: + case ts.SyntaxKind.ClassDeclaration: + case ts.SyntaxKind.InterfaceDeclaration: + case ts.SyntaxKind.EnumDeclaration: + case ts.SyntaxKind.ModuleDeclaration: + return node; + } + } + } + + function getSymbolKind(symbol: ts.Symbol): string { + var flags = symbol.getFlags(); + + if (flags & ts.SymbolFlags.Module) return ScriptElementKind.moduleElement; + if (flags & ts.SymbolFlags.Class) return ScriptElementKind.classElement; + if (flags & ts.SymbolFlags.Interface) return ScriptElementKind.interfaceElement; + if (flags & ts.SymbolFlags.Enum) return ScriptElementKind.enumElement; + if (flags & ts.SymbolFlags.Variable) return ScriptElementKind.variableElement; + if (flags & ts.SymbolFlags.Function) return ScriptElementKind.functionElement; + if (flags & ts.SymbolFlags.GetAccessor) return ScriptElementKind.memberGetAccessorElement; + if (flags & ts.SymbolFlags.SetAccessor) return ScriptElementKind.memberSetAccessorElement; + if (flags & ts.SymbolFlags.Method) return ScriptElementKind.memberFunctionElement; + if (flags & ts.SymbolFlags.Property) return ScriptElementKind.memberVariableElement; + if (flags & ts.SymbolFlags.IndexSignature) return ScriptElementKind.indexSignatureElement; + if (flags & ts.SymbolFlags.ConstructSignature) return ScriptElementKind.constructSignatureElement; + if (flags & ts.SymbolFlags.CallSignature) return ScriptElementKind.callSignatureElement; + if (flags & ts.SymbolFlags.Constructor) return ScriptElementKind.constructorImplementationElement; + if (flags & ts.SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; + if (flags & ts.SymbolFlags.EnumMember) return ScriptElementKind.variableElement; + + return ScriptElementKind.unknown; + } + + function getTypeKind(type: ts.Type): string { + var flags = type.getFlags(); + + if (flags & ts.TypeFlags.Enum) return ScriptElementKind.enumElement; + if (flags & ts.TypeFlags.Class) return ScriptElementKind.classElement; + if (flags & ts.TypeFlags.Interface) return ScriptElementKind.interfaceElement; + if (flags & ts.TypeFlags.TypeParameter) return ScriptElementKind.typeParameterElement; + if (flags & ts.TypeFlags.Intrinsic) return ScriptElementKind.primitiveType; + if (flags & ts.TypeFlags.StringLiteral) return ScriptElementKind.primitiveType; + + return ScriptElementKind.unknown; + } + + function getNodeModifiers(node: ts.Node): string { + var flags = node.flags; + var result: string[] = []; + + if (flags & ts.NodeFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier); + if (flags & ts.NodeFlags.Public) result.push(ScriptElementKindModifier.publicMemberModifier); + if (flags & ts.NodeFlags.Static) result.push(ScriptElementKindModifier.staticModifier); + if (flags & ts.NodeFlags.Export) result.push(ScriptElementKindModifier.exportedModifier); + if (ts.isInAmbientContext(node)) result.push(ScriptElementKindModifier.ambientModifier); + + return result.length > 0 ? result.join(',') : ScriptElementKindModifier.none; + } + + /// QuickInfo + function getTypeAtPosition(filename: string, position: number): TypeInfo { + synchronizeHostData(); + + filename = TypeScript.switchToForwardSlashes(filename); + var document = documentsByName[filename]; + var node = getNodeAtPosition(document.sourceFile(), position); + if (!node) return undefined; + + switch (node.kind) { + // A declaration + case ts.SyntaxKind.Identifier: + if (node.parent.kind === ts.SyntaxKind.CallExpression || node.parent.kind === ts.SyntaxKind.NewExpression) { + // TODO: handle new and call expressions + } + + var symbol = typeChecker.getSymbolOfIdentifier(node); + Debug.assert(symbol, "getTypeAtPosition: Could not find symbol for node"); + var type = typeChecker.getTypeOfSymbol(symbol); + + return { + memberName: new MemberNameString(typeChecker.typeToString(type)), + docComment: "", + fullSymbolName: typeChecker.symbolToString(symbol, getEnclosingDeclaration(node)), + kind: getSymbolKind(symbol), + minChar: node.pos, + limChar: node.end + }; + + // An Expression + case ts.SyntaxKind.ThisKeyword: + case ts.SyntaxKind.QualifiedName: + case ts.SyntaxKind.SuperKeyword: + case ts.SyntaxKind.StringLiteral: + var type = typeChecker.getTypeOfExpression(node); + Debug.assert(type, "getTypeAtPosition: Could not find type for node"); + return { + memberName: new MemberNameString(""), + docComment: "", + fullSymbolName: typeChecker.typeToString(type, getEnclosingDeclaration(node)), + kind: getTypeKind(type), + minChar: node.pos, + limChar: node.end + }; + break; + } + } + + /// Syntactic features + function getSyntaxTree(filename: string): TypeScript.SyntaxTree { + filename = TypeScript.switchToForwardSlashes(filename); + return _syntaxTreeCache.getCurrentFileSyntaxTree(filename); + } + + function getNameOrDottedNameSpan(filename: string, startPos: number, endPos: number): SpanInfo { + function getTypeInfoEligiblePath(filename: string, position: number, isConstructorValidPosition: boolean) { + var sourceUnit = _syntaxTreeCache.getCurrentFileSyntaxTree(filename).sourceUnit(); + + var ast = TypeScript.ASTHelpers.getAstAtPosition(sourceUnit, position, /*useTrailingTriviaAsLimChar*/ false, /*forceInclusive*/ true); + if (ast === null) { + return null; + } + + if (ast.kind() === SyntaxKind.ParameterList && ast.parent.kind() === SyntaxKind.CallSignature && ast.parent.parent.kind() === SyntaxKind.ConstructorDeclaration) { + ast = ast.parent.parent; + } + + switch (ast.kind()) { + default: + return null; + case TypeScript.SyntaxKind.ConstructorDeclaration: + var constructorAST = ast; + if (!isConstructorValidPosition || !(position >= start(constructorAST) && position <= start(constructorAST) + "constructor".length)) { + return null; + } + else { + return ast; + } + case TypeScript.SyntaxKind.FunctionDeclaration: + return null; + case TypeScript.SyntaxKind.MemberAccessExpression: + case TypeScript.SyntaxKind.QualifiedName: + case TypeScript.SyntaxKind.SuperKeyword: + case TypeScript.SyntaxKind.StringLiteral: + case TypeScript.SyntaxKind.ThisKeyword: + case TypeScript.SyntaxKind.IdentifierName: + return ast; + } + } + + filename = TypeScript.switchToForwardSlashes(filename); + + var node = getTypeInfoEligiblePath(filename, startPos, false); + if (!node) return null; + + while (node) { + if (TypeScript.ASTHelpers.isNameOfMemberAccessExpression(node) || + TypeScript.ASTHelpers.isRightSideOfQualifiedName(node)) { + node = node.parent; + } + else { + break; + } + } + + return { + minChar: start(node), + limChar: end(node) + }; + } + + function getBreakpointStatementAtPosition(filename: string, position: number) { + // doesn't use compiler - no need to synchronize with host + filename = TypeScript.switchToForwardSlashes(filename); + + var syntaxtree = getSyntaxTree(filename); + return TypeScript.Services.Breakpoints.getBreakpointLocation(syntaxtree, position); + } + + function getScriptLexicalStructure(filename: string) { + filename = TypeScript.switchToForwardSlashes(filename); + var syntaxTree = getSyntaxTree(filename); + var items: NavigateToItem[] = []; + GetScriptLexicalStructureWalker.getListsOfAllScriptLexicalStructure(items, filename, syntaxTree.sourceUnit()); + return items; + } + + function getOutliningRegions(filename: string) { + // doesn't use compiler - no need to synchronize with host + filename = TypeScript.switchToForwardSlashes(filename); + var syntaxTree = getSyntaxTree(filename); + return OutliningElementsCollector.collectElements(syntaxTree.sourceUnit()); + } + + function getBraceMatchingAtPosition(filename: string, position: number) { + filename = TypeScript.switchToForwardSlashes(filename); + var syntaxTree = getSyntaxTree(filename); + return BraceMatcher.getMatchSpans(syntaxTree, position); + } + + function getIndentationAtPosition(filename: string, position: number, editorOptions: EditorOptions) { + filename = TypeScript.switchToForwardSlashes(filename); + + var syntaxTree = getSyntaxTree(filename); + + var scriptSnapshot = _syntaxTreeCache.getCurrentScriptSnapshot(filename); + var scriptText = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot); + var textSnapshot = new TypeScript.Services.Formatting.TextSnapshot(scriptText); + var options = new FormattingOptions(!editorOptions.ConvertTabsToSpaces, editorOptions.TabSize, editorOptions.IndentSize, editorOptions.NewLineCharacter) + + return TypeScript.Services.Formatting.SingleTokenIndenter.getIndentationAmount(position, syntaxTree.sourceUnit(), textSnapshot, options); + } + + function getFormattingManager(filename: string, options: FormatCodeOptions) { + // Ensure rules are initialized and up to date wrt to formatting options + if (formattingRulesProvider == null) { + formattingRulesProvider = new TypeScript.Services.Formatting.RulesProvider(logger); + } + + formattingRulesProvider.ensureUpToDate(options); + + // Get the Syntax Tree + var syntaxTree = getSyntaxTree(filename); + + // Convert IScriptSnapshot to ITextSnapshot + var scriptSnapshot = _syntaxTreeCache.getCurrentScriptSnapshot(filename); + var scriptText = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot); + var textSnapshot = new TypeScript.Services.Formatting.TextSnapshot(scriptText); + + var manager = new TypeScript.Services.Formatting.FormattingManager(syntaxTree, textSnapshot, formattingRulesProvider, options); + + return manager; + } + + function getFormattingEditsForRange(filename: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[] { + filename = TypeScript.switchToForwardSlashes(filename); + + var manager = getFormattingManager(filename, options); + return manager.formatSelection(minChar, limChar); + } + + function getFormattingEditsForDocument(filename: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[] { + filename = TypeScript.switchToForwardSlashes(filename); + + var manager = getFormattingManager(filename, options); + return manager.formatDocument(minChar, limChar); + } + + function getFormattingEditsOnPaste(filename: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[] { + filename = TypeScript.switchToForwardSlashes(filename); + + var manager = getFormattingManager(filename, options); + return manager.formatOnPaste(minChar, limChar); + } + + function getFormattingEditsAfterKeystroke(filename: string, position: number, key: string, options: FormatCodeOptions): TextEdit[] { + filename = TypeScript.switchToForwardSlashes(filename); + + var manager = getFormattingManager(filename, options); + if (key === "}") return manager.formatOnClosingCurlyBrace(position); + else if (key === ";") return manager.formatOnSemicolon(position); + else if (key === "\n") return manager.formatOnEnter(position); + else return []; + } + + + return { + dispose: dispose, + refresh: () => { }, + cleanupSemanticCache: () => { }, + getSyntacticDiagnostics: getSyntacticDiagnostics, + getSemanticDiagnostics: getSemanticDiagnostics, + getCompilerOptionsDiagnostics: getCompilerOptionsDiagnostics, + getCompletionsAtPosition: getCompletionsAtPosition, + getCompletionEntryDetails: getCompletionEntryDetails, + getTypeAtPosition: getTypeAtPosition, + getSignatureAtPosition: (filename, position) => undefined, + getDefinitionAtPosition: (filename, position) => [], + getReferencesAtPosition: (filename, position) => [], + getOccurrencesAtPosition: (filename, position) => [], + getImplementorsAtPosition: (filename, position) => [], + getNameOrDottedNameSpan: getNameOrDottedNameSpan, + getBreakpointStatementAtPosition: getBreakpointStatementAtPosition, + getNavigateToItems: (searchValue) => [], + getScriptLexicalStructure: getScriptLexicalStructure, + getOutliningRegions: getOutliningRegions, + getBraceMatchingAtPosition: getBraceMatchingAtPosition, + getIndentationAtPosition: getIndentationAtPosition, + getFormattingEditsForRange: getFormattingEditsForRange, + getFormattingEditsForDocument: getFormattingEditsForDocument, + getFormattingEditsOnPaste: getFormattingEditsOnPaste, + getFormattingEditsAfterKeystroke: getFormattingEditsAfterKeystroke, + getEmitOutput: (filename) => undefined, + }; + } +} \ No newline at end of file diff --git a/src/services/typescriptServices.ts b/src/services/typescriptServices.ts index d4af024bd31..249afeaf9b9 100644 --- a/src/services/typescriptServices.ts +++ b/src/services/typescriptServices.ts @@ -20,32 +20,14 @@ /// /// -/// - -/// -/// -/// /// -/// -/// -/// -/// -/// -/// -/// -/// - - -/// /// /// -/// /// /// /// /// -/// /// /// /// From bfdf2ac69a8cf043aa76d3e8a0955fa0dbe6e604 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 24 Jul 2014 15:33:59 -0700 Subject: [PATCH 30/59] remove some more unused files --- src/services/compiler/precompile.ts | 16 +- src/services/compiler/referenceResolution.ts | 32 --- src/services/compiler/referenceResolver.ts | 255 ------------------- src/services/formatting/formatting.ts | 2 +- src/services/services.ts | 15 +- src/services/shims.ts | 5 +- src/services/typescriptServices.ts | 38 --- 7 files changed, 33 insertions(+), 330 deletions(-) delete mode 100644 src/services/compiler/referenceResolution.ts delete mode 100644 src/services/compiler/referenceResolver.ts delete mode 100644 src/services/typescriptServices.ts diff --git a/src/services/compiler/precompile.ts b/src/services/compiler/precompile.ts index 5c03b1f0a06..a45ea5134a1 100644 --- a/src/services/compiler/precompile.ts +++ b/src/services/compiler/precompile.ts @@ -13,9 +13,21 @@ // limitations under the License. // -/// - module TypeScript { + export interface ILineAndCharacter { + line: number; + character: number; + } + + // Note: This is being using by the host (VS) and is marshaled back and forth. When changing this make sure the changes + // are reflected in the managed side as well. + export interface IFileReference extends ILineAndCharacter { + path: string; + isResident: boolean; + position: number; + length: number; + } + /// /// Preprocessing /// diff --git a/src/services/compiler/referenceResolution.ts b/src/services/compiler/referenceResolution.ts deleted file mode 100644 index 528347a6ea8..00000000000 --- a/src/services/compiler/referenceResolution.ts +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -/// - -module TypeScript { - export interface ILineAndCharacter { - line: number; - character: number; - } - - // Note: This is being using by the host (VS) and is marshaled back and forth. When changing this make sure the changes - // are reflected in the managed side as well. - export interface IFileReference extends ILineAndCharacter { - path: string; - isResident: boolean; - position: number; - length: number; - } -} \ No newline at end of file diff --git a/src/services/compiler/referenceResolver.ts b/src/services/compiler/referenceResolver.ts deleted file mode 100644 index b67d65ead6d..00000000000 --- a/src/services/compiler/referenceResolver.ts +++ /dev/null @@ -1,255 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -/// - -module TypeScript { - export interface IResolvedFile { - path: string; - referencedFiles: string[]; - importedFiles: string[]; - } - - export interface IReferenceResolverHost { - getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot; - resolveRelativePath(path: string, directory: string): string; - fileExists(path: string): boolean; - directoryExists(path: string): boolean; - getParentDirectory(path: string): string; - } - - export class ReferenceResolutionResult { - resolvedFiles: IResolvedFile[] = []; - diagnostics: TypeScript.Diagnostic[] = []; - seenNoDefaultLibTag: boolean = false; - } - - class ReferenceLocation { - constructor(public filePath: string, public lineMap: LineMap, public position: number, public length: number, public isImported: boolean) { - } - } - - export class ReferenceResolver { - private inputFileNames: string[]; - private host: IReferenceResolverHost; - private visited: ts.Map; - - constructor(inputFileNames: string[], host: IReferenceResolverHost, private useCaseSensitiveFileResolution: boolean) { - this.inputFileNames = inputFileNames; - this.host = host; - this.visited = {}; - } - - public static resolve(inputFileNames: string[], host: IReferenceResolverHost, useCaseSensitiveFileResolution: boolean): ReferenceResolutionResult { - var resolver = new ReferenceResolver(inputFileNames, host, useCaseSensitiveFileResolution); - return resolver.resolveInputFiles(); - } - - public resolveInputFiles(): ReferenceResolutionResult { - var result = new ReferenceResolutionResult(); - - if (!this.inputFileNames || this.inputFileNames.length <= 0) { - // Nothing to do. - return result; - } - - // Loop over the files and extract references - var referenceLocation = new ReferenceLocation(null, null, 0, 0, false); - this.inputFileNames.forEach(fileName => - this.resolveIncludedFile(fileName, referenceLocation, result)); - - return result; - } - - private resolveIncludedFile(path: string, referenceLocation: ReferenceLocation, resolutionResult: ReferenceResolutionResult): string { - var normalizedPath = this.getNormalizedFilePath(path, referenceLocation.filePath); - - if (this.isSameFile(normalizedPath, referenceLocation.filePath)) { - // Cannot reference self - if (!referenceLocation.isImported) { - resolutionResult.diagnostics.push( - new TypeScript.Diagnostic(referenceLocation.filePath, referenceLocation.lineMap, - referenceLocation.position, referenceLocation.length, DiagnosticCode.A_file_cannot_have_a_reference_to_itself, null)); - } - - return normalizedPath; - } - - if (!isTSFile(normalizedPath) && !isDTSFile(normalizedPath)) { - var dtsFile = normalizedPath + ".d.ts"; - var tsFile = normalizedPath + ".ts"; - - if (this.host.fileExists(tsFile)) { - normalizedPath = tsFile; - } - else { - normalizedPath = dtsFile; - } - } - - if (!this.host.fileExists(normalizedPath)) { - if (!referenceLocation.isImported) { - resolutionResult.diagnostics.push( - new TypeScript.Diagnostic(referenceLocation.filePath, referenceLocation.lineMap, - referenceLocation.position, referenceLocation.length, DiagnosticCode.Cannot_resolve_referenced_file_0, [path])); - } - - return normalizedPath; - } - - // Preprocess the file and resolve its imports/references - return this.resolveFile(normalizedPath, resolutionResult); - } - - private resolveImportedFile(path: string, referenceLocation: ReferenceLocation, resolutionResult: ReferenceResolutionResult): string { - var isRelativePath = TypeScript.isRelative(path); - var isRootedPath = isRelativePath ? false : isRooted(path); - - if (isRelativePath || isRootedPath) { - // Handle as a normal include file - return this.resolveIncludedFile(path, referenceLocation, resolutionResult); - } - else { - // Search for the file - var parentDirectory = this.host.getParentDirectory(referenceLocation.filePath); - var searchFilePath: string = null; - var dtsFileName = path + ".d.ts"; - var tsFilePath = path + ".ts"; - - var start = new Date().getTime(); - - // SPEC: Nov 18 - // An external import declaration that specifies a relative external module name (section 11.2.1) resolves the name - // relative to the directory of the containing source file. - // If a source file with the resulting path and file extension '.ts' exists, that file is added as a dependency. - // Otherwise, if a source file with the resulting path and file extension '.d.ts' exists, that file is added as a dependency. - do { - // Search for ".ts" file first - currentFilePath = this.host.resolveRelativePath(tsFilePath, parentDirectory); - if (this.host.fileExists(currentFilePath)) { - // Found the file - searchFilePath = currentFilePath; - break; - } - - // Search for ".d.ts" file - var currentFilePath = this.host.resolveRelativePath(dtsFileName, parentDirectory); - if (this.host.fileExists(currentFilePath)) { - // Found the file - searchFilePath = currentFilePath; - break; - } - - parentDirectory = this.host.getParentDirectory(parentDirectory); - } - while (parentDirectory); - - //TypeScript.fileResolutionImportFileSearchTime += new Date().getTime() - start; - - if (!searchFilePath) { - // Cannot find file import, do not reprot an error, the typeChecker will report it later on - return path; - } - - // Preprocess the file and resolve its imports/references - return this.resolveFile(searchFilePath, resolutionResult); - } - } - - private resolveFile(normalizedPath: string, resolutionResult: ReferenceResolutionResult): string { - // If we have processed this file before, skip it - var visitedPath = this.isVisited(normalizedPath); - if (!visitedPath) { - // Record that we have seen it - this.recordVisitedFile(normalizedPath); - - // Preprocess the file - var start = new Date().getTime(); - var scriptSnapshot = this.host.getScriptSnapshot(normalizedPath); - var totalTime = new Date().getTime() - start; - //TypeScript.fileResolutionIOTime += totalTime; - - var lineMap = LineMap1.fromScriptSnapshot(scriptSnapshot); - var preprocessedFileInformation = TypeScript.preProcessFile(normalizedPath, scriptSnapshot); - resolutionResult.diagnostics.push.apply(resolutionResult.diagnostics, preprocessedFileInformation.diagnostics); - - // If this file has a "no-default-lib = 'true'" tag - if (preprocessedFileInformation.isLibFile) { - resolutionResult.seenNoDefaultLibTag = true; - } - - // Resolve explicit references - var normalizedReferencePaths: string[] = []; - preprocessedFileInformation.referencedFiles.forEach(fileReference => { - var currentReferenceLocation = new ReferenceLocation(normalizedPath, lineMap, fileReference.position, fileReference.length, /* isImported */ false); - var normalizedReferencePath = this.resolveIncludedFile(fileReference.path, currentReferenceLocation, resolutionResult); - normalizedReferencePaths.push(normalizedReferencePath); - }); - - // Resolve imports - var normalizedImportPaths: string[] = []; - for (var i = 0; i < preprocessedFileInformation.importedFiles.length; i++) { - var fileImport = preprocessedFileInformation.importedFiles[i]; - var currentReferenceLocation = new ReferenceLocation(normalizedPath, lineMap, fileImport.position, fileImport.length, /* isImported */ true); - var normalizedImportPath = this.resolveImportedFile(fileImport.path, currentReferenceLocation, resolutionResult); - normalizedImportPaths.push(normalizedImportPath); - } - - // Add the file to the result list - resolutionResult.resolvedFiles.push({ - path: normalizedPath, - referencedFiles: normalizedReferencePaths, - importedFiles: normalizedImportPaths - }); - } - else { - normalizedPath = visitedPath; - } - - return normalizedPath; - } - - private getNormalizedFilePath(path: string, parentFilePath: string): string { - var parentFileDirectory = parentFilePath ? this.host.getParentDirectory(parentFilePath) : ""; - var normalizedPath = this.host.resolveRelativePath(path, parentFileDirectory); - return normalizedPath; - } - - private getUniqueFileId(filePath: string): string { - return this.useCaseSensitiveFileResolution ? filePath : filePath.toLocaleUpperCase(); - } - - private recordVisitedFile(filePath: string): void { - this.visited[this.getUniqueFileId(filePath)] = filePath; - } - - private isVisited(filePath: string): string { - return this.visited[this.getUniqueFileId(filePath)]; - } - - private isSameFile(filePath1: string, filePath2: string): boolean { - if (!filePath1 || !filePath2) { - return false; - } - - if (this.useCaseSensitiveFileResolution) { - return filePath1 === filePath2; - } - else { - return filePath1.toLocaleUpperCase() === filePath2.toLocaleUpperCase(); - } - } - } -} \ No newline at end of file diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index d8e510b13a6..c334e1864ab 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -13,7 +13,7 @@ // limitations under the License. // -/// +/// /// /// /// diff --git a/src/services/services.ts b/src/services/services.ts index 4d6dbd1c058..23f1bdd8a14 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -13,6 +13,19 @@ /// /// /// +/// + +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// module ts { @@ -450,7 +463,7 @@ module TypeScript.Services { // // Public interface of the host of a language service instance. // - export interface LanguageServiceHost extends TypeScript.Logger, TypeScript.IReferenceResolverHost { + export interface LanguageServiceHost extends TypeScript.Logger { getCompilationSettings(): ts.CompilerOptions; getScriptFileNames(): string[]; getScriptVersion(fileName: string): number; diff --git a/src/services/shims.ts b/src/services/shims.ts index de49c57687f..0df08322731 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -13,7 +13,10 @@ // limitations under the License. // -/// +/// + +/// +/// var debugObjectHost = (this); module TypeScript.Services { export interface IScriptSnapshotShim { diff --git a/src/services/typescriptServices.ts b/src/services/typescriptServices.ts deleted file mode 100644 index 249afeaf9b9..00000000000 --- a/src/services/typescriptServices.ts +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -/// - -/// -/// -/// -/// - -/// - -/// -/// -/// -/// -/// -/// -/// -/// -/// -/// - - -/// - From 792f9c9ac805912b267e9d5ff1bf4e7740f543f0 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 24 Jul 2014 15:42:04 -0700 Subject: [PATCH 31/59] reorganize definitions --- src/services/services.ts | 683 +++++++++++++++++++-------------------- 1 file changed, 338 insertions(+), 345 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 23f1bdd8a14..2a950f8fc89 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -303,160 +303,6 @@ module ts { initializeServices(); } -module TypeScript.Services { - export interface IncrementalParse { - (oldSyntaxTree: SyntaxTree, textChangeRange: TextChangeRange, newText: ISimpleText): SyntaxTree - } - - - export class Document { - private _bloomFilter: BloomFilter = null; - - // By default, our Document class doesn't support incremental update of its contents. - // However, we enable other layers (like teh services layer) to inject the capability - // into us by setting this function. - public static incrementalParse: IncrementalParse = null; - - constructor(private compilationSettings: ts.CompilerOptions, - public filename: string, - public referencedFiles: string[], - private _scriptSnapshot: IScriptSnapshot, - public byteOrderMark: ts.ByteOrderMark, - public version: number, - public isOpen: boolean, - private _syntaxTree: SyntaxTree, - private _soruceFile: ts.SourceFile) { - } - - public isDeclareFile(): boolean { - return isDTSFile(this.filename); - } - - public sourceUnit(): SourceUnitSyntax { - // If we don't have a script, create one from our parse tree. - return this.syntaxTree().sourceUnit(); - } - - public diagnostics(): Diagnostic[] { - return this.syntaxTree().diagnostics(); - } - - public lineMap(): LineMap { - return this.syntaxTree().lineMap(); - } - - public syntaxTree(): SyntaxTree { - if (!this._syntaxTree) { - var start = new Date().getTime(); - - this._syntaxTree = Parser.parse( - this.filename, SimpleText.fromScriptSnapshot(this._scriptSnapshot), this.compilationSettings.target, this.isDeclareFile()); - - var time = new Date().getTime() - start; - - //TypeScript.syntaxTreeParseTime += time; - } - - return this._syntaxTree; - } - - public sourceFile(): ts.SourceFile { - if (!this._soruceFile) { - var start = new Date().getTime(); - - this._soruceFile = ts.createSourceFile(this.filename, this._scriptSnapshot.getText(0, this._scriptSnapshot.getLength()), this.compilationSettings.target); - - var time = new Date().getTime() - start; - - //TypeScript.astParseTime += time; - } - - return this._soruceFile; - } - - public bloomFilter(): BloomFilter { - if (!this._bloomFilter) { - var identifiers = createIntrinsicsObject(); - var pre = function (cur: TypeScript.ISyntaxElement) { - if (ASTHelpers.isValidAstNode(cur)) { - if (cur.kind() === SyntaxKind.IdentifierName) { - var nodeText = tokenValueText((cur)); - - identifiers[nodeText] = true; - } - } - }; - - TypeScript.getAstWalkerFactory().simpleWalk(this.sourceUnit(), pre, null, identifiers); - - var identifierCount = 0; - for (var name in identifiers) { - if (identifiers[name]) { - identifierCount++; - } - } - - this._bloomFilter = new BloomFilter(identifierCount); - this._bloomFilter.addKeys(identifiers); - } - return this._bloomFilter; - } - - // Returns true if this file should get emitted into its own unique output file. - // Otherwise, it should be written into a single output file along with the rest of hte - // documents in the compilation. - public emitToOwnOutputFile(): boolean { - // If we haven't specified an output file in our settings, then we're definitely - // emitting to our own file. Also, if we're an external module, then we're - // definitely emitting to our own file. - return !this.compilationSettings.out || this.syntaxTree().isExternalModule(); - } - - public update(scriptSnapshot: IScriptSnapshot, version: number, isOpen: boolean, textChangeRange: TextChangeRange): Document { - // See if we are currently holding onto a syntax tree. We may not be because we're - // either a closed file, or we've just been lazy and haven't had to create the syntax - // tree yet. Access the field instead of the method so we don't accidently realize - // the old syntax tree. - var oldSyntaxTree = this._syntaxTree; - - if (textChangeRange !== null && Debug.shouldAssert(AssertionLevel.Normal)) { - var oldText = this._scriptSnapshot; - var newText = scriptSnapshot; - - TypeScript.Debug.assert((oldText.getLength() - textChangeRange.span().length() + textChangeRange.newLength()) === newText.getLength()); - - if (Debug.shouldAssert(AssertionLevel.VeryAggressive)) { - var oldTextPrefix = oldText.getText(0, textChangeRange.span().start()); - var newTextPrefix = newText.getText(0, textChangeRange.span().start()); - TypeScript.Debug.assert(oldTextPrefix === newTextPrefix); - - var oldTextSuffix = oldText.getText(textChangeRange.span().end(), oldText.getLength()); - var newTextSuffix = newText.getText(textChangeRange.newSpan().end(), newText.getLength()); - TypeScript.Debug.assert(oldTextSuffix === newTextSuffix); - } - } - - var text = SimpleText.fromScriptSnapshot(scriptSnapshot); - - // If we don't have a text change, or we don't have an old syntax tree, then do a full - // parse. Otherwise, do an incremental parse. - var newSyntaxTree = textChangeRange === null || oldSyntaxTree === null || Document.incrementalParse === null - ? TypeScript.Parser.parse(this.filename, text, this.compilationSettings.target, TypeScript.isDTSFile(this.filename)) - : Document.incrementalParse(oldSyntaxTree, textChangeRange, text); - - return new Document(this.compilationSettings, this.filename, this.referencedFiles, scriptSnapshot, this.byteOrderMark, version, isOpen, newSyntaxTree, /*soruceFile*/ null); - } - - public static create(compilationSettings: ts.CompilerOptions, fileName: string, scriptSnapshot: IScriptSnapshot, byteOrderMark: ts.ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]): Document { - return new Document(compilationSettings, fileName, referencedFiles, scriptSnapshot, byteOrderMark, version, isOpen, /*syntaxTree:*/ null, /*soruceFile*/ null); - } - } -} - -module TypeScript.Services { - // Inject support for incremental parsing to the core compiler Document class. - Document.incrementalParse = IncrementalParser.parse; -} module TypeScript.Services { @@ -708,6 +554,62 @@ module TypeScript.Services { sourceMapOutput: any; } + export enum EndOfLineState { + Start, + InMultiLineCommentTrivia, + InSingleQuoteStringLiteral, + InDoubleQuoteStringLiteral, + } + + export enum TokenClass { + Punctuation, + Keyword, + Operator, + Comment, + Whitespace, + Identifier, + NumberLiteral, + StringLiteral, + RegExpLiteral, + } + + export interface ClassificationResult { + finalLexState: EndOfLineState; + entries: ClassificationInfo[]; + } + + export interface ClassificationInfo { + length: number; + classification: TokenClass; + } + + export interface Classifier { + getClassificationsForLine(text: string, lexState: EndOfLineState): ClassificationResult; + } + + export interface IDocumentRegistry { + acquireDocument( + filename: string, + compilationSettings: ts.CompilerOptions, + scriptSnapshot: IScriptSnapshot, + byteOrderMark: ts.ByteOrderMark, + version: number, + isOpen: boolean, + referencedFiles: string[]): Document; + + updateDocument( + document: Document, + filename: string, + compilationSettings: ts.CompilerOptions, + scriptSnapshot: IScriptSnapshot, + version: number, + isOpen: boolean, + textChangeRange: TextChangeRange + ): Document; + + releaseDocument(filename: string, compilationSettings: ts.CompilerOptions): void + } + // TODO: move these to enums export class ScriptElementKind { static unknown = ""; @@ -797,192 +699,156 @@ module TypeScript.Services { static warning = "warning"; static message = "message"; } -} -module TypeScript.Services { - export enum EndOfLineState { - Start, - InMultiLineCommentTrivia, - InSingleQuoteStringLiteral, - InDoubleQuoteStringLiteral, + interface IncrementalParse { + (oldSyntaxTree: SyntaxTree, textChangeRange: TextChangeRange, newText: ISimpleText): SyntaxTree } - export enum TokenClass { - Punctuation, - Keyword, - Operator, - Comment, - Whitespace, - Identifier, - NumberLiteral, - StringLiteral, - RegExpLiteral, - } + export class Document { + private _bloomFilter: BloomFilter = null; - export interface ClassificationResult { - finalLexState: EndOfLineState; - entries: ClassificationInfo[]; - } + // By default, our Document class doesn't support incremental update of its contents. + // However, we enable other layers (like teh services layer) to inject the capability + // into us by setting this function. + public static incrementalParse: IncrementalParse = IncrementalParser.parse; - export interface ClassificationInfo { - length: number; - classification: TokenClass; - } - - export interface Classifier { - getClassificationsForLine(text: string, lexState: EndOfLineState): ClassificationResult; - } - - export function createClassifier(host: Logger): Classifier { - var scanner: TypeScript.Scanner.IScanner; - var lastDiagnosticKey: string = null; - var noRegexTable: boolean[]; - var reportDiagnostic = (position: number, fullWidth: number, key: string, args: any[]) => { - lastDiagnosticKey = key; - }; - - if (!noRegexTable) { - noRegexTable = []; - noRegexTable[TypeScript.SyntaxKind.IdentifierName] = true; - noRegexTable[TypeScript.SyntaxKind.StringLiteral] = true; - noRegexTable[TypeScript.SyntaxKind.NumericLiteral] = true; - noRegexTable[TypeScript.SyntaxKind.RegularExpressionLiteral] = true; - noRegexTable[TypeScript.SyntaxKind.ThisKeyword] = true; - noRegexTable[TypeScript.SyntaxKind.PlusPlusToken] = true; - noRegexTable[TypeScript.SyntaxKind.MinusMinusToken] = true; - noRegexTable[TypeScript.SyntaxKind.CloseParenToken] = true; - noRegexTable[TypeScript.SyntaxKind.CloseBracketToken] = true; - noRegexTable[TypeScript.SyntaxKind.CloseBraceToken] = true; - noRegexTable[TypeScript.SyntaxKind.TrueKeyword] = true; - noRegexTable[TypeScript.SyntaxKind.FalseKeyword] = true; + constructor(private compilationSettings: ts.CompilerOptions, + public filename: string, + public referencedFiles: string[], + private _scriptSnapshot: IScriptSnapshot, + public byteOrderMark: ts.ByteOrderMark, + public version: number, + public isOpen: boolean, + private _syntaxTree: SyntaxTree, + private _soruceFile: ts.SourceFile) { } - function getClassificationsForLine(text: string, lexState: EndOfLineState): ClassificationResult { - var offset = 0; - if (lexState !== EndOfLineState.Start) { - // If we're in a string literal, then prepend: "\ - // (and a newline). That way when we lex we'll think we're still in a string literal. - // - // If we're in a multiline comment, then prepend: /* - // (and a newline). That way when we lex we'll think we're still in a multiline comment. - if (lexState === EndOfLineState.InDoubleQuoteStringLiteral) { - text = '"\\\n' + text; - } - else if (lexState === EndOfLineState.InSingleQuoteStringLiteral) { - text = "'\\\n" + text; - } - else if (lexState === EndOfLineState.InMultiLineCommentTrivia) { - text = "/*\n" + text; - } - - offset = 3; - } - - var result = { - finalLexState: EndOfLineState.Start, - entries: [] - }; - - var simpleText = TypeScript.SimpleText.fromString(text); - scanner = Scanner.createScanner(ts.ScriptTarget.ES5, simpleText, reportDiagnostic); - - var lastTokenKind = TypeScript.SyntaxKind.None; - var token: ISyntaxToken = null; - do { - lastDiagnosticKey = null; - - token = scanner.scan(!noRegexTable[lastTokenKind]); - lastTokenKind = token.kind(); - - processToken(text, simpleText, offset, token, result); - } - while (token.kind() !== SyntaxKind.EndOfFileToken); - - lastDiagnosticKey = null; - return result; + public isDeclareFile(): boolean { + return isDTSFile(this.filename); } - function processToken(text: string, simpleText: ISimpleText, offset: number, token: TypeScript.ISyntaxToken, result: ClassificationResult): void { - processTriviaList(text, offset, token.leadingTrivia(simpleText), result); - addResult(text, offset, result, width(token), token.kind()); - processTriviaList(text, offset, token.trailingTrivia(simpleText), result); + public sourceUnit(): SourceUnitSyntax { + // If we don't have a script, create one from our parse tree. + return this.syntaxTree().sourceUnit(); + } - if (fullEnd(token) >= text.length) { - // We're at the end. - if (lastDiagnosticKey === TypeScript.DiagnosticCode.AsteriskSlash_expected) { - result.finalLexState = EndOfLineState.InMultiLineCommentTrivia; - return; - } + public diagnostics(): Diagnostic[] { + return this.syntaxTree().diagnostics(); + } - if (token.kind() === TypeScript.SyntaxKind.StringLiteral) { - var tokenText = token.text(); - if (tokenText.length > 0 && tokenText.charCodeAt(tokenText.length - 1) === TypeScript.CharacterCodes.backslash) { - var quoteChar = tokenText.charCodeAt(0); - result.finalLexState = quoteChar === TypeScript.CharacterCodes.doubleQuote - ? EndOfLineState.InDoubleQuoteStringLiteral - : EndOfLineState.InSingleQuoteStringLiteral; - return; + public lineMap(): LineMap { + return this.syntaxTree().lineMap(); + } + + public syntaxTree(): SyntaxTree { + if (!this._syntaxTree) { + var start = new Date().getTime(); + + this._syntaxTree = Parser.parse( + this.filename, SimpleText.fromScriptSnapshot(this._scriptSnapshot), this.compilationSettings.target, this.isDeclareFile()); + + var time = new Date().getTime() - start; + + //TypeScript.syntaxTreeParseTime += time; + } + + return this._syntaxTree; + } + + public sourceFile(): ts.SourceFile { + if (!this._soruceFile) { + var start = new Date().getTime(); + + this._soruceFile = ts.createSourceFile(this.filename, this._scriptSnapshot.getText(0, this._scriptSnapshot.getLength()), this.compilationSettings.target); + + var time = new Date().getTime() - start; + + //TypeScript.astParseTime += time; + } + + return this._soruceFile; + } + + public bloomFilter(): BloomFilter { + if (!this._bloomFilter) { + var identifiers = createIntrinsicsObject(); + var pre = function (cur: TypeScript.ISyntaxElement) { + if (ASTHelpers.isValidAstNode(cur)) { + if (cur.kind() === SyntaxKind.IdentifierName) { + var nodeText = tokenValueText((cur)); + + identifiers[nodeText] = true; + } + } + }; + + TypeScript.getAstWalkerFactory().simpleWalk(this.sourceUnit(), pre, null, identifiers); + + var identifierCount = 0; + for (var name in identifiers) { + if (identifiers[name]) { + identifierCount++; } } + + this._bloomFilter = new BloomFilter(identifierCount); + this._bloomFilter.addKeys(identifiers); } + return this._bloomFilter; } - function processTriviaList(text: string, offset: number, triviaList: TypeScript.ISyntaxTriviaList, result: ClassificationResult): void { - for (var i = 0, n = triviaList.count(); i < n; i++) { - var trivia = triviaList.syntaxTriviaAt(i); - addResult(text, offset, result, trivia.fullWidth(), trivia.kind()); - } + // Returns true if this file should get emitted into its own unique output file. + // Otherwise, it should be written into a single output file along with the rest of hte + // documents in the compilation. + public emitToOwnOutputFile(): boolean { + // If we haven't specified an output file in our settings, then we're definitely + // emitting to our own file. Also, if we're an external module, then we're + // definitely emitting to our own file. + return !this.compilationSettings.out || this.syntaxTree().isExternalModule(); } - function addResult(text: string, offset: number, result: ClassificationResult, length: number, kind: TypeScript.SyntaxKind): void { - if (length > 0) { - // If this is the first classification we're adding to the list, then remove any - // offset we have if we were continuing a construct from the previous line. - if (result.entries.length === 0) { - length -= offset; + public update(scriptSnapshot: IScriptSnapshot, version: number, isOpen: boolean, textChangeRange: TextChangeRange): Document { + // See if we are currently holding onto a syntax tree. We may not be because we're + // either a closed file, or we've just been lazy and haven't had to create the syntax + // tree yet. Access the field instead of the method so we don't accidently realize + // the old syntax tree. + var oldSyntaxTree = this._syntaxTree; + + if (textChangeRange !== null && Debug.shouldAssert(AssertionLevel.Normal)) { + var oldText = this._scriptSnapshot; + var newText = scriptSnapshot; + + TypeScript.Debug.assert((oldText.getLength() - textChangeRange.span().length() + textChangeRange.newLength()) === newText.getLength()); + + if (Debug.shouldAssert(AssertionLevel.VeryAggressive)) { + var oldTextPrefix = oldText.getText(0, textChangeRange.span().start()); + var newTextPrefix = newText.getText(0, textChangeRange.span().start()); + TypeScript.Debug.assert(oldTextPrefix === newTextPrefix); + + var oldTextSuffix = oldText.getText(textChangeRange.span().end(), oldText.getLength()); + var newTextSuffix = newText.getText(textChangeRange.newSpan().end(), newText.getLength()); + TypeScript.Debug.assert(oldTextSuffix === newTextSuffix); } - - result.entries.push({ length: length, classification: classFromKind(kind) }); } + + var text = SimpleText.fromScriptSnapshot(scriptSnapshot); + + // If we don't have a text change, or we don't have an old syntax tree, then do a full + // parse. Otherwise, do an incremental parse. + var newSyntaxTree = textChangeRange === null || oldSyntaxTree === null || Document.incrementalParse === null + ? TypeScript.Parser.parse(this.filename, text, this.compilationSettings.target, TypeScript.isDTSFile(this.filename)) + : Document.incrementalParse(oldSyntaxTree, textChangeRange, text); + + return new Document(this.compilationSettings, this.filename, this.referencedFiles, scriptSnapshot, this.byteOrderMark, version, isOpen, newSyntaxTree, /*soruceFile*/ null); } - function classFromKind(kind: TypeScript.SyntaxKind) { - if (TypeScript.SyntaxFacts.isAnyKeyword(kind)) { - return TokenClass.Keyword; - } - else if (TypeScript.SyntaxFacts.isBinaryExpressionOperatorToken(kind) || - TypeScript.SyntaxFacts.isPrefixUnaryExpressionOperatorToken(kind)) { - return TokenClass.Operator; - } - else if (TypeScript.SyntaxFacts.isAnyPunctuation(kind)) { - return TokenClass.Punctuation; - } - - switch (kind) { - case TypeScript.SyntaxKind.WhitespaceTrivia: - return TokenClass.Whitespace; - case TypeScript.SyntaxKind.MultiLineCommentTrivia: - case TypeScript.SyntaxKind.SingleLineCommentTrivia: - return TokenClass.Comment; - case TypeScript.SyntaxKind.NumericLiteral: - return TokenClass.NumberLiteral; - case TypeScript.SyntaxKind.StringLiteral: - return TokenClass.StringLiteral; - case TypeScript.SyntaxKind.RegularExpressionLiteral: - return TokenClass.RegExpLiteral; - case TypeScript.SyntaxKind.IdentifierName: - default: - return TokenClass.Identifier; - } + public static create(compilationSettings: ts.CompilerOptions, fileName: string, scriptSnapshot: IScriptSnapshot, byteOrderMark: ts.ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]): Document { + return new Document(compilationSettings, fileName, referencedFiles, scriptSnapshot, byteOrderMark, version, isOpen, /*syntaxTree:*/ null, /*soruceFile*/ null); } - - return { - getClassificationsForLine: getClassificationsForLine - }; } -} -module TypeScript.Services { + /// Language Service + interface CompletionSession { filename: string; // the file where the completion was requested position: number; // position in the file where the completion was requested @@ -992,6 +858,13 @@ module TypeScript.Services { typeChecker: ts.TypeChecker;// the typeChecker used to generate this completion } + interface FormattingOptions { + useTabs: boolean; + spacesPerTab: number; + indentSpaces: number; + newLineCharacter: string; + } + // Information about a specific host file. interface HostFileInformation { filename: string; @@ -1261,13 +1134,6 @@ module TypeScript.Services { } } - interface FormattingOptions { - useTabs: boolean; - spacesPerTab: number; - indentSpaces: number; - newLineCharacter: string; - } - class DocumentRegistryEntry { public refCount: number = 0; public owners: string[] = []; @@ -1275,29 +1141,6 @@ module TypeScript.Services { } } - export interface IDocumentRegistry { - acquireDocument( - filename: string, - compilationSettings: ts.CompilerOptions, - scriptSnapshot: IScriptSnapshot, - byteOrderMark: ts.ByteOrderMark, - version: number, - isOpen: boolean, - referencedFiles: string[]): Document; - - updateDocument( - document: Document, - filename: string, - compilationSettings: ts.CompilerOptions, - scriptSnapshot: IScriptSnapshot, - version: number, - isOpen: boolean, - textChangeRange: TextChangeRange - ): Document; - - releaseDocument(filename: string, compilationSettings: ts.CompilerOptions): void - } - export class DocumentRegistry implements IDocumentRegistry { private buckets: ts.Map> = {}; @@ -2063,4 +1906,154 @@ module TypeScript.Services { getEmitOutput: (filename) => undefined, }; } + + /// Classifier + + export function createClassifier(host: Logger): Classifier { + var scanner: TypeScript.Scanner.IScanner; + var lastDiagnosticKey: string = null; + var noRegexTable: boolean[]; + var reportDiagnostic = (position: number, fullWidth: number, key: string, args: any[]) => { + lastDiagnosticKey = key; + }; + + if (!noRegexTable) { + noRegexTable = []; + noRegexTable[TypeScript.SyntaxKind.IdentifierName] = true; + noRegexTable[TypeScript.SyntaxKind.StringLiteral] = true; + noRegexTable[TypeScript.SyntaxKind.NumericLiteral] = true; + noRegexTable[TypeScript.SyntaxKind.RegularExpressionLiteral] = true; + noRegexTable[TypeScript.SyntaxKind.ThisKeyword] = true; + noRegexTable[TypeScript.SyntaxKind.PlusPlusToken] = true; + noRegexTable[TypeScript.SyntaxKind.MinusMinusToken] = true; + noRegexTable[TypeScript.SyntaxKind.CloseParenToken] = true; + noRegexTable[TypeScript.SyntaxKind.CloseBracketToken] = true; + noRegexTable[TypeScript.SyntaxKind.CloseBraceToken] = true; + noRegexTable[TypeScript.SyntaxKind.TrueKeyword] = true; + noRegexTable[TypeScript.SyntaxKind.FalseKeyword] = true; + } + + function getClassificationsForLine(text: string, lexState: EndOfLineState): ClassificationResult { + var offset = 0; + if (lexState !== EndOfLineState.Start) { + // If we're in a string literal, then prepend: "\ + // (and a newline). That way when we lex we'll think we're still in a string literal. + // + // If we're in a multiline comment, then prepend: /* + // (and a newline). That way when we lex we'll think we're still in a multiline comment. + if (lexState === EndOfLineState.InDoubleQuoteStringLiteral) { + text = '"\\\n' + text; + } + else if (lexState === EndOfLineState.InSingleQuoteStringLiteral) { + text = "'\\\n" + text; + } + else if (lexState === EndOfLineState.InMultiLineCommentTrivia) { + text = "/*\n" + text; + } + + offset = 3; + } + + var result = { + finalLexState: EndOfLineState.Start, + entries: [] + }; + + var simpleText = TypeScript.SimpleText.fromString(text); + scanner = Scanner.createScanner(ts.ScriptTarget.ES5, simpleText, reportDiagnostic); + + var lastTokenKind = TypeScript.SyntaxKind.None; + var token: ISyntaxToken = null; + do { + lastDiagnosticKey = null; + + token = scanner.scan(!noRegexTable[lastTokenKind]); + lastTokenKind = token.kind(); + + processToken(text, simpleText, offset, token, result); + } + while (token.kind() !== SyntaxKind.EndOfFileToken); + + lastDiagnosticKey = null; + return result; + } + + function processToken(text: string, simpleText: ISimpleText, offset: number, token: TypeScript.ISyntaxToken, result: ClassificationResult): void { + processTriviaList(text, offset, token.leadingTrivia(simpleText), result); + addResult(text, offset, result, width(token), token.kind()); + processTriviaList(text, offset, token.trailingTrivia(simpleText), result); + + if (fullEnd(token) >= text.length) { + // We're at the end. + if (lastDiagnosticKey === TypeScript.DiagnosticCode.AsteriskSlash_expected) { + result.finalLexState = EndOfLineState.InMultiLineCommentTrivia; + return; + } + + if (token.kind() === TypeScript.SyntaxKind.StringLiteral) { + var tokenText = token.text(); + if (tokenText.length > 0 && tokenText.charCodeAt(tokenText.length - 1) === TypeScript.CharacterCodes.backslash) { + var quoteChar = tokenText.charCodeAt(0); + result.finalLexState = quoteChar === TypeScript.CharacterCodes.doubleQuote + ? EndOfLineState.InDoubleQuoteStringLiteral + : EndOfLineState.InSingleQuoteStringLiteral; + return; + } + } + } + } + + function processTriviaList(text: string, offset: number, triviaList: TypeScript.ISyntaxTriviaList, result: ClassificationResult): void { + for (var i = 0, n = triviaList.count(); i < n; i++) { + var trivia = triviaList.syntaxTriviaAt(i); + addResult(text, offset, result, trivia.fullWidth(), trivia.kind()); + } + } + + function addResult(text: string, offset: number, result: ClassificationResult, length: number, kind: TypeScript.SyntaxKind): void { + if (length > 0) { + // If this is the first classification we're adding to the list, then remove any + // offset we have if we were continuing a construct from the previous line. + if (result.entries.length === 0) { + length -= offset; + } + + result.entries.push({ length: length, classification: classFromKind(kind) }); + } + } + + function classFromKind(kind: TypeScript.SyntaxKind) { + if (TypeScript.SyntaxFacts.isAnyKeyword(kind)) { + return TokenClass.Keyword; + } + else if (TypeScript.SyntaxFacts.isBinaryExpressionOperatorToken(kind) || + TypeScript.SyntaxFacts.isPrefixUnaryExpressionOperatorToken(kind)) { + return TokenClass.Operator; + } + else if (TypeScript.SyntaxFacts.isAnyPunctuation(kind)) { + return TokenClass.Punctuation; + } + + switch (kind) { + case TypeScript.SyntaxKind.WhitespaceTrivia: + return TokenClass.Whitespace; + case TypeScript.SyntaxKind.MultiLineCommentTrivia: + case TypeScript.SyntaxKind.SingleLineCommentTrivia: + return TokenClass.Comment; + case TypeScript.SyntaxKind.NumericLiteral: + return TokenClass.NumberLiteral; + case TypeScript.SyntaxKind.StringLiteral: + return TokenClass.StringLiteral; + case TypeScript.SyntaxKind.RegularExpressionLiteral: + return TokenClass.RegExpLiteral; + case TypeScript.SyntaxKind.IdentifierName: + default: + return TokenClass.Identifier; + } + } + + return { + getClassificationsForLine: getClassificationsForLine + }; + } } \ No newline at end of file From f1ef9664428e77918f9f66482cd1470d6ef87126 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 24 Jul 2014 15:57:11 -0700 Subject: [PATCH 32/59] Switch classes to interfaces --- src/services/formatting/formattingManager.ts | 7 +- src/services/formatting/rulesProvider.ts | 2 +- src/services/services.ts | 94 +++++++------------- 3 files changed, 38 insertions(+), 65 deletions(-) diff --git a/src/services/formatting/formattingManager.ts b/src/services/formatting/formattingManager.ts index b3cdf5fd4f6..bc700d068ef 100644 --- a/src/services/formatting/formattingManager.ts +++ b/src/services/formatting/formattingManager.ts @@ -115,8 +115,11 @@ module TypeScript.Services.Formatting { // // TODO: Change the ILanguageService interface to return TextEditInfo (with start, and length) instead of TextEdit (with minChar and limChar) formattingEdits.forEach((item) => { - var edit = new TypeScript.Services.TextEdit(item.position, item.position + item.length, item.replaceWith); - result.push(edit); + result.push({ + minChar: item.position, + limChar: item.position + item.length, + text: item.replaceWith + }); }); return result; diff --git a/src/services/formatting/rulesProvider.ts b/src/services/formatting/rulesProvider.ts index 1b55676c7df..87c803658bf 100644 --- a/src/services/formatting/rulesProvider.ts +++ b/src/services/formatting/rulesProvider.ts @@ -45,7 +45,7 @@ module TypeScript.Services.Formatting { this.activeRules = activeRules; this.rulesMap = rulesMap; - this.options = TypeScript.Services.FormatCodeOptions.clone(options); + this.options = ts.clone(options); } } diff --git a/src/services/services.ts b/src/services/services.ts index 2a950f8fc89..2ca69559519 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -305,7 +305,6 @@ module ts { module TypeScript.Services { - // // Public interface of the host of a language service instance. // @@ -393,59 +392,28 @@ module TypeScript.Services { containerKind: string; // see ScriptElementKind } - export class TextEdit { - constructor(public minChar: number, public limChar: number, public text: string) { - } - - static createInsert(pos: number, text: string): TextEdit { - return new TextEdit(pos, pos, text); - } - static createDelete(minChar: number, limChar: number): TextEdit { - return new TextEdit(minChar, limChar, ""); - } - static createReplace(minChar: number, limChar: number, text: string): TextEdit { - return new TextEdit(minChar, limChar, text); - } + export interface TextEdit { + minChar: number; + limChar: number; + text: string; } - export class EditorOptions { - public IndentSize: number = 4; - public TabSize: number = 4; - public NewLineCharacter: string = "\r\n"; - public ConvertTabsToSpaces: boolean = true; - - public static clone(objectToClone: EditorOptions): EditorOptions { - var editorOptions = new EditorOptions(); - editorOptions.IndentSize = objectToClone.IndentSize; - editorOptions.TabSize = objectToClone.TabSize; - editorOptions.NewLineCharacter = objectToClone.NewLineCharacter; - editorOptions.ConvertTabsToSpaces = objectToClone.ConvertTabsToSpaces; - return editorOptions; - } + export interface EditorOptions { + IndentSize: number; + TabSize: number; + NewLineCharacter: string; + ConvertTabsToSpaces: boolean; } - export class FormatCodeOptions extends EditorOptions { - public InsertSpaceAfterCommaDelimiter: boolean = true; - public InsertSpaceAfterSemicolonInForStatements: boolean = true; - public InsertSpaceBeforeAndAfterBinaryOperators: boolean = true; - public InsertSpaceAfterKeywordsInControlFlowStatements: boolean = true; - public InsertSpaceAfterFunctionKeywordForAnonymousFunctions: boolean = false; - public InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: boolean = false; - public PlaceOpenBraceOnNewLineForFunctions: boolean = false; - public PlaceOpenBraceOnNewLineForControlBlocks: boolean = false; - - public static clone(objectToClone: FormatCodeOptions): FormatCodeOptions { - var formatCodeOptions = EditorOptions.clone(objectToClone); - formatCodeOptions.InsertSpaceAfterCommaDelimiter = objectToClone.InsertSpaceAfterCommaDelimiter; - formatCodeOptions.InsertSpaceAfterSemicolonInForStatements = objectToClone.InsertSpaceAfterSemicolonInForStatements; - formatCodeOptions.InsertSpaceBeforeAndAfterBinaryOperators = objectToClone.InsertSpaceBeforeAndAfterBinaryOperators; - formatCodeOptions.InsertSpaceAfterKeywordsInControlFlowStatements = objectToClone.InsertSpaceAfterKeywordsInControlFlowStatements; - formatCodeOptions.InsertSpaceAfterFunctionKeywordForAnonymousFunctions = objectToClone.InsertSpaceAfterFunctionKeywordForAnonymousFunctions; - formatCodeOptions.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis = objectToClone.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis; - formatCodeOptions.PlaceOpenBraceOnNewLineForFunctions = objectToClone.PlaceOpenBraceOnNewLineForFunctions; - formatCodeOptions.PlaceOpenBraceOnNewLineForControlBlocks = objectToClone.PlaceOpenBraceOnNewLineForControlBlocks; - return formatCodeOptions; - } + export interface FormatCodeOptions extends EditorOptions { + InsertSpaceAfterCommaDelimiter: boolean; + InsertSpaceAfterSemicolonInForStatements: boolean; + InsertSpaceBeforeAndAfterBinaryOperators: boolean; + InsertSpaceAfterKeywordsInControlFlowStatements: boolean; + InsertSpaceAfterFunctionKeywordForAnonymousFunctions: boolean; + InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: boolean; + PlaceOpenBraceOnNewLineForFunctions: boolean; + PlaceOpenBraceOnNewLineForControlBlocks: boolean; } export interface DefinitionInfo { @@ -609,7 +577,7 @@ module TypeScript.Services { releaseDocument(filename: string, compilationSettings: ts.CompilerOptions): void } - + // TODO: move these to enums export class ScriptElementKind { static unknown = ""; @@ -700,7 +668,7 @@ module TypeScript.Services { static message = "message"; } - interface IncrementalParse { + export interface IncrementalParse { (oldSyntaxTree: SyntaxTree, textChangeRange: TextChangeRange, newText: ISimpleText): SyntaxTree } @@ -847,7 +815,7 @@ module TypeScript.Services { } } - /// Language Service + /// Language Service interface CompletionSession { filename: string; // the file where the completion was requested @@ -874,6 +842,12 @@ module TypeScript.Services { _sourceText?: TypeScript.IScriptSnapshot; } + interface DocumentRegistryEntry { + document: Document; + refCount: number; + owners: string[]; + } + export function getDefaultCompilerOptions(): ts.CompilerOptions { // Set "ES5" target by default for language service return { @@ -1134,13 +1108,6 @@ module TypeScript.Services { } } - class DocumentRegistryEntry { - public refCount: number = 0; - public owners: string[] = []; - constructor(public document: Document) { - } - } - export class DocumentRegistry implements IDocumentRegistry { private buckets: ts.Map> = {}; @@ -1189,8 +1156,11 @@ module TypeScript.Services { if (!entry) { var document = Document.create(compilationSettings, filename, scriptSnapshot, byteOrderMark, version, isOpen, referencedFiles); - entry = new DocumentRegistryEntry(document); - bucket[filename] = entry; + bucket[filename] = entry = { + document: document, + refCount: 0, + owners: [] + }; } entry.refCount++; From 70b8a569d9e014eca1b00a2d2d64e42ab4f07e6f Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 24 Jul 2014 15:58:33 -0700 Subject: [PATCH 33/59] move logInternalError to where it is used --- src/services/services.ts | 4 ---- src/services/shims.ts | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 2ca69559519..024a7fe7122 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -368,10 +368,6 @@ module TypeScript.Services { dispose(): void; } - export function logInternalError(logger: TypeScript.Logger, err: Error) { - logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message); - } - export interface ReferenceEntry { fileName: string; minChar: number; diff --git a/src/services/shims.ts b/src/services/shims.ts index 0df08322731..d70515d9755 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -249,6 +249,10 @@ module TypeScript.Services { return settings; } + function logInternalError(logger: TypeScript.Logger, err: Error) { + logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message); + } + class ScriptSnapshotShimAdapter implements TypeScript.IScriptSnapshot { private lineStartPositions: number[] = null; From 4afbcf7b18c8a6325096dbff4623714101670f57 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 24 Jul 2014 16:01:51 -0700 Subject: [PATCH 34/59] Add Logger definition to services.ts --- src/services/services.ts | 16 ++++++++++++---- src/services/shims.ts | 10 +++++----- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 024a7fe7122..d3810d30059 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -305,10 +305,19 @@ module ts { module TypeScript.Services { + export interface Logger { + information(): boolean; + debug(): boolean; + warning(): boolean; + error(): boolean; + fatal(): boolean; + log(s: string): void; + } + // // Public interface of the host of a language service instance. // - export interface LanguageServiceHost extends TypeScript.Logger { + export interface LanguageServiceHost extends Logger { getCompilationSettings(): ts.CompilerOptions; getScriptFileNames(): string[]; getScriptVersion(fileName: string): number; @@ -1201,7 +1210,6 @@ module TypeScript.Services { } export function createLanguageService(host: LanguageServiceHost, documentRegistry: IDocumentRegistry): LanguageService { - var logger: TypeScript.Logger = host; var _syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host); var formattingRulesProvider: Formatting.RulesProvider; var hostCache: HostCache; // A cache of all the information about the files on the host side. @@ -1386,7 +1394,7 @@ module TypeScript.Services { var sourceUnit = document.sourceUnit(); if (CompletionHelpers.isCompletionListBlocker(document.syntaxTree().sourceUnit(), position)) { - logger.log("Returning an empty list because completion was blocked."); + host.log("Returning an empty list because completion was blocked."); return null; } @@ -1793,7 +1801,7 @@ module TypeScript.Services { function getFormattingManager(filename: string, options: FormatCodeOptions) { // Ensure rules are initialized and up to date wrt to formatting options if (formattingRulesProvider == null) { - formattingRulesProvider = new TypeScript.Services.Formatting.RulesProvider(logger); + formattingRulesProvider = new TypeScript.Services.Formatting.RulesProvider(host); } formattingRulesProvider.ensureUpToDate(options); diff --git a/src/services/shims.ts b/src/services/shims.ts index d70515d9755..5c334993156 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -40,7 +40,7 @@ module TypeScript.Services { // // Public interface of the host of a language service shim instance. // - export interface LanguageServiceShimHost extends TypeScript.Logger { + export interface LanguageServiceShimHost extends Logger { getCompilationSettings(): string; // Returns a JSON encoded value of the type: @@ -249,7 +249,7 @@ module TypeScript.Services { return settings; } - function logInternalError(logger: TypeScript.Logger, err: Error) { + function logInternalError(logger: Logger, err: Error) { logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message); } @@ -389,7 +389,7 @@ module TypeScript.Services { } } - function simpleForwardCall(logger: TypeScript.Logger, actionDescription: string, action: () => any): any { + function simpleForwardCall(logger: Logger, actionDescription: string, action: () => any): any { logger.log(actionDescription); var start = Date.now(); var result = action(); @@ -405,7 +405,7 @@ module TypeScript.Services { return result; } - function forwardJSONCall(logger: TypeScript.Logger, actionDescription: string, action: () => any): string { + function forwardJSONCall(logger: Logger, actionDescription: string, action: () => any): string { try { var result = simpleForwardCall(logger, actionDescription, action); return JSON.stringify({ result: result }); @@ -430,7 +430,7 @@ module TypeScript.Services { } class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim { - private logger: TypeScript.Logger; + private logger: Logger; constructor(factory: ShimFactory, private host: LanguageServiceShimHost, From 7d5da6c8ab03ba70e0035ccdcc5b13051cd67a65 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 24 Jul 2014 16:03:48 -0700 Subject: [PATCH 35/59] remove the I prefix from interface name --- src/services/shims.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/services/shims.ts b/src/services/shims.ts index 5c334993156..a8821b1ea44 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -19,7 +19,7 @@ /// var debugObjectHost = (this); module TypeScript.Services { - export interface IScriptSnapshotShim { + export interface ScriptSnapshotShim { // Get's a portion of the script snapshot specified by [start, end). getText(start: number, end: number): string; @@ -49,7 +49,7 @@ module TypeScript.Services { getScriptVersion(fileName: string): number; getScriptIsOpen(fileName: string): boolean; getScriptByteOrderMark(fileName: string): number; - getScriptSnapshot(fileName: string): IScriptSnapshotShim; + getScriptSnapshot(fileName: string): ScriptSnapshotShim; resolveRelativePath(path: string, directory: string): string; fileExists(path: string): boolean; directoryExists(path: string): boolean; @@ -256,7 +256,7 @@ module TypeScript.Services { class ScriptSnapshotShimAdapter implements TypeScript.IScriptSnapshot { private lineStartPositions: number[] = null; - constructor(private scriptSnapshotShim: IScriptSnapshotShim) { + constructor(private scriptSnapshotShim: ScriptSnapshotShim) { } public getText(start: number, end: number): string { From 6ca9a1a6d875b76dddb1f9ed57e4fdbe29e82c14 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 24 Jul 2014 17:36:06 -0700 Subject: [PATCH 36/59] Move updated code to the ts namespace --- src/services/breakpoints.ts | 92 ++++----- src/services/formatting/formattingManager.ts | 18 +- src/services/formatting/rulesProvider.ts | 8 +- .../getScriptLexicalStructureWalker.ts | 52 ++--- src/services/keywordCompletions.ts | 10 +- src/services/services.ts | 184 +++++++++--------- src/services/shims.ts | 6 +- 7 files changed, 183 insertions(+), 187 deletions(-) diff --git a/src/services/breakpoints.ts b/src/services/breakpoints.ts index 237df5afce0..5dd057ac2af 100644 --- a/src/services/breakpoints.ts +++ b/src/services/breakpoints.ts @@ -4,7 +4,7 @@ /// module TypeScript.Services.Breakpoints { - function createBreakpointSpanInfo(parentElement: TypeScript.ISyntaxElement, ...childElements: TypeScript.ISyntaxElement[]): SpanInfo { + function createBreakpointSpanInfo(parentElement: TypeScript.ISyntaxElement, ...childElements: TypeScript.ISyntaxElement[]): ts.SpanInfo { if (!parentElement) { return null; } @@ -34,7 +34,7 @@ module TypeScript.Services.Breakpoints { }; } - function createBreakpointSpanInfoWithLimChar(startElement: TypeScript.ISyntaxElement, limChar: number): SpanInfo { + function createBreakpointSpanInfoWithLimChar(startElement: TypeScript.ISyntaxElement, limChar: number): ts.SpanInfo { return { minChar: start(startElement), limChar: limChar @@ -45,7 +45,7 @@ module TypeScript.Services.Breakpoints { constructor(private posLine: number, private lineMap: TypeScript.LineMap) { } - private breakpointSpanOfToken(positionedToken: TypeScript.ISyntaxToken): SpanInfo { + private breakpointSpanOfToken(positionedToken: TypeScript.ISyntaxToken): ts.SpanInfo { switch (positionedToken.kind()) { case TypeScript.SyntaxKind.OpenBraceToken: return this.breakpointSpanOfOpenBrace(positionedToken); @@ -74,7 +74,7 @@ module TypeScript.Services.Breakpoints { return this.breakpointSpanOfContainingNode(positionedToken); } - private breakpointSpanOfOpenBrace(openBraceToken: TypeScript.ISyntaxToken): SpanInfo { + private breakpointSpanOfOpenBrace(openBraceToken: TypeScript.ISyntaxToken): ts.SpanInfo { var container = Syntax.containingNode(openBraceToken); if (container) { var originalContainer = container; @@ -168,7 +168,7 @@ module TypeScript.Services.Breakpoints { return null; } - private breakpointSpanOfCloseBrace(closeBraceToken: TypeScript.ISyntaxToken): SpanInfo { + private breakpointSpanOfCloseBrace(closeBraceToken: TypeScript.ISyntaxToken): ts.SpanInfo { var container = Syntax.containingNode(closeBraceToken); if (container) { var originalContainer = container; @@ -243,7 +243,7 @@ module TypeScript.Services.Breakpoints { } - private breakpointSpanOfComma(commaToken: TypeScript.ISyntaxToken): SpanInfo { + private breakpointSpanOfComma(commaToken: TypeScript.ISyntaxToken): ts.SpanInfo { var commaParent = commaToken.parent; if (isSeparatedList(commaParent)) { var grandParent = commaParent.parent; @@ -271,7 +271,7 @@ module TypeScript.Services.Breakpoints { return this.breakpointSpanOfContainingNode(commaToken); } - private breakpointSpanOfCloseParen(closeParenToken: TypeScript.ISyntaxToken): SpanInfo { + private breakpointSpanOfCloseParen(closeParenToken: TypeScript.ISyntaxToken): ts.SpanInfo { var closeParenParent = closeParenToken.parent; if (closeParenParent) { switch (closeParenParent.kind()) { @@ -293,7 +293,7 @@ module TypeScript.Services.Breakpoints { return blockSyntax.statements && blockSyntax.statements.length != 0; } - private breakpointSpanOfFirstStatementInBlock(blockNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfFirstStatementInBlock(blockNode: TypeScript.ISyntaxNode): ts.SpanInfo { if (!blockNode) { return null; } @@ -316,7 +316,7 @@ module TypeScript.Services.Breakpoints { } } - private breakpointSpanOfLastStatementInBlock(blockNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfLastStatementInBlock(blockNode: TypeScript.ISyntaxNode): ts.SpanInfo { if (!blockNode) { return null; } @@ -339,7 +339,7 @@ module TypeScript.Services.Breakpoints { } } - private breakpointSpanOfFirstChildOfSyntaxList(positionedList: TypeScript.ISyntaxNodeOrToken[]): SpanInfo { + private breakpointSpanOfFirstChildOfSyntaxList(positionedList: TypeScript.ISyntaxNodeOrToken[]): ts.SpanInfo { if (!positionedList) { return null; } @@ -363,7 +363,7 @@ module TypeScript.Services.Breakpoints { } } - private breakpointSpanOfLastChildOfSyntaxList(positionedList: TypeScript.ISyntaxNodeOrToken[]): SpanInfo { + private breakpointSpanOfLastChildOfSyntaxList(positionedList: TypeScript.ISyntaxNodeOrToken[]): ts.SpanInfo { if (!positionedList) { return null; } @@ -385,7 +385,7 @@ module TypeScript.Services.Breakpoints { } } - private breakpointSpanOfNode(positionedNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfNode(positionedNode: TypeScript.ISyntaxNode): ts.SpanInfo { var node = positionedNode; switch (node.kind()) { // Declarations with elements @@ -552,12 +552,12 @@ module TypeScript.Services.Breakpoints { return false; } - private breakpointOfLeftOfCommaExpression(commaExpressionNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointOfLeftOfCommaExpression(commaExpressionNode: TypeScript.ISyntaxNode): ts.SpanInfo { var commaExpression = commaExpressionNode; return this.breakpointSpanOf(commaExpression.left); } - private breakpointOfExpression(expressionNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointOfExpression(expressionNode: TypeScript.ISyntaxNode): ts.SpanInfo { if (this.isInitializerOfForStatement(expressionNode) || this.isConditionOfForStatement(expressionNode) || this.isIncrememtorOfForStatement(expressionNode)) { @@ -582,7 +582,7 @@ module TypeScript.Services.Breakpoints { return this.breakpointSpanOfContainingNode(expressionNode); } - private breakpointSpanOfStatement(statementNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfStatement(statementNode: TypeScript.ISyntaxNode): ts.SpanInfo { var statement = statementNode; if (statement.kind() == TypeScript.SyntaxKind.EmptyStatement) { return null; @@ -722,7 +722,7 @@ module TypeScript.Services.Breakpoints { return positionedNode && !TypeScript.SyntaxUtilities.isAmbientDeclarationSyntax(positionedNode); } - private breakpointSpanOfDeclarationWithElements(positionedNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfDeclarationWithElements(positionedNode: TypeScript.ISyntaxNode): ts.SpanInfo { if (!this.canHaveBreakpointInDeclaration(positionedNode)) { return null; } @@ -751,7 +751,7 @@ module TypeScript.Services.Breakpoints { return !!varDeclaratorSyntax.equalsValueClause; } - private breakpointSpanOfVariableDeclarator(varDeclaratorNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfVariableDeclarator(varDeclaratorNode: TypeScript.ISyntaxNode): ts.SpanInfo { if (!this.canHaveBreakpointInVariableDeclarator(varDeclaratorNode)) { return null; } @@ -799,7 +799,7 @@ module TypeScript.Services.Breakpoints { return false; } - private breakpointSpanOfVariableDeclaration(varDeclarationNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfVariableDeclaration(varDeclarationNode: TypeScript.ISyntaxNode): ts.SpanInfo { if (!this.canHaveBreakpointInDeclaration(varDeclarationNode)) { return null; } @@ -830,7 +830,7 @@ module TypeScript.Services.Breakpoints { return this.canHaveBreakpointInVariableDeclaration(variableStatement.variableDeclaration); } - private breakpointSpanOfVariableStatement(varStatementNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfVariableStatement(varStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo { if (!this.canHaveBreakpointInVariableStatement(varStatementNode)) { return null; } @@ -842,7 +842,7 @@ module TypeScript.Services.Breakpoints { return createBreakpointSpanInfoWithLimChar(varStatementNode, end(childAt(varDeclarators, 0))); } - private breakpointSpanOfParameter(parameterNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfParameter(parameterNode: TypeScript.ISyntaxNode): ts.SpanInfo { if (parameterNode.parent.kind() === SyntaxKind.SimpleArrowFunctionExpression) { return this.breakpointSpanOfNode(parameterNode.parent); } @@ -860,7 +860,7 @@ module TypeScript.Services.Breakpoints { } } - private breakpointSpanOfMemberVariableDeclaration(memberVarDeclarationNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfMemberVariableDeclaration(memberVarDeclarationNode: TypeScript.ISyntaxNode): ts.SpanInfo { if (TypeScript.SyntaxUtilities.isAmbientDeclarationSyntax(memberVarDeclarationNode)) { return null; } @@ -874,7 +874,7 @@ module TypeScript.Services.Breakpoints { } } - private breakpointSpanOfImportDeclaration(importDeclarationNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfImportDeclaration(importDeclarationNode: TypeScript.ISyntaxNode): ts.SpanInfo { if (TypeScript.SyntaxUtilities.isAmbientDeclarationSyntax(importDeclarationNode)) { return null; } @@ -883,7 +883,7 @@ module TypeScript.Services.Breakpoints { return createBreakpointSpanInfo(importDeclarationNode, importSyntax.modifiers, importSyntax.importKeyword, importSyntax.identifier, importSyntax.equalsToken, importSyntax.moduleReference); } - private breakpointSpanOfEnumDeclaration(enumDeclarationNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfEnumDeclaration(enumDeclarationNode: TypeScript.ISyntaxNode): ts.SpanInfo { if (!this.canHaveBreakpointInDeclaration(enumDeclarationNode)) { return null; } @@ -891,7 +891,7 @@ module TypeScript.Services.Breakpoints { return createBreakpointSpanInfo(enumDeclarationNode); } - private breakpointSpanOfFirstEnumElement(enumDeclarationNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfFirstEnumElement(enumDeclarationNode: TypeScript.ISyntaxNode): ts.SpanInfo { var enumDeclarationSyntax = enumDeclarationNode; var enumElements = enumDeclarationSyntax.enumElements; if (enumElements && childCount(enumElements)) { @@ -901,7 +901,7 @@ module TypeScript.Services.Breakpoints { return null; } - private breakpointSpanOfEnumElement(enumElementNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfEnumElement(enumElementNode: TypeScript.ISyntaxNode): ts.SpanInfo { if (TypeScript.SyntaxUtilities.isAmbientDeclarationSyntax(enumElementNode)) { return null; } @@ -909,45 +909,45 @@ module TypeScript.Services.Breakpoints { return createBreakpointSpanInfo(enumElementNode); } - private breakpointSpanOfIfStatement(ifStatementNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfIfStatement(ifStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo { var ifStatement = ifStatementNode; return createBreakpointSpanInfo(ifStatementNode, ifStatement.ifKeyword, ifStatement.openParenToken, ifStatement.condition, ifStatement.closeParenToken); } - private breakpointSpanOfElseClause(elseClauseNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfElseClause(elseClauseNode: TypeScript.ISyntaxNode): ts.SpanInfo { var elseClause = elseClauseNode; return this.breakpointSpanOf(elseClause.statement); } - private breakpointSpanOfForInStatement(forInStatementNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfForInStatement(forInStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo { var forInStatement = forInStatementNode; return createBreakpointSpanInfo(forInStatementNode, forInStatement.forKeyword, forInStatement.openParenToken, forInStatement.variableDeclaration, forInStatement.left, forInStatement.inKeyword, forInStatement.expression, forInStatement.closeParenToken); } - private breakpointSpanOfForStatement(forStatementNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfForStatement(forStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo { var forStatement = forStatementNode; return this.breakpointSpanOf(forStatement.variableDeclaration ? forStatement.variableDeclaration : forStatement.initializer); } - private breakpointSpanOfWhileStatement(whileStatementNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfWhileStatement(whileStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo { var whileStatement = whileStatementNode; return createBreakpointSpanInfo(whileStatementNode, whileStatement.whileKeyword, whileStatement.openParenToken, whileStatement.condition, whileStatement.closeParenToken); } - private breakpointSpanOfDoStatement(doStatementNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfDoStatement(doStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo { var doStatement = doStatementNode; return createBreakpointSpanInfo(doStatementNode, doStatement.whileKeyword, doStatement.openParenToken, doStatement.condition, doStatement.closeParenToken); } - private breakpointSpanOfSwitchStatement(switchStatementNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfSwitchStatement(switchStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo { var switchStatement = switchStatementNode; return createBreakpointSpanInfo(switchStatementNode, switchStatement.switchKeyword, switchStatement.openParenToken, switchStatement.expression, switchStatement.closeParenToken); } - private breakpointSpanOfFirstStatementOfFirstCaseClause(switchStatementNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfFirstStatementOfFirstCaseClause(switchStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo { var switchStatement = switchStatementNode; if (switchStatement.switchClauses && switchStatement.switchClauses.length == 0) { return null; @@ -964,7 +964,7 @@ module TypeScript.Services.Breakpoints { return this.breakpointSpanOfFirstChildOfSyntaxList(statements); } - private breakpointSpanOfLastStatementOfLastCaseClause(switchStatementNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfLastStatementOfLastCaseClause(switchStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo { var switchStatement = switchStatementNode; if (switchStatement.switchClauses && switchStatement.switchClauses.length == 0) { return null; @@ -981,37 +981,37 @@ module TypeScript.Services.Breakpoints { return this.breakpointSpanOfLastChildOfSyntaxList(statements); } - private breakpointSpanOfCaseSwitchClause(caseClauseNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfCaseSwitchClause(caseClauseNode: TypeScript.ISyntaxNode): ts.SpanInfo { var caseSwitchClause = caseClauseNode; return this.breakpointSpanOfFirstChildOfSyntaxList(caseSwitchClause.statements); } - private breakpointSpanOfDefaultSwitchClause(defaultSwithClauseNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfDefaultSwitchClause(defaultSwithClauseNode: TypeScript.ISyntaxNode): ts.SpanInfo { var defaultSwitchClause = defaultSwithClauseNode; return this.breakpointSpanOfFirstChildOfSyntaxList(defaultSwitchClause.statements); } - private breakpointSpanOfWithStatement(withStatementNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfWithStatement(withStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo { var withStatement = withStatementNode; return this.breakpointSpanOf(withStatement.statement); } - private breakpointSpanOfTryStatement(tryStatementNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfTryStatement(tryStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo { var tryStatement = tryStatementNode; return this.breakpointSpanOfFirstStatementInBlock(tryStatement.block); } - private breakpointSpanOfCatchClause(catchClauseNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfCatchClause(catchClauseNode: TypeScript.ISyntaxNode): ts.SpanInfo { var catchClause = catchClauseNode; return createBreakpointSpanInfo(catchClauseNode, catchClause.catchKeyword, catchClause.openParenToken, catchClause.identifier, catchClause.typeAnnotation, catchClause.closeParenToken); } - private breakpointSpanOfFinallyClause(finallyClauseNode: TypeScript.ISyntaxNode): SpanInfo { + private breakpointSpanOfFinallyClause(finallyClauseNode: TypeScript.ISyntaxNode): ts.SpanInfo { var finallyClause = finallyClauseNode; return this.breakpointSpanOfFirstStatementInBlock(finallyClause.block); } - private breakpointSpanOfParenthesizedArrowFunctionExpression(arrowFunctionExpression: ParenthesizedArrowFunctionExpressionSyntax): SpanInfo { + private breakpointSpanOfParenthesizedArrowFunctionExpression(arrowFunctionExpression: ParenthesizedArrowFunctionExpressionSyntax): ts.SpanInfo { if (arrowFunctionExpression.block) { return this.breakpointSpanOfFirstStatementInBlock(arrowFunctionExpression.block); } @@ -1020,7 +1020,7 @@ module TypeScript.Services.Breakpoints { } } - private breakpointSpanOfSimpleArrowFunctionExpression(arrowFunctionExpression: SimpleArrowFunctionExpressionSyntax): SpanInfo { + private breakpointSpanOfSimpleArrowFunctionExpression(arrowFunctionExpression: SimpleArrowFunctionExpressionSyntax): ts.SpanInfo { if (arrowFunctionExpression.block) { return this.breakpointSpanOfFirstStatementInBlock(arrowFunctionExpression.block); } @@ -1029,7 +1029,7 @@ module TypeScript.Services.Breakpoints { } } - private breakpointSpanOfContainingNode(positionedElement: ISyntaxElement): SpanInfo { + private breakpointSpanOfContainingNode(positionedElement: ISyntaxElement): ts.SpanInfo { var current = positionedElement.parent; while (!isNode(current)) { current = current.parent; @@ -1038,7 +1038,7 @@ module TypeScript.Services.Breakpoints { return this.breakpointSpanOf(current); } - private breakpointSpanIfStartsOnSameLine(positionedElement: TypeScript.ISyntaxElement): SpanInfo { + private breakpointSpanIfStartsOnSameLine(positionedElement: TypeScript.ISyntaxElement): ts.SpanInfo { if (positionedElement && this.posLine == this.lineMap.getLineNumberFromPosition(start(positionedElement))) { return this.breakpointSpanOf(positionedElement); } @@ -1046,7 +1046,7 @@ module TypeScript.Services.Breakpoints { return null; } - public breakpointSpanOf(positionedElement: TypeScript.ISyntaxElement): SpanInfo { + public breakpointSpanOf(positionedElement: TypeScript.ISyntaxElement): ts.SpanInfo { if (!positionedElement) { return null; } @@ -1075,7 +1075,7 @@ module TypeScript.Services.Breakpoints { } } - export function getBreakpointLocation(syntaxTree: TypeScript.SyntaxTree, askedPos: number): SpanInfo { + export function getBreakpointLocation(syntaxTree: TypeScript.SyntaxTree, askedPos: number): ts.SpanInfo { // Cannot set breakpoint in dts file if (TypeScript.isDTSFile(syntaxTree.fileName())) { return null; diff --git a/src/services/formatting/formattingManager.ts b/src/services/formatting/formattingManager.ts index bc700d068ef..4756b6eb240 100644 --- a/src/services/formatting/formattingManager.ts +++ b/src/services/formatting/formattingManager.ts @@ -19,28 +19,28 @@ module TypeScript.Services.Formatting { export class FormattingManager { private options: FormattingOptions; - constructor(private syntaxTree: SyntaxTree, private snapshot: ITextSnapshot, private rulesProvider: RulesProvider, editorOptions: TypeScript.Services.EditorOptions) { + constructor(private syntaxTree: SyntaxTree, private snapshot: ITextSnapshot, private rulesProvider: RulesProvider, editorOptions: ts.EditorOptions) { // // TODO: convert to use FormattingOptions instead of EditorOptions this.options = new FormattingOptions(!editorOptions.ConvertTabsToSpaces, editorOptions.TabSize, editorOptions.IndentSize, editorOptions.NewLineCharacter) } - public formatSelection(minChar: number, limChar: number): TypeScript.Services.TextEdit[] { + public formatSelection(minChar: number, limChar: number): ts.TextEdit[] { var span = TextSpan.fromBounds(minChar, limChar); return this.formatSpan(span, FormattingRequestKind.FormatSelection); } - public formatDocument(minChar: number, limChar: number): TypeScript.Services.TextEdit[] { + public formatDocument(minChar: number, limChar: number): ts.TextEdit[] { var span = TextSpan.fromBounds(minChar, limChar); return this.formatSpan(span, FormattingRequestKind.FormatDocument); } - public formatOnPaste(minChar: number, limChar: number): TypeScript.Services.TextEdit[] { + public formatOnPaste(minChar: number, limChar: number): ts.TextEdit[] { var span = TextSpan.fromBounds(minChar, limChar); return this.formatSpan(span, FormattingRequestKind.FormatOnPaste); } - public formatOnSemicolon(caretPosition: number): TypeScript.Services.TextEdit[] { + public formatOnSemicolon(caretPosition: number): ts.TextEdit[] { var sourceUnit = this.syntaxTree.sourceUnit(); var semicolonPositionedToken = findToken(sourceUnit, caretPosition - 1); @@ -63,7 +63,7 @@ module TypeScript.Services.Formatting { return []; } - public formatOnClosingCurlyBrace(caretPosition: number): TypeScript.Services.TextEdit[] { + public formatOnClosingCurlyBrace(caretPosition: number): ts.TextEdit[] { var sourceUnit = this.syntaxTree.sourceUnit(); var closeBracePositionedToken = findToken(sourceUnit, caretPosition - 1); @@ -86,7 +86,7 @@ module TypeScript.Services.Formatting { return []; } - public formatOnEnter(caretPosition: number): TypeScript.Services.TextEdit[] { + public formatOnEnter(caretPosition: number): ts.TextEdit[] { var lineNumber = this.snapshot.getLineNumberFromPosition(caretPosition); if (lineNumber > 0) { @@ -103,12 +103,12 @@ module TypeScript.Services.Formatting { return []; } - private formatSpan(span: TextSpan, formattingRequestKind: FormattingRequestKind): TypeScript.Services.TextEdit[] { + private formatSpan(span: TextSpan, formattingRequestKind: FormattingRequestKind): ts.TextEdit[] { // Always format from the beginning of the line var startLine = this.snapshot.getLineFromPosition(span.start()); span = TextSpan.fromBounds(startLine.startPosition(), span.end()); - var result: TypeScript.Services.TextEdit[] = []; + var result: ts.TextEdit[] = []; var formattingEdits = Formatter.getEdits(span, this.syntaxTree.sourceUnit(), this.options, true, this.snapshot, this.rulesProvider, formattingRequestKind); diff --git a/src/services/formatting/rulesProvider.ts b/src/services/formatting/rulesProvider.ts index 87c803658bf..608ee97254a 100644 --- a/src/services/formatting/rulesProvider.ts +++ b/src/services/formatting/rulesProvider.ts @@ -18,7 +18,7 @@ module TypeScript.Services.Formatting { export class RulesProvider { private globalRules: Rules; - private options: TypeScript.Services.FormatCodeOptions; + private options: ts.FormatCodeOptions; private activeRules: Rule[]; private rulesMap: RulesMap; @@ -38,8 +38,8 @@ module TypeScript.Services.Formatting { return this.rulesMap; } - public ensureUpToDate(options: TypeScript.Services.FormatCodeOptions) { - if (this.options == null || !compareDataObjects(this.options, options)) { + public ensureUpToDate(options: ts.FormatCodeOptions) { + if (this.options == null || !ts.compareDataObjects(this.options, options)) { var activeRules: Rule[] = TypeScript.timeFunction(this.logger, "RulesProvider: createActiveRules()", () => { return this.createActiveRules(options); }); var rulesMap: RulesMap = TypeScript.timeFunction(this.logger, "RulesProvider: RulesMap.create()", () => { return RulesMap.create(activeRules); }); @@ -49,7 +49,7 @@ module TypeScript.Services.Formatting { } } - private createActiveRules(options: TypeScript.Services.FormatCodeOptions): Rule[] { + private createActiveRules(options: ts.FormatCodeOptions): Rule[] { var rules = this.globalRules.HighPriorityCommonRules.slice(0); if (options.InsertSpaceAfterCommaDelimiter) { diff --git a/src/services/getScriptLexicalStructureWalker.ts b/src/services/getScriptLexicalStructureWalker.ts index a9a179e51b7..df182d3b404 100644 --- a/src/services/getScriptLexicalStructureWalker.ts +++ b/src/services/getScriptLexicalStructureWalker.ts @@ -2,7 +2,7 @@ /// module TypeScript.Services { interface LexicalScope { - items: ts.Map; + items: ts.Map; itemNames: string[]; childScopes: ts.Map; childScopeNames: string[]; @@ -17,7 +17,7 @@ module TypeScript.Services { private createScope(): LexicalScope { return { - items: TypeScript.createIntrinsicsObject(), + items: TypeScript.createIntrinsicsObject(), childScopes: TypeScript.createIntrinsicsObject(), childScopeNames: [], itemNames: [] @@ -57,7 +57,7 @@ module TypeScript.Services { this.currentScope = this.createScope(); } - private collectItems(items: NavigateToItem[], scope = this.currentScope) { + private collectItems(items: ts.NavigateToItem[], scope = this.currentScope) { scope.itemNames.forEach(item => { items.push(scope.items[item]); }); @@ -67,7 +67,7 @@ module TypeScript.Services { }); } - static getListsOfAllScriptLexicalStructure(items: NavigateToItem[], fileName: string, unit: TypeScript.SourceUnitSyntax) { + static getListsOfAllScriptLexicalStructure(items: ts.NavigateToItem[], fileName: string, unit: TypeScript.SourceUnitSyntax) { var visitor = new GetScriptLexicalStructureWalker(fileName); visitNodeOrToken(visitor, unit); visitor.collectItems(items); @@ -81,10 +81,10 @@ module TypeScript.Services { return; } - var item: NavigateToItem = { + var item: ts.NavigateToItem = { name: name, kind: kind, - matchKind: MatchKind.exact, + matchKind: ts.MatchKind.exact, fileName: this.fileName, kindModifiers: this.getKindModifiers(modifiers), minChar: start(node), @@ -104,7 +104,7 @@ module TypeScript.Services { Debug.assert(item !== undefined); var start = TypeScript.start(node); - var span: SpanInfo = { + var span: ts.SpanInfo = { minChar: start, limChar: start + width(node) }; @@ -125,7 +125,7 @@ module TypeScript.Services { result.push(modifiers[i].text()); } - return result.length > 0 ? result.join(',') : ScriptElementKindModifier.none; + return result.length > 0 ? result.join(',') : ts.ScriptElementKindModifier.none; } public visitModuleDeclaration(node: TypeScript.ModuleDeclarationSyntax): void { @@ -140,7 +140,7 @@ module TypeScript.Services { } else { var name = names[nameIndex]; - var kind = ScriptElementKind.moduleElement; + var kind = ts.ScriptElementKind.moduleElement; this.createItem(node, node.modifiers, kind, name); @@ -178,7 +178,7 @@ module TypeScript.Services { public visitClassDeclaration(node: TypeScript.ClassDeclarationSyntax): void { var name = node.identifier.text(); - var kind = ScriptElementKind.classElement; + var kind = ts.ScriptElementKind.classElement; this.createItem(node, node.modifiers, kind, name); @@ -191,7 +191,7 @@ module TypeScript.Services { public visitInterfaceDeclaration(node: TypeScript.InterfaceDeclarationSyntax): void { var name = node.identifier.text(); - var kind = ScriptElementKind.interfaceElement; + var kind = ts.ScriptElementKind.interfaceElement; this.createItem(node, node.modifiers, kind, name); @@ -212,7 +212,7 @@ module TypeScript.Services { public visitEnumDeclaration(node: TypeScript.EnumDeclarationSyntax): void { var name = node.identifier.text(); - var kind = ScriptElementKind.enumElement; + var kind = ts.ScriptElementKind.enumElement; this.createItem(node, node.modifiers, kind, name); @@ -224,7 +224,7 @@ module TypeScript.Services { } public visitConstructorDeclaration(node: TypeScript.ConstructorDeclarationSyntax): void { - this.createItem(node, TypeScript.Syntax.emptyList(), ScriptElementKind.constructorImplementationElement, "constructor"); + this.createItem(node, TypeScript.Syntax.emptyList(), ts.ScriptElementKind.constructorImplementationElement, "constructor"); // Search the parameter list of class properties var parameters = node.callSignature.parameterList.parameters; @@ -236,7 +236,7 @@ module TypeScript.Services { if (SyntaxUtilities.containsToken(parameter.modifiers, SyntaxKind.PublicKeyword) || SyntaxUtilities.containsToken(parameter.modifiers, SyntaxKind.PrivateKeyword)) { - this.createItem(node, parameter.modifiers, ScriptElementKind.memberVariableElement, parameter.identifier.text()); + this.createItem(node, parameter.modifiers, ts.ScriptElementKind.memberVariableElement, parameter.identifier.text()); } } } @@ -245,19 +245,19 @@ module TypeScript.Services { } public visitMemberFunctionDeclaration(node: TypeScript.MemberFunctionDeclarationSyntax): void { - this.createItem(node, node.modifiers, ScriptElementKind.memberFunctionElement, node.propertyName.text()); + this.createItem(node, node.modifiers, ts.ScriptElementKind.memberFunctionElement, node.propertyName.text()); // No need to descend into a member function; } public visitGetAccessor(node: TypeScript.GetAccessorSyntax): void { - this.createItem(node, node.modifiers, ScriptElementKind.memberGetAccessorElement, node.propertyName.text()); + this.createItem(node, node.modifiers, ts.ScriptElementKind.memberGetAccessorElement, node.propertyName.text()); // No need to descend into a member accessor; } public visitSetAccessor(node: TypeScript.SetAccessorSyntax): void { - this.createItem(node, node.modifiers, ScriptElementKind.memberSetAccessorElement, node.propertyName.text()); + this.createItem(node, node.modifiers, ts.ScriptElementKind.memberSetAccessorElement, node.propertyName.text()); // No need to descend into a member accessor; } @@ -267,45 +267,45 @@ module TypeScript.Services { ? (node.parent).modifiers : TypeScript.Syntax.emptyList(); var kind = node.parent.kind() === SyntaxKind.MemberVariableDeclaration - ? ScriptElementKind.memberVariableElement - : ScriptElementKind.variableElement; + ? ts.ScriptElementKind.memberVariableElement + : ts.ScriptElementKind.variableElement; this.createItem(node, modifiers, kind, node.propertyName.text()); // No need to descend into a variable declarator; } public visitIndexSignature(node: TypeScript.IndexSignatureSyntax): void { - this.createItem(node, TypeScript.Syntax.emptyList(), ScriptElementKind.indexSignatureElement, "[]"); + this.createItem(node, TypeScript.Syntax.emptyList(), ts.ScriptElementKind.indexSignatureElement, "[]"); // No need to descend into an index signature; } public visitEnumElement(node: TypeScript.EnumElementSyntax): void { - this.createItem(node, TypeScript.Syntax.emptyList(), ScriptElementKind.memberVariableElement, node.propertyName.text()); + this.createItem(node, TypeScript.Syntax.emptyList(), ts.ScriptElementKind.memberVariableElement, node.propertyName.text()); // No need to descend into an enum element; } public visitCallSignature(node: TypeScript.CallSignatureSyntax): void { - this.createItem(node, TypeScript.Syntax.emptyList(), ScriptElementKind.callSignatureElement, "()"); + this.createItem(node, TypeScript.Syntax.emptyList(), ts.ScriptElementKind.callSignatureElement, "()"); // No need to descend into a call signature; } public visitConstructSignature(node: TypeScript.ConstructSignatureSyntax): void { - this.createItem(node, TypeScript.Syntax.emptyList(), ScriptElementKind.constructSignatureElement, "new()"); + this.createItem(node, TypeScript.Syntax.emptyList(), ts.ScriptElementKind.constructSignatureElement, "new()"); // No need to descend into a construct signature; } public visitMethodSignature(node: TypeScript.MethodSignatureSyntax): void { - this.createItem(node, TypeScript.Syntax.emptyList(), ScriptElementKind.memberFunctionElement, node.propertyName.text()); + this.createItem(node, TypeScript.Syntax.emptyList(), ts.ScriptElementKind.memberFunctionElement, node.propertyName.text()); // No need to descend into a method signature; } public visitPropertySignature(node: TypeScript.PropertySignatureSyntax): void { - this.createItem(node, TypeScript.Syntax.emptyList(), ScriptElementKind.memberVariableElement, node.propertyName.text()); + this.createItem(node, TypeScript.Syntax.emptyList(), ts.ScriptElementKind.memberVariableElement, node.propertyName.text()); // No need to descend into a property signature; } @@ -316,7 +316,7 @@ module TypeScript.Services { // the parser will synthesize an identifier. // we shouldn't add an unnamed function declaration if (width(node.identifier) > 0) { - this.createItem(node, node.modifiers, ScriptElementKind.functionElement, node.identifier.text()); + this.createItem(node, node.modifiers, ts.ScriptElementKind.functionElement, node.identifier.text()); } // No need to descend into a function declaration; diff --git a/src/services/keywordCompletions.ts b/src/services/keywordCompletions.ts index 3233a0f95a7..5e6b667b2d9 100644 --- a/src/services/keywordCompletions.ts +++ b/src/services/keywordCompletions.ts @@ -53,17 +53,17 @@ module TypeScript.Services { "with", ]; - private static keywordCompletions: CompletionEntry[] = null; + private static keywordCompletions: ts.CompletionEntry[] = null; - public static getKeywordCompltions(): CompletionEntry[]{ + public static getKeywordCompltions(): ts.CompletionEntry[]{ if (KeywordCompletions.keywordCompletions === null) { - var completions: CompletionEntry[] = []; + var completions: ts.CompletionEntry[] = []; for (var i = 0, n = KeywordCompletions.keywords.length; i < n; i++) { var keyword = KeywordCompletions.keywords[i]; completions.push({ name: keyword, - kind: ScriptElementKind.keyword, - kindModifiers: ScriptElementKindModifier.none + kind: ts.ScriptElementKind.keyword, + kindModifiers: ts.ScriptElementKindModifier.none }); } diff --git a/src/services/services.ts b/src/services/services.ts index d3810d30059..488cd4a7282 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -280,31 +280,6 @@ module ts { } } - function initializeServices() { - objectAllocator = { - getNodeConstructor: kind => { - function Node() { - } - var proto = new NodeObject(); - proto.kind = kind; - proto.pos = 0; - proto.end = 0; - proto.flags = 0; - proto.parent = undefined; - Node.prototype = proto; - return Node; - }, - getSymbolConstructor: () => SymbolObject, - getTypeConstructor: () => TypeObject, - getSignatureConstructor: () => SignatureObject, - }; - } - - initializeServices(); -} - - -module TypeScript.Services { export interface Logger { information(): boolean; debug(): boolean; @@ -363,7 +338,7 @@ module TypeScript.Services { getOutliningRegions(fileName: string): TypeScript.TextSpan[]; getBraceMatchingAtPosition(fileName: string, position: number): TypeScript.TextSpan[]; - getIndentationAtPosition(fileName: string, position: number, options: TypeScript.Services.EditorOptions): number; + getIndentationAtPosition(fileName: string, position: number, options: EditorOptions): number; getFormattingEditsForRange(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[]; getFormattingEditsForDocument(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[]; @@ -431,8 +406,14 @@ module TypeScript.Services { containerName: string; } + export interface MemberName { + prefix: string; + suffix: string; + text: string; + } + export interface TypeInfo { - memberName: TypeScript.MemberName; + memberName: MemberName; docComment: string; fullSymbolName: string; kind: string; @@ -564,7 +545,7 @@ module TypeScript.Services { acquireDocument( filename: string, compilationSettings: ts.CompilerOptions, - scriptSnapshot: IScriptSnapshot, + scriptSnapshot: TypeScript.IScriptSnapshot, byteOrderMark: ts.ByteOrderMark, version: number, isOpen: boolean, @@ -574,10 +555,10 @@ module TypeScript.Services { document: Document, filename: string, compilationSettings: ts.CompilerOptions, - scriptSnapshot: IScriptSnapshot, + scriptSnapshot: TypeScript.IScriptSnapshot, version: number, isOpen: boolean, - textChangeRange: TextChangeRange + textChangeRange: TypeScript.TextChangeRange ): Document; releaseDocument(filename: string, compilationSettings: ts.CompilerOptions): void @@ -666,59 +647,52 @@ module TypeScript.Services { static prefix = "prefix"; } - export class DiagnosticCategory { - static none = ""; - static error = "error"; - static warning = "warning"; - static message = "message"; - } - export interface IncrementalParse { - (oldSyntaxTree: SyntaxTree, textChangeRange: TextChangeRange, newText: ISimpleText): SyntaxTree + (oldSyntaxTree: TypeScript.SyntaxTree, textChangeRange: TypeScript.TextChangeRange, newText: TypeScript.ISimpleText): TypeScript.SyntaxTree } export class Document { - private _bloomFilter: BloomFilter = null; + private _bloomFilter: TypeScript.BloomFilter = null; // By default, our Document class doesn't support incremental update of its contents. // However, we enable other layers (like teh services layer) to inject the capability // into us by setting this function. - public static incrementalParse: IncrementalParse = IncrementalParser.parse; + public static incrementalParse: IncrementalParse = TypeScript.IncrementalParser.parse; constructor(private compilationSettings: ts.CompilerOptions, public filename: string, public referencedFiles: string[], - private _scriptSnapshot: IScriptSnapshot, + private _scriptSnapshot: TypeScript.IScriptSnapshot, public byteOrderMark: ts.ByteOrderMark, public version: number, public isOpen: boolean, - private _syntaxTree: SyntaxTree, + private _syntaxTree: TypeScript.SyntaxTree, private _soruceFile: ts.SourceFile) { } public isDeclareFile(): boolean { - return isDTSFile(this.filename); + return TypeScript.isDTSFile(this.filename); } - public sourceUnit(): SourceUnitSyntax { + public sourceUnit(): TypeScript.SourceUnitSyntax { // If we don't have a script, create one from our parse tree. return this.syntaxTree().sourceUnit(); } - public diagnostics(): Diagnostic[] { - return this.syntaxTree().diagnostics(); - } + //public diagnostics(): Diagnostic[] { + // return this.syntaxTree().diagnostics(); + //} - public lineMap(): LineMap { + public lineMap(): TypeScript.LineMap { return this.syntaxTree().lineMap(); } - public syntaxTree(): SyntaxTree { + public syntaxTree(): TypeScript.SyntaxTree { if (!this._syntaxTree) { var start = new Date().getTime(); - this._syntaxTree = Parser.parse( - this.filename, SimpleText.fromScriptSnapshot(this._scriptSnapshot), this.compilationSettings.target, this.isDeclareFile()); + this._syntaxTree = TypeScript.Parser.parse( + this.filename, TypeScript.SimpleText.fromScriptSnapshot(this._scriptSnapshot), this.compilationSettings.target, this.isDeclareFile()); var time = new Date().getTime() - start; @@ -742,13 +716,13 @@ module TypeScript.Services { return this._soruceFile; } - public bloomFilter(): BloomFilter { + public bloomFilter(): TypeScript.BloomFilter { if (!this._bloomFilter) { - var identifiers = createIntrinsicsObject(); + var identifiers = TypeScript.createIntrinsicsObject(); var pre = function (cur: TypeScript.ISyntaxElement) { - if (ASTHelpers.isValidAstNode(cur)) { - if (cur.kind() === SyntaxKind.IdentifierName) { - var nodeText = tokenValueText((cur)); + if (TypeScript.ASTHelpers.isValidAstNode(cur)) { + if (cur.kind() === TypeScript.SyntaxKind.IdentifierName) { + var nodeText = TypeScript.tokenValueText((cur)); identifiers[nodeText] = true; } @@ -764,7 +738,7 @@ module TypeScript.Services { } } - this._bloomFilter = new BloomFilter(identifierCount); + this._bloomFilter = new TypeScript.BloomFilter(identifierCount); this._bloomFilter.addKeys(identifiers); } return this._bloomFilter; @@ -780,7 +754,7 @@ module TypeScript.Services { return !this.compilationSettings.out || this.syntaxTree().isExternalModule(); } - public update(scriptSnapshot: IScriptSnapshot, version: number, isOpen: boolean, textChangeRange: TextChangeRange): Document { + public update(scriptSnapshot: TypeScript.IScriptSnapshot, version: number, isOpen: boolean, textChangeRange: TypeScript.TextChangeRange): Document { // See if we are currently holding onto a syntax tree. We may not be because we're // either a closed file, or we've just been lazy and haven't had to create the syntax // tree yet. Access the field instead of the method so we don't accidently realize @@ -804,7 +778,7 @@ module TypeScript.Services { } } - var text = SimpleText.fromScriptSnapshot(scriptSnapshot); + var text = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot); // If we don't have a text change, or we don't have an old syntax tree, then do a full // parse. Otherwise, do an incremental parse. @@ -815,7 +789,7 @@ module TypeScript.Services { return new Document(this.compilationSettings, this.filename, this.referencedFiles, scriptSnapshot, this.byteOrderMark, version, isOpen, newSyntaxTree, /*soruceFile*/ null); } - public static create(compilationSettings: ts.CompilerOptions, fileName: string, scriptSnapshot: IScriptSnapshot, byteOrderMark: ts.ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]): Document { + public static create(compilationSettings: ts.CompilerOptions, fileName: string, scriptSnapshot: TypeScript.IScriptSnapshot, byteOrderMark: ts.ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]): Document { return new Document(compilationSettings, fileName, referencedFiles, scriptSnapshot, byteOrderMark, version, isOpen, /*syntaxTree:*/ null, /*soruceFile*/ null); } } @@ -1015,7 +989,7 @@ module TypeScript.Services { return this._currentFileSyntaxTree; } - public getCurrentScriptSnapshot(filename: string): IScriptSnapshot { + public getCurrentScriptSnapshot(filename: string): TypeScript.IScriptSnapshot { // update _currentFileScriptSnapshot as a part of 'getCurrentFileSyntaxTree' call this.getCurrentFileSyntaxTree(filename); return this._currentFileScriptSnapshot; @@ -1042,8 +1016,8 @@ module TypeScript.Services { return this.createSyntaxTree(filename, scriptSnapshot); } - var nextSyntaxTree = IncrementalParser.parse( - previousSyntaxTree, editRange, SimpleText.fromScriptSnapshot(scriptSnapshot)); + var nextSyntaxTree = TypeScript.IncrementalParser.parse( + previousSyntaxTree, editRange, TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot)); this.ensureInvariants(filename, editRange, nextSyntaxTree, this._currentFileScriptSnapshot, scriptSnapshot); @@ -1106,7 +1080,7 @@ module TypeScript.Services { // Ok, the trees looked good. So at least our incremental parser agrees with the // normal parser. Now, verify that the incremental tree matches the contents of the // script snapshot. - var incrementalTreeText = fullText(incrementalTree.sourceUnit()); + var incrementalTreeText = TypeScript.fullText(incrementalTree.sourceUnit()); var actualSnapshotText = newScriptSnapshot.getText(0, newScriptSnapshot.getLength()); Debug.assert(incrementalTreeText === actualSnapshotText, 'Expected full texts to be equal'); } @@ -1150,7 +1124,7 @@ module TypeScript.Services { public acquireDocument( filename: string, compilationSettings: ts.CompilerOptions, - scriptSnapshot: IScriptSnapshot, + scriptSnapshot: TypeScript.IScriptSnapshot, byteOrderMark: ts.ByteOrderMark, version: number, isOpen: boolean, @@ -1176,10 +1150,10 @@ module TypeScript.Services { document: Document, filename: string, compilationSettings: ts.CompilerOptions, - scriptSnapshot: IScriptSnapshot, + scriptSnapshot: TypeScript.IScriptSnapshot, version: number, isOpen: boolean, - textChangeRange: TextChangeRange + textChangeRange: TypeScript.TextChangeRange ): Document { var bucket = this.getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ false); @@ -1211,7 +1185,7 @@ module TypeScript.Services { export function createLanguageService(host: LanguageServiceHost, documentRegistry: IDocumentRegistry): LanguageService { var _syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host); - var formattingRulesProvider: Formatting.RulesProvider; + var formattingRulesProvider: TypeScript.Services.Formatting.RulesProvider; var hostCache: HostCache; // A cache of all the information about the files on the host side. var program: ts.Program; var typeChecker: ts.TypeChecker; @@ -1313,7 +1287,7 @@ module TypeScript.Services { // file was closed, then we always want to reparse. This is so our tree doesn't keep // the old buffer alive that represented the file on disk (as the host has moved to a // new text buffer). - var textChangeRange: TextChangeRange = null; + var textChangeRange: TypeScript.TextChangeRange = null; if (document.isOpen && isOpen) { textChangeRange = hostCache.getScriptTextChangeRangeSinceVersion(filename, document.version); } @@ -1361,7 +1335,7 @@ module TypeScript.Services { // Try to get a valid display name for this symbol, if we could not find one, then ignore it. // We would like to only show things that can be added after a dot, so for instance numeric properties can // not be accessed with a dot (a.1 <- invalid) - var displayName = CompletionHelpers.getValidCompletionEntryDisplayName(symbol.getName(), program.getCompilerOptions().target); + var displayName = TypeScript.Services.CompletionHelpers.getValidCompletionEntryDisplayName(symbol.getName(), program.getCompilerOptions().target); if (!displayName) { return undefined; } @@ -1393,7 +1367,7 @@ module TypeScript.Services { var document = documentsByName[filename]; var sourceUnit = document.sourceUnit(); - if (CompletionHelpers.isCompletionListBlocker(document.syntaxTree().sourceUnit(), position)) { + if (TypeScript.Services.CompletionHelpers.isCompletionListBlocker(document.syntaxTree().sourceUnit(), position)) { host.log("Returning an empty list because completion was blocked."); return null; } @@ -1401,7 +1375,7 @@ module TypeScript.Services { var node = TypeScript.ASTHelpers.getAstAtPosition(sourceUnit, position, /*useTrailingTriviaAsLimChar*/ true, /*forceInclusive*/ true); if (node && node.kind() === TypeScript.SyntaxKind.IdentifierName && - start(node) === end(node)) { + TypeScript.start(node) === TypeScript.end(node)) { // Ignore missing name nodes node = node.parent; } @@ -1409,14 +1383,14 @@ module TypeScript.Services { var isRightOfDot = false; if (node && node.kind() === TypeScript.SyntaxKind.MemberAccessExpression && - end((node).expression) < position) { + TypeScript.end((node).expression) < position) { isRightOfDot = true; node = (node).expression; } else if (node && node.kind() === TypeScript.SyntaxKind.QualifiedName && - end((node).left) < position) { + TypeScript.end((node).left) < position) { isRightOfDot = true; node = (node).left; @@ -1439,7 +1413,7 @@ module TypeScript.Services { } // TODO: this is a hack for now, we need a proper walking mechanism to verify that we have the correct node - var mappedNode = getNodeAtPosition(document.sourceFile(), end(node) - 1); + var mappedNode = getNodeAtPosition(document.sourceFile(), TypeScript.end(node) - 1); Debug.assert(mappedNode, "Could not map a Fidelity node to an AST node"); @@ -1465,11 +1439,11 @@ module TypeScript.Services { getCompletionEntriesFromSymbols(symbols, activeCompletionSession); } else { - var containingObjectLiteral = CompletionHelpers.getContainingObjectLiteralApplicableForCompletion(document.syntaxTree().sourceUnit(), position); + var containingObjectLiteral = TypeScript.Services.CompletionHelpers.getContainingObjectLiteralApplicableForCompletion(document.syntaxTree().sourceUnit(), position); // Object literal expression, look up possible property names from contextual type if (containingObjectLiteral) { - var searchPosition = Math.min(position, end(containingObjectLiteral)); + var searchPosition = Math.min(position, TypeScript.end(containingObjectLiteral)); var path = TypeScript.ASTHelpers.getAstAtPosition(sourceUnit, searchPosition); // Get the object literal node @@ -1511,7 +1485,7 @@ module TypeScript.Services { // Add keywords if this is not a member completion list if (!isMemberCompletion) { - Array.prototype.push.apply(activeCompletionSession.entries, KeywordCompletions.getKeywordCompltions()); + Array.prototype.push.apply(activeCompletionSession.entries, TypeScript.Services.KeywordCompletions.getKeywordCompltions()); } return { @@ -1666,7 +1640,7 @@ module TypeScript.Services { var type = typeChecker.getTypeOfSymbol(symbol); return { - memberName: new MemberNameString(typeChecker.typeToString(type)), + memberName: new TypeScript.MemberNameString(typeChecker.typeToString(type)), docComment: "", fullSymbolName: typeChecker.symbolToString(symbol, getEnclosingDeclaration(node)), kind: getSymbolKind(symbol), @@ -1682,7 +1656,7 @@ module TypeScript.Services { var type = typeChecker.getTypeOfExpression(node); Debug.assert(type, "getTypeAtPosition: Could not find type for node"); return { - memberName: new MemberNameString(""), + memberName: new TypeScript.MemberNameString(""), docComment: "", fullSymbolName: typeChecker.typeToString(type, getEnclosingDeclaration(node)), kind: getTypeKind(type), @@ -1708,7 +1682,7 @@ module TypeScript.Services { return null; } - if (ast.kind() === SyntaxKind.ParameterList && ast.parent.kind() === SyntaxKind.CallSignature && ast.parent.parent.kind() === SyntaxKind.ConstructorDeclaration) { + if (ast.kind() === TypeScript.SyntaxKind.ParameterList && ast.parent.kind() === TypeScript.SyntaxKind.CallSignature && ast.parent.parent.kind() === TypeScript.SyntaxKind.ConstructorDeclaration) { ast = ast.parent.parent; } @@ -1717,7 +1691,7 @@ module TypeScript.Services { return null; case TypeScript.SyntaxKind.ConstructorDeclaration: var constructorAST = ast; - if (!isConstructorValidPosition || !(position >= start(constructorAST) && position <= start(constructorAST) + "constructor".length)) { + if (!isConstructorValidPosition || !(position >= TypeScript.start(constructorAST) && position <= TypeScript.start(constructorAST) + "constructor".length)) { return null; } else { @@ -1751,8 +1725,8 @@ module TypeScript.Services { } return { - minChar: start(node), - limChar: end(node) + minChar: TypeScript.start(node), + limChar: TypeScript.end(node) }; } @@ -1768,7 +1742,7 @@ module TypeScript.Services { filename = TypeScript.switchToForwardSlashes(filename); var syntaxTree = getSyntaxTree(filename); var items: NavigateToItem[] = []; - GetScriptLexicalStructureWalker.getListsOfAllScriptLexicalStructure(items, filename, syntaxTree.sourceUnit()); + TypeScript.Services.GetScriptLexicalStructureWalker.getListsOfAllScriptLexicalStructure(items, filename, syntaxTree.sourceUnit()); return items; } @@ -1776,13 +1750,13 @@ module TypeScript.Services { // doesn't use compiler - no need to synchronize with host filename = TypeScript.switchToForwardSlashes(filename); var syntaxTree = getSyntaxTree(filename); - return OutliningElementsCollector.collectElements(syntaxTree.sourceUnit()); + return TypeScript.Services.OutliningElementsCollector.collectElements(syntaxTree.sourceUnit()); } function getBraceMatchingAtPosition(filename: string, position: number) { filename = TypeScript.switchToForwardSlashes(filename); var syntaxTree = getSyntaxTree(filename); - return BraceMatcher.getMatchSpans(syntaxTree, position); + return TypeScript.Services.BraceMatcher.getMatchSpans(syntaxTree, position); } function getIndentationAtPosition(filename: string, position: number, editorOptions: EditorOptions) { @@ -1793,7 +1767,7 @@ module TypeScript.Services { var scriptSnapshot = _syntaxTreeCache.getCurrentScriptSnapshot(filename); var scriptText = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot); var textSnapshot = new TypeScript.Services.Formatting.TextSnapshot(scriptText); - var options = new FormattingOptions(!editorOptions.ConvertTabsToSpaces, editorOptions.TabSize, editorOptions.IndentSize, editorOptions.NewLineCharacter) + var options = new TypeScript.FormattingOptions(!editorOptions.ConvertTabsToSpaces, editorOptions.TabSize, editorOptions.IndentSize, editorOptions.NewLineCharacter) return TypeScript.Services.Formatting.SingleTokenIndenter.getIndentationAmount(position, syntaxTree.sourceUnit(), textSnapshot, options); } @@ -1934,10 +1908,10 @@ module TypeScript.Services { }; var simpleText = TypeScript.SimpleText.fromString(text); - scanner = Scanner.createScanner(ts.ScriptTarget.ES5, simpleText, reportDiagnostic); + scanner = TypeScript.Scanner.createScanner(ts.ScriptTarget.ES5, simpleText, reportDiagnostic); var lastTokenKind = TypeScript.SyntaxKind.None; - var token: ISyntaxToken = null; + var token: TypeScript.ISyntaxToken = null; do { lastDiagnosticKey = null; @@ -1946,18 +1920,18 @@ module TypeScript.Services { processToken(text, simpleText, offset, token, result); } - while (token.kind() !== SyntaxKind.EndOfFileToken); + while (token.kind() !== TypeScript.SyntaxKind.EndOfFileToken); lastDiagnosticKey = null; return result; } - function processToken(text: string, simpleText: ISimpleText, offset: number, token: TypeScript.ISyntaxToken, result: ClassificationResult): void { + function processToken(text: string, simpleText: TypeScript.ISimpleText, offset: number, token: TypeScript.ISyntaxToken, result: ClassificationResult): void { processTriviaList(text, offset, token.leadingTrivia(simpleText), result); - addResult(text, offset, result, width(token), token.kind()); + addResult(text, offset, result, TypeScript.width(token), token.kind()); processTriviaList(text, offset, token.trailingTrivia(simpleText), result); - if (fullEnd(token) >= text.length) { + if (TypeScript.fullEnd(token) >= text.length) { // We're at the end. if (lastDiagnosticKey === TypeScript.DiagnosticCode.AsteriskSlash_expected) { result.finalLexState = EndOfLineState.InMultiLineCommentTrivia; @@ -2030,4 +2004,26 @@ module TypeScript.Services { getClassificationsForLine: getClassificationsForLine }; } + + function initializeServices() { + objectAllocator = { + getNodeConstructor: kind => { + function Node() { + } + var proto = new NodeObject(); + proto.kind = kind; + proto.pos = 0; + proto.end = 0; + proto.flags = 0; + proto.parent = undefined; + Node.prototype = proto; + return Node; + }, + getSymbolConstructor: () => SymbolObject, + getTypeConstructor: () => TypeObject, + getSignatureConstructor: () => SignatureObject, + }; + } + + initializeServices(); } \ No newline at end of file diff --git a/src/services/shims.ts b/src/services/shims.ts index a8821b1ea44..71fd0ba0320 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -18,7 +18,7 @@ /// /// var debugObjectHost = (this); -module TypeScript.Services { +module ts { export interface ScriptSnapshotShim { // Get's a portion of the script snapshot specified by [start, end). getText(start: number, end: number): string; @@ -904,7 +904,7 @@ module TypeScript.Services { /// TODO: this is used by VS, clean this up on both sides of the interfrace -module Services { - export var TypeScriptServicesFactory = TypeScriptServicesFactory; +module TypeScript.Services { + export var TypeScriptServicesFactory = ts.TypeScriptServicesFactory; } From 2b04bcf5a3699f68027f9737a58ed0857e79735a Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Fri, 25 Jul 2014 10:53:52 -0700 Subject: [PATCH 37/59] merge keyword completions in services.ts --- src/services/keywordCompletions.ts | 76 ------------------------------ src/services/services.ts | 35 +++++++++++++- 2 files changed, 33 insertions(+), 78 deletions(-) delete mode 100644 src/services/keywordCompletions.ts diff --git a/src/services/keywordCompletions.ts b/src/services/keywordCompletions.ts deleted file mode 100644 index 5e6b667b2d9..00000000000 --- a/src/services/keywordCompletions.ts +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0. -// See LICENSE.txt in the project root for complete license information. - -/// - -module TypeScript.Services { - export class KeywordCompletions { - private static keywords = [ - "break", - "case", - "catch", - "class", - "constructor", - "continue", - "debugger", - "declare", - "default", - "delete", - "do", - "else", - "enum", - "export", - "extends", - "false", - "finally", - "for", - "function", - "get", - "if", - "implements", - "import", - "in", - "instanceof", - "interface", - "module", - "new", - "null", - "private", - "public", - "require", - "return", - "set", - "static", - "super", - "switch", - "this", - "throw", - "true", - "try", - "typeof", - "var", - "while", - "with", - ]; - - private static keywordCompletions: ts.CompletionEntry[] = null; - - public static getKeywordCompltions(): ts.CompletionEntry[]{ - if (KeywordCompletions.keywordCompletions === null) { - var completions: ts.CompletionEntry[] = []; - for (var i = 0, n = KeywordCompletions.keywords.length; i < n; i++) { - var keyword = KeywordCompletions.keywords[i]; - completions.push({ - name: keyword, - kind: ts.ScriptElementKind.keyword, - kindModifiers: ts.ScriptElementKindModifier.none - }); - } - - KeywordCompletions.keywordCompletions = completions; - } - - return KeywordCompletions.keywordCompletions; - } - } -} \ No newline at end of file diff --git a/src/services/services.ts b/src/services/services.ts index 488cd4a7282..99e2b60b23f 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -12,7 +12,6 @@ /// /// /// -/// /// /// @@ -1194,6 +1193,7 @@ module ts { var documentRegistry = documentRegistry; var cancellationToken = new CancellationToken(host.getCancellationToken()); var activeCompletionSession: CompletionSession; + var keywordCompletions = getKeywordCompletionEntries(); // Check if the localized messages json is set, otherwise query the host for it if (!TypeScript.LocalizedDiagnosticMessages) { @@ -1349,6 +1349,37 @@ module ts { }; } + function getKeywordCompletionEntries(): CompletionEntry[] { + var keywords = [ + "break", + "case", "catch", "class", "constructor", "continue", + "debugger", "declare", "default", "delete", "do", + "else", "enum", "export", "extends", + "false", "finally", "for", "function", + "get", + "if","implements", "import", "in", "instanceof", "interface", + "module", + "new", "null", + "private", "public", + "require","return", + "set", "static", "super", "switch", + "this", "throw", "true", "try", "typeof", + "var", + "while","with", + ]; + + var result = []; + forEach(keywords, (keyword) => { + result.push({ + name: keyword, + kind: ScriptElementKind.keyword, + kindModifiers: ScriptElementKindModifier.none + }); + }); + + return result; + } + function getCompletionsAtPosition(filename: string, position: number, isMemberCompletion: boolean) { function getCompletionEntriesFromSymbols(symbols: ts.Symbol[], session: CompletionSession): void { ts.forEach(symbols, (symbol) => { @@ -1485,7 +1516,7 @@ module ts { // Add keywords if this is not a member completion list if (!isMemberCompletion) { - Array.prototype.push.apply(activeCompletionSession.entries, TypeScript.Services.KeywordCompletions.getKeywordCompltions()); + Array.prototype.push.apply(activeCompletionSession.entries, keywordCompletions); } return { From f8f061ac4d65f06867c292042af6499b0044aac3 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Fri, 25 Jul 2014 10:54:11 -0700 Subject: [PATCH 38/59] merge completion helpers in services.ts --- src/services/completionHelpers.ts | 193 ------------------------------ src/services/services.ts | 153 +++++++++++++++++++++-- 2 files changed, 146 insertions(+), 200 deletions(-) delete mode 100644 src/services/completionHelpers.ts diff --git a/src/services/completionHelpers.ts b/src/services/completionHelpers.ts deleted file mode 100644 index 17a68d097b0..00000000000 --- a/src/services/completionHelpers.ts +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0. -// See LICENSE.txt in the project root for complete license information. - -/// - -module TypeScript.Services { - export class CompletionHelpers { - private static getSpan(ast: ISyntaxElement): TextSpan { - return new TextSpan(start(ast), width(ast)); - } - - //private static symbolDeclarationIntersectsPosition(symbol: PullSymbol, fileName: string, position: number) { - // var decl = symbol.getDeclarations()[0]; - // if (decl.fileName() === fileName && this.getSpan(decl.ast()).intersectsWithPosition(position)) { - // // This is the symbol declaration from the given position in the file - // return true; - // } - - // return false; - //} - - //public static filterContextualMembersList(contextualMemberSymbols: TypeScript.PullSymbol[], existingMembers: TypeScript.PullVisibleSymbolsInfo, fileName: string, position: number): TypeScript.PullSymbol[] { - // if (!existingMembers || !existingMembers.symbols || existingMembers.symbols.length === 0) { - // return contextualMemberSymbols; - // } - - // var existingMemberSymbols = existingMembers.symbols; - // var existingMemberNames = TypeScript.createIntrinsicsObject(); - // for (var i = 0, n = existingMemberSymbols.length; i < n; i++) { - // if (this.symbolDeclarationIntersectsPosition(existingMemberSymbols[i], fileName, position)) { - // // If this is the current item we are editing right now, do not filter it out - // continue; - // } - - // existingMemberNames[TypeScript.stripStartAndEndQuotes(existingMemberSymbols[i].getDisplayName())] = true; - // } - - // var filteredMembers: TypeScript.PullSymbol[] = []; - // for (var j = 0, m = contextualMemberSymbols.length; j < m; j++) { - // var contextualMemberSymbol = contextualMemberSymbols[j]; - // if (!existingMemberNames[TypeScript.stripStartAndEndQuotes(contextualMemberSymbol.getDisplayName())]) { - // if (this.symbolDeclarationIntersectsPosition(contextualMemberSymbol, fileName, position)) { - // // If this contextual member symbol was created as part of editing the current position, do not use it - // continue; - // } - // filteredMembers.push(contextualMemberSymbol); - // } - // } - - // return filteredMembers; - //} - - public static isCompletionListBlocker(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean { - // We shouldn't be getting a possition that is outside the file because - // isEntirelyInsideComment can't handle when the position is out of bounds, - // callers should be fixed, however we should be resiliant to bad inputs - // so we return true (this position is a blocker for getting completions) - if (position < 0 || position > fullWidth(sourceUnit)) { - return true; - } - - // This method uses Fidelity completely. Some information can be reached using the AST, but not everything. - return TypeScript.Syntax.isEntirelyInsideComment(sourceUnit, position) || - TypeScript.Syntax.isEntirelyInStringOrRegularExpressionLiteral(sourceUnit, position) || - CompletionHelpers.isIdentifierDefinitionLocation(sourceUnit, position) || - CompletionHelpers.isRightOfIllegalDot(sourceUnit, position); - } - - public static getContainingObjectLiteralApplicableForCompletion(sourceUnit: TypeScript.SourceUnitSyntax, position: number): TypeScript.ISyntaxElement { - // The locations in an object literal expression that are applicable for completion are property name definition locations. - var previousToken = CompletionHelpers.getNonIdentifierCompleteTokenOnLeft(sourceUnit, position); - - if (previousToken) { - var parent = previousToken.parent; - - switch (previousToken.kind()) { - case TypeScript.SyntaxKind.OpenBraceToken: // var x = { | - case TypeScript.SyntaxKind.CommaToken: // var x = { a: 0, | - if (parent && parent.kind() === TypeScript.SyntaxKind.SeparatedList) { - parent = parent.parent; - } - - if (parent && parent.kind() === TypeScript.SyntaxKind.ObjectLiteralExpression) { - return parent; - } - - break; - } - } - - return null; - } - - public static isIdentifierDefinitionLocation(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean { - var positionedToken = CompletionHelpers.getNonIdentifierCompleteTokenOnLeft(sourceUnit, position); - - if (positionedToken) { - var containingNodeKind = Syntax.containingNode(positionedToken) && Syntax.containingNode(positionedToken).kind(); - switch (positionedToken.kind()) { - case TypeScript.SyntaxKind.CommaToken: - return containingNodeKind === TypeScript.SyntaxKind.ParameterList || - containingNodeKind === TypeScript.SyntaxKind.VariableDeclaration || - containingNodeKind === TypeScript.SyntaxKind.EnumDeclaration; // enum { foo, | - - case TypeScript.SyntaxKind.OpenParenToken: - return containingNodeKind === TypeScript.SyntaxKind.ParameterList || - containingNodeKind === TypeScript.SyntaxKind.CatchClause; - - case TypeScript.SyntaxKind.OpenBraceToken: - return containingNodeKind === TypeScript.SyntaxKind.EnumDeclaration; // enum { | - - case TypeScript.SyntaxKind.PublicKeyword: - case TypeScript.SyntaxKind.PrivateKeyword: - case TypeScript.SyntaxKind.StaticKeyword: - case TypeScript.SyntaxKind.DotDotDotToken: - return containingNodeKind === TypeScript.SyntaxKind.Parameter; - - case TypeScript.SyntaxKind.ClassKeyword: - case TypeScript.SyntaxKind.ModuleKeyword: - case TypeScript.SyntaxKind.EnumKeyword: - case TypeScript.SyntaxKind.InterfaceKeyword: - case TypeScript.SyntaxKind.FunctionKeyword: - case TypeScript.SyntaxKind.VarKeyword: - case TypeScript.SyntaxKind.GetKeyword: - case TypeScript.SyntaxKind.SetKeyword: - return true; - } - - // Previous token may have been a keyword that was converted to an identifier. - switch (positionedToken.text()) { - case "class": - case "interface": - case "enum": - case "module": - return true; - } - } - - return false; - } - - public static getNonIdentifierCompleteTokenOnLeft(sourceUnit: TypeScript.SourceUnitSyntax, position: number): TypeScript.ISyntaxToken { - var positionedToken = Syntax.findCompleteTokenOnLeft(sourceUnit, position, /*includeSkippedTokens*/true); - - if (positionedToken && position === end(positionedToken) && positionedToken.kind() == TypeScript.SyntaxKind.EndOfFileToken) { - // EndOfFile token is not intresting, get the one before it - positionedToken = previousToken(positionedToken, /*includeSkippedTokens*/true); - } - - if (positionedToken && position === end(positionedToken) && positionedToken.kind() === TypeScript.SyntaxKind.IdentifierName) { - // The caret is at the end of an identifier, the decession to provide completion depends on the previous token - positionedToken = previousToken(positionedToken, /*includeSkippedTokens*/true); - } - - return positionedToken; - } - - public static isRightOfIllegalDot(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean { - var positionedToken = CompletionHelpers.getNonIdentifierCompleteTokenOnLeft(sourceUnit, position); - - if (positionedToken) { - switch (positionedToken.kind()) { - case TypeScript.SyntaxKind.DotToken: - var leftOfDotPositionedToken = previousToken(positionedToken, /*includeSkippedTokens*/true); - return leftOfDotPositionedToken && leftOfDotPositionedToken.kind() === TypeScript.SyntaxKind.NumericLiteral; - - case TypeScript.SyntaxKind.NumericLiteral: - var text = positionedToken.text(); - return text.charAt(text.length - 1) === "."; - } - } - - return false; - } - - public static getValidCompletionEntryDisplayName(displayName: string, target: ts.ScriptTarget): string { - if (displayName && displayName.length > 0) { - var firstChar = displayName.charCodeAt(0); - if (firstChar === TypeScript.CharacterCodes.singleQuote || firstChar === TypeScript.CharacterCodes.doubleQuote) { - // If the user entered name for the symbol was quoted, removing the quotes is not enough, as the name could be an - // invalid identifer name. We need to check if whatever was inside the quotes is actually a valid identifier name. - displayName = TypeScript.stripStartAndEndQuotes(displayName); - } - - if (TypeScript.Scanner.isValidIdentifier(TypeScript.SimpleText.fromString(displayName), target)) { - return displayName; - } - } - - return null; - } - } -} \ No newline at end of file diff --git a/src/services/services.ts b/src/services/services.ts index 99e2b60b23f..3039725e9c1 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -11,7 +11,6 @@ /// /// /// -/// /// /// @@ -1192,8 +1191,8 @@ module ts { var documentsByName: ts.Map = {}; var documentRegistry = documentRegistry; var cancellationToken = new CancellationToken(host.getCancellationToken()); - var activeCompletionSession: CompletionSession; - var keywordCompletions = getKeywordCompletionEntries(); + var activeCompletionSession: CompletionSession; // The current active completion session, used to get the completion entry details + var keywordCompletions = getKeywordCompletionEntries(); // A cache of completion entries for keywords, these do not change between sessions // Check if the localized messages json is set, otherwise query the host for it if (!TypeScript.LocalizedDiagnosticMessages) { @@ -1331,11 +1330,28 @@ module ts { } /// Completion + function getValidCompletionEntryDisplayName(displayName: string, target: ts.ScriptTarget): string { + if (displayName && displayName.length > 0) { + var firstChar = displayName.charCodeAt(0); + if (firstChar === TypeScript.CharacterCodes.singleQuote || firstChar === TypeScript.CharacterCodes.doubleQuote) { + // If the user entered name for the symbol was quoted, removing the quotes is not enough, as the name could be an + // invalid identifer name. We need to check if whatever was inside the quotes is actually a valid identifier name. + displayName = TypeScript.stripStartAndEndQuotes(displayName); + } + + if (TypeScript.Scanner.isValidIdentifier(TypeScript.SimpleText.fromString(displayName), target)) { + return displayName; + } + } + + return undefined; + } + function createCompletionEntry(symbol: ts.Symbol): CompletionEntry { // Try to get a valid display name for this symbol, if we could not find one, then ignore it. // We would like to only show things that can be added after a dot, so for instance numeric properties can // not be accessed with a dot (a.1 <- invalid) - var displayName = TypeScript.Services.CompletionHelpers.getValidCompletionEntryDisplayName(symbol.getName(), program.getCompilerOptions().target); + var displayName = getValidCompletionEntryDisplayName(symbol.getName(), program.getCompilerOptions().target); if (!displayName) { return undefined; } @@ -1391,6 +1407,129 @@ module ts { }); } + function isCompletionListBlocker(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean { + // We shouldn't be getting a possition that is outside the file because + // isEntirelyInsideComment can't handle when the position is out of bounds, + // callers should be fixed, however we should be resiliant to bad inputs + // so we return true (this position is a blocker for getting completions) + if (position < 0 || position > TypeScript.fullWidth(sourceUnit)) { + return true; + } + + // This method uses Fidelity completely. Some information can be reached using the AST, but not everything. + return TypeScript.Syntax.isEntirelyInsideComment(sourceUnit, position) || + TypeScript.Syntax.isEntirelyInStringOrRegularExpressionLiteral(sourceUnit, position) || + isIdentifierDefinitionLocation(sourceUnit, position) || + isRightOfIllegalDot(sourceUnit, position); + } + + function getContainingObjectLiteralApplicableForCompletion(sourceUnit: TypeScript.SourceUnitSyntax, position: number): TypeScript.ISyntaxElement { + // The locations in an object literal expression that are applicable for completion are property name definition locations. + var previousToken = getNonIdentifierCompleteTokenOnLeft(sourceUnit, position); + + if (previousToken) { + var parent = previousToken.parent; + + switch (previousToken.kind()) { + case TypeScript.SyntaxKind.OpenBraceToken: // var x = { | + case TypeScript.SyntaxKind.CommaToken: // var x = { a: 0, | + if (parent && parent.kind() === TypeScript.SyntaxKind.SeparatedList) { + parent = parent.parent; + } + + if (parent && parent.kind() === TypeScript.SyntaxKind.ObjectLiteralExpression) { + return parent; + } + + break; + } + } + + return undefined; + } + + function isIdentifierDefinitionLocation(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean { + var positionedToken = getNonIdentifierCompleteTokenOnLeft(sourceUnit, position); + + if (positionedToken) { + var containingNodeKind = TypeScript.Syntax.containingNode(positionedToken) && TypeScript.Syntax.containingNode(positionedToken).kind(); + switch (positionedToken.kind()) { + case TypeScript.SyntaxKind.CommaToken: + return containingNodeKind === TypeScript.SyntaxKind.ParameterList || + containingNodeKind === TypeScript.SyntaxKind.VariableDeclaration || + containingNodeKind === TypeScript.SyntaxKind.EnumDeclaration; // enum { foo, | + + case TypeScript.SyntaxKind.OpenParenToken: + return containingNodeKind === TypeScript.SyntaxKind.ParameterList || + containingNodeKind === TypeScript.SyntaxKind.CatchClause; + + case TypeScript.SyntaxKind.OpenBraceToken: + return containingNodeKind === TypeScript.SyntaxKind.EnumDeclaration; // enum { | + + case TypeScript.SyntaxKind.PublicKeyword: + case TypeScript.SyntaxKind.PrivateKeyword: + case TypeScript.SyntaxKind.StaticKeyword: + case TypeScript.SyntaxKind.DotDotDotToken: + return containingNodeKind === TypeScript.SyntaxKind.Parameter; + + case TypeScript.SyntaxKind.ClassKeyword: + case TypeScript.SyntaxKind.ModuleKeyword: + case TypeScript.SyntaxKind.EnumKeyword: + case TypeScript.SyntaxKind.InterfaceKeyword: + case TypeScript.SyntaxKind.FunctionKeyword: + case TypeScript.SyntaxKind.VarKeyword: + case TypeScript.SyntaxKind.GetKeyword: + case TypeScript.SyntaxKind.SetKeyword: + return true; + } + + // Previous token may have been a keyword that was converted to an identifier. + switch (positionedToken.text()) { + case "class": + case "interface": + case "enum": + case "module": + return true; + } + } + + return false; + } + + function getNonIdentifierCompleteTokenOnLeft(sourceUnit: TypeScript.SourceUnitSyntax, position: number): TypeScript.ISyntaxToken { + var positionedToken = TypeScript.Syntax.findCompleteTokenOnLeft(sourceUnit, position, /*includeSkippedTokens*/true); + + if (positionedToken && position === TypeScript.end(positionedToken) && positionedToken.kind() == TypeScript.SyntaxKind.EndOfFileToken) { + // EndOfFile token is not intresting, get the one before it + positionedToken = TypeScript. previousToken(positionedToken, /*includeSkippedTokens*/true); + } + + if (positionedToken && position === TypeScript.end(positionedToken) && positionedToken.kind() === TypeScript.SyntaxKind.IdentifierName) { + // The caret is at the end of an identifier, the decession to provide completion depends on the previous token + positionedToken = TypeScript.previousToken(positionedToken, /*includeSkippedTokens*/true); + } + + return positionedToken; + } + + function isRightOfIllegalDot(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean { + var positionedToken = getNonIdentifierCompleteTokenOnLeft(sourceUnit, position); + + if (positionedToken) { + switch (positionedToken.kind()) { + case TypeScript.SyntaxKind.DotToken: + var leftOfDotPositionedToken = TypeScript.previousToken(positionedToken, /*includeSkippedTokens*/true); + return leftOfDotPositionedToken && leftOfDotPositionedToken.kind() === TypeScript.SyntaxKind.NumericLiteral; + + case TypeScript.SyntaxKind.NumericLiteral: + var text = positionedToken.text(); + return text.charAt(text.length - 1) === "."; + } + } + + return false; + } + synchronizeHostData(); filename = TypeScript.switchToForwardSlashes(filename); @@ -1398,7 +1537,7 @@ module ts { var document = documentsByName[filename]; var sourceUnit = document.sourceUnit(); - if (TypeScript.Services.CompletionHelpers.isCompletionListBlocker(document.syntaxTree().sourceUnit(), position)) { + if (isCompletionListBlocker(document.syntaxTree().sourceUnit(), position)) { host.log("Returning an empty list because completion was blocked."); return null; } @@ -1470,7 +1609,7 @@ module ts { getCompletionEntriesFromSymbols(symbols, activeCompletionSession); } else { - var containingObjectLiteral = TypeScript.Services.CompletionHelpers.getContainingObjectLiteralApplicableForCompletion(document.syntaxTree().sourceUnit(), position); + var containingObjectLiteral = getContainingObjectLiteralApplicableForCompletion(document.syntaxTree().sourceUnit(), position); // Object literal expression, look up possible property names from contextual type if (containingObjectLiteral) { @@ -1498,7 +1637,7 @@ module ts { // // Add filtterd items to the completion list // getCompletionEntriesFromSymbols({ - // symbols: CompletionHelpers.filterContextualMembersList(contextualMembers.symbols, existingMembers, filename, position), + // symbols: filterContextualMembersList(contextualMembers.symbols, existingMembers, filename, position), // enclosingScopeSymbol: contextualMembers.enclosingScopeSymbol // }, entries); //} From ee8c4e961eeb387a51e6859fff2b72b428fc7fad Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Fri, 25 Jul 2014 11:17:10 -0700 Subject: [PATCH 39/59] remove _ prefix when applicable --- src/services/services.ts | 84 ++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 3039725e9c1..6097a267c07 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -816,7 +816,7 @@ module ts { version: number; isOpen: boolean; byteOrderMark: ts.ByteOrderMark; - _sourceText?: TypeScript.IScriptSnapshot; + sourceText?: TypeScript.IScriptSnapshot; } interface DocumentRegistryEntry { @@ -871,17 +871,17 @@ module ts { // at each language service public entry point, since we don't know when // set of scripts handled by the host changes. class HostCache { - private _filenameToEntry: ts.Map; + private filenameToEntry: ts.Map; private _compilationSettings: ts.CompilerOptions; constructor(private host: LanguageServiceHost) { // script id => script index - this._filenameToEntry = {}; + this.filenameToEntry = {}; var filenames = host.getScriptFileNames(); for (var i = 0, n = filenames.length; i < n; i++) { var filename = filenames[i]; - this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)] = { + this.filenameToEntry[TypeScript.switchToForwardSlashes(filename)] = { filename: filename, version: host.getScriptVersion(filename), isOpen: host.getScriptIsOpen(filename), @@ -897,11 +897,11 @@ module ts { } public contains(filename: string): boolean { - return !!this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)]; + return !!this.filenameToEntry[TypeScript.switchToForwardSlashes(filename)]; } public getHostfilename(filename: string) { - var hostCacheEntry = this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)]; + var hostCacheEntry = this.filenameToEntry[TypeScript.switchToForwardSlashes(filename)]; if (hostCacheEntry) { return hostCacheEntry.filename; } @@ -910,30 +910,30 @@ module ts { public getfilenames(): string[] { var fileNames: string[] = []; - for (var id in this._filenameToEntry) { + for (var id in this.filenameToEntry) { fileNames.push(id); } return fileNames; } public getVersion(filename: string): number { - return this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)].version; + return this.filenameToEntry[TypeScript.switchToForwardSlashes(filename)].version; } public isOpen(filename: string): boolean { - return this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)].isOpen; + return this.filenameToEntry[TypeScript.switchToForwardSlashes(filename)].isOpen; } public getByteOrderMark(filename: string): ts.ByteOrderMark { - return this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)].byteOrderMark; + return this.filenameToEntry[TypeScript.switchToForwardSlashes(filename)].byteOrderMark; } public getScriptSnapshot(filename: string): TypeScript.IScriptSnapshot { - var file = this._filenameToEntry[TypeScript.switchToForwardSlashes(filename)]; - if (!file._sourceText) { - file._sourceText = this.host.getScriptSnapshot(file.filename); + var file = this.filenameToEntry[TypeScript.switchToForwardSlashes(filename)]; + if (!file.sourceText) { + file.sourceText = this.host.getScriptSnapshot(file.filename); } - return file._sourceText; + return file.sourceText; } public getScriptTextChangeRangeSinceVersion(filename: string, lastKnownVersion: number): TypeScript.TextChangeRange { @@ -948,49 +948,49 @@ module ts { } class SyntaxTreeCache { - private _hostCache: HostCache; + private hostCache: HostCache; // For our syntactic only features, we also keep a cache of the syntax tree for the // currently edited file. - private _currentfilename: string = ""; - private _currentFileVersion: number = -1; - private _currentFileSyntaxTree: TypeScript.SyntaxTree = null; - private _currentFileScriptSnapshot: TypeScript.IScriptSnapshot = null; + private currentfilename: string = ""; + private currentFileVersion: number = -1; + private currentFileSyntaxTree: TypeScript.SyntaxTree = null; + private currentFileScriptSnapshot: TypeScript.IScriptSnapshot = null; - constructor(private _host: LanguageServiceHost) { - this._hostCache = new HostCache(_host); + constructor(private host: LanguageServiceHost) { + this.hostCache = new HostCache(host); } public getCurrentFileSyntaxTree(filename: string): TypeScript.SyntaxTree { - this._hostCache = new HostCache(this._host); + this.hostCache = new HostCache(this.host); - var version = this._hostCache.getVersion(filename); + var version = this.hostCache.getVersion(filename); var syntaxTree: TypeScript.SyntaxTree = null; - if (this._currentFileSyntaxTree === null || this._currentfilename !== filename) { - var scriptSnapshot = this._hostCache.getScriptSnapshot(filename); + if (this.currentFileSyntaxTree === null || this.currentfilename !== filename) { + var scriptSnapshot = this.hostCache.getScriptSnapshot(filename); syntaxTree = this.createSyntaxTree(filename, scriptSnapshot); } - else if (this._currentFileVersion !== version) { - var scriptSnapshot = this._hostCache.getScriptSnapshot(filename); - syntaxTree = this.updateSyntaxTree(filename, scriptSnapshot, this._currentFileSyntaxTree, this._currentFileVersion); + else if (this.currentFileVersion !== version) { + var scriptSnapshot = this.hostCache.getScriptSnapshot(filename); + syntaxTree = this.updateSyntaxTree(filename, scriptSnapshot, this.currentFileSyntaxTree, this.currentFileVersion); } if (syntaxTree !== null) { // All done, ensure state is up to date - this._currentFileScriptSnapshot = scriptSnapshot; - this._currentFileVersion = version; - this._currentfilename = filename; - this._currentFileSyntaxTree = syntaxTree; + this.currentFileScriptSnapshot = scriptSnapshot; + this.currentFileVersion = version; + this.currentfilename = filename; + this.currentFileSyntaxTree = syntaxTree; } - return this._currentFileSyntaxTree; + return this.currentFileSyntaxTree; } public getCurrentScriptSnapshot(filename: string): TypeScript.IScriptSnapshot { - // update _currentFileScriptSnapshot as a part of 'getCurrentFileSyntaxTree' call + // update currentFileScriptSnapshot as a part of 'getCurrentFileSyntaxTree' call this.getCurrentFileSyntaxTree(filename); - return this._currentFileScriptSnapshot; + return this.currentFileScriptSnapshot; } private createSyntaxTree(filename: string, scriptSnapshot: TypeScript.IScriptSnapshot): TypeScript.SyntaxTree { @@ -1005,7 +1005,7 @@ module ts { } private updateSyntaxTree(filename: string, scriptSnapshot: TypeScript.IScriptSnapshot, previousSyntaxTree: TypeScript.SyntaxTree, previousFileVersion: number): TypeScript.SyntaxTree { - var editRange = this._hostCache.getScriptTextChangeRangeSinceVersion(filename, previousFileVersion); + var editRange = this.hostCache.getScriptTextChangeRangeSinceVersion(filename, previousFileVersion); // Debug.assert(newLength >= 0); @@ -1017,7 +1017,7 @@ module ts { var nextSyntaxTree = TypeScript.IncrementalParser.parse( previousSyntaxTree, editRange, TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot)); - this.ensureInvariants(filename, editRange, nextSyntaxTree, this._currentFileScriptSnapshot, scriptSnapshot); + this.ensureInvariants(filename, editRange, nextSyntaxTree, this.currentFileScriptSnapshot, scriptSnapshot); return nextSyntaxTree; } @@ -1182,7 +1182,7 @@ module ts { } export function createLanguageService(host: LanguageServiceHost, documentRegistry: IDocumentRegistry): LanguageService { - var _syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host); + var syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host); var formattingRulesProvider: TypeScript.Services.Formatting.RulesProvider; var hostCache: HostCache; // A cache of all the information about the files on the host side. var program: ts.Program; @@ -1840,12 +1840,12 @@ module ts { /// Syntactic features function getSyntaxTree(filename: string): TypeScript.SyntaxTree { filename = TypeScript.switchToForwardSlashes(filename); - return _syntaxTreeCache.getCurrentFileSyntaxTree(filename); + return syntaxTreeCache.getCurrentFileSyntaxTree(filename); } function getNameOrDottedNameSpan(filename: string, startPos: number, endPos: number): SpanInfo { function getTypeInfoEligiblePath(filename: string, position: number, isConstructorValidPosition: boolean) { - var sourceUnit = _syntaxTreeCache.getCurrentFileSyntaxTree(filename).sourceUnit(); + var sourceUnit = syntaxTreeCache.getCurrentFileSyntaxTree(filename).sourceUnit(); var ast = TypeScript.ASTHelpers.getAstAtPosition(sourceUnit, position, /*useTrailingTriviaAsLimChar*/ false, /*forceInclusive*/ true); if (ast === null) { @@ -1934,7 +1934,7 @@ module ts { var syntaxTree = getSyntaxTree(filename); - var scriptSnapshot = _syntaxTreeCache.getCurrentScriptSnapshot(filename); + var scriptSnapshot = syntaxTreeCache.getCurrentScriptSnapshot(filename); var scriptText = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot); var textSnapshot = new TypeScript.Services.Formatting.TextSnapshot(scriptText); var options = new TypeScript.FormattingOptions(!editorOptions.ConvertTabsToSpaces, editorOptions.TabSize, editorOptions.IndentSize, editorOptions.NewLineCharacter) @@ -1954,7 +1954,7 @@ module ts { var syntaxTree = getSyntaxTree(filename); // Convert IScriptSnapshot to ITextSnapshot - var scriptSnapshot = _syntaxTreeCache.getCurrentScriptSnapshot(filename); + var scriptSnapshot = syntaxTreeCache.getCurrentScriptSnapshot(filename); var scriptText = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot); var textSnapshot = new TypeScript.Services.Formatting.TextSnapshot(scriptText); From 89161c7bc76d7379290c8ca262fd63b8fee76657 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Fri, 25 Jul 2014 11:21:17 -0700 Subject: [PATCH 40/59] move DocumentRegistry to an interface --- src/services/services.ts | 43 +++++++++++++++++++++++----------------- src/services/shims.ts | 8 +++++--- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 6097a267c07..5dffef73e29 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -539,7 +539,7 @@ module ts { getClassificationsForLine(text: string, lexState: EndOfLineState): ClassificationResult; } - export interface IDocumentRegistry { + export interface DocumentRegistry { acquireDocument( filename: string, compilationSettings: ts.CompilerOptions, @@ -1085,25 +1085,25 @@ module ts { } } - export class DocumentRegistry implements IDocumentRegistry { - private buckets: ts.Map> = {}; + export function createDocumentRegistry(): DocumentRegistry { + var buckets: ts.Map> = {}; - private getKeyFromCompilationSettings(settings: ts.CompilerOptions): string { + function getKeyFromCompilationSettings(settings: ts.CompilerOptions): string { return "_" + ts.ScriptTarget[settings.target]; // + "|" + settings.propagateEnumConstants.toString() } - private getBucketForCompilationSettings(settings: ts.CompilerOptions, createIfMissing: boolean): ts.Map { - var key = this.getKeyFromCompilationSettings(settings); - var bucket = this.buckets[key]; + function getBucketForCompilationSettings(settings: ts.CompilerOptions, createIfMissing: boolean): ts.Map { + var key = getKeyFromCompilationSettings(settings); + var bucket = buckets[key]; if (!bucket && createIfMissing) { - this.buckets[key] = bucket = {}; + buckets[key] = bucket = {}; } return bucket; } - public reportStats() { - var bucketInfoArray = Object.keys(this.buckets).filter(name => name && name.charAt(0) === '_').map(name => { - var entries = this.buckets[name]; + function reportStats() { + var bucketInfoArray = Object.keys(buckets).filter(name => name && name.charAt(0) === '_').map(name => { + var entries = buckets[name]; var documents = []; for (var i in entries) { var entry = entries[i]; @@ -1119,7 +1119,7 @@ module ts { return JSON.stringify(bucketInfoArray, null, 2); } - public acquireDocument( + function acquireDocument( filename: string, compilationSettings: ts.CompilerOptions, scriptSnapshot: TypeScript.IScriptSnapshot, @@ -1128,7 +1128,7 @@ module ts { isOpen: boolean, referencedFiles: string[]= []): Document { - var bucket = this.getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ true); + var bucket = getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ true); var entry = bucket[filename]; if (!entry) { var document = Document.create(compilationSettings, filename, scriptSnapshot, byteOrderMark, version, isOpen, referencedFiles); @@ -1144,7 +1144,7 @@ module ts { return entry.document; } - public updateDocument( + function updateDocument( document: Document, filename: string, compilationSettings: ts.CompilerOptions, @@ -1154,7 +1154,7 @@ module ts { textChangeRange: TypeScript.TextChangeRange ): Document { - var bucket = this.getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ false); + var bucket = getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ false); Debug.assert(bucket); var entry = bucket[filename]; Debug.assert(entry); @@ -1167,8 +1167,8 @@ module ts { return entry.document; } - public releaseDocument(filename: string, compilationSettings: ts.CompilerOptions): void { - var bucket = this.getBucketForCompilationSettings(compilationSettings, false); + function releaseDocument(filename: string, compilationSettings: ts.CompilerOptions): void { + var bucket = getBucketForCompilationSettings(compilationSettings, false); Debug.assert(bucket); var entry = bucket[filename]; @@ -1179,9 +1179,16 @@ module ts { delete bucket[filename]; } } + + return { + acquireDocument: acquireDocument, + updateDocument: updateDocument, + releaseDocument: releaseDocument, + reportStats: reportStats + }; } - export function createLanguageService(host: LanguageServiceHost, documentRegistry: IDocumentRegistry): LanguageService { + export function createLanguageService(host: LanguageServiceHost, documentRegistry: DocumentRegistry): LanguageService { var syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host); var formattingRulesProvider: TypeScript.Services.Formatting.RulesProvider; var hostCache: HostCache; // A cache of all the information about the files on the host side. diff --git a/src/services/shims.ts b/src/services/shims.ts index 71fd0ba0320..247c4314e66 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -17,7 +17,9 @@ /// /// - var debugObjectHost = (this); + +var debugObjectHost = (this); + module ts { export interface ScriptSnapshotShim { // Get's a portion of the script snapshot specified by [start, end). @@ -845,7 +847,7 @@ module ts { export class TypeScriptServicesFactory implements ShimFactory { private _shims: Shim[] = []; - private documentRegistry: DocumentRegistry = new DocumentRegistry(); + private documentRegistry: DocumentRegistry = createDocumentRegistry(); public createLanguageServiceShim(host: LanguageServiceShimHost): LanguageServiceShim { try { @@ -882,7 +884,7 @@ module ts { public close(): void { // Forget all the registered shims this._shims = []; - this.documentRegistry = new DocumentRegistry(); + this.documentRegistry = createDocumentRegistry(); } public registerShim(shim: Shim): void { From 87ddcbf632b1925b09723b58525081dad5271c4c Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Fri, 25 Jul 2014 12:01:31 -0700 Subject: [PATCH 41/59] switch document to an interface --- src/services/services.ts | 119 +++++++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 48 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 5dffef73e29..b0c4fbd93c1 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -649,8 +649,20 @@ module ts { (oldSyntaxTree: TypeScript.SyntaxTree, textChangeRange: TypeScript.TextChangeRange, newText: TypeScript.ISimpleText): TypeScript.SyntaxTree } - export class Document { - private _bloomFilter: TypeScript.BloomFilter = null; + export interface Document { + getFilename(): string; + getByteOrderMark(): ts.ByteOrderMark; + getVersion(): number; + isOpen(): boolean; + getSourceUnit(): TypeScript.SourceUnitSyntax; + getSyntaxTree(): TypeScript.SyntaxTree; + getSourceFile(): ts.SourceFile; + getBloomFilter(): TypeScript.BloomFilter; + update(scriptSnapshot: TypeScript.IScriptSnapshot, version: number, isOpen: boolean, textChangeRange: TypeScript.TextChangeRange): Document; + } + + class DocumentObject implements Document { + private bloomFilter: TypeScript.BloomFilter = null; // By default, our Document class doesn't support incremental update of its contents. // However, we enable other layers (like teh services layer) to inject the capability @@ -660,62 +672,73 @@ module ts { constructor(private compilationSettings: ts.CompilerOptions, public filename: string, public referencedFiles: string[], - private _scriptSnapshot: TypeScript.IScriptSnapshot, + private scriptSnapshot: TypeScript.IScriptSnapshot, public byteOrderMark: ts.ByteOrderMark, public version: number, - public isOpen: boolean, - private _syntaxTree: TypeScript.SyntaxTree, - private _soruceFile: ts.SourceFile) { + public _isOpen: boolean, + private syntaxTree: TypeScript.SyntaxTree, + private soruceFile: ts.SourceFile) { } + public getFilename(): string { + return this.filename; + } + + public getVersion(): number { + return this.version; + } + + public isOpen(): boolean { + return this._isOpen; + } + + public getByteOrderMark(): ByteOrderMark { + return this.byteOrderMark; + } public isDeclareFile(): boolean { return TypeScript.isDTSFile(this.filename); } - public sourceUnit(): TypeScript.SourceUnitSyntax { + public getSourceUnit(): TypeScript.SourceUnitSyntax { // If we don't have a script, create one from our parse tree. - return this.syntaxTree().sourceUnit(); + return this.getSyntaxTree().sourceUnit(); } - //public diagnostics(): Diagnostic[] { - // return this.syntaxTree().diagnostics(); - //} - - public lineMap(): TypeScript.LineMap { - return this.syntaxTree().lineMap(); + public getLineMap(): TypeScript.LineMap { + return this.getSyntaxTree().lineMap(); } - public syntaxTree(): TypeScript.SyntaxTree { - if (!this._syntaxTree) { + public getSyntaxTree(): TypeScript.SyntaxTree { + if (!this.syntaxTree) { var start = new Date().getTime(); - this._syntaxTree = TypeScript.Parser.parse( - this.filename, TypeScript.SimpleText.fromScriptSnapshot(this._scriptSnapshot), this.compilationSettings.target, this.isDeclareFile()); + this.syntaxTree = TypeScript.Parser.parse( + this.filename, TypeScript.SimpleText.fromScriptSnapshot(this.scriptSnapshot), this.compilationSettings.target, this.isDeclareFile()); var time = new Date().getTime() - start; //TypeScript.syntaxTreeParseTime += time; } - return this._syntaxTree; + return this.syntaxTree; } - public sourceFile(): ts.SourceFile { - if (!this._soruceFile) { + public getSourceFile(): ts.SourceFile { + if (!this.soruceFile) { var start = new Date().getTime(); - this._soruceFile = ts.createSourceFile(this.filename, this._scriptSnapshot.getText(0, this._scriptSnapshot.getLength()), this.compilationSettings.target); + this.soruceFile = ts.createSourceFile(this.filename, this.scriptSnapshot.getText(0, this.scriptSnapshot.getLength()), this.compilationSettings.target); var time = new Date().getTime() - start; //TypeScript.astParseTime += time; } - return this._soruceFile; + return this.soruceFile; } - public bloomFilter(): TypeScript.BloomFilter { - if (!this._bloomFilter) { + public getBloomFilter(): TypeScript.BloomFilter { + if (!this.bloomFilter) { var identifiers = TypeScript.createIntrinsicsObject(); var pre = function (cur: TypeScript.ISyntaxElement) { if (TypeScript.ASTHelpers.isValidAstNode(cur)) { @@ -727,7 +750,7 @@ module ts { } }; - TypeScript.getAstWalkerFactory().simpleWalk(this.sourceUnit(), pre, null, identifiers); + TypeScript.getAstWalkerFactory().simpleWalk(this.getSourceUnit(), pre, null, identifiers); var identifierCount = 0; for (var name in identifiers) { @@ -736,10 +759,10 @@ module ts { } } - this._bloomFilter = new TypeScript.BloomFilter(identifierCount); - this._bloomFilter.addKeys(identifiers); + this.bloomFilter = new TypeScript.BloomFilter(identifierCount); + this.bloomFilter.addKeys(identifiers); } - return this._bloomFilter; + return this.bloomFilter; } // Returns true if this file should get emitted into its own unique output file. @@ -749,7 +772,7 @@ module ts { // If we haven't specified an output file in our settings, then we're definitely // emitting to our own file. Also, if we're an external module, then we're // definitely emitting to our own file. - return !this.compilationSettings.out || this.syntaxTree().isExternalModule(); + return !this.compilationSettings.out || this.getSyntaxTree().isExternalModule(); } public update(scriptSnapshot: TypeScript.IScriptSnapshot, version: number, isOpen: boolean, textChangeRange: TypeScript.TextChangeRange): Document { @@ -757,10 +780,10 @@ module ts { // either a closed file, or we've just been lazy and haven't had to create the syntax // tree yet. Access the field instead of the method so we don't accidently realize // the old syntax tree. - var oldSyntaxTree = this._syntaxTree; + var oldSyntaxTree = this.syntaxTree; if (textChangeRange !== null && Debug.shouldAssert(AssertionLevel.Normal)) { - var oldText = this._scriptSnapshot; + var oldText = this.scriptSnapshot; var newText = scriptSnapshot; TypeScript.Debug.assert((oldText.getLength() - textChangeRange.span().length() + textChangeRange.newLength()) === newText.getLength()); @@ -780,16 +803,16 @@ module ts { // If we don't have a text change, or we don't have an old syntax tree, then do a full // parse. Otherwise, do an incremental parse. - var newSyntaxTree = textChangeRange === null || oldSyntaxTree === null || Document.incrementalParse === null + var newSyntaxTree = textChangeRange === null || oldSyntaxTree === null || DocumentObject.incrementalParse === null ? TypeScript.Parser.parse(this.filename, text, this.compilationSettings.target, TypeScript.isDTSFile(this.filename)) - : Document.incrementalParse(oldSyntaxTree, textChangeRange, text); + : DocumentObject.incrementalParse(oldSyntaxTree, textChangeRange, text); - return new Document(this.compilationSettings, this.filename, this.referencedFiles, scriptSnapshot, this.byteOrderMark, version, isOpen, newSyntaxTree, /*soruceFile*/ null); + return new DocumentObject(this.compilationSettings, this.filename, this.referencedFiles, scriptSnapshot, this.byteOrderMark, version, isOpen, newSyntaxTree, /*soruceFile*/ null); } + } - public static create(compilationSettings: ts.CompilerOptions, fileName: string, scriptSnapshot: TypeScript.IScriptSnapshot, byteOrderMark: ts.ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]): Document { - return new Document(compilationSettings, fileName, referencedFiles, scriptSnapshot, byteOrderMark, version, isOpen, /*syntaxTree:*/ null, /*soruceFile*/ null); - } + function createDocument(compilationSettings: ts.CompilerOptions, fileName: string, scriptSnapshot: TypeScript.IScriptSnapshot, byteOrderMark: ts.ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]): Document { + return new DocumentObject(compilationSettings, fileName, referencedFiles, scriptSnapshot, byteOrderMark, version, isOpen, /*syntaxTree:*/ null, /*soruceFile*/ null); } /// Language Service @@ -1131,7 +1154,7 @@ module ts { var bucket = getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ true); var entry = bucket[filename]; if (!entry) { - var document = Document.create(compilationSettings, filename, scriptSnapshot, byteOrderMark, version, isOpen, referencedFiles); + var document = createDocument(compilationSettings, filename, scriptSnapshot, byteOrderMark, version, isOpen, referencedFiles); bucket[filename] = entry = { document: document, @@ -1159,7 +1182,7 @@ module ts { var entry = bucket[filename]; Debug.assert(entry); - if (entry.document.isOpen === isOpen && entry.document.version === version) { + if (entry.document.isOpen() === isOpen && entry.document.getVersion() === version) { return entry.document; } @@ -1213,7 +1236,7 @@ module ts { Debug.assert(!!document, "document can not be undefined"); - return document.sourceFile(); + return document.getSourceFile(); }, getCancellationToken: () => cancellationToken, getCanonicalFileName: (filename) => useCaseSensitivefilenames ? filename : filename.toLowerCase(), @@ -1283,7 +1306,7 @@ module ts { // // If the document is the same, assume no update // - if (document.version === version && document.isOpen === isOpen) { + if (document.getVersion() === version && document.isOpen() === isOpen) { continue; } @@ -1295,7 +1318,7 @@ module ts { // new text buffer). var textChangeRange: TypeScript.TextChangeRange = null; if (document.isOpen && isOpen) { - textChangeRange = hostCache.getScriptTextChangeRangeSinceVersion(filename, document.version); + textChangeRange = hostCache.getScriptTextChangeRangeSinceVersion(filename, document.getVersion()); } document = documentRegistry.updateDocument(document, filename, compilationSettings, scriptSnapshot, version, isOpen, textChangeRange); @@ -1542,9 +1565,9 @@ module ts { filename = TypeScript.switchToForwardSlashes(filename); var document = documentsByName[filename]; - var sourceUnit = document.sourceUnit(); + var sourceUnit = document.getSourceUnit(); - if (isCompletionListBlocker(document.syntaxTree().sourceUnit(), position)) { + if (isCompletionListBlocker(document.getSyntaxTree().sourceUnit(), position)) { host.log("Returning an empty list because completion was blocked."); return null; } @@ -1590,7 +1613,7 @@ module ts { } // TODO: this is a hack for now, we need a proper walking mechanism to verify that we have the correct node - var mappedNode = getNodeAtPosition(document.sourceFile(), TypeScript.end(node) - 1); + var mappedNode = getNodeAtPosition(document.getSourceFile(), TypeScript.end(node) - 1); Debug.assert(mappedNode, "Could not map a Fidelity node to an AST node"); @@ -1616,7 +1639,7 @@ module ts { getCompletionEntriesFromSymbols(symbols, activeCompletionSession); } else { - var containingObjectLiteral = getContainingObjectLiteralApplicableForCompletion(document.syntaxTree().sourceUnit(), position); + var containingObjectLiteral = getContainingObjectLiteralApplicableForCompletion(document.getSyntaxTree().sourceUnit(), position); // Object literal expression, look up possible property names from contextual type if (containingObjectLiteral) { @@ -1802,7 +1825,7 @@ module ts { filename = TypeScript.switchToForwardSlashes(filename); var document = documentsByName[filename]; - var node = getNodeAtPosition(document.sourceFile(), position); + var node = getNodeAtPosition(document.getSourceFile(), position); if (!node) return undefined; switch (node.kind) { From e9f0c0ae49e5bce9bb925728082d13cbef9696d4 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Fri, 25 Jul 2014 12:10:11 -0700 Subject: [PATCH 42/59] Fix noimplicitany issues --- src/services/compiler/astHelpers.ts | 2 +- src/services/services.ts | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/services/compiler/astHelpers.ts b/src/services/compiler/astHelpers.ts index 51d7f5e87fd..74d072846db 100644 --- a/src/services/compiler/astHelpers.ts +++ b/src/services/compiler/astHelpers.ts @@ -18,7 +18,7 @@ module TypeScript.ASTHelpers { - var sentinelEmptyArray = []; + var sentinelEmptyArray: any[] = []; //export function scriptIsElided(sourceUnit: SourceUnitSyntax): boolean { // return isDTSFile(sourceUnit.syntaxTree.fileName()) || moduleMembersAreElided(sourceUnit.moduleElements); diff --git a/src/services/services.ts b/src/services/services.ts index b0c4fbd93c1..30d17c68425 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -645,7 +645,7 @@ module ts { static prefix = "prefix"; } - export interface IncrementalParse { + interface IncrementalParse { (oldSyntaxTree: TypeScript.SyntaxTree, textChangeRange: TypeScript.TextChangeRange, newText: TypeScript.ISimpleText): TypeScript.SyntaxTree } @@ -1127,7 +1127,7 @@ module ts { function reportStats() { var bucketInfoArray = Object.keys(buckets).filter(name => name && name.charAt(0) === '_').map(name => { var entries = buckets[name]; - var documents = []; + var documents: { name: string; refCount: number; references: string[]; }[] = []; for (var i in entries) { var entry = entries[i]; documents.push({ @@ -1414,7 +1414,7 @@ module ts { "while","with", ]; - var result = []; + var result: CompletionEntry[] = []; forEach(keywords, (keyword) => { result.push({ name: keyword, @@ -2035,7 +2035,7 @@ module ts { getCompletionsAtPosition: getCompletionsAtPosition, getCompletionEntryDetails: getCompletionEntryDetails, getTypeAtPosition: getTypeAtPosition, - getSignatureAtPosition: (filename, position) => undefined, + getSignatureAtPosition: (filename, position): SignatureInfo => undefined, getDefinitionAtPosition: (filename, position) => [], getReferencesAtPosition: (filename, position) => [], getOccurrencesAtPosition: (filename, position) => [], @@ -2051,7 +2051,7 @@ module ts { getFormattingEditsForDocument: getFormattingEditsForDocument, getFormattingEditsOnPaste: getFormattingEditsOnPaste, getFormattingEditsAfterKeystroke: getFormattingEditsAfterKeystroke, - getEmitOutput: (filename) => undefined, + getEmitOutput: (filename): EmitOutput => undefined, }; } @@ -2102,7 +2102,7 @@ module ts { offset = 3; } - var result = { + var result: ClassificationResult = { finalLexState: EndOfLineState.Start, entries: [] }; From 96a9cc9b5541d2b330177eae9af81f646ae83bda Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Fri, 25 Jul 2014 12:18:12 -0700 Subject: [PATCH 43/59] remove unneded ts. qualifiers --- src/services/services.ts | 210 +++++++++++++++++++-------------------- src/services/shims.ts | 52 +++++----- 2 files changed, 131 insertions(+), 131 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 30d17c68425..8e969ceb5a0 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -291,14 +291,14 @@ module ts { // Public interface of the host of a language service instance. // export interface LanguageServiceHost extends Logger { - getCompilationSettings(): ts.CompilerOptions; + getCompilationSettings(): CompilerOptions; getScriptFileNames(): string[]; getScriptVersion(fileName: string): number; getScriptIsOpen(fileName: string): boolean; - getScriptByteOrderMark(fileName: string): ts.ByteOrderMark; + getScriptByteOrderMark(fileName: string): ByteOrderMark; getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot; getLocalizedDiagnosticMessages(): any; - getCancellationToken(): ts.CancellationToken; + getCancellationToken(): CancellationToken; } // @@ -311,9 +311,9 @@ module ts { cleanupSemanticCache(): void; - getSyntacticDiagnostics(fileName: string): ts.Diagnostic[]; - getSemanticDiagnostics(fileName: string): ts.Diagnostic[]; - getCompilerOptionsDiagnostics(): ts.Diagnostic[]; + getSyntacticDiagnostics(fileName: string): Diagnostic[]; + getSemanticDiagnostics(fileName: string): Diagnostic[]; + getCompilerOptionsDiagnostics(): Diagnostic[]; getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean): CompletionInfo; getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails; @@ -542,9 +542,9 @@ module ts { export interface DocumentRegistry { acquireDocument( filename: string, - compilationSettings: ts.CompilerOptions, + compilationSettings: CompilerOptions, scriptSnapshot: TypeScript.IScriptSnapshot, - byteOrderMark: ts.ByteOrderMark, + byteOrderMark: ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]): Document; @@ -552,14 +552,14 @@ module ts { updateDocument( document: Document, filename: string, - compilationSettings: ts.CompilerOptions, + compilationSettings: CompilerOptions, scriptSnapshot: TypeScript.IScriptSnapshot, version: number, isOpen: boolean, textChangeRange: TypeScript.TextChangeRange ): Document; - releaseDocument(filename: string, compilationSettings: ts.CompilerOptions): void + releaseDocument(filename: string, compilationSettings: CompilerOptions): void } // TODO: move these to enums @@ -651,12 +651,12 @@ module ts { export interface Document { getFilename(): string; - getByteOrderMark(): ts.ByteOrderMark; + getByteOrderMark(): ByteOrderMark; getVersion(): number; isOpen(): boolean; getSourceUnit(): TypeScript.SourceUnitSyntax; getSyntaxTree(): TypeScript.SyntaxTree; - getSourceFile(): ts.SourceFile; + getSourceFile(): SourceFile; getBloomFilter(): TypeScript.BloomFilter; update(scriptSnapshot: TypeScript.IScriptSnapshot, version: number, isOpen: boolean, textChangeRange: TypeScript.TextChangeRange): Document; } @@ -664,20 +664,20 @@ module ts { class DocumentObject implements Document { private bloomFilter: TypeScript.BloomFilter = null; - // By default, our Document class doesn't support incremental update of its contents. + // By default, our Document class doesn't support incremental update of its conten // However, we enable other layers (like teh services layer) to inject the capability // into us by setting this function. public static incrementalParse: IncrementalParse = TypeScript.IncrementalParser.parse; - constructor(private compilationSettings: ts.CompilerOptions, + constructor(private compilationSettings: CompilerOptions, public filename: string, public referencedFiles: string[], private scriptSnapshot: TypeScript.IScriptSnapshot, - public byteOrderMark: ts.ByteOrderMark, + public byteOrderMark: ByteOrderMark, public version: number, public _isOpen: boolean, private syntaxTree: TypeScript.SyntaxTree, - private soruceFile: ts.SourceFile) { + private soruceFile: SourceFile) { } public getFilename(): string { @@ -723,11 +723,11 @@ module ts { return this.syntaxTree; } - public getSourceFile(): ts.SourceFile { + public getSourceFile(): SourceFile { if (!this.soruceFile) { var start = new Date().getTime(); - this.soruceFile = ts.createSourceFile(this.filename, this.scriptSnapshot.getText(0, this.scriptSnapshot.getLength()), this.compilationSettings.target); + this.soruceFile = createSourceFile(this.filename, this.scriptSnapshot.getText(0, this.scriptSnapshot.getLength()), this.compilationSettings.target); var time = new Date().getTime() - start; @@ -811,7 +811,7 @@ module ts { } } - function createDocument(compilationSettings: ts.CompilerOptions, fileName: string, scriptSnapshot: TypeScript.IScriptSnapshot, byteOrderMark: ts.ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]): Document { + function createDocument(compilationSettings: CompilerOptions, fileName: string, scriptSnapshot: TypeScript.IScriptSnapshot, byteOrderMark: ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]): Document { return new DocumentObject(compilationSettings, fileName, referencedFiles, scriptSnapshot, byteOrderMark, version, isOpen, /*syntaxTree:*/ null, /*soruceFile*/ null); } @@ -821,9 +821,9 @@ module ts { filename: string; // the file where the completion was requested position: number; // position in the file where the completion was requested entries: CompletionEntry[]; // entries for this completion - symbols: ts.Map; // symbols by entry name map - location: ts.Node; // the node where the completion was requested - typeChecker: ts.TypeChecker;// the typeChecker used to generate this completion + symbols: Map; // symbols by entry name map + location: Node; // the node where the completion was requested + typeChecker: TypeChecker;// the typeChecker used to generate this completion } interface FormattingOptions { @@ -838,7 +838,7 @@ module ts { filename: string; version: number; isOpen: boolean; - byteOrderMark: ts.ByteOrderMark; + byteOrderMark: ByteOrderMark; sourceText?: TypeScript.IScriptSnapshot; } @@ -848,11 +848,11 @@ module ts { owners: string[]; } - export function getDefaultCompilerOptions(): ts.CompilerOptions { + export function getDefaultCompilerOptions(): CompilerOptions { // Set "ES5" target by default for language service return { - target: ts.ScriptTarget.ES5, - module: ts.ModuleKind.None, + target: ScriptTarget.ES5, + module: ModuleKind.None, }; } @@ -872,11 +872,11 @@ module ts { export class OperationCanceledException { } - class CancellationToken { + class CancellationTokenObject { - public static None: CancellationToken = new CancellationToken(null) + public static None: CancellationTokenObject = new CancellationTokenObject(null) - constructor(private cancellationToken: ts.CancellationToken) { + constructor(private cancellationToken: CancellationToken) { } public isCancellationRequested() { @@ -890,12 +890,12 @@ module ts { } } - // Cache host information about scripts. Should be refreshed + // Cache host information about scrip Should be refreshed // at each language service public entry point, since we don't know when // set of scripts handled by the host changes. class HostCache { - private filenameToEntry: ts.Map; - private _compilationSettings: ts.CompilerOptions; + private filenameToEntry: Map; + private _compilationSettings: CompilerOptions; constructor(private host: LanguageServiceHost) { // script id => script index @@ -947,7 +947,7 @@ module ts { return this.filenameToEntry[TypeScript.switchToForwardSlashes(filename)].isOpen; } - public getByteOrderMark(filename: string): ts.ByteOrderMark { + public getByteOrderMark(filename: string): ByteOrderMark { return this.filenameToEntry[TypeScript.switchToForwardSlashes(filename)].byteOrderMark; } @@ -1109,13 +1109,13 @@ module ts { } export function createDocumentRegistry(): DocumentRegistry { - var buckets: ts.Map> = {}; + var buckets: Map> = {}; - function getKeyFromCompilationSettings(settings: ts.CompilerOptions): string { - return "_" + ts.ScriptTarget[settings.target]; // + "|" + settings.propagateEnumConstants.toString() + function getKeyFromCompilationSettings(settings: CompilerOptions): string { + return "_" + ScriptTarget[settings.target]; // + "|" + settings.propagateEnumConstantoString() } - function getBucketForCompilationSettings(settings: ts.CompilerOptions, createIfMissing: boolean): ts.Map { + function getBucketForCompilationSettings(settings: CompilerOptions, createIfMissing: boolean): Map { var key = getKeyFromCompilationSettings(settings); var bucket = buckets[key]; if (!bucket && createIfMissing) { @@ -1144,9 +1144,9 @@ module ts { function acquireDocument( filename: string, - compilationSettings: ts.CompilerOptions, + compilationSettings: CompilerOptions, scriptSnapshot: TypeScript.IScriptSnapshot, - byteOrderMark: ts.ByteOrderMark, + byteOrderMark: ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]= []): Document { @@ -1170,7 +1170,7 @@ module ts { function updateDocument( document: Document, filename: string, - compilationSettings: ts.CompilerOptions, + compilationSettings: CompilerOptions, scriptSnapshot: TypeScript.IScriptSnapshot, version: number, isOpen: boolean, @@ -1190,7 +1190,7 @@ module ts { return entry.document; } - function releaseDocument(filename: string, compilationSettings: ts.CompilerOptions): void { + function releaseDocument(filename: string, compilationSettings: CompilerOptions): void { var bucket = getBucketForCompilationSettings(compilationSettings, false); Debug.assert(bucket); @@ -1215,12 +1215,12 @@ module ts { var syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host); var formattingRulesProvider: TypeScript.Services.Formatting.RulesProvider; var hostCache: HostCache; // A cache of all the information about the files on the host side. - var program: ts.Program; - var typeChecker: ts.TypeChecker; + var program: Program; + var typeChecker: TypeChecker; var useCaseSensitivefilenames = false; - var documentsByName: ts.Map = {}; + var documentsByName: Map = {}; var documentRegistry = documentRegistry; - var cancellationToken = new CancellationToken(host.getCancellationToken()); + var cancellationToken = new CancellationTokenObject(host.getCancellationToken()); var activeCompletionSession: CompletionSession; // The current active completion session, used to get the completion entry details var keywordCompletions = getKeywordCompletionEntries(); // A cache of completion entries for keywords, these do not change between sessions @@ -1229,7 +1229,7 @@ module ts { TypeScript.LocalizedDiagnosticMessages = host.getLocalizedDiagnosticMessages(); } - function createCompilerHost(): ts.CompilerHost { + function createCompilerHost(): CompilerHost { return { getSourceFile: (filename, languageVersion) => { var document = documentsByName[filename]; @@ -1332,13 +1332,13 @@ module ts { } // Now create a new compiler - program = ts.createProgram(hostfilenames, compilationSettings, createCompilerHost()); + program = createProgram(hostfilenames, compilationSettings, createCompilerHost()); typeChecker = program.getTypeChecker(); } function dispose(): void { if (program) { - ts.forEach(program.getSourceFiles(), + forEach(program.getSourceFiles(), (f) => documentRegistry.releaseDocument(f.filename, program.getCompilerOptions())); } } @@ -1360,7 +1360,7 @@ module ts { } /// Completion - function getValidCompletionEntryDisplayName(displayName: string, target: ts.ScriptTarget): string { + function getValidCompletionEntryDisplayName(displayName: string, target: ScriptTarget): string { if (displayName && displayName.length > 0) { var firstChar = displayName.charCodeAt(0); if (firstChar === TypeScript.CharacterCodes.singleQuote || firstChar === TypeScript.CharacterCodes.doubleQuote) { @@ -1377,7 +1377,7 @@ module ts { return undefined; } - function createCompletionEntry(symbol: ts.Symbol): CompletionEntry { + function createCompletionEntry(symbol: Symbol): CompletionEntry { // Try to get a valid display name for this symbol, if we could not find one, then ignore it. // We would like to only show things that can be added after a dot, so for instance numeric properties can // not be accessed with a dot (a.1 <- invalid) @@ -1427,8 +1427,8 @@ module ts { } function getCompletionsAtPosition(filename: string, position: number, isMemberCompletion: boolean) { - function getCompletionEntriesFromSymbols(symbols: ts.Symbol[], session: CompletionSession): void { - ts.forEach(symbols, (symbol) => { + function getCompletionEntriesFromSymbols(symbols: Symbol[], session: CompletionSession): void { + forEach(symbols, (symbol) => { var entry = createCompletionEntry(symbol); if (entry) { session.entries.push(entry); @@ -1629,7 +1629,7 @@ module ts { // Right of dot member completion list if (isRightOfDot) { - var type: ts.Type = typeChecker.getTypeOfExpression(mappedNode); + var type: Type = typeChecker.getTypeOfExpression(mappedNode); if (!type) { return undefined; } @@ -1676,7 +1676,7 @@ module ts { else { isMemberCompletion = false; /// TODO filter meaning based on the current context - var symbolMeanings = ts.SymbolFlags.Type | ts.SymbolFlags.Value | ts.SymbolFlags.Namespace; + var symbolMeanings = SymbolFlags.Type | SymbolFlags.Value | SymbolFlags.Namespace; var symbols = typeChecker.getSymbolsInScope(mappedNode, symbolMeanings); getCompletionEntriesFromSymbols(symbols, activeCompletionSession); @@ -1733,13 +1733,13 @@ module ts { } } - function getNodeAtPosition(sourceFile: ts.SourceFile, position: number) { - var current: ts.Node = sourceFile; + function getNodeAtPosition(sourceFile: SourceFile, position: number) { + var current: Node = sourceFile; outer: while (true) { // find the child that has this for (var i = 0, n = current.getChildCount(); i < n; i++) { var child = current.getChildAt(i); - if (ts.getTokenPosOfNode(child) <= position && position < child.end) { + if (getTokenPosOfNode(child) <= position && position < child.end) { current = child; continue outer; } @@ -1749,72 +1749,72 @@ module ts { } } - function getEnclosingDeclaration(node: ts.Node): ts.Node { + function getEnclosingDeclaration(node: Node): Node { while (true) { node = node.parent; if (!node) { return node; } switch (node.kind) { - case ts.SyntaxKind.Method: - case ts.SyntaxKind.FunctionDeclaration: - case ts.SyntaxKind.FunctionExpression: - case ts.SyntaxKind.GetAccessor: - case ts.SyntaxKind.SetAccessor: - case ts.SyntaxKind.ClassDeclaration: - case ts.SyntaxKind.InterfaceDeclaration: - case ts.SyntaxKind.EnumDeclaration: - case ts.SyntaxKind.ModuleDeclaration: + case SyntaxKind.Method: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.ModuleDeclaration: return node; } } } - function getSymbolKind(symbol: ts.Symbol): string { + function getSymbolKind(symbol: Symbol): string { var flags = symbol.getFlags(); - if (flags & ts.SymbolFlags.Module) return ScriptElementKind.moduleElement; - if (flags & ts.SymbolFlags.Class) return ScriptElementKind.classElement; - if (flags & ts.SymbolFlags.Interface) return ScriptElementKind.interfaceElement; - if (flags & ts.SymbolFlags.Enum) return ScriptElementKind.enumElement; - if (flags & ts.SymbolFlags.Variable) return ScriptElementKind.variableElement; - if (flags & ts.SymbolFlags.Function) return ScriptElementKind.functionElement; - if (flags & ts.SymbolFlags.GetAccessor) return ScriptElementKind.memberGetAccessorElement; - if (flags & ts.SymbolFlags.SetAccessor) return ScriptElementKind.memberSetAccessorElement; - if (flags & ts.SymbolFlags.Method) return ScriptElementKind.memberFunctionElement; - if (flags & ts.SymbolFlags.Property) return ScriptElementKind.memberVariableElement; - if (flags & ts.SymbolFlags.IndexSignature) return ScriptElementKind.indexSignatureElement; - if (flags & ts.SymbolFlags.ConstructSignature) return ScriptElementKind.constructSignatureElement; - if (flags & ts.SymbolFlags.CallSignature) return ScriptElementKind.callSignatureElement; - if (flags & ts.SymbolFlags.Constructor) return ScriptElementKind.constructorImplementationElement; - if (flags & ts.SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; - if (flags & ts.SymbolFlags.EnumMember) return ScriptElementKind.variableElement; + if (flags & SymbolFlags.Module) return ScriptElementKind.moduleElement; + if (flags & SymbolFlags.Class) return ScriptElementKind.classElement; + if (flags & SymbolFlags.Interface) return ScriptElementKind.interfaceElement; + if (flags & SymbolFlags.Enum) return ScriptElementKind.enumElement; + if (flags & SymbolFlags.Variable) return ScriptElementKind.variableElement; + if (flags & SymbolFlags.Function) return ScriptElementKind.functionElement; + if (flags & SymbolFlags.GetAccessor) return ScriptElementKind.memberGetAccessorElement; + if (flags & SymbolFlags.SetAccessor) return ScriptElementKind.memberSetAccessorElement; + if (flags & SymbolFlags.Method) return ScriptElementKind.memberFunctionElement; + if (flags & SymbolFlags.Property) return ScriptElementKind.memberVariableElement; + if (flags & SymbolFlags.IndexSignature) return ScriptElementKind.indexSignatureElement; + if (flags & SymbolFlags.ConstructSignature) return ScriptElementKind.constructSignatureElement; + if (flags & SymbolFlags.CallSignature) return ScriptElementKind.callSignatureElement; + if (flags & SymbolFlags.Constructor) return ScriptElementKind.constructorImplementationElement; + if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; + if (flags & SymbolFlags.EnumMember) return ScriptElementKind.variableElement; return ScriptElementKind.unknown; } - function getTypeKind(type: ts.Type): string { + function getTypeKind(type: Type): string { var flags = type.getFlags(); - if (flags & ts.TypeFlags.Enum) return ScriptElementKind.enumElement; - if (flags & ts.TypeFlags.Class) return ScriptElementKind.classElement; - if (flags & ts.TypeFlags.Interface) return ScriptElementKind.interfaceElement; - if (flags & ts.TypeFlags.TypeParameter) return ScriptElementKind.typeParameterElement; - if (flags & ts.TypeFlags.Intrinsic) return ScriptElementKind.primitiveType; - if (flags & ts.TypeFlags.StringLiteral) return ScriptElementKind.primitiveType; + if (flags & TypeFlags.Enum) return ScriptElementKind.enumElement; + if (flags & TypeFlags.Class) return ScriptElementKind.classElement; + if (flags & TypeFlags.Interface) return ScriptElementKind.interfaceElement; + if (flags & TypeFlags.TypeParameter) return ScriptElementKind.typeParameterElement; + if (flags & TypeFlags.Intrinsic) return ScriptElementKind.primitiveType; + if (flags & TypeFlags.StringLiteral) return ScriptElementKind.primitiveType; return ScriptElementKind.unknown; } - function getNodeModifiers(node: ts.Node): string { + function getNodeModifiers(node: Node): string { var flags = node.flags; var result: string[] = []; - if (flags & ts.NodeFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier); - if (flags & ts.NodeFlags.Public) result.push(ScriptElementKindModifier.publicMemberModifier); - if (flags & ts.NodeFlags.Static) result.push(ScriptElementKindModifier.staticModifier); - if (flags & ts.NodeFlags.Export) result.push(ScriptElementKindModifier.exportedModifier); - if (ts.isInAmbientContext(node)) result.push(ScriptElementKindModifier.ambientModifier); + if (flags & NodeFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier); + if (flags & NodeFlags.Public) result.push(ScriptElementKindModifier.publicMemberModifier); + if (flags & NodeFlags.Static) result.push(ScriptElementKindModifier.staticModifier); + if (flags & NodeFlags.Export) result.push(ScriptElementKindModifier.exportedModifier); + if (isInAmbientContext(node)) result.push(ScriptElementKindModifier.ambientModifier); return result.length > 0 ? result.join(',') : ScriptElementKindModifier.none; } @@ -1830,12 +1830,12 @@ module ts { switch (node.kind) { // A declaration - case ts.SyntaxKind.Identifier: - if (node.parent.kind === ts.SyntaxKind.CallExpression || node.parent.kind === ts.SyntaxKind.NewExpression) { + case SyntaxKind.Identifier: + if (node.parent.kind === SyntaxKind.CallExpression || node.parent.kind === SyntaxKind.NewExpression) { // TODO: handle new and call expressions } - var symbol = typeChecker.getSymbolOfIdentifier(node); + var symbol = typeChecker.getSymbolOfIdentifier(node); Debug.assert(symbol, "getTypeAtPosition: Could not find symbol for node"); var type = typeChecker.getTypeOfSymbol(symbol); @@ -1849,10 +1849,10 @@ module ts { }; // An Expression - case ts.SyntaxKind.ThisKeyword: - case ts.SyntaxKind.QualifiedName: - case ts.SyntaxKind.SuperKeyword: - case ts.SyntaxKind.StringLiteral: + case SyntaxKind.ThisKeyword: + case SyntaxKind.QualifiedName: + case SyntaxKind.SuperKeyword: + case SyntaxKind.StringLiteral: var type = typeChecker.getTypeOfExpression(node); Debug.assert(type, "getTypeAtPosition: Could not find type for node"); return { @@ -2108,7 +2108,7 @@ module ts { }; var simpleText = TypeScript.SimpleText.fromString(text); - scanner = TypeScript.Scanner.createScanner(ts.ScriptTarget.ES5, simpleText, reportDiagnostic); + scanner = TypeScript.Scanner.createScanner(ScriptTarget.ES5, simpleText, reportDiagnostic); var lastTokenKind = TypeScript.SyntaxKind.None; var token: TypeScript.ISyntaxToken = null; diff --git a/src/services/shims.ts b/src/services/shims.ts index 247c4314e66..1949d58d6c2 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -57,7 +57,7 @@ module ts { directoryExists(path: string): boolean; getParentDirectory(path: string): string; getLocalizedDiagnosticMessages(): string; - getCancellationToken(): ts.CancellationToken; + getCancellationToken(): CancellationToken; } // @@ -176,43 +176,43 @@ module ts { codepage?: number; } - function languageVersionToScriptTarget(languageVersion: LanguageVersion): ts.ScriptTarget { + function languageVersionToScriptTarget(languageVersion: LanguageVersion): ScriptTarget { switch (languageVersion) { - case LanguageVersion.EcmaScript3: return ts.ScriptTarget.ES3; - case LanguageVersion.EcmaScript5: return ts.ScriptTarget.ES5; + case LanguageVersion.EcmaScript3: return ScriptTarget.ES3; + case LanguageVersion.EcmaScript5: return ScriptTarget.ES5; default: throw Error("unsuported LanguageVersion value: " + languageVersion); } } - function moduleGenTargetToModuleKind(moduleGenTarget: ModuleGenTarget): ts.ModuleKind { + function moduleGenTargetToModuleKind(moduleGenTarget: ModuleGenTarget): ModuleKind { switch (moduleGenTarget) { - case ModuleGenTarget.Asynchronous: return ts.ModuleKind.AMD; - case ModuleGenTarget.Synchronous: return ts.ModuleKind.CommonJS; - case ModuleGenTarget.Unspecified: return ts.ModuleKind.None; + case ModuleGenTarget.Asynchronous: return ModuleKind.AMD; + case ModuleGenTarget.Synchronous: return ModuleKind.CommonJS; + case ModuleGenTarget.Unspecified: return ModuleKind.None; default: throw Error("unsuported ModuleGenTarget value: " + moduleGenTarget); } } - function scriptTargetTolanguageVersion(scriptTarget: ts.ScriptTarget): LanguageVersion { + function scriptTargetTolanguageVersion(scriptTarget: ScriptTarget): LanguageVersion { switch (scriptTarget) { - case ts.ScriptTarget.ES3: return LanguageVersion.EcmaScript3; - case ts.ScriptTarget.ES5: return LanguageVersion.EcmaScript5; + case ScriptTarget.ES3: return LanguageVersion.EcmaScript3; + case ScriptTarget.ES5: return LanguageVersion.EcmaScript5; default: throw Error("unsuported ScriptTarget value: " + scriptTarget); } } - function moduleKindToModuleGenTarget(moduleKind: ts.ModuleKind): ModuleGenTarget { + function moduleKindToModuleGenTarget(moduleKind: ModuleKind): ModuleGenTarget { switch (moduleKind) { - case ts.ModuleKind.AMD: return ModuleGenTarget.Asynchronous; - case ts.ModuleKind.CommonJS: return ModuleGenTarget.Synchronous; - case ts.ModuleKind.None: return ModuleGenTarget.Unspecified; + case ModuleKind.AMD: return ModuleGenTarget.Asynchronous; + case ModuleKind.CommonJS: return ModuleGenTarget.Synchronous; + case ModuleKind.None: return ModuleGenTarget.Unspecified; default: throw Error("unsuported ModuleKind value: " + moduleKind); } } - function compilationSettingsToCompilerOptions(settings: CompilationSettings): ts.CompilerOptions { + function compilationSettingsToCompilerOptions(settings: CompilationSettings): CompilerOptions { // TODO: we should not be converting, but use options all the way - var options: ts.CompilerOptions = {}; + var options: CompilerOptions = {}; //options.propagateEnumConstants = settings.propagateEnumConstants; options.removeComments = settings.removeComments; options.noResolve = settings.noResolve; @@ -231,7 +231,7 @@ module ts { return options; } - function compilerOptionsToCompilationSettings(options: ts.CompilerOptions): CompilationSettings { + function compilerOptionsToCompilationSettings(options: CompilerOptions): CompilationSettings { var settings: CompilationSettings = {}; //options.propagateEnumConstants = settings.propagateEnumConstants; settings.removeComments = options.removeComments; @@ -317,13 +317,13 @@ module ts { this.shimHost.log(s); } - public getCompilationSettings(): ts.CompilerOptions { + public getCompilationSettings(): CompilerOptions { var settingsJson = this.shimHost.getCompilationSettings(); if (settingsJson == null || settingsJson == "") { throw Error("LanguageServiceShimHostAdapter.getCompilationSettings: empty compilationSettings"); return null; } - var options = compilationSettingsToCompilerOptions(JSON.parse(settingsJson)); + var options = compilationSettingsToCompilerOptions(JSON.parse(settingsJson)); /// TODO: this should be pushed into VS. /// We can not ask the LS instance to resolve, as this will lead to asking the host about files it does not know about, @@ -351,7 +351,7 @@ module ts { return this.shimHost.getScriptIsOpen(fileName); } - public getScriptByteOrderMark(fileName: string): ts.ByteOrderMark { + public getScriptByteOrderMark(fileName: string): ByteOrderMark { return this.shimHost.getScriptByteOrderMark(fileName); } @@ -369,7 +369,7 @@ module ts { } } - public getCancellationToken(): ts.CancellationToken { + public getCancellationToken(): CancellationToken { return this.shimHost.getCancellationToken(); } @@ -486,24 +486,24 @@ module ts { /// SQUIGGLES /// - private static realizeDiagnostic(diagnostic: ts.Diagnostic): { message: string; start: number; length: number; category: string; } { + private static realizeDiagnostic(diagnostic: Diagnostic): { message: string; start: number; length: number; category: string; } { return { message: diagnostic.messageText, start: diagnostic.start, length: diagnostic.length, /// TODO: no need for the tolowerCase call - category: ts.DiagnosticCategory[diagnostic.category].toLowerCase() + category: DiagnosticCategory[diagnostic.category].toLowerCase() }; } - private realizeDiagnosticWithFileName(diagnostic: ts.Diagnostic): { fileName: string; message: string; start: number; length: number; category: string; } { + private realizeDiagnosticWithFileName(diagnostic: Diagnostic): { fileName: string; message: string; start: number; length: number; category: string; } { return { fileName: diagnostic.file.filename, message: diagnostic.messageText, start: diagnostic.start, length: diagnostic.length, /// TODO: no need for the tolowerCase call - category: ts.DiagnosticCategory[diagnostic.category].toLowerCase() + category: DiagnosticCategory[diagnostic.category].toLowerCase() }; } From eb9fa722ec2f3c08276e5aa517d61928e291c067 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Fri, 25 Jul 2014 12:25:42 -0700 Subject: [PATCH 44/59] Add missing getNewLine method to test implementations of CompilerHost --- src/harness/harness.ts | 3 ++- src/harness/projectsRunner.ts | 3 ++- src/harness/rwcRunner.ts | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/harness/harness.ts b/src/harness/harness.ts index c4032c2d600..4611b90e80e 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -557,7 +557,8 @@ module Harness { getDefaultLibFilename: () => 'lib.d.ts', writeFile: writeFile, getCanonicalFileName: ts.getCanonicalFileName, - useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames + useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames, + getNewLine: ()=> sys.newLine } } diff --git a/src/harness/projectsRunner.ts b/src/harness/projectsRunner.ts index f7d2ec22cd2..f3fc650e55c 100644 --- a/src/harness/projectsRunner.ts +++ b/src/harness/projectsRunner.ts @@ -223,7 +223,8 @@ class ProjectRunner extends RunnerBase { writeFile: writeFile, getCurrentDirectory: getCurrentDirectory, getCanonicalFileName: ts.getCanonicalFileName, - useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames + useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames, + getNewLine:()=> sys.newLine }; } diff --git a/src/harness/rwcRunner.ts b/src/harness/rwcRunner.ts index e4038eb76e6..576b06e3435 100644 --- a/src/harness/rwcRunner.ts +++ b/src/harness/rwcRunner.ts @@ -112,7 +112,8 @@ module RWC { getDefaultLibFilename: () => libPath, writeFile: (fn, contents) => emitterIOHost.writeFile(fn, contents, false), getCanonicalFileName: ts.getCanonicalFileName, - useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames + useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames, + getNewLine: () => sys.newLine }; var resolvedProgram = ts.createProgram(opts.filenames, opts.options, host); From 9061e58dffbeaf3f72cee1c6ca6d8fc0b98b1ea5 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Fri, 25 Jul 2014 12:32:24 -0700 Subject: [PATCH 45/59] Change services output file name to typescriptservices.js --- Jakefile | 2 +- src/harness/harness.ts | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Jakefile b/Jakefile index 7a8ee59d532..f8d7f15e7a6 100644 --- a/Jakefile +++ b/Jakefile @@ -233,7 +233,7 @@ task("generate-diagnostics", [diagnosticInfoMapTs]) var tcFile = path.join(builtLocalDirectory, "tc.js"); compileFile(tcFile, compilerSources, [builtLocalDirectory, copyright].concat(compilerSources), [copyright], /*useBuiltCompiler:*/ false); -var tcServicesFile = path.join(builtLocalDirectory, "services.js"); +var tcServicesFile = path.join(builtLocalDirectory, "typescriptservices.js"); compileFile(tcServicesFile, servicesSources, [builtLocalDirectory, copyright].concat(servicesSources), [copyright], /*useBuiltCompiler:*/ true); // Local target to build the compiler and services diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 4611b90e80e..f90d096f536 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -429,25 +429,21 @@ module Harness { module Harness { - var typescriptServiceFileName = "typescriptServices.js"; - // Services files are exported because we need to eval them at global scope in order for them to be available everywhere - export var typescriptServiceFile: string; - - var tcServicesFilename = "services.js"; + var tcServicesFilename = "typescriptServices.js"; export var libFolder: string; switch (Utils.getExecutionEnvironment()) { case Utils.ExecutionEnvironment.CScript: libFolder = Path.filePath(global['WScript'].ScriptFullName); - tcServicesFilename = "built/local/services.js"; + tcServicesFilename = "built/local/typescriptServices.js"; break; case Utils.ExecutionEnvironment.Node: libFolder = (__dirname + '/'); - tcServicesFilename = "built/local/services.js"; + tcServicesFilename = "built/local/typescriptServices.js"; break; case Utils.ExecutionEnvironment.Browser: libFolder = "bin/"; - tcServicesFilename = "built/local/services.js"; + tcServicesFilename = "built/local/typescriptServices.js"; break; default: throw new Error('Unknown context'); From 4e570248d6c2253c798665cf3d8415daa3f8c354 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Fri, 25 Jul 2014 14:38:53 -0700 Subject: [PATCH 46/59] remove unused methods --- src/services/shims.ts | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/services/shims.ts b/src/services/shims.ts index 1949d58d6c2..c2402aebd52 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -52,10 +52,6 @@ module ts { getScriptIsOpen(fileName: string): boolean; getScriptByteOrderMark(fileName: string): number; getScriptSnapshot(fileName: string): ScriptSnapshotShim; - resolveRelativePath(path: string, directory: string): string; - fileExists(path: string): boolean; - directoryExists(path: string): boolean; - getParentDirectory(path: string): string; getLocalizedDiagnosticMessages(): string; getCancellationToken(): CancellationToken; } @@ -372,23 +368,6 @@ module ts { public getCancellationToken(): CancellationToken { return this.shimHost.getCancellationToken(); } - - // IReferenceResolverHost methods - public resolveRelativePath(path: string, directory: string): string { - return this.shimHost.resolveRelativePath(path, directory); - } - - public fileExists(path: string): boolean { - return this.shimHost.fileExists(path); - } - - public directoryExists(path: string): boolean { - return this.shimHost.directoryExists(path); - } - - public getParentDirectory(path: string): string { - return this.shimHost.getParentDirectory(path); - } } function simpleForwardCall(logger: Logger, actionDescription: string, action: () => any): any { From c6c77ea989d80e5832f1c5681173feb2c4a9c854 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Fri, 25 Jul 2014 16:51:48 -0700 Subject: [PATCH 47/59] move todoComment tests to old for now --- tests/cases/{fourslash => fourslash_old}/todoComments1.ts | 0 tests/cases/{fourslash => fourslash_old}/todoComments10.ts | 0 tests/cases/{fourslash => fourslash_old}/todoComments11.ts | 0 tests/cases/{fourslash => fourslash_old}/todoComments12.ts | 0 tests/cases/{fourslash => fourslash_old}/todoComments13.ts | 0 tests/cases/{fourslash => fourslash_old}/todoComments14.ts | 0 tests/cases/{fourslash => fourslash_old}/todoComments15.ts | 0 tests/cases/{fourslash => fourslash_old}/todoComments16.ts | 0 tests/cases/{fourslash => fourslash_old}/todoComments17.ts | 0 tests/cases/{fourslash => fourslash_old}/todoComments2.ts | 0 tests/cases/{fourslash => fourslash_old}/todoComments3.ts | 0 tests/cases/{fourslash => fourslash_old}/todoComments4.ts | 0 tests/cases/{fourslash => fourslash_old}/todoComments5.ts | 0 tests/cases/{fourslash => fourslash_old}/todoComments6.ts | 0 tests/cases/{fourslash => fourslash_old}/todoComments7.ts | 0 tests/cases/{fourslash => fourslash_old}/todoComments8.ts | 0 tests/cases/{fourslash => fourslash_old}/todoComments9.ts | 0 17 files changed, 0 insertions(+), 0 deletions(-) rename tests/cases/{fourslash => fourslash_old}/todoComments1.ts (100%) rename tests/cases/{fourslash => fourslash_old}/todoComments10.ts (100%) rename tests/cases/{fourslash => fourslash_old}/todoComments11.ts (100%) rename tests/cases/{fourslash => fourslash_old}/todoComments12.ts (100%) rename tests/cases/{fourslash => fourslash_old}/todoComments13.ts (100%) rename tests/cases/{fourslash => fourslash_old}/todoComments14.ts (100%) rename tests/cases/{fourslash => fourslash_old}/todoComments15.ts (100%) rename tests/cases/{fourslash => fourslash_old}/todoComments16.ts (100%) rename tests/cases/{fourslash => fourslash_old}/todoComments17.ts (100%) rename tests/cases/{fourslash => fourslash_old}/todoComments2.ts (100%) rename tests/cases/{fourslash => fourslash_old}/todoComments3.ts (100%) rename tests/cases/{fourslash => fourslash_old}/todoComments4.ts (100%) rename tests/cases/{fourslash => fourslash_old}/todoComments5.ts (100%) rename tests/cases/{fourslash => fourslash_old}/todoComments6.ts (100%) rename tests/cases/{fourslash => fourslash_old}/todoComments7.ts (100%) rename tests/cases/{fourslash => fourslash_old}/todoComments8.ts (100%) rename tests/cases/{fourslash => fourslash_old}/todoComments9.ts (100%) diff --git a/tests/cases/fourslash/todoComments1.ts b/tests/cases/fourslash_old/todoComments1.ts similarity index 100% rename from tests/cases/fourslash/todoComments1.ts rename to tests/cases/fourslash_old/todoComments1.ts diff --git a/tests/cases/fourslash/todoComments10.ts b/tests/cases/fourslash_old/todoComments10.ts similarity index 100% rename from tests/cases/fourslash/todoComments10.ts rename to tests/cases/fourslash_old/todoComments10.ts diff --git a/tests/cases/fourslash/todoComments11.ts b/tests/cases/fourslash_old/todoComments11.ts similarity index 100% rename from tests/cases/fourslash/todoComments11.ts rename to tests/cases/fourslash_old/todoComments11.ts diff --git a/tests/cases/fourslash/todoComments12.ts b/tests/cases/fourslash_old/todoComments12.ts similarity index 100% rename from tests/cases/fourslash/todoComments12.ts rename to tests/cases/fourslash_old/todoComments12.ts diff --git a/tests/cases/fourslash/todoComments13.ts b/tests/cases/fourslash_old/todoComments13.ts similarity index 100% rename from tests/cases/fourslash/todoComments13.ts rename to tests/cases/fourslash_old/todoComments13.ts diff --git a/tests/cases/fourslash/todoComments14.ts b/tests/cases/fourslash_old/todoComments14.ts similarity index 100% rename from tests/cases/fourslash/todoComments14.ts rename to tests/cases/fourslash_old/todoComments14.ts diff --git a/tests/cases/fourslash/todoComments15.ts b/tests/cases/fourslash_old/todoComments15.ts similarity index 100% rename from tests/cases/fourslash/todoComments15.ts rename to tests/cases/fourslash_old/todoComments15.ts diff --git a/tests/cases/fourslash/todoComments16.ts b/tests/cases/fourslash_old/todoComments16.ts similarity index 100% rename from tests/cases/fourslash/todoComments16.ts rename to tests/cases/fourslash_old/todoComments16.ts diff --git a/tests/cases/fourslash/todoComments17.ts b/tests/cases/fourslash_old/todoComments17.ts similarity index 100% rename from tests/cases/fourslash/todoComments17.ts rename to tests/cases/fourslash_old/todoComments17.ts diff --git a/tests/cases/fourslash/todoComments2.ts b/tests/cases/fourslash_old/todoComments2.ts similarity index 100% rename from tests/cases/fourslash/todoComments2.ts rename to tests/cases/fourslash_old/todoComments2.ts diff --git a/tests/cases/fourslash/todoComments3.ts b/tests/cases/fourslash_old/todoComments3.ts similarity index 100% rename from tests/cases/fourslash/todoComments3.ts rename to tests/cases/fourslash_old/todoComments3.ts diff --git a/tests/cases/fourslash/todoComments4.ts b/tests/cases/fourslash_old/todoComments4.ts similarity index 100% rename from tests/cases/fourslash/todoComments4.ts rename to tests/cases/fourslash_old/todoComments4.ts diff --git a/tests/cases/fourslash/todoComments5.ts b/tests/cases/fourslash_old/todoComments5.ts similarity index 100% rename from tests/cases/fourslash/todoComments5.ts rename to tests/cases/fourslash_old/todoComments5.ts diff --git a/tests/cases/fourslash/todoComments6.ts b/tests/cases/fourslash_old/todoComments6.ts similarity index 100% rename from tests/cases/fourslash/todoComments6.ts rename to tests/cases/fourslash_old/todoComments6.ts diff --git a/tests/cases/fourslash/todoComments7.ts b/tests/cases/fourslash_old/todoComments7.ts similarity index 100% rename from tests/cases/fourslash/todoComments7.ts rename to tests/cases/fourslash_old/todoComments7.ts diff --git a/tests/cases/fourslash/todoComments8.ts b/tests/cases/fourslash_old/todoComments8.ts similarity index 100% rename from tests/cases/fourslash/todoComments8.ts rename to tests/cases/fourslash_old/todoComments8.ts diff --git a/tests/cases/fourslash/todoComments9.ts b/tests/cases/fourslash_old/todoComments9.ts similarity index 100% rename from tests/cases/fourslash/todoComments9.ts rename to tests/cases/fourslash_old/todoComments9.ts From d4ba45cb36ddff8f7f86e76f4fd69798a0565fe7 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Jul 2014 10:26:20 -0700 Subject: [PATCH 48/59] move failing tests to old --- .../breakpointValidationFunctionExpressions.ts | 14 -------------- ...vingVariableDeclOfMergedVariableAndClassDecl.ts | 0 2 files changed, 14 deletions(-) delete mode 100644 tests/cases/fourslash/breakpointValidationFunctionExpressions.ts rename tests/cases/{fourslash => fourslash_old}/errorsAfterResolvingVariableDeclOfMergedVariableAndClassDecl.ts (100%) diff --git a/tests/cases/fourslash/breakpointValidationFunctionExpressions.ts b/tests/cases/fourslash/breakpointValidationFunctionExpressions.ts deleted file mode 100644 index e47a56cc08f..00000000000 --- a/tests/cases/fourslash/breakpointValidationFunctionExpressions.ts +++ /dev/null @@ -1,14 +0,0 @@ -/// - -// @BaselineFile: bpSpan_functionExpressions.baseline -// @Filename: bpSpan_functionExpressions.ts -////var greetings = 0; -////var greet = (greeting: string): number => { -//// greetings++; -//// return greetings; -////} -////greet("Hello"); -////var incrGreetings = () => greetings++; -////var greetNewMsg = msg => greet(msg); -debugger; -verify.baselineCurrentFileBreakpointLocations(); \ No newline at end of file diff --git a/tests/cases/fourslash/errorsAfterResolvingVariableDeclOfMergedVariableAndClassDecl.ts b/tests/cases/fourslash_old/errorsAfterResolvingVariableDeclOfMergedVariableAndClassDecl.ts similarity index 100% rename from tests/cases/fourslash/errorsAfterResolvingVariableDeclOfMergedVariableAndClassDecl.ts rename to tests/cases/fourslash_old/errorsAfterResolvingVariableDeclOfMergedVariableAndClassDecl.ts From 17f7ed5cbe2b44f228f97cc05c1787392b4f06c9 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Jul 2014 10:27:05 -0700 Subject: [PATCH 49/59] delete unused file --- src/harness/fourslashRun.ts | 48 ------------------------------------- 1 file changed, 48 deletions(-) delete mode 100644 src/harness/fourslashRun.ts diff --git a/src/harness/fourslashRun.ts b/src/harness/fourslashRun.ts deleted file mode 100644 index 28f0b2dd637..00000000000 --- a/src/harness/fourslashRun.ts +++ /dev/null @@ -1,48 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -/// - -var testList: string[] = []; - -if (IO.arguments.length === 0) { - IO.dir(Harness.userSpecifiedroot + 'tests/ls/fourslash', /\.ts$/).forEach(fn => { - if (!fn.match(/fourslash.ts$/i)) { - testList.push(fn); - } - }); -} else { - IO.arguments.forEach(tests => tests.split(',').forEach(test => { - testList.push(test); - })); -} - -var passCount = 0, failCount = 0; -testList.forEach(test => { - try { - IO.print('Running ' + test.substr(IO.dirName(test).length + 1) + '... '); - FourSlash.runFourSlashTest(test); - IO.printLine('passed.'); - passCount++; - } catch (e) { - IO.printLine(e); - if (e.stack) { - IO.printLine(e.stack); - } - failCount++; - } -}); - -IO.printLine(passCount + ' passed, ' + failCount + ' failed.'); \ No newline at end of file From 85393abfd99a718e8e6f41ba2f4d8309a6db33a9 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Jul 2014 10:36:43 -0700 Subject: [PATCH 50/59] enable formatting tests --- ...gnmentAfterFormattingOnMultilineExpressionAndParametersList.ts | 0 .../cases/{fourslash_old => fourslash}/autoFormattingOnPasting.ts | 0 .../{fourslash_old => fourslash}/chainedFatArrowFormatting.ts | 0 .../consistenceOnIndentionsOfObjectsInAListAfterFormatting.ts | 0 .../{fourslash_old => fourslash}/constructorBraceFormatting.ts | 0 .../{fourslash_old => fourslash}/formatAfterObjectLiteral.ts | 0 tests/cases/{fourslash_old => fourslash}/formatAnyTypeLiteral.ts | 0 .../formatArrayOrObjectLiteralsInVariableList.ts | 0 tests/cases/{fourslash_old => fourslash}/formatColonAndQMark.ts | 0 .../{fourslash_old => fourslash}/formatControlFlowConstructs.ts | 0 .../cases/{fourslash_old => fourslash}/formatDebuggerStatement.ts | 0 tests/cases/{fourslash_old => fourslash}/formatEmptyBlock.ts | 0 tests/cases/{fourslash_old => fourslash}/formatImplicitModule.ts | 0 .../cases/{fourslash_old => fourslash}/formatImportDeclaration.ts | 0 .../cases/{fourslash_old => fourslash}/formatMultilineComment.ts | 0 .../{fourslash_old => fourslash}/formatOnSemiColonAfterBreak.ts | 0 .../{fourslash_old => fourslash}/formatSelectionWithTrivia.ts | 0 tests/cases/{fourslash_old => fourslash}/formatTryCatch.ts | 0 .../{fourslash_old => fourslash}/formatVariableDeclarationList.ts | 0 tests/cases/{fourslash_old => fourslash}/formatWithStatement.ts | 0 .../formattingAfterChainedFatArrow.ts | 0 .../formattingAfterMultiLineIfCondition.ts | 0 .../formattingAfterMultiLineString.ts | 0 .../cases/{fourslash_old => fourslash}/formattingArrayLiteral.ts | 0 tests/cases/{fourslash_old => fourslash}/formattingComma.ts | 0 tests/cases/{fourslash_old => fourslash}/formattingCrash.ts | 0 .../{fourslash_old => fourslash}/formattingElseInsideAFunction.ts | 0 .../{fourslash_old => fourslash}/formattingFatArrowFunctions.ts | 0 tests/cases/{fourslash_old => fourslash}/formattingForIn.ts | 0 .../{fourslash_old => fourslash}/formattingForLoopSemicolons.ts | 0 .../cases/{fourslash_old => fourslash}/formattingObjectLiteral.ts | 0 .../{fourslash_old => fourslash}/formattingOfChainedLambda.ts | 0 .../{fourslash_old => fourslash}/formattingOfModuleExport.ts | 0 .../formattingOfMultilineBlockConstructs.ts | 0 tests/cases/{fourslash_old => fourslash}/formattingOnClasses.ts | 0 .../cases/{fourslash_old => fourslash}/formattingOnCloseBrace.ts | 0 .../{fourslash_old => fourslash}/formattingOnClosingBracket.ts | 0 .../{fourslash_old => fourslash}/formattingOnCommaOperator.ts | 0 .../formattingOnDoWhileNoSemicolon.ts | 0 .../formattingOnDocumentReadyFunction.ts | 0 .../formattingOnEmptyInterfaceLiteral.ts | 0 tests/cases/{fourslash_old => fourslash}/formattingOnEnter.ts | 0 .../{fourslash_old => fourslash}/formattingOnEnterInComments.ts | 0 .../{fourslash_old => fourslash}/formattingOnEnterInStrings.ts | 0 .../cases/{fourslash_old => fourslash}/formattingOnInterfaces.ts | 0 .../{fourslash_old => fourslash}/formattingOnInvalidCodes.ts | 0 .../{fourslash_old => fourslash}/formattingOnModuleIndentation.ts | 0 .../formattingOnNestedDoWhileByEnter.ts | 0 .../{fourslash_old => fourslash}/formattingOnNestedStatements.ts | 0 .../{fourslash_old => fourslash}/formattingOnObjectLiteral.ts | 0 .../formattingOnOpenBraceOfFunctions.ts | 0 tests/cases/{fourslash_old => fourslash}/formattingOnSemiColon.ts | 0 .../{fourslash_old => fourslash}/formattingOnSingleLineBlocks.ts | 0 .../formattingOnStatementsWithNoSemicolon.ts | 0 .../formattingOnTabAfterCloseCurly.ts | 0 tests/cases/{fourslash_old => fourslash}/formattingOnVariety.ts | 0 .../cases/{fourslash_old => fourslash}/formattingOptionsChange.ts | 0 .../formattingSingleLineWithNewLineOptionSet.ts | 0 .../cases/{fourslash_old => fourslash}/formattingSkippedTokens.ts | 0 .../formattingSpacesAfterConstructor.ts | 0 tests/cases/{fourslash_old => fourslash}/formattingVoid.ts | 0 .../formattingWithEnterAfterMultilineString.ts | 0 .../{fourslash_old => fourslash}/formattingWithLimitedSpan.ts | 0 .../formattingofSingleLineBlockConstructs.ts | 0 tests/cases/{fourslash_old => fourslash}/functionFormatting.ts | 0 .../cases/{fourslash_old => fourslash}/functionTypeFormatting.ts | 0 tests/cases/{fourslash_old => fourslash}/genericsFormatting.ts | 0 .../indentionsOfCommentBlockAfterFormatting.ts | 0 tests/cases/{fourslash_old => fourslash}/semicolonFormatting.ts | 0 .../semicolonFormattingAfterArrayLiteral.ts | 0 .../semicolonFormattingInsideAComment.ts | 0 .../semicolonFormattingInsideAStringLiteral.ts | 0 .../semicolonFormattingNestedStatements.ts | 0 .../{fourslash_old => fourslash}/semicolonFormattingNewline.ts | 0 .../singleLineTypeLiteralFormatting.ts | 0 .../{fourslash_old => fourslash}/tryCatchFinallyFormating.ts | 0 .../unclosedStringLiteralAutoformating.ts | 0 .../whiteSpaceBeforeReturnTypeFormatting.ts | 0 78 files changed, 0 insertions(+), 0 deletions(-) rename tests/cases/{fourslash_old => fourslash}/alignmentAfterFormattingOnMultilineExpressionAndParametersList.ts (100%) rename tests/cases/{fourslash_old => fourslash}/autoFormattingOnPasting.ts (100%) rename tests/cases/{fourslash_old => fourslash}/chainedFatArrowFormatting.ts (100%) rename tests/cases/{fourslash_old => fourslash}/consistenceOnIndentionsOfObjectsInAListAfterFormatting.ts (100%) rename tests/cases/{fourslash_old => fourslash}/constructorBraceFormatting.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formatAfterObjectLiteral.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formatAnyTypeLiteral.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formatArrayOrObjectLiteralsInVariableList.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formatColonAndQMark.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formatControlFlowConstructs.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formatDebuggerStatement.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formatEmptyBlock.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formatImplicitModule.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formatImportDeclaration.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formatMultilineComment.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formatOnSemiColonAfterBreak.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formatSelectionWithTrivia.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formatTryCatch.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formatVariableDeclarationList.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formatWithStatement.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingAfterChainedFatArrow.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingAfterMultiLineIfCondition.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingAfterMultiLineString.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingArrayLiteral.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingComma.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingCrash.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingElseInsideAFunction.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingFatArrowFunctions.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingForIn.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingForLoopSemicolons.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingObjectLiteral.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOfChainedLambda.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOfModuleExport.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOfMultilineBlockConstructs.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnClasses.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnCloseBrace.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnClosingBracket.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnCommaOperator.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnDoWhileNoSemicolon.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnDocumentReadyFunction.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnEmptyInterfaceLiteral.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnEnter.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnEnterInComments.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnEnterInStrings.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnInterfaces.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnInvalidCodes.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnModuleIndentation.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnNestedDoWhileByEnter.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnNestedStatements.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnObjectLiteral.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnOpenBraceOfFunctions.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnSemiColon.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnSingleLineBlocks.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnStatementsWithNoSemicolon.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnTabAfterCloseCurly.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOnVariety.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingOptionsChange.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingSingleLineWithNewLineOptionSet.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingSkippedTokens.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingSpacesAfterConstructor.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingVoid.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingWithEnterAfterMultilineString.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingWithLimitedSpan.ts (100%) rename tests/cases/{fourslash_old => fourslash}/formattingofSingleLineBlockConstructs.ts (100%) rename tests/cases/{fourslash_old => fourslash}/functionFormatting.ts (100%) rename tests/cases/{fourslash_old => fourslash}/functionTypeFormatting.ts (100%) rename tests/cases/{fourslash_old => fourslash}/genericsFormatting.ts (100%) rename tests/cases/{fourslash_old => fourslash}/indentionsOfCommentBlockAfterFormatting.ts (100%) rename tests/cases/{fourslash_old => fourslash}/semicolonFormatting.ts (100%) rename tests/cases/{fourslash_old => fourslash}/semicolonFormattingAfterArrayLiteral.ts (100%) rename tests/cases/{fourslash_old => fourslash}/semicolonFormattingInsideAComment.ts (100%) rename tests/cases/{fourslash_old => fourslash}/semicolonFormattingInsideAStringLiteral.ts (100%) rename tests/cases/{fourslash_old => fourslash}/semicolonFormattingNestedStatements.ts (100%) rename tests/cases/{fourslash_old => fourslash}/semicolonFormattingNewline.ts (100%) rename tests/cases/{fourslash_old => fourslash}/singleLineTypeLiteralFormatting.ts (100%) rename tests/cases/{fourslash_old => fourslash}/tryCatchFinallyFormating.ts (100%) rename tests/cases/{fourslash_old => fourslash}/unclosedStringLiteralAutoformating.ts (100%) rename tests/cases/{fourslash_old => fourslash}/whiteSpaceBeforeReturnTypeFormatting.ts (100%) diff --git a/tests/cases/fourslash_old/alignmentAfterFormattingOnMultilineExpressionAndParametersList.ts b/tests/cases/fourslash/alignmentAfterFormattingOnMultilineExpressionAndParametersList.ts similarity index 100% rename from tests/cases/fourslash_old/alignmentAfterFormattingOnMultilineExpressionAndParametersList.ts rename to tests/cases/fourslash/alignmentAfterFormattingOnMultilineExpressionAndParametersList.ts diff --git a/tests/cases/fourslash_old/autoFormattingOnPasting.ts b/tests/cases/fourslash/autoFormattingOnPasting.ts similarity index 100% rename from tests/cases/fourslash_old/autoFormattingOnPasting.ts rename to tests/cases/fourslash/autoFormattingOnPasting.ts diff --git a/tests/cases/fourslash_old/chainedFatArrowFormatting.ts b/tests/cases/fourslash/chainedFatArrowFormatting.ts similarity index 100% rename from tests/cases/fourslash_old/chainedFatArrowFormatting.ts rename to tests/cases/fourslash/chainedFatArrowFormatting.ts diff --git a/tests/cases/fourslash_old/consistenceOnIndentionsOfObjectsInAListAfterFormatting.ts b/tests/cases/fourslash/consistenceOnIndentionsOfObjectsInAListAfterFormatting.ts similarity index 100% rename from tests/cases/fourslash_old/consistenceOnIndentionsOfObjectsInAListAfterFormatting.ts rename to tests/cases/fourslash/consistenceOnIndentionsOfObjectsInAListAfterFormatting.ts diff --git a/tests/cases/fourslash_old/constructorBraceFormatting.ts b/tests/cases/fourslash/constructorBraceFormatting.ts similarity index 100% rename from tests/cases/fourslash_old/constructorBraceFormatting.ts rename to tests/cases/fourslash/constructorBraceFormatting.ts diff --git a/tests/cases/fourslash_old/formatAfterObjectLiteral.ts b/tests/cases/fourslash/formatAfterObjectLiteral.ts similarity index 100% rename from tests/cases/fourslash_old/formatAfterObjectLiteral.ts rename to tests/cases/fourslash/formatAfterObjectLiteral.ts diff --git a/tests/cases/fourslash_old/formatAnyTypeLiteral.ts b/tests/cases/fourslash/formatAnyTypeLiteral.ts similarity index 100% rename from tests/cases/fourslash_old/formatAnyTypeLiteral.ts rename to tests/cases/fourslash/formatAnyTypeLiteral.ts diff --git a/tests/cases/fourslash_old/formatArrayOrObjectLiteralsInVariableList.ts b/tests/cases/fourslash/formatArrayOrObjectLiteralsInVariableList.ts similarity index 100% rename from tests/cases/fourslash_old/formatArrayOrObjectLiteralsInVariableList.ts rename to tests/cases/fourslash/formatArrayOrObjectLiteralsInVariableList.ts diff --git a/tests/cases/fourslash_old/formatColonAndQMark.ts b/tests/cases/fourslash/formatColonAndQMark.ts similarity index 100% rename from tests/cases/fourslash_old/formatColonAndQMark.ts rename to tests/cases/fourslash/formatColonAndQMark.ts diff --git a/tests/cases/fourslash_old/formatControlFlowConstructs.ts b/tests/cases/fourslash/formatControlFlowConstructs.ts similarity index 100% rename from tests/cases/fourslash_old/formatControlFlowConstructs.ts rename to tests/cases/fourslash/formatControlFlowConstructs.ts diff --git a/tests/cases/fourslash_old/formatDebuggerStatement.ts b/tests/cases/fourslash/formatDebuggerStatement.ts similarity index 100% rename from tests/cases/fourslash_old/formatDebuggerStatement.ts rename to tests/cases/fourslash/formatDebuggerStatement.ts diff --git a/tests/cases/fourslash_old/formatEmptyBlock.ts b/tests/cases/fourslash/formatEmptyBlock.ts similarity index 100% rename from tests/cases/fourslash_old/formatEmptyBlock.ts rename to tests/cases/fourslash/formatEmptyBlock.ts diff --git a/tests/cases/fourslash_old/formatImplicitModule.ts b/tests/cases/fourslash/formatImplicitModule.ts similarity index 100% rename from tests/cases/fourslash_old/formatImplicitModule.ts rename to tests/cases/fourslash/formatImplicitModule.ts diff --git a/tests/cases/fourslash_old/formatImportDeclaration.ts b/tests/cases/fourslash/formatImportDeclaration.ts similarity index 100% rename from tests/cases/fourslash_old/formatImportDeclaration.ts rename to tests/cases/fourslash/formatImportDeclaration.ts diff --git a/tests/cases/fourslash_old/formatMultilineComment.ts b/tests/cases/fourslash/formatMultilineComment.ts similarity index 100% rename from tests/cases/fourslash_old/formatMultilineComment.ts rename to tests/cases/fourslash/formatMultilineComment.ts diff --git a/tests/cases/fourslash_old/formatOnSemiColonAfterBreak.ts b/tests/cases/fourslash/formatOnSemiColonAfterBreak.ts similarity index 100% rename from tests/cases/fourslash_old/formatOnSemiColonAfterBreak.ts rename to tests/cases/fourslash/formatOnSemiColonAfterBreak.ts diff --git a/tests/cases/fourslash_old/formatSelectionWithTrivia.ts b/tests/cases/fourslash/formatSelectionWithTrivia.ts similarity index 100% rename from tests/cases/fourslash_old/formatSelectionWithTrivia.ts rename to tests/cases/fourslash/formatSelectionWithTrivia.ts diff --git a/tests/cases/fourslash_old/formatTryCatch.ts b/tests/cases/fourslash/formatTryCatch.ts similarity index 100% rename from tests/cases/fourslash_old/formatTryCatch.ts rename to tests/cases/fourslash/formatTryCatch.ts diff --git a/tests/cases/fourslash_old/formatVariableDeclarationList.ts b/tests/cases/fourslash/formatVariableDeclarationList.ts similarity index 100% rename from tests/cases/fourslash_old/formatVariableDeclarationList.ts rename to tests/cases/fourslash/formatVariableDeclarationList.ts diff --git a/tests/cases/fourslash_old/formatWithStatement.ts b/tests/cases/fourslash/formatWithStatement.ts similarity index 100% rename from tests/cases/fourslash_old/formatWithStatement.ts rename to tests/cases/fourslash/formatWithStatement.ts diff --git a/tests/cases/fourslash_old/formattingAfterChainedFatArrow.ts b/tests/cases/fourslash/formattingAfterChainedFatArrow.ts similarity index 100% rename from tests/cases/fourslash_old/formattingAfterChainedFatArrow.ts rename to tests/cases/fourslash/formattingAfterChainedFatArrow.ts diff --git a/tests/cases/fourslash_old/formattingAfterMultiLineIfCondition.ts b/tests/cases/fourslash/formattingAfterMultiLineIfCondition.ts similarity index 100% rename from tests/cases/fourslash_old/formattingAfterMultiLineIfCondition.ts rename to tests/cases/fourslash/formattingAfterMultiLineIfCondition.ts diff --git a/tests/cases/fourslash_old/formattingAfterMultiLineString.ts b/tests/cases/fourslash/formattingAfterMultiLineString.ts similarity index 100% rename from tests/cases/fourslash_old/formattingAfterMultiLineString.ts rename to tests/cases/fourslash/formattingAfterMultiLineString.ts diff --git a/tests/cases/fourslash_old/formattingArrayLiteral.ts b/tests/cases/fourslash/formattingArrayLiteral.ts similarity index 100% rename from tests/cases/fourslash_old/formattingArrayLiteral.ts rename to tests/cases/fourslash/formattingArrayLiteral.ts diff --git a/tests/cases/fourslash_old/formattingComma.ts b/tests/cases/fourslash/formattingComma.ts similarity index 100% rename from tests/cases/fourslash_old/formattingComma.ts rename to tests/cases/fourslash/formattingComma.ts diff --git a/tests/cases/fourslash_old/formattingCrash.ts b/tests/cases/fourslash/formattingCrash.ts similarity index 100% rename from tests/cases/fourslash_old/formattingCrash.ts rename to tests/cases/fourslash/formattingCrash.ts diff --git a/tests/cases/fourslash_old/formattingElseInsideAFunction.ts b/tests/cases/fourslash/formattingElseInsideAFunction.ts similarity index 100% rename from tests/cases/fourslash_old/formattingElseInsideAFunction.ts rename to tests/cases/fourslash/formattingElseInsideAFunction.ts diff --git a/tests/cases/fourslash_old/formattingFatArrowFunctions.ts b/tests/cases/fourslash/formattingFatArrowFunctions.ts similarity index 100% rename from tests/cases/fourslash_old/formattingFatArrowFunctions.ts rename to tests/cases/fourslash/formattingFatArrowFunctions.ts diff --git a/tests/cases/fourslash_old/formattingForIn.ts b/tests/cases/fourslash/formattingForIn.ts similarity index 100% rename from tests/cases/fourslash_old/formattingForIn.ts rename to tests/cases/fourslash/formattingForIn.ts diff --git a/tests/cases/fourslash_old/formattingForLoopSemicolons.ts b/tests/cases/fourslash/formattingForLoopSemicolons.ts similarity index 100% rename from tests/cases/fourslash_old/formattingForLoopSemicolons.ts rename to tests/cases/fourslash/formattingForLoopSemicolons.ts diff --git a/tests/cases/fourslash_old/formattingObjectLiteral.ts b/tests/cases/fourslash/formattingObjectLiteral.ts similarity index 100% rename from tests/cases/fourslash_old/formattingObjectLiteral.ts rename to tests/cases/fourslash/formattingObjectLiteral.ts diff --git a/tests/cases/fourslash_old/formattingOfChainedLambda.ts b/tests/cases/fourslash/formattingOfChainedLambda.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOfChainedLambda.ts rename to tests/cases/fourslash/formattingOfChainedLambda.ts diff --git a/tests/cases/fourslash_old/formattingOfModuleExport.ts b/tests/cases/fourslash/formattingOfModuleExport.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOfModuleExport.ts rename to tests/cases/fourslash/formattingOfModuleExport.ts diff --git a/tests/cases/fourslash_old/formattingOfMultilineBlockConstructs.ts b/tests/cases/fourslash/formattingOfMultilineBlockConstructs.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOfMultilineBlockConstructs.ts rename to tests/cases/fourslash/formattingOfMultilineBlockConstructs.ts diff --git a/tests/cases/fourslash_old/formattingOnClasses.ts b/tests/cases/fourslash/formattingOnClasses.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnClasses.ts rename to tests/cases/fourslash/formattingOnClasses.ts diff --git a/tests/cases/fourslash_old/formattingOnCloseBrace.ts b/tests/cases/fourslash/formattingOnCloseBrace.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnCloseBrace.ts rename to tests/cases/fourslash/formattingOnCloseBrace.ts diff --git a/tests/cases/fourslash_old/formattingOnClosingBracket.ts b/tests/cases/fourslash/formattingOnClosingBracket.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnClosingBracket.ts rename to tests/cases/fourslash/formattingOnClosingBracket.ts diff --git a/tests/cases/fourslash_old/formattingOnCommaOperator.ts b/tests/cases/fourslash/formattingOnCommaOperator.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnCommaOperator.ts rename to tests/cases/fourslash/formattingOnCommaOperator.ts diff --git a/tests/cases/fourslash_old/formattingOnDoWhileNoSemicolon.ts b/tests/cases/fourslash/formattingOnDoWhileNoSemicolon.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnDoWhileNoSemicolon.ts rename to tests/cases/fourslash/formattingOnDoWhileNoSemicolon.ts diff --git a/tests/cases/fourslash_old/formattingOnDocumentReadyFunction.ts b/tests/cases/fourslash/formattingOnDocumentReadyFunction.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnDocumentReadyFunction.ts rename to tests/cases/fourslash/formattingOnDocumentReadyFunction.ts diff --git a/tests/cases/fourslash_old/formattingOnEmptyInterfaceLiteral.ts b/tests/cases/fourslash/formattingOnEmptyInterfaceLiteral.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnEmptyInterfaceLiteral.ts rename to tests/cases/fourslash/formattingOnEmptyInterfaceLiteral.ts diff --git a/tests/cases/fourslash_old/formattingOnEnter.ts b/tests/cases/fourslash/formattingOnEnter.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnEnter.ts rename to tests/cases/fourslash/formattingOnEnter.ts diff --git a/tests/cases/fourslash_old/formattingOnEnterInComments.ts b/tests/cases/fourslash/formattingOnEnterInComments.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnEnterInComments.ts rename to tests/cases/fourslash/formattingOnEnterInComments.ts diff --git a/tests/cases/fourslash_old/formattingOnEnterInStrings.ts b/tests/cases/fourslash/formattingOnEnterInStrings.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnEnterInStrings.ts rename to tests/cases/fourslash/formattingOnEnterInStrings.ts diff --git a/tests/cases/fourslash_old/formattingOnInterfaces.ts b/tests/cases/fourslash/formattingOnInterfaces.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnInterfaces.ts rename to tests/cases/fourslash/formattingOnInterfaces.ts diff --git a/tests/cases/fourslash_old/formattingOnInvalidCodes.ts b/tests/cases/fourslash/formattingOnInvalidCodes.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnInvalidCodes.ts rename to tests/cases/fourslash/formattingOnInvalidCodes.ts diff --git a/tests/cases/fourslash_old/formattingOnModuleIndentation.ts b/tests/cases/fourslash/formattingOnModuleIndentation.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnModuleIndentation.ts rename to tests/cases/fourslash/formattingOnModuleIndentation.ts diff --git a/tests/cases/fourslash_old/formattingOnNestedDoWhileByEnter.ts b/tests/cases/fourslash/formattingOnNestedDoWhileByEnter.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnNestedDoWhileByEnter.ts rename to tests/cases/fourslash/formattingOnNestedDoWhileByEnter.ts diff --git a/tests/cases/fourslash_old/formattingOnNestedStatements.ts b/tests/cases/fourslash/formattingOnNestedStatements.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnNestedStatements.ts rename to tests/cases/fourslash/formattingOnNestedStatements.ts diff --git a/tests/cases/fourslash_old/formattingOnObjectLiteral.ts b/tests/cases/fourslash/formattingOnObjectLiteral.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnObjectLiteral.ts rename to tests/cases/fourslash/formattingOnObjectLiteral.ts diff --git a/tests/cases/fourslash_old/formattingOnOpenBraceOfFunctions.ts b/tests/cases/fourslash/formattingOnOpenBraceOfFunctions.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnOpenBraceOfFunctions.ts rename to tests/cases/fourslash/formattingOnOpenBraceOfFunctions.ts diff --git a/tests/cases/fourslash_old/formattingOnSemiColon.ts b/tests/cases/fourslash/formattingOnSemiColon.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnSemiColon.ts rename to tests/cases/fourslash/formattingOnSemiColon.ts diff --git a/tests/cases/fourslash_old/formattingOnSingleLineBlocks.ts b/tests/cases/fourslash/formattingOnSingleLineBlocks.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnSingleLineBlocks.ts rename to tests/cases/fourslash/formattingOnSingleLineBlocks.ts diff --git a/tests/cases/fourslash_old/formattingOnStatementsWithNoSemicolon.ts b/tests/cases/fourslash/formattingOnStatementsWithNoSemicolon.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnStatementsWithNoSemicolon.ts rename to tests/cases/fourslash/formattingOnStatementsWithNoSemicolon.ts diff --git a/tests/cases/fourslash_old/formattingOnTabAfterCloseCurly.ts b/tests/cases/fourslash/formattingOnTabAfterCloseCurly.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnTabAfterCloseCurly.ts rename to tests/cases/fourslash/formattingOnTabAfterCloseCurly.ts diff --git a/tests/cases/fourslash_old/formattingOnVariety.ts b/tests/cases/fourslash/formattingOnVariety.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOnVariety.ts rename to tests/cases/fourslash/formattingOnVariety.ts diff --git a/tests/cases/fourslash_old/formattingOptionsChange.ts b/tests/cases/fourslash/formattingOptionsChange.ts similarity index 100% rename from tests/cases/fourslash_old/formattingOptionsChange.ts rename to tests/cases/fourslash/formattingOptionsChange.ts diff --git a/tests/cases/fourslash_old/formattingSingleLineWithNewLineOptionSet.ts b/tests/cases/fourslash/formattingSingleLineWithNewLineOptionSet.ts similarity index 100% rename from tests/cases/fourslash_old/formattingSingleLineWithNewLineOptionSet.ts rename to tests/cases/fourslash/formattingSingleLineWithNewLineOptionSet.ts diff --git a/tests/cases/fourslash_old/formattingSkippedTokens.ts b/tests/cases/fourslash/formattingSkippedTokens.ts similarity index 100% rename from tests/cases/fourslash_old/formattingSkippedTokens.ts rename to tests/cases/fourslash/formattingSkippedTokens.ts diff --git a/tests/cases/fourslash_old/formattingSpacesAfterConstructor.ts b/tests/cases/fourslash/formattingSpacesAfterConstructor.ts similarity index 100% rename from tests/cases/fourslash_old/formattingSpacesAfterConstructor.ts rename to tests/cases/fourslash/formattingSpacesAfterConstructor.ts diff --git a/tests/cases/fourslash_old/formattingVoid.ts b/tests/cases/fourslash/formattingVoid.ts similarity index 100% rename from tests/cases/fourslash_old/formattingVoid.ts rename to tests/cases/fourslash/formattingVoid.ts diff --git a/tests/cases/fourslash_old/formattingWithEnterAfterMultilineString.ts b/tests/cases/fourslash/formattingWithEnterAfterMultilineString.ts similarity index 100% rename from tests/cases/fourslash_old/formattingWithEnterAfterMultilineString.ts rename to tests/cases/fourslash/formattingWithEnterAfterMultilineString.ts diff --git a/tests/cases/fourslash_old/formattingWithLimitedSpan.ts b/tests/cases/fourslash/formattingWithLimitedSpan.ts similarity index 100% rename from tests/cases/fourslash_old/formattingWithLimitedSpan.ts rename to tests/cases/fourslash/formattingWithLimitedSpan.ts diff --git a/tests/cases/fourslash_old/formattingofSingleLineBlockConstructs.ts b/tests/cases/fourslash/formattingofSingleLineBlockConstructs.ts similarity index 100% rename from tests/cases/fourslash_old/formattingofSingleLineBlockConstructs.ts rename to tests/cases/fourslash/formattingofSingleLineBlockConstructs.ts diff --git a/tests/cases/fourslash_old/functionFormatting.ts b/tests/cases/fourslash/functionFormatting.ts similarity index 100% rename from tests/cases/fourslash_old/functionFormatting.ts rename to tests/cases/fourslash/functionFormatting.ts diff --git a/tests/cases/fourslash_old/functionTypeFormatting.ts b/tests/cases/fourslash/functionTypeFormatting.ts similarity index 100% rename from tests/cases/fourslash_old/functionTypeFormatting.ts rename to tests/cases/fourslash/functionTypeFormatting.ts diff --git a/tests/cases/fourslash_old/genericsFormatting.ts b/tests/cases/fourslash/genericsFormatting.ts similarity index 100% rename from tests/cases/fourslash_old/genericsFormatting.ts rename to tests/cases/fourslash/genericsFormatting.ts diff --git a/tests/cases/fourslash_old/indentionsOfCommentBlockAfterFormatting.ts b/tests/cases/fourslash/indentionsOfCommentBlockAfterFormatting.ts similarity index 100% rename from tests/cases/fourslash_old/indentionsOfCommentBlockAfterFormatting.ts rename to tests/cases/fourslash/indentionsOfCommentBlockAfterFormatting.ts diff --git a/tests/cases/fourslash_old/semicolonFormatting.ts b/tests/cases/fourslash/semicolonFormatting.ts similarity index 100% rename from tests/cases/fourslash_old/semicolonFormatting.ts rename to tests/cases/fourslash/semicolonFormatting.ts diff --git a/tests/cases/fourslash_old/semicolonFormattingAfterArrayLiteral.ts b/tests/cases/fourslash/semicolonFormattingAfterArrayLiteral.ts similarity index 100% rename from tests/cases/fourslash_old/semicolonFormattingAfterArrayLiteral.ts rename to tests/cases/fourslash/semicolonFormattingAfterArrayLiteral.ts diff --git a/tests/cases/fourslash_old/semicolonFormattingInsideAComment.ts b/tests/cases/fourslash/semicolonFormattingInsideAComment.ts similarity index 100% rename from tests/cases/fourslash_old/semicolonFormattingInsideAComment.ts rename to tests/cases/fourslash/semicolonFormattingInsideAComment.ts diff --git a/tests/cases/fourslash_old/semicolonFormattingInsideAStringLiteral.ts b/tests/cases/fourslash/semicolonFormattingInsideAStringLiteral.ts similarity index 100% rename from tests/cases/fourslash_old/semicolonFormattingInsideAStringLiteral.ts rename to tests/cases/fourslash/semicolonFormattingInsideAStringLiteral.ts diff --git a/tests/cases/fourslash_old/semicolonFormattingNestedStatements.ts b/tests/cases/fourslash/semicolonFormattingNestedStatements.ts similarity index 100% rename from tests/cases/fourslash_old/semicolonFormattingNestedStatements.ts rename to tests/cases/fourslash/semicolonFormattingNestedStatements.ts diff --git a/tests/cases/fourslash_old/semicolonFormattingNewline.ts b/tests/cases/fourslash/semicolonFormattingNewline.ts similarity index 100% rename from tests/cases/fourslash_old/semicolonFormattingNewline.ts rename to tests/cases/fourslash/semicolonFormattingNewline.ts diff --git a/tests/cases/fourslash_old/singleLineTypeLiteralFormatting.ts b/tests/cases/fourslash/singleLineTypeLiteralFormatting.ts similarity index 100% rename from tests/cases/fourslash_old/singleLineTypeLiteralFormatting.ts rename to tests/cases/fourslash/singleLineTypeLiteralFormatting.ts diff --git a/tests/cases/fourslash_old/tryCatchFinallyFormating.ts b/tests/cases/fourslash/tryCatchFinallyFormating.ts similarity index 100% rename from tests/cases/fourslash_old/tryCatchFinallyFormating.ts rename to tests/cases/fourslash/tryCatchFinallyFormating.ts diff --git a/tests/cases/fourslash_old/unclosedStringLiteralAutoformating.ts b/tests/cases/fourslash/unclosedStringLiteralAutoformating.ts similarity index 100% rename from tests/cases/fourslash_old/unclosedStringLiteralAutoformating.ts rename to tests/cases/fourslash/unclosedStringLiteralAutoformating.ts diff --git a/tests/cases/fourslash_old/whiteSpaceBeforeReturnTypeFormatting.ts b/tests/cases/fourslash/whiteSpaceBeforeReturnTypeFormatting.ts similarity index 100% rename from tests/cases/fourslash_old/whiteSpaceBeforeReturnTypeFormatting.ts rename to tests/cases/fourslash/whiteSpaceBeforeReturnTypeFormatting.ts From 0a08a42abed4f26cb2103a52660ea6c3a11add0f Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Jul 2014 10:37:01 -0700 Subject: [PATCH 51/59] enbale fourslash tests --- Jakefile | 10 +- src/compiler/core.ts | 8 + src/harness/fourslash.ts | 462 ++++++++++++-------------- src/harness/harnessLanguageService.ts | 213 +++++++----- src/harness/runner.ts | 6 +- src/services/core/diagnosticCore.ts | 7 +- src/services/services.ts | 4 +- src/services/shims.ts | 8 + 8 files changed, 361 insertions(+), 357 deletions(-) diff --git a/Jakefile b/Jakefile index f8d7f15e7a6..d738359e221 100644 --- a/Jakefile +++ b/Jakefile @@ -62,19 +62,17 @@ var servicesSources = [ var harnessSources = [ "harness.ts", "sourceMapRecorder.ts", -// TODO Re-enable -// "harnessLanguageService.ts", -// "fourslash.ts", - "runner.ts", + "harnessLanguageService.ts", + "fourslash.ts", "external/json2.ts", "runnerbase.ts", "compilerRunner.ts", "typeWriter.ts", -// TODO Re-enable fourslash and project tests -// "fourslashRunner.ts", + "fourslashRunner.ts", "projectsRunner.ts", "unittestrunner.ts", "rwcRunner.ts", + "runner.ts" ].map(function (f) { return path.join(harnessDirectory, f); }); diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 6f9f2629a80..824aaca5a46 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -134,6 +134,14 @@ module ts { return result; } + export function forEachKey(map: Map, callback: (key: string) => U): U { + var result: U; + for (var id in map) { + if (result = callback(id)) break; + } + return result; + } + export function mapToArray(map: Map): T[] { var result: T[] = []; for (var id in map) result.push(map[id]); diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 3037971471a..ac11fecbd3f 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -14,6 +14,7 @@ // /// +/// /// module FourSlash { @@ -108,7 +109,7 @@ module FourSlash { High } - var entityMap: TypeScript.IIndexable = { + var entityMap: ts.Map = { '&': '&', '"': '"', "'": ''', @@ -127,7 +128,7 @@ module FourSlash { export var currentTestState: TestState = null; - export class TestCancellationToken implements TypeScript.ICancellationToken { + export class TestCancellationToken implements ts.CancellationToken { // 0 - cancelled // >0 - not cancelled // <0 - not cancelled and value denotes number of isCancellationRequested after which token become cancelled @@ -162,7 +163,7 @@ module FourSlash { f(); } catch (e) { - if (e instanceof TypeScript.OperationCanceledException) { + if (e instanceof ts.OperationCanceledException) { return; } } @@ -172,9 +173,8 @@ module FourSlash { export class TestState { // Language service instance - public languageServiceShimHost: Harness.TypeScriptLS = null; - private languageService: TypeScript.Services.ILanguageService = null; - private newLanguageService: ts.LanguageService = null; + public languageServiceShimHost: Harness.LanguageService.TypeScriptLS; + private languageService: ts.LanguageService; // A reference to the language service's compiler state's compiler instance private compiler: () => { getSyntaxTree(fileName: string): TypeScript.SyntaxTree; getSourceUnit(fileName: string): TypeScript.SourceUnitSyntax; }; @@ -189,7 +189,7 @@ module FourSlash { // Whether or not we should format on keystrokes public enableFormatting = true; - public formatCodeOptions: TypeScript.Services.FormatCodeOptions = null; + public formatCodeOptions: ts.FormatCodeOptions; public cancellationToken: TestCancellationToken; @@ -202,7 +202,7 @@ module FourSlash { constructor(public testData: FourSlashData) { // Initialize the language service with all the scripts this.cancellationToken = new TestCancellationToken(); - this.languageServiceShimHost = new Harness.TypeScriptLS(this.cancellationToken); + this.languageServiceShimHost = new Harness.LanguageService.TypeScriptLS(this.cancellationToken); var harnessCompiler = Harness.Compiler.getCompiler(); var inputFiles: { unitName: string; content: string }[] = []; @@ -226,40 +226,48 @@ module FourSlash { }); } - // NEWTODO: Re-implement commented-out section - // harnessCompiler.addInputFiles(inputFiles); - try { - // var resolvedFiles = harnessCompiler.resolve(); + // NEWTODO: Re-implement commented-out section + //harnessCompiler.addInputFiles(inputFiles); + //try { + // var resolvedFiles = harnessCompiler.resolve(); - //resolvedFiles.forEach(file => { - // if (!Harness.isLibraryFile(file.path)) { - // var fixedPath = file.path.substr(file.path.indexOf('tests/')); - // var content = harnessCompiler.getContentForFile(fixedPath); - // this.languageServiceShimHost.addScript(fixedPath, content); - // } - //}); + // resolvedFiles.forEach(file => { + // if (!Harness.isLibraryFile(file.path)) { + // var fixedPath = file.path.substr(file.path.indexOf('tests/')); + // var content = harnessCompiler.getContentForFile(fixedPath); + // this.languageServiceShimHost.addScript(fixedPath, content); + // } + // }); - // NEWTODO: For now do not resolve, just use the input files - inputFiles.forEach(file => { - if (!Harness.isLibraryFile(file.unitName)) { - this.languageServiceShimHost.addScript(file.unitName, file.content); - } - }); + // this.languageServiceShimHost.addScript('lib.d.ts', Harness.Compiler.libTextMinimal); + //} + //finally { + // // harness no longer needs the results of the above work, make sure the next test operations are in a clean state + // harnessCompiler.reset(); + //} - this.languageServiceShimHost.addScript('lib.d.ts', Harness.Compiler.libTextMinimal); - } - finally { - // harness no longer needs the results of the above work, make sure the next test operations are in a clean state - //harnessCompiler.reset(); - } + /// NEWTODO: For now do not resolve, just use the input files inputFiles.forEach(file => { if (!Harness.isLibraryFile(file.unitName)) { this.languageServiceShimHost.addScript(file.unitName, file.content); } }); + this.languageServiceShimHost.addScript('lib.d.ts', Harness.Compiler.libTextMinimal); // Sneak into the language service and get its compiler so we can examine the syntax trees this.languageService = this.languageServiceShimHost.getLanguageService().languageService; - this.newLanguageService = this.languageServiceShimHost.newLS; var compilerState = (this.languageService).compiler; this.compiler = () => compilerState.compiler; - this.formatCodeOptions = new TypeScript.Services.FormatCodeOptions(); + this.formatCodeOptions = { + IndentSize: 4, + TabSize: 4, + NewLineCharacter: sys.newLine, + ConvertTabsToSpaces: true, + InsertSpaceAfterCommaDelimiter: true, + InsertSpaceAfterSemicolonInForStatements: true, + InsertSpaceBeforeAndAfterBinaryOperators: true, + InsertSpaceAfterKeywordsInControlFlowStatements: true, + InsertSpaceAfterFunctionKeywordForAnonymousFunctions: false, + InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false, + PlaceOpenBraceOnNewLineForFunctions: false, + PlaceOpenBraceOnNewLineForControlBlocks: false, + }; this.testData.files.forEach(file => { var filename = file.fileName.replace(Harness.IO.directoryName(file.fileName), '').substr(1); @@ -308,7 +316,7 @@ module FourSlash { public openFile(name: string): void; public openFile(indexOrName: any) { var fileToOpen: FourSlashFile = this.findFile(indexOrName); - fileToOpen.fileName = Harness.Path.switchToForwardSlashes(fileToOpen.fileName); + fileToOpen.fileName = ts.normalizeSlashes(fileToOpen.fileName); this.activeFile = fileToOpen; var filename = fileToOpen.fileName.replace(Harness.IO.directoryName(fileToOpen.fileName), '').substr(1); this.scenarioActions.push(''); @@ -318,9 +326,7 @@ module FourSlash { var startMarker = this.getMarkerByName(startMarkerName); var endMarker = this.getMarkerByName(endMarkerName); var predicate = function (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) { - // NEWTODO: make this more specific again - //return ((errorMinChar === startPos) && (errorLimChar === endPos)) ? true : false; - return ((errorMinChar >= startPos) && (errorLimChar <= endPos)) ? true : false; + return ((errorMinChar === startPos) && (errorLimChar === endPos)) ? true : false; }; var exists = this.anyErrorInRange(predicate, startMarker, endMarker); @@ -328,28 +334,15 @@ module FourSlash { this.taoInvalidReason = 'verifyErrorExistsBetweenMarkers NYI'; if (exists !== negative) { - this.new_printErrorLog(negative, this.new_getAllDiagnostics()); + this.printErrorLog(negative, this.getAllDiagnostics()); throw new Error("Failure between markers: " + startMarkerName + ", " + endMarkerName); } } - private getDiagnostics(fileName: string): TypeScript.Diagnostic[] { + private getDiagnostics(fileName: string): ts.Diagnostic[] { var syntacticErrors = this.languageService.getSyntacticDiagnostics(fileName); var semanticErrors = this.languageService.getSemanticDiagnostics(fileName); - var diagnostics: TypeScript.Diagnostic[] = []; - diagnostics.push.apply(diagnostics, syntacticErrors); - diagnostics.push.apply(diagnostics, semanticErrors); - - return diagnostics; - } - - - private new_getDiagnostics(fileName: string): ts.Diagnostic[] { - var syntacticErrors = this.newLanguageService.getSyntacticDiagnostics(fileName); - var semanticErrors = this.newLanguageService.getSemanticDiagnostics(fileName); - - var diagnostics: ts.Diagnostic[] = []; diagnostics.push.apply(diagnostics, syntacticErrors); diagnostics.push.apply(diagnostics, semanticErrors); @@ -357,9 +350,8 @@ module FourSlash { return diagnostics; } - - private getAllDiagnostics(): TypeScript.Diagnostic[] { - var diagnostics: TypeScript.Diagnostic[] = []; + private getAllDiagnostics(): ts.Diagnostic[] { + var diagnostics: ts.Diagnostic[] = []; var fileNames = JSON.parse(this.languageServiceShimHost.getScriptFileNames()); for (var i = 0, n = fileNames.length; i < n; i++) { @@ -369,17 +361,6 @@ module FourSlash { return diagnostics; } - private new_getAllDiagnostics(): ts.Diagnostic[] { - var diagnostics: ts.Diagnostic[] = []; - - var fileNames = JSON.parse(this.languageServiceShimHost.getScriptFileNames()); - for (var i = 0, n = fileNames.length; i < n; i++) { - diagnostics.push.apply(this.new_getDiagnostics(fileNames[i])); - } - - return diagnostics; - } - public verifyErrorExistsAfterMarker(markerName: string, negative: boolean, after: boolean) { var marker: Marker = this.getMarkerByName(markerName); var predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => boolean; @@ -397,17 +378,17 @@ module FourSlash { this.taoInvalidReason = 'verifyErrorExistsAfterMarker NYI'; var exists = this.anyErrorInRange(predicate, marker); - var diagnostics = this.new_getAllDiagnostics(); + var diagnostics = this.getAllDiagnostics(); if (exists !== negative) { - this.new_printErrorLog(negative, diagnostics); + this.printErrorLog(negative, diagnostics); throw new Error("Failure at marker: " + markerName); } } private anyErrorInRange(predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => boolean, startMarker: Marker, endMarker?: Marker) { - var errors = this.new_getDiagnostics(startMarker.fileName); + var errors = this.getDiagnostics(startMarker.fileName); var exists = false; var startPos = startMarker.position; @@ -415,7 +396,7 @@ module FourSlash { var endPos = endMarker.position; } - errors.forEach((error)=> { + errors.forEach(function (error: ts.Diagnostic) { if (predicate(error.start, error.start + error.length, startPos, endPos)) { exists = true; } @@ -424,26 +405,14 @@ module FourSlash { return exists; } - private printErrorLog(expectErrors: boolean, errors: TypeScript.Diagnostic[]) { + private printErrorLog(expectErrors: boolean, errors: ts.Diagnostic[]) { if (expectErrors) { Harness.IO.log("Expected error not found. Error list is:"); } else { Harness.IO.log("Unexpected error(s) found. Error list is:"); } - errors.forEach(function (error: TypeScript.Diagnostic) { - Harness.IO.log(" minChar: " + error.start() + ", limChar: " + (error.start() + error.length()) + ", message: " + error.message() + "\n"); - }); - } - - private new_printErrorLog(expectErrors: boolean, errors: ts.Diagnostic[]) { - if (expectErrors) { - Harness.IO.log("Expected error not found. Error list is:"); - } else { - Harness.IO.log("Unexpected error(s) found. Error list is:"); - } - - errors.forEach(error => { + errors.forEach(function (error: ts.Diagnostic) { Harness.IO.log(" minChar: " + error.start + ", limChar: " + (error.start + error.length) + ", message: " + error.messageText + "\n"); }); } @@ -754,22 +723,22 @@ module FourSlash { this.taoInvalidReason = 'verifyCurrentSignatureHelpIs NYI'; var help = this.getActiveSignatureHelp(); - assert.equal(help.prefix + help.parameters.map(p => p.display).join(help.separator) + help.suffix, expected); + assert.equal(help.signatureInfo, expected); } public verifyCurrentParameterIsVariable(isVariable: boolean) { this.taoInvalidReason = 'verifyCurrentParameterIsVariable NYI'; - var signature = this.getActiveSignatureHelp(); - assert.isNotNull(signature); - assert.equal(isVariable, signature.isVariadic); + var activeParameter = this.getActiveParameter(); + assert.isNotNull(activeParameter.parameter); + assert.equal(isVariable, activeParameter.parameter.isVariable); } public verifyCurrentParameterHelpName(name: string) { this.taoInvalidReason = 'verifyCurrentParameterHelpName NYI'; var activeParameter = this.getActiveParameter(); - var activeParameterName = activeParameter.name; + var activeParameterName = activeParameter.parameter ? activeParameter.parameter.name : activeParameter.typeParameter.name; assert.equal(activeParameterName, name); } @@ -778,14 +747,16 @@ module FourSlash { var activeSignature = this.getActiveSignatureHelp(); var activeParameter = this.getActiveParameter(); - assert.equal(activeParameter.display, parameter); + var activeParameterMinChar = activeParameter.parameter ? activeParameter.parameter.minChar : activeParameter.typeParameter.minChar; + var activeParameterLimChar = activeParameter.parameter ? activeParameter.parameter.limChar : activeParameter.typeParameter.limChar; + assert.equal(activeSignature.signatureInfo.substring(activeParameterMinChar, activeParameterLimChar), parameter); } public verifyCurrentParameterHelpDocComment(docComment: string) { this.taoInvalidReason = 'verifyCurrentParameterHelpDocComment NYI'; var activeParameter = this.getActiveParameter(); - var activeParameterDocComment = activeParameter.documentation; + var activeParameterDocComment = activeParameter.parameter ? activeParameter.parameter.docComment : activeParameter.typeParameter.docComment; assert.equal(activeParameterDocComment, docComment); } @@ -798,13 +769,13 @@ module FourSlash { public verifyCurrentSignatureHelpTypeParameterCount(expectedCount: number) { this.taoInvalidReason = 'verifyCurrentSignatureHelpTypeParameterCount NYI'; - // assert.equal(this.getActiveSignatureHelp().typeParameters.length, expectedCount); + assert.equal(this.getActiveSignatureHelp().typeParameters.length, expectedCount); } public verifyCurrentSignatureHelpDocComment(docComment: string) { this.taoInvalidReason = 'verifyCurrentSignatureHelpDocComment NYI'; - var actualDocComment = this.getActiveSignatureHelp().documentation; + var actualDocComment = this.getActiveSignatureHelp().docComment; assert.equal(actualDocComment, docComment); } @@ -812,15 +783,15 @@ module FourSlash { this.scenarioActions.push(''); this.scenarioActions.push(''); - var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition); - var actual = help && help.items ? help.items.length : 0; + var help = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition); + var actual = help && help.formal ? help.formal.length : 0; assert.equal(actual, expected); } public verifySignatureHelpPresent(shouldBePresent = true) { this.taoInvalidReason = 'verifySignatureHelpPresent NYI'; - var actual = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition); + var actual = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition); if (shouldBePresent) { if (!actual) { throw new Error("Expected signature help to be present, but it wasn't"); @@ -832,32 +803,45 @@ module FourSlash { } } - //private getFormalParameter() { - // var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition); - // return help.formal; - //} + private getFormalParameter() { + var help = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition); + return help.formal; + } private getActiveSignatureHelp() { - var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition); + var help = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition); + var activeFormal = help.activeFormal; // If the signature hasn't been narrowed down yet (e.g. no parameters have yet been entered), // 'activeFormal' will be -1 (even if there is only 1 signature). Signature help will show the // first signature in the signature group, so go with that - var index = help.selectedItemIndex < 0 ? 0 : help.selectedItemIndex; + if (activeFormal === -1) { + activeFormal = 0; + } - return help.items[index]; + return help.formal[activeFormal]; } - private getActiveParameter(): TypeScript.Services.SignatureHelpParameter { + private getActiveParameter(): { parameter: ts.FormalParameterInfo; typeParameter: ts.FormalTypeParameterInfo; } { var currentSig = this.getActiveSignatureHelp(); - var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition); - - var item = help.items[help.selectedItemIndex]; - var state = this.languageService.getSignatureHelpCurrentArgumentState(this.activeFile.fileName, this.currentCaretPosition, help.applicableSpan.start()); + var help = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition); // Same logic as in getActiveSignatureHelp - this value might be -1 until a parameter value actually gets typed - var currentParam = state === null ? 0 : state.argumentIndex; - return item.parameters[currentParam]; + var currentParam = help.actual.currentParameter; + if (currentParam === -1) currentParam = 0; + + if (help.actual.currentParameterIsTypeParameter) { + return { + parameter: null, + typeParameter: currentSig.typeParameters[currentParam] + }; + } + else { + return { + parameter: currentSig.parameters[currentParam], + typeParameter: null + }; + } } public getBreakpointStatementLocation(pos: number) { @@ -866,7 +850,7 @@ module FourSlash { var spanInfo = this.languageService.getBreakpointStatementAtPosition(this.activeFile.fileName, pos); var resultString = "\n**Pos: " + pos + " SpanInfo: " + JSON.stringify(spanInfo) + "\n** Statement: "; if (spanInfo !== null) { - resultString = resultString + this.activeFile.content.substr(spanInfo.start(), spanInfo.length()); + resultString = resultString + this.activeFile.content.substr(spanInfo.minChar, spanInfo.limChar - spanInfo.minChar); } return resultString; } @@ -884,7 +868,8 @@ module FourSlash { resultString = resultString + this.getBreakpointStatementLocation(pos); } return resultString; - }); + }, + true /* run immediately */); } public printBreakpointLocation(pos: number) { @@ -896,7 +881,7 @@ module FourSlash { } public printCurrentParameterHelp() { - var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition); + var help = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition); Harness.IO.log(JSON.stringify(help)); } @@ -906,10 +891,6 @@ module FourSlash { } public printErrorList() { - Harness.IO.log("--------------"); - Harness.IO.log("Old Errors"); - Harness.IO.log("--------------"); - var syntacticErrors = this.languageService.getSyntacticDiagnostics(this.activeFile.fileName); var semanticErrors = this.languageService.getSemanticDiagnostics(this.activeFile.fileName); var errorList = syntacticErrors.concat(semanticErrors); @@ -917,27 +898,7 @@ module FourSlash { if (errorList.length) { errorList.forEach(err => { - Harness.IO.log("start: " + err.start() + ", length: " + err.length() + ", message: " + err.message()); - }); - } - - Harness.IO.log("--------------"); - Harness.IO.log("New Errors"); - Harness.IO.log("--------------"); - this.new_printErrorList(); - } - - public new_printErrorList() { - var syntacticErrors = this.newLanguageService.getSyntacticDiagnostics(this.activeFile.fileName); - var semanticErrors = this.newLanguageService.getSemanticDiagnostics(this.activeFile.fileName); - var errorList = syntacticErrors.concat(semanticErrors); - Harness.IO.log('Error list (' + errorList.length + ' errors)'); - - - if (errorList.length) { - errorList.forEach(error => { - Harness.IO.log("start: " + error.start + ", length: " + error.length + - ", message: " + error.messageText); + Harness.IO.log("start: " + err.start + ", length: " + err.length + ", message: " + err.messageText); }); } } @@ -1100,10 +1061,10 @@ module FourSlash { offset++; if (ch === '(' || ch === ',') { - // Signature help - this.languageService.getSignatureHelpItems(this.activeFile.fileName, offset); + /* Signature help*/ + this.languageService.getSignatureAtPosition(this.activeFile.fileName, offset); } else if (prevChar === ' ' && /A-Za-z_/.test(ch)) { - // Completions + /* Completions */ this.languageService.getCompletionsAtPosition(this.activeFile.fileName, offset, false); } @@ -1141,7 +1102,7 @@ module FourSlash { // Handle formatting if (this.enableFormatting) { - var edits = this.languageService.getFormattingEditsForRange(this.activeFile.fileName, start, offset, this.formatCodeOptions); + var edits = this.languageService.getFormattingEditsOnPaste(this.activeFile.fileName, start, offset, this.formatCodeOptions); offset += this.applyEdits(this.activeFile.fileName, edits, true); this.editCheckpoint(this.activeFile.fileName); } @@ -1154,46 +1115,44 @@ module FourSlash { } private checkPostEditInvariants() { - if (this.editValidation === IncrementalEditValidation.None) { - return; - } + return; - // Get syntactic errors (to force a refresh) - var incrSyntaxErrs = JSON.stringify(this.languageService.getSyntacticDiagnostics(this.activeFile.fileName)); + /// TODO: reimplement this section + //if (this.editValidation === IncrementalEditValidation.None) { + // return; + //} - // Check syntactic structure - var compilationSettings = new TypeScript.CompilationSettings(); - compilationSettings.codeGenTarget = TypeScript.LanguageVersion.EcmaScript5; - var immutableSettings = TypeScript.ImmutableCompilationSettings.fromCompilationSettings(compilationSettings); + //// Get syntactic errors (to force a refresh) + //var incrSyntaxErrs = JSON.stringify(this.languageService.getSyntacticDiagnostics(this.activeFile.fileName)); - var parseOptions = immutableSettings.codeGenTarget(); - var snapshot = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName); - var content = snapshot.getText(0, snapshot.getLength()); - var refSyntaxTree = TypeScript.Parser.parse(this.activeFile.fileName, TypeScript.SimpleText.fromString(content), parseOptions, TypeScript.isDTSFile(this.activeFile.fileName)); - var fullSyntaxErrs = JSON.stringify(refSyntaxTree.diagnostics()); + //// Check syntactic structure + //var snapshot = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName); + //var content = snapshot.getText(0, snapshot.getLength()); + //var refSyntaxTree = TypeScript.Parser.parse(this.activeFile.fileName, TypeScript.SimpleText.fromString(content), ts.ScriptTarget.ES5, TypeScript.isDTSFile(this.activeFile.fileName)); + //var fullSyntaxErrs = JSON.stringify(refSyntaxTree.diagnostics()); - if (incrSyntaxErrs !== fullSyntaxErrs) { - throw new Error('Mismatched incremental/full syntactic errors for file ' + this.activeFile.fileName + '.\n=== Incremental errors ===\n' + incrSyntaxErrs + '\n=== Full Errors ===\n' + fullSyntaxErrs); - } + //if (incrSyntaxErrs !== fullSyntaxErrs) { + // throw new Error('Mismatched incremental/full syntactic errors for file ' + this.activeFile.fileName + '.\n=== Incremental errors ===\n' + incrSyntaxErrs + '\n=== Full Errors ===\n' + fullSyntaxErrs); + //} - if (this.editValidation !== IncrementalEditValidation.SyntacticOnly) { - var compiler = new TypeScript.TypeScriptCompiler(); - for (var i = 0; i < this.testData.files.length; i++) { - snapshot = this.languageServiceShimHost.getScriptSnapshot(this.testData.files[i].fileName); - compiler.addFile(this.testData.files[i].fileName, TypeScript.ScriptSnapshot.fromString(snapshot.getText(0, snapshot.getLength())), TypeScript.ByteOrderMark.None, "0", true); - } + // if (this.editValidation !== IncrementalEditValidation.SyntacticOnly) { + // var compiler = new TypeScript.TypeScriptCompiler(); + // for (var i = 0; i < this.testData.files.length; i++) { + // snapshot = this.languageServiceShimHost.getScriptSnapshot(this.testData.files[i].fileName); + // compiler.addFile(this.testData.files[i].fileName, TypeScript.ScriptSnapshot.fromString(snapshot.getText(0, snapshot.getLength())), ts.ByteOrderMark.None, 0, true); + // } - compiler.addFile('lib.d.ts', TypeScript.ScriptSnapshot.fromString(Harness.Compiler.libTextMinimal), TypeScript.ByteOrderMark.None, "0", true); + // compiler.addFile('lib.d.ts', TypeScript.ScriptSnapshot.fromString(Harness.Compiler.libTextMinimal), ts.ByteOrderMark.None, 0, true); - for (var i = 0; i < this.testData.files.length; i++) { - var refSemanticErrs = JSON.stringify(compiler.getSemanticDiagnostics(this.testData.files[i].fileName)); - var incrSemanticErrs = JSON.stringify(this.languageService.getSemanticDiagnostics(this.testData.files[i].fileName)); + // for (var i = 0; i < this.testData.files.length; i++) { + // var refSemanticErrs = JSON.stringify(compiler.getSemanticDiagnostics(this.testData.files[i].fileName)); + // var incrSemanticErrs = JSON.stringify(this.languageService.getSemanticDiagnostics(this.testData.files[i].fileName)); - if (incrSemanticErrs !== refSemanticErrs) { - throw new Error('Mismatched incremental/full semantic errors for file ' + this.testData.files[i].fileName + '\n=== Incremental errors ===\n' + incrSemanticErrs + '\n=== Full Errors ===\n' + refSemanticErrs); - } - } - } + // if (incrSemanticErrs !== refSemanticErrs) { + // throw new Error('Mismatched incremental/full semantic errors for file ' + this.testData.files[i].fileName + '\n=== Incremental errors ===\n' + incrSemanticErrs + '\n=== Full Errors ===\n' + refSemanticErrs); + // } + // } + // } } private fixCaretPosition() { @@ -1207,18 +1166,18 @@ module FourSlash { }; } - private applyEdits(fileName: string, edits: TypeScript.Services.TextChange[], isFormattingEdit = false): number { + private applyEdits(fileName: string, edits: ts.TextEdit[], isFormattingEdit = false): number { // We get back a set of edits, but langSvc.editScript only accepts one at a time. Use this to keep track // of the incremental offest from each edit to the next. Assumption is that these edit ranges don't overlap var runningOffset = 0; - edits = edits.sort((a, b) => a.span.start() - b.span.start()); + edits = edits.sort((a, b) => a.minChar - b.minChar); // Get a snapshot of the content of the file so we can make sure any formatting edits didn't destroy non-whitespace characters var snapshot = this.languageServiceShimHost.getScriptSnapshot(fileName); var oldContent = snapshot.getText(0, snapshot.getLength()); for (var j = 0; j < edits.length; j++) { - this.languageServiceShimHost.editScript(fileName, edits[j].span.start() + runningOffset, edits[j].span.end() + runningOffset, edits[j].newText); - this.updateMarkersForEdit(fileName, edits[j].span.start() + runningOffset, edits[j].span.end() + runningOffset, edits[j].newText); - var change = (edits[j].span.start() - edits[j].span.end()) + edits[j].newText.length; + this.languageServiceShimHost.editScript(fileName, edits[j].minChar + runningOffset, edits[j].limChar + runningOffset, edits[j].text); + this.updateMarkersForEdit(fileName, edits[j].minChar + runningOffset, edits[j].limChar + runningOffset, edits[j].text); + var change = (edits[j].minChar - edits[j].limChar) + edits[j].text.length; runningOffset += change; // TODO: Consider doing this at least some of the time for higher fidelity. Currently causes a failure (bug 707150) // this.languageService.getScriptLexicalStructure(fileName); @@ -1238,7 +1197,7 @@ module FourSlash { public formatDocument() { this.scenarioActions.push(''); - var edits = this.languageService.getFormattingEditsForDocument(this.activeFile.fileName, this.formatCodeOptions); + var edits = this.languageService.getFormattingEditsForDocument(this.activeFile.fileName, 0, this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getLength(), this.formatCodeOptions); this.currentCaretPosition += this.applyEdits(this.activeFile.fileName, edits, true); this.fixCaretPosition(); } @@ -1295,7 +1254,7 @@ module FourSlash { var definition = definitions[definitionIndex]; this.openFile(definition.fileName); - this.currentCaretPosition = definition.textSpan.start(); + this.currentCaretPosition = definition.minChar; } public verifyDefinitionLocationExists(negative: boolean) { @@ -1331,7 +1290,7 @@ module FourSlash { throw new Error('verifyCaretAtMarker failed - expected to be in file "' + pos.fileName + '", but was in file "' + this.activeFile.fileName + '"'); } if (pos.position !== this.currentCaretPosition) { - throw new Error('verifyCaretAtMarker failed - expected to be at marker "/*' + markerName + '*' + '/, but was at position ' + this.currentCaretPosition + '(' + this.getLineColStringAtCaret() + ')'); + throw new Error('verifyCaretAtMarker failed - expected to be at marker "/*' + markerName + '*/, but was at position ' + this.currentCaretPosition + '(' + this.getLineColStringAtCaret() + ')'); } } @@ -1401,7 +1360,7 @@ module FourSlash { '\t Actual: null'); } - var actual = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(span.start(), span.end()); + var actual = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(span.minChar, span.limChar); if (actual !== text) { throw new Error('verifyCurrentNameOrDottedNameSpanText\n' + '\tExpected: "' + text + '"\n' + @@ -1413,7 +1372,7 @@ module FourSlash { var spanInfo = this.languageService.getNameOrDottedNameSpan(this.activeFile.fileName, pos, pos); var resultString = "\n**Pos: " + pos + " SpanInfo: " + JSON.stringify(spanInfo) + "\n** Statement: "; if (spanInfo !== null) { - resultString = resultString + this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(spanInfo.start(), spanInfo.end()); + resultString = resultString + this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(spanInfo.minChar, spanInfo.limChar); } return resultString; } @@ -1431,7 +1390,8 @@ module FourSlash { resultString = resultString + this.getNameOrDottedNameSpan(pos); } return resultString; - }); + }, + true /* run immediately */); } public printNameOrDottedNameSpans(pos: number) { @@ -1441,7 +1401,7 @@ module FourSlash { public verifyOutliningSpans(spans: TextSpan[]) { this.taoInvalidReason = 'verifyOutliningSpans NYI'; - var actual = this.languageService.getOutliningSpans(this.activeFile.fileName); + var actual = this.languageService.getOutliningRegions(this.activeFile.fileName); if (actual.length !== spans.length) { throw new Error('verifyOutliningSpans failed - expected total spans to be ' + spans.length + ', but was ' + actual.length); @@ -1450,27 +1410,8 @@ module FourSlash { for (var i = 0; i < spans.length; i++) { var expectedSpan = spans[i]; var actualSpan = actual[i]; - if (expectedSpan.start !== actualSpan.textSpan.start() || expectedSpan.end !== actualSpan.textSpan.end()) { - throw new Error('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualSpan.textSpan.start() + ',' + actualSpan.textSpan.end() + ')'); - } - } - } - - public verifyTodoComments(descriptors: string[], spans: TextSpan[]) { - var actual = this.languageService.getTodoComments(this.activeFile.fileName, - descriptors.map(d => new TypeScript.Services.TodoCommentDescriptor(d, 0))); - - if (actual.length !== spans.length) { - throw new Error('verifyTodoComments failed - expected total spans to be ' + spans.length + ', but was ' + actual.length); - } - - for (var i = 0; i < spans.length; i++) { - var expectedSpan = spans[i]; - var actualComment = actual[i]; - var actualCommentSpan = new TypeScript.TextSpan(actualComment.position, actualComment.message.length); - - if (expectedSpan.start !== actualCommentSpan.start() || expectedSpan.end !== actualCommentSpan.end()) { - throw new Error('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualCommentSpan.start() + ',' + actualCommentSpan.end() + ')'); + if (expectedSpan.start !== actualSpan.start() || expectedSpan.end !== actualSpan.end()) { + throw new Error('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualSpan.start() + ',' + actualSpan.end() + ')'); } } } @@ -1485,9 +1426,9 @@ module FourSlash { } var actualMatchPosition = -1; - if (bracePosition == actual[0].start()) { + if (bracePosition >= actual[0].start() && bracePosition <= actual[0].end()) { actualMatchPosition = actual[1].start(); - } else if (bracePosition == actual[1].start()) { + } else if (bracePosition >= actual[1].start() && bracePosition <= actual[1].end()) { actualMatchPosition = actual[0].start(); } else { throw new Error('verifyMatchingBracePosition failed - could not find the brace position: ' + bracePosition + ' in the returned list: (' + actual[0].start() + ',' + actual[0].end() + ') and (' + actual[1].start() + ',' + actual[1].end() + ')'); @@ -1512,7 +1453,7 @@ module FourSlash { this.taoInvalidReason = 'verifyTypesAgainstFullCheckAtPositions impossible'; // Create a from-scratch LS to check against - var referenceLanguageServiceShimHost = new Harness.TypeScriptLS(); + var referenceLanguageServiceShimHost = new Harness.LanguageService.TypeScriptLS(); var referenceLanguageServiceShim = referenceLanguageServiceShimHost.getLanguageService(); var referenceLanguageService = referenceLanguageServiceShim.languageService; @@ -1528,7 +1469,7 @@ module FourSlash { } for (i = 0; i < positions.length; i++) { - var nameOf = (type: TypeScript.Services.TypeInfo) => type ? type.fullSymbolName : '(none)'; + var nameOf = (type: ts.TypeInfo) => type ? type.fullSymbolName : '(none)'; var pullName: string, refName: string; var anyFailed = false; @@ -1571,14 +1512,16 @@ module FourSlash { } } - /// Check number of navigationItems which match both searchValue and matchKind. - /// Report an error if expected value and actual value do not match. + /* + Check number of navigationItems which match both searchValue and matchKind. + Report an error if expected value and actual value do not match. + */ public verifyNavigationItemsCount(expected: number, searchValue: string, matchKind?: string) { this.taoInvalidReason = 'verifyNavigationItemsCount NYI'; var items = this.languageService.getNavigateToItems(searchValue); var actual = 0; - var item: TypeScript.Services.NavigateToItem = null; + var item: ts.NavigateToItem = null; // Count only the match that match the same MatchKind for (var i = 0; i < items.length; ++i) { @@ -1593,8 +1536,10 @@ module FourSlash { } } - /// Verify that returned navigationItems from getNavigateToItems have matched searchValue, matchKind, and kind. - /// Report an error if getNavigateToItems does not find any matched searchValue. + /* + Verify that returned navigationItems from getNavigateToItems have matched searchValue, matchKind, and kind. + Report an error if getNavigateToItems does not find any matched searchValue. + */ public verifyNavigationItemsListContains( name: string, kind: string, @@ -1630,61 +1575,70 @@ module FourSlash { public verifyGetScriptLexicalStructureListCount(expected: number) { this.taoInvalidReason = 'verifyNavigationItemsListContains impossible'; - var items = this.languageService.getNavigationBarItems(this.activeFile.fileName); - var actual = this.getNavigationBarItemsCount(items); - + var items = this.languageService.getScriptLexicalStructure(this.activeFile.fileName); + var actual = (items && items.length) || 0; if (expected != actual) { throw new Error('verifyGetScriptLexicalStructureListCount failed - found: ' + actual + ' navigation items, expected: ' + expected + '.'); } } - private getNavigationBarItemsCount(items: TypeScript.Services.NavigationBarItem[]) { - var result = 0; - if (items) { - for (var i = 0, n = items.length; i < n; i++) { - result++; - result += this.getNavigationBarItemsCount(items[i].childItems); - } - } - - return result; - } - public verifGetScriptLexicalStructureListContains( name: string, kind: string, + fileName?: string, + parentName?: string, + isAdditionalSpan?: boolean, markerPosition?: number) { this.taoInvalidReason = 'verifGetScriptLexicalStructureListContains impossible'; - var items = this.languageService.getNavigationBarItems(this.activeFile.fileName); + var items = this.languageService.getScriptLexicalStructure(this.activeFile.fileName); if (!items || items.length === 0) { throw new Error('verifyGetScriptLexicalStructureListContains failed - found 0 navigation items, expected at least one.'); } - if (this.navigationBarItemsContains(items, name, kind)) { - return; - } - - var missingItem = { name: name, kind: kind }; - throw new Error('verifyGetScriptLexicalStructureListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(items) + ')'); - } - - private navigationBarItemsContains(items: TypeScript.Services.NavigationBarItem[], name: string, kind: string) { - if (items) { - for (var i = 0; i < items.length; i++) { - var item = items[i]; - if (item && item.text === name && item.kind === kind) { - return true; + for (var i = 0; i < items.length; i++) { + var item = items[i]; + if (item && item.name === name && item.kind === kind && + (fileName === undefined || item.fileName === fileName) && + (parentName === undefined || item.containerName === parentName)) { + if (markerPosition !== undefined || isAdditionalSpan !== undefined) { + if (isAdditionalSpan) { + if (item.additionalSpans && + item.additionalSpans.some(span => span.minChar <= markerPosition && markerPosition <= span.limChar)) { + // marker is in an additional span for this item. + return; + } + else { + throw new Error( + 'verifGetScriptLexicalStructureListContains failed - ' + + 'no additional span was found that contained the position: ' + JSON.stringify(markerPosition) + + ' in the item: ' + JSON.stringify(item)); + } + } + else if (!isAdditionalSpan) { + if (item.minChar <= markerPosition && + markerPosition <= item.minChar) { + // marker is in span normal item's span + return; + } + else { + throw new Error( + 'verifGetScriptLexicalStructureListContains failed - ' + + 'marker was positioned: ' + JSON.stringify(markerPosition) + + ' which is not in the item: ' + JSON.stringify(item)); + } + } } - - if (this.navigationBarItemsContains(item.childItems, name, kind)) { - return true; + else { + return; } } } - return false; + + var missingItem = { name: name, kind: kind, fileName: fileName, parentName: parentName }; + throw new Error('verifyGetScriptLexicalStructureListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(items) + ')'); } public printNavigationItems(searchValue: string) { @@ -1700,14 +1654,14 @@ module FourSlash { } public printScriptLexicalStructureItems() { - var items = this.languageService.getNavigationBarItems(this.activeFile.fileName); + var items = this.languageService.getScriptLexicalStructure(this.activeFile.fileName); var length = items && items.length; Harness.IO.log('NavigationItems list (' + length + ' items)'); for (var i = 0; i < length; i++) { var item = items[i]; - Harness.IO.log('name: ' + item.text + ', kind: ' + item.kind); + Harness.IO.log('name: ' + item.name + ', kind: ' + item.kind + ', parentName: ' + item.containerName + ', fileName: ' + item.fileName); } } @@ -1726,7 +1680,7 @@ module FourSlash { for (var i = 0; i < occurances.length; i++) { var occurance = occurances[i]; - if (occurance && occurance.fileName === fileName && occurance.textSpan.start() === start && occurance.textSpan.end() === end) { + if (occurance && occurance.fileName === fileName && occurance.minChar === start && occurance.limChar === end) { if (typeof isWriteAccess !== "undefined" && occurance.isWriteAccess !== isWriteAccess) { throw new Error('verifyOccurancesAtPositionListContains failed - item isWriteAccess value doe not match, actual: ' + occurance.isWriteAccess + ', expected: ' + isWriteAccess + '.'); } @@ -1798,7 +1752,7 @@ module FourSlash { return result; } - private assertItemInCompletionList(items: TypeScript.Services.CompletionEntry[], name: string, type?: string, docComment?: string, fullSymbolName?: string, kind?: string) { + private assertItemInCompletionList(items: ts.CompletionEntry[], name: string, type?: string, docComment?: string, fullSymbolName?: string, kind?: string) { this.scenarioActions.push(''); this.scenarioActions.push(''); diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index c9075949dd6..e3646b98e03 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -1,10 +1,13 @@ -module Harness.LanguageService { +/// +/// + +module Harness.LanguageService { export class ScriptInfo { public version: number = 1; public editRanges: { length: number; textChangeRange: TypeScript.TextChangeRange; }[] = []; public lineMap: TypeScript.LineMap = null; - constructor(public fileName: string, public content: string, public isOpen = true, public byteOrderMark: TypeScript.ByteOrderMark = TypeScript.ByteOrderMark.None) { + constructor(public fileName: string, public content: string, public isOpen = true, public byteOrderMark: ts.ByteOrderMark = ts.ByteOrderMark.None) { this.setContent(content); } @@ -51,7 +54,7 @@ } } - class ScriptSnapshotShim implements TypeScript.Services.IScriptSnapshotShim { + class ScriptSnapshotShim implements ts.ScriptSnapshotShim { private lineMap: TypeScript.LineMap = null; private textSnapshot: string; private version: number; @@ -77,9 +80,8 @@ return JSON.stringify(this.lineMap.lineStarts()); } - public getChangeRange(oldScript: TypeScript.Services.IScriptSnapshotShim): string { - var oldShim = oldScript; - var range = this.scriptInfo.getTextChangeRangeBetweenVersions(oldShim.version, this.version); + public getTextChangeRangeSinceVersion(scriptVersion: number): string { + var range = this.scriptInfo.getTextChangeRangeBetweenVersions(scriptVersion, this.version); if (range === null) { return null; } @@ -88,14 +90,91 @@ } } - export class TypeScriptLS implements TypeScript.Services.ILanguageServiceShimHost { - IO = TypeScript.Environment ? TypeScript.Environment : Network.getEnvironment(); - private ls: TypeScript.Services.ILanguageServiceShim = null; + class CancellationToken { + public static None: CancellationToken = new CancellationToken(null) + + constructor(private cancellationToken: ts.CancellationToken) { + } + + public isCancellationRequested() { + return this.cancellationToken && this.cancellationToken.isCancellationRequested(); + } + } + + class ScriptSnapshotShimAdapter implements TypeScript.IScriptSnapshot { + private lineStartPositions: number[] = null; + constructor(private scriptSnapshotShim: ts.ScriptSnapshotShim) {} + getText(start: number, end: number): string {return this.scriptSnapshotShim.getText(start, end);} + getLength(): number {return this.scriptSnapshotShim.getLength();} + getLineStartPositions(): number[] { return JSON.parse(this.scriptSnapshotShim.getLineStartPositions()); } + getTextChangeRangeSinceVersion(scriptVersion: number): TypeScript.TextChangeRange { + var encoded = this.scriptSnapshotShim.getTextChangeRangeSinceVersion(scriptVersion); + if (encoded == null) { + return null; + } + + var decoded: { span: { start: number; length: number; }; newLength: number; } = JSON.parse(encoded); + return new TypeScript.TextChangeRange( + new TypeScript.TextSpan(decoded.span.start, decoded.span.length), decoded.newLength); + } + } + + class LanguageServiceShimHostAdapter implements ts.LanguageServiceHost { + constructor(private shimHost: ts.LanguageServiceShimHost) { } + information(): boolean { return this.shimHost.information(); } + debug(): boolean { return this.shimHost.debug(); } + warning(): boolean { return this.shimHost.warning();} + error(): boolean { return this.shimHost.error(); } + fatal(): boolean { return this.shimHost.fatal(); } + log(s: string): void { this.shimHost.log(s); } + getCompilationSettings(): ts.CompilerOptions { return JSON.parse(this.shimHost.getCompilationSettings()); } + getScriptFileNames(): string[] { return JSON.parse(this.shimHost.getScriptFileNames());} + getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot { return new ScriptSnapshotShimAdapter(this.shimHost.getScriptSnapshot(fileName));} + getScriptVersion(fileName: string): number { return this.shimHost.getScriptVersion(fileName);} + getScriptIsOpen(fileName: string): boolean { return this.shimHost.getScriptIsOpen(fileName); } + getScriptByteOrderMark(fileName: string): ts.ByteOrderMark { return this.shimHost.getScriptByteOrderMark(fileName);} + getLocalizedDiagnosticMessages(): any { JSON.parse(this.shimHost.getLocalizedDiagnosticMessages());} + getCancellationToken(): ts.CancellationToken { return this.shimHost.getCancellationToken(); } + } + + export class NonCachingDocumentRegistry implements ts.DocumentRegistry { + + public static Instance: ts.DocumentRegistry = new NonCachingDocumentRegistry(); + + public acquireDocument( + fileName: string, + compilationSettings: ts.CompilerOptions, + scriptSnapshot: TypeScript.IScriptSnapshot, + byteOrderMark: ts.ByteOrderMark, + version: number, + isOpen: boolean, + referencedFiles: string[]= []): ts.Document { + return ts.createDocument(compilationSettings, fileName, scriptSnapshot, byteOrderMark, version, isOpen, referencedFiles); + } + + public updateDocument( + document: ts.Document, + fileName: string, + compilationSettings: ts.CompilerOptions, + scriptSnapshot: TypeScript.IScriptSnapshot, + version: number, + isOpen: boolean, + textChangeRange: TypeScript.TextChangeRange + ): ts.Document { + return document.update(scriptSnapshot, version, isOpen, textChangeRange); + } + + public releaseDocument(fileName: string, compilationSettings: ts.CompilerOptions): void { + // no op since this class doesn't cache anything + } + } + export class TypeScriptLS implements ts.LanguageServiceShimHost { + private ls: ts.LanguageServiceShim = null; public newLS: ts.LanguageService; - private fileNameToScript = new TypeScript.StringHashTable(); + private fileNameToScript: ts.Map = {}; - constructor(private cancellationToken: TypeScript.ICancellationToken = TypeScript.CancellationToken.None) { + constructor(private cancellationToken: ts.CancellationToken = CancellationToken.None) { } public addDefaultLibrary() { @@ -107,17 +186,16 @@ } public addFile(fileName: string) { - var code = Harness.Environment.readFile(fileName); + var code = Harness.IO.readFile(fileName); this.addScript(fileName, code); } private getScriptInfo(fileName: string): ScriptInfo { - return this.fileNameToScript.lookup(fileName); + return this.fileNameToScript[fileName]; } public addScript(fileName: string, content: string) { - var script = new ScriptInfo(fileName, content); - this.fileNameToScript.add(fileName, script); + this.fileNameToScript[fileName] = new ScriptInfo(fileName, content); } public updateScript(fileName: string, content: string) { @@ -155,91 +233,64 @@ } ////////////////////////////////////////////////////////////////////// - // ILanguageServiceShimHost implementation + // LanguageServiceShimHost implementation // /// Returns json for Tools.CompilationSettings public getCompilationSettings(): string { - return ""; // i.e. default settings + return JSON.stringify({}); // i.e. default settings } - public getCancellationToken(): TypeScript.ICancellationToken { + public getCancellationToken(): ts.CancellationToken { return this.cancellationToken; } public getScriptFileNames(): string { - return JSON.stringify(this.fileNameToScript.getAllKeys()); + var fileNames: string[] = []; + ts.forEachKey(this.fileNameToScript, (fileName) => { fileNames.push(fileName); }); + return JSON.stringify(fileNames); } - public getScriptSnapshot(fileName: string): TypeScript.Services.IScriptSnapshotShim { + public getScriptSnapshot(fileName: string): ts.ScriptSnapshotShim { return new ScriptSnapshotShim(this.getScriptInfo(fileName)); } - public getScriptVersion(fileName: string): string { - return this.getScriptInfo(fileName).version.toString(); + public getScriptVersion(fileName: string): number { + return this.getScriptInfo(fileName).version; } public getScriptIsOpen(fileName: string): boolean { return this.getScriptInfo(fileName).isOpen; } - public getScriptByteOrderMark(fileName: string): TypeScript.ByteOrderMark { + public getScriptByteOrderMark(fileName: string): ts.ByteOrderMark { return this.getScriptInfo(fileName).byteOrderMark; } - public getDiagnosticsObject(): TypeScript.Services.ILanguageServicesDiagnostics { - return new LanguageServicesDiagnostics(""); - } - public getLocalizedDiagnosticMessages(): string { - return ""; - } - - public fileExists(s: string) { - return this.IO.fileExists(s); - } - - public directoryExists(s: string) { - return this.IO.directoryExists(s); - } - - public resolveRelativePath(path: string, directory: string): string { - if (TypeScript.isRooted(path) || !directory) { - return this.IO.absolutePath(path); - } - else { - return this.IO.absolutePath(TypeScript.IOUtils.combine(directory, path)); - } - } - - public getParentDirectory(path: string): string { - return this.IO.directoryName(path); + return JSON.stringify({}); } /** Return a new instance of the language service shim, up-to-date wrt to typecheck. * To access the non-shim (i.e. actual) language service, use the "ls.languageService" property. */ - public getLanguageService(): TypeScript.Services.ILanguageServiceShim { + public getLanguageService(): ts.LanguageServiceShim { var ls = new TypeScript.Services.TypeScriptServicesFactory().createLanguageServiceShim(this); this.ls = ls; - var hostAdapter = new ts.LanguageServiceShimHostAdapter(this); - this.newLS = ts.createLanguageService(hostAdapter); + var hostAdapter = new LanguageServiceShimHostAdapter(this); + + this.newLS = ts.createLanguageService(hostAdapter, NonCachingDocumentRegistry.Instance); return ls; } /** Parse file given its source text */ public parseSourceText(fileName: string, sourceText: TypeScript.IScriptSnapshot): TypeScript.SourceUnitSyntax { - var compilationSettings = new TypeScript.CompilationSettings(); - compilationSettings.codeGenTarget = TypeScript.LanguageVersion.EcmaScript5; - - var settings = TypeScript.ImmutableCompilationSettings.fromCompilationSettings(compilationSettings); - var parseOptions = settings.codeGenTarget(); - return TypeScript.Parser.parse(fileName, TypeScript.SimpleText.fromScriptSnapshot(sourceText), parseOptions, TypeScript.isDTSFile(fileName)).sourceUnit(); + return TypeScript.Parser.parse(fileName, TypeScript.SimpleText.fromScriptSnapshot(sourceText), ts.ScriptTarget.ES5, TypeScript.isDTSFile(fileName)).sourceUnit(); } /** Parse a file on disk given its fileName */ public parseFile(fileName: string) { - var sourceText = TypeScript.ScriptSnapshot.fromString(this.IO.readFile(fileName, /*codepage:*/ null).contents) + var sourceText = TypeScript.ScriptSnapshot.fromString(Harness.IO.readFile(fileName)) return this.parseSourceText(fileName, sourceText); } @@ -248,7 +299,7 @@ * @param col 1 based index */ public lineColToPosition(fileName: string, line: number, col: number): number { - var script: ScriptInfo = this.fileNameToScript.lookup(fileName); + var script: ScriptInfo = this.fileNameToScript[fileName]; assert.isNotNull(script); assert.isTrue(line >= 1); assert.isTrue(col >= 1); @@ -261,7 +312,7 @@ * @param col 0 based index */ public positionToZeroBasedLineCol(fileName: string, position: number): TypeScript.ILineAndCharacter { - var script: ScriptInfo = this.fileNameToScript.lookup(fileName); + var script: ScriptInfo = this.fileNameToScript[fileName]; assert.isNotNull(script); var result = script.lineMap.getLineAndCharacterFromPosition(position); @@ -272,10 +323,10 @@ } /** Verify that applying edits to sourceFileName result in the content of the file baselineFileName */ - public checkEdits(sourceFileName: string, baselineFileName: string, edits: TypeScript.Services.TextChange[]) { - var script = Utils.readFile(sourceFileName); - var formattedScript = this.applyEdits(script.contents, edits); - var baseline = Utils.readFile(baselineFileName).contents; + public checkEdits(sourceFileName: string, baselineFileName: string, edits: ts.TextEdit[]) { + var script = Harness.IO.readFile(sourceFileName); + var formattedScript = this.applyEdits(script, edits); + var baseline = Harness.IO.readFile(baselineFileName); function noDiff(text1: string, text2: string) { text1 = text1.replace(/^\s+|\s+$/g, "").replace(/\r\n?/g, "\n"); @@ -301,26 +352,26 @@ /** Apply an array of text edits to a string, and return the resulting string. */ - public applyEdits(content: string, edits: TypeScript.Services.TextChange[]): string { + public applyEdits(content: string, edits: ts.TextEdit[]): string { var result = content; edits = this.normalizeEdits(edits); for (var i = edits.length - 1; i >= 0; i--) { var edit = edits[i]; - var prefix = result.substring(0, edit.span.start()); - var middle = edit.newText; - var suffix = result.substring(edit.span.end()); + var prefix = result.substring(0, edit.minChar); + var middle = edit.text; + var suffix = result.substring(edit.limChar); result = prefix + middle + suffix; } return result; } /** Normalize an array of edits by removing overlapping entries and sorting entries on the minChar position. */ - private normalizeEdits(edits: TypeScript.Services.TextChange[]): TypeScript.Services.TextChange[] { - var result: TypeScript.Services.TextChange[] = []; + private normalizeEdits(edits: ts.TextEdit[]): ts.TextEdit[] { + var result: ts.TextEdit[] = []; - function mapEdits(edits: TypeScript.Services.TextChange[]): { edit: TypeScript.Services.TextChange; index: number; }[] { - var result: { edit: TypeScript.Services.TextChange; index: number; }[] = []; + function mapEdits(edits: ts.TextEdit[]): { edit: ts.TextEdit; index: number; }[] { + var result: { edit: ts.TextEdit; index: number; }[] = []; for (var i = 0; i < edits.length; i++) { result.push({ edit: edits[i], index: i }); } @@ -328,7 +379,7 @@ } var temp = mapEdits(edits).sort(function (a, b) { - var result = a.edit.span.start() - b.edit.span.start(); + var result = a.edit.minChar - b.edit.limChar; if (result === 0) result = a.index - b.index; return result; @@ -347,7 +398,7 @@ } var nextEdit = temp[next].edit; - var gap = nextEdit.span.start() - currentEdit.span.end(); + var gap = nextEdit.minChar - currentEdit.limChar; // non-overlapping edits if (gap >= 0) { @@ -359,7 +410,7 @@ // overlapping edits: for now, we only support ignoring an next edit // entirely contained in the current edit. - if (currentEdit.span.end() >= nextEdit.span.end()) { + if (currentEdit.minChar >= nextEdit.limChar) { next++; continue; } @@ -371,15 +422,5 @@ return result; } } - - export class LanguageServicesDiagnostics implements TypeScript.Services.ILanguageServicesDiagnostics { - - constructor(private destination: string) { } - - public log(content: string): void { - //Imitates the LanguageServicesDiagnostics object when not in Visual Studio - } - - } } \ No newline at end of file diff --git a/src/harness/runner.ts b/src/harness/runner.ts index 26b768729fc..accf41684c0 100644 --- a/src/harness/runner.ts +++ b/src/harness/runner.ts @@ -62,12 +62,10 @@ if (testConfigFile !== '') { runners.push(new ProjectRunner()); break; case 'fourslash': - // TODO: Re-enable Fourslash tests - // runners.push(new FourslashRunner()); + runners.push(new FourslashRunner()); break; case 'fourslash-generated': - // TODO: Re-enable Fourslash tests - // runners.push(new GeneratedFourslashRunner()); + runners.push(new GeneratedFourslashRunner()); break; case 'unittests': runners.push(new UnitTestRunner(UnittestTestType.Compiler)); diff --git a/src/services/core/diagnosticCore.ts b/src/services/core/diagnosticCore.ts index 8485052af8f..0c12a354933 100644 --- a/src/services/core/diagnosticCore.ts +++ b/src/services/core/diagnosticCore.ts @@ -145,11 +145,8 @@ module TypeScript { } export function getLocalizedText(diagnosticKey: string, args: any[]): string { - if (LocalizedDiagnosticMessages) { - //Debug.assert(LocalizedDiagnosticMessages.hasOwnProperty(diagnosticKey)); - } - - var diagnosticMessageText: string = LocalizedDiagnosticMessages ? LocalizedDiagnosticMessages[diagnosticKey] : diagnosticKey; + + var diagnosticMessageText: string = diagnosticKey; Debug.assert(diagnosticMessageText !== undefined && diagnosticMessageText !== null); var actualCount = args ? args.length : 0; diff --git a/src/services/services.ts b/src/services/services.ts index 8e969ceb5a0..14581c0c3d6 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -811,7 +811,7 @@ module ts { } } - function createDocument(compilationSettings: CompilerOptions, fileName: string, scriptSnapshot: TypeScript.IScriptSnapshot, byteOrderMark: ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]): Document { + export function createDocument(compilationSettings: CompilerOptions, fileName: string, scriptSnapshot: TypeScript.IScriptSnapshot, byteOrderMark: ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]): Document { return new DocumentObject(compilationSettings, fileName, referencedFiles, scriptSnapshot, byteOrderMark, version, isOpen, /*syntaxTree:*/ null, /*soruceFile*/ null); } @@ -1339,7 +1339,7 @@ module ts { function dispose(): void { if (program) { forEach(program.getSourceFiles(), - (f) => documentRegistry.releaseDocument(f.filename, program.getCompilerOptions())); + (f) => { documentRegistry.releaseDocument(f.filename, program.getCompilerOptions()); }); } } diff --git a/src/services/shims.ts b/src/services/shims.ts index c2402aebd52..8debe8f973b 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -173,6 +173,8 @@ module ts { } function languageVersionToScriptTarget(languageVersion: LanguageVersion): ScriptTarget { + if (typeof languageVersion === "undefined") return undefined; + switch (languageVersion) { case LanguageVersion.EcmaScript3: return ScriptTarget.ES3; case LanguageVersion.EcmaScript5: return ScriptTarget.ES5; @@ -181,6 +183,8 @@ module ts { } function moduleGenTargetToModuleKind(moduleGenTarget: ModuleGenTarget): ModuleKind { + if (typeof moduleGenTarget === "undefined") return undefined; + switch (moduleGenTarget) { case ModuleGenTarget.Asynchronous: return ModuleKind.AMD; case ModuleGenTarget.Synchronous: return ModuleKind.CommonJS; @@ -190,6 +194,8 @@ module ts { } function scriptTargetTolanguageVersion(scriptTarget: ScriptTarget): LanguageVersion { + if (typeof scriptTarget === "undefined") return undefined; + switch (scriptTarget) { case ScriptTarget.ES3: return LanguageVersion.EcmaScript3; case ScriptTarget.ES5: return LanguageVersion.EcmaScript5; @@ -198,6 +204,8 @@ module ts { } function moduleKindToModuleGenTarget(moduleKind: ModuleKind): ModuleGenTarget { + if (typeof moduleKind === "undefined") return undefined; + switch (moduleKind) { case ModuleKind.AMD: return ModuleGenTarget.Asynchronous; case ModuleKind.CommonJS: return ModuleGenTarget.Synchronous; From 4ad7452a586eb8acf4e66502371d1c9e96e7ff84 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Jul 2014 11:23:30 -0700 Subject: [PATCH 52/59] Enable passing fourslash tests --- .../addDeclareToFunction.ts | 0 .../{fourslash_old => fourslash}/addDeclareToModule.ts | 0 .../{fourslash_old => fourslash}/addDuplicateSetter.ts | 0 .../addFunctionAboveMultiLineLambdaExpression.ts | 0 .../addFunctionInDuplicatedConstructorClassBody.ts | 0 .../addInterfaceMemberAboveClass.ts | 0 .../addInterfaceToNotSatisfyConstraint.ts | 0 .../addMemberToInterface.ts | 0 .../addMethodToInterface1.ts | 0 .../addSignaturePartial.ts | 0 .../addVarToConstructor1.ts | 0 .../aliasToVarUsedAsType.ts | 0 .../ambientVariablesWithSameName.ts | 0 .../argumentsAreAvailableAfterEditsAtEndOfFunction.ts | 0 .../argumentsIndexExpression.ts | 0 .../arrayCallAndConstructTypings.ts | 0 .../arrayConcatTypeCheck0.ts | 0 .../arrayConcatTypeCheck1.ts | 0 .../arrayTypeMismatchIncrementalTypeCheck.ts | 0 .../assertContextualType.ts | 0 .../assignToExistingClass.ts | 0 .../brokenClassErrorRecovery.ts | 0 .../chainedFunctionFunctionArgIndent.ts | 0 .../chainedFunctionLambdaArgIndex.ts | 0 .../classInterfaceInsert.ts | 0 .../classRenamingErrorRecovery.ts | 0 .../{fourslash_old => fourslash}/cloduleAsBaseClass.ts | 0 .../closedCommentsInConstructor.ts | 0 .../{fourslash_old => fourslash}/commentsBlocks.ts | 0 .../completionInTypeOf2.ts | 0 .../completionListAfterAnyType.ts | 0 .../completionListAfterClassExtends.ts | 0 .../completionListAfterInvalidCharacter.ts | 0 .../completionListAfterNumericLiteral1.ts | 0 .../completionListAfterRegularExpressionLiteral1.ts | 0 .../completionListAfterStringLiteral1.ts | 0 .../completionListAndMemberListOnCommentedDot.ts | 0 .../completionListAndMemberListOnCommentedLine.ts | 0 ...completionListAndMemberListOnCommentedWhiteSpace.ts | 0 .../completionListAtDeclarationOfParameterType.ts | 0 .../completionListAtEOF.ts | 0 .../completionListAtEOF1.ts | 0 .../completionListAtIdentifierDefinitionLocations.ts | 0 .../completionListAtInvalidLocations.ts | 0 .../completionListErrorRecovery.ts | 0 .../completionListErrorRecovery2.ts | 0 .../completionListForGenericInstance1.ts | 0 .../completionListFunctionMembers.ts | 0 .../completionListInComments.ts | 0 .../completionListInEmptyFile.ts | 0 .../completionListInFatArrow.ts | 0 .../completionListInFunctionDeclaration.ts | 0 .../completionListInFunctionExpression.ts | 0 .../completionListInObjectLiteral.ts | 0 .../completionListInObjectLiteral2.ts | 0 ...ListInObjectLiteralThatIsParameterOfFunctionCall.ts | 0 .../completionListInScope.ts | 0 .../completionListKeywords.ts | 0 .../completionListOfSplitInterface.ts | 0 .../completionListOnAliasedModule.ts | 0 .../completionListOnMethodParameterName.ts | 0 .../completionListOnParamInClass.ts | 0 .../completionListOnParamOfGenericType1.ts | 0 .../completionListOnPrivateVariableInModule.ts | 0 .../completionListOnSuper.ts | 0 .../completionListsThroughTransitiveBaseClasses.ts | 0 .../completionListsThroughTransitiveBaseClasses2.ts | 0 ...nvalid-identifiers-should-not-show-in-completion.ts | 0 .../consistenceOnIndentionsOfChainedFunctionCalls.ts | 0 .../consistentContextualTypeErrorsAfterEdits.ts | 0 .../constructorQuickInfo.ts | 0 .../contextuallyTypedFunctionExpressionGeneric1.ts | 0 .../debuggerStatementIndent.ts | 0 .../{fourslash_old => fourslash}/declareFunction.ts | 0 .../deleteClassWithEnumPresent.ts | 0 .../deleteExtensionInReopenedInterface.ts | 0 .../deleteReopenedModule.ts | 0 .../deleteTypeParameter.ts | 0 .../duplicateClassModuleError0.ts | 0 .../duplicateFunctionImplementation.ts | 0 .../editLambdaArgToTypeParameter1.ts | 0 .../emptyTypeArgumentList.ts | 0 .../cases/{fourslash_old => fourslash}/enumAddition.ts | 0 .../cases/{fourslash_old => fourslash}/enumUpdate1.ts | 0 .../exportClauseErrorReporting0.ts | 0 .../exportEqualsInterfaceA.ts | 0 .../extendArrayInterface.ts | 0 .../failureToImplementClass.ts | 0 tests/cases/{fourslash_old => fourslash}/forIn.ts | 0 .../forceIndentAfterNewLineInsert.ts | 0 .../{fourslash_old => fourslash}/forwardReference.ts | 0 .../fsEditMarkerPositions.ts | 0 .../functionIndentation.ts | 0 .../functionRenamingErrorRecovery.ts | 0 .../{fourslash_old => fourslash}/functionTypes.ts | 0 .../{fourslash_old => fourslash}/generated/dummy.txt | 0 .../genericArityEnforcementAfterEdit.ts | 0 .../genericAssignmentCompat.ts | 0 .../genericCloduleCompletionList.ts | 0 .../genericFunctionWithGenericParams1.ts | 0 .../genericInterfacePropertyInference1.ts | 0 .../genericInterfacePropertyInference2.ts | 0 .../genericInterfaceWithInheritanceEdit1.ts | 0 .../genericInterfacesWithConstraints1.ts | 0 .../{fourslash_old => fourslash}/genericMethodParam.ts | 0 .../genericObjectBaseType.ts | 0 .../genericParameterHelp.ts | 0 .../genericRespecialization1.ts | 0 .../genericSignaturesAreProperlyCleaned.ts | 0 .../genericTypeWithMultipleBases1MultiFile.ts | 10 +++++----- .../getCompletionEntryDetails.ts | 0 .../getCompletionEntryDetails2.ts | 0 .../{fourslash_old => fourslash}/getImplementors1.ts | 0 .../getImplementorsForFunction.ts | 0 .../getMatchingBracesNegativeCases.ts | 0 .../getNameOrDottedNameSpan.ts | 0 .../getOccurrencesOfAny.ts | 0 .../getTypeAtModuleExtends.ts | 0 .../globalCompletionListInsideObjectLiterals.ts | 0 .../goToDefinitionPrimitives.ts | 0 .../goToDefinitionSourceUnit.ts | 0 .../goToDefinitionUndefinedSymbols.ts | 0 .../identationAfterInterfaceCall.ts | 0 .../identifierErrorRecovery.ts | 0 .../{fourslash_old => fourslash}/importDeclPaste0.ts | 0 .../importValueUsedAsType.ts | 0 .../incompatibleOverride.ts | 0 .../incrementalResolveConstructorDeclaration.ts | 0 .../incrementalResolveFunctionPropertyAssignment.ts | 0 ...incrementalUpdateToClassImplementingGenericClass.ts | 0 .../indentAfterFunctionClosingBraces.ts | 0 .../{fourslash_old => fourslash}/indentAfterImport.ts | 0 .../cases/{fourslash_old => fourslash}/indentation.ts | 0 .../indentationAfterModuleImport.ts | 0 .../indexSignatureWithoutAnnotation.ts | 0 .../inheritedModuleMembersForClodule2.ts | 0 .../insertArgumentBeforeOverloadedConstructor.ts | 0 .../insertInterfaceAndCheckTypeLiteralField.ts | 0 .../insertMethodCallAboveOthers.ts | 0 .../insertPublicBeforeSetter.ts | 0 ...sertReturnStatementInDuplicateIdentifierFunction.ts | 0 .../insertSecondTryCatchBlock.ts | 0 .../insertVarAfterEmptyTypeParamList.ts | 0 .../interfaceExtendsPrimitive.ts | 0 .../{fourslash_old => fourslash}/interfaceIndent.ts | 0 .../interfaceRecursiveInheritanceErrors0.ts | 0 .../interfaceRecursiveInheritanceErrors1.ts | 0 .../invalidRestArgError.ts | 0 .../invertedCloduleAfterQuickInfo.ts | 0 .../invertedFunduleAfterQuickInfo.ts | 0 .../{fourslash_old => fourslash}/lambdaThisMembers.ts | 0 .../malformedObjectLiteral.ts | 0 .../memberConstructorEdits.ts | 0 .../memberListAfterSingleDot.ts | 0 .../memberListErrorRecovery.ts | 0 .../memberListInFunctionCall.ts | 0 .../memberListOfEnumInModule.ts | 0 .../memberListOfModuleAfterInvalidCharater.ts | 0 .../memberListOnConstructorType.ts | 0 .../memberOverloadEdits.ts | 0 .../{fourslash_old => fourslash}/memberlistOnDDot.ts | 0 .../mergedDeclarations1.ts | 0 .../mergedDeclarations2.ts | 0 .../mispeltVariableForInLoopErrorRecovery.ts | 0 .../{fourslash_old => fourslash}/moduleEnumModule.ts | 0 .../cases/{fourslash_old => fourslash}/moduleIndent.ts | 0 .../moduleMembersOfGenericType.ts | 0 .../moduleRenamingErrorRecovery.ts | 0 .../multiModuleClodule1.ts | 0 .../multilineCommentBeforeOpenBrace.ts | 0 .../multipleExportAssignmentsErrorList0.ts | 0 .../navbar_contains-no-duplicates.ts | 0 .../noCompletionListOnCommentsInsideObjectLiterals.ts | 0 .../noQuickInfoInWhitespace.ts | 0 .../noSmartIndentInsideMultilineString.ts | 0 .../{fourslash_old => fourslash}/nonExistingImport.ts | 0 .../{fourslash_old => fourslash}/numberAssignement0.ts | 0 .../outliningForNonCompleteInterfaceDeclaration.ts | 0 .../overloadObjectLiteralCrash.ts | 0 .../parameterlessSetter.ts | 0 .../parenthesisFatArrows.ts | 0 tests/cases/{fourslash_old => fourslash}/paste.ts | 0 .../pasteLambdaOverModule.ts | 0 .../propertyDuplicateIdentifierError.ts | 0 .../cases/{fourslash_old => fourslash}/publicBreak.ts | 0 .../pullFullDiffTypeParameterExtends0.ts | 0 .../quickInfoFromEmptyBlockComment.ts | 0 .../quickInfoInvalidLocations.ts | 0 .../quickInfoOfLablledForStatementIterator.ts | 0 .../quickInfoOnCircularTypes.ts | 0 .../quickInfoOnMergedInterfaces.ts | 0 .../quickInfoOnUnResolvedBaseConstructorSignature.ts | 0 .../quickinfoIsConsistent.ts | 0 .../{fourslash_old => fourslash}/recursiveGenerics2.ts | 0 .../recursiveInternalModuleImport.ts | 0 .../recursiveWrappedTypeParameters1.ts | 0 .../referencesForNoContext.ts | 0 .../referencesInComment.ts | 0 .../{fourslash_old => fourslash}/regexDetection.ts | 0 .../{fourslash_old => fourslash}/regexErrorRecovery.ts | 0 .../removeDeclareFunctionExports.ts | 0 .../removeDeclareInModule.ts | 0 .../removeDeclareKeyword.ts | 0 .../removeDeclareParamTypeAnnotation.ts | 0 .../removeDuplicateIdentifier.ts | 0 .../removeExportFromInterfaceError0.ts | 0 .../removeExportFromInterfaceError1.ts | 0 .../removeExportedClassFromReopenedModule.ts | 0 .../removeInterfaceExtendsClause.ts | 0 .../removeInterfaceUsedAsGenericTypeArgument.ts | 0 .../removeParameterBetweenCommentAndParameter.ts | 0 .../removeVarFromModuleWithReopenedEnums.ts | 0 .../{fourslash_old => fourslash}/renameModuleToVar.ts | 0 .../restParametersTypeValidation1.ts | 0 .../returnRecursiveType.ts | 0 .../scriptLexicalStructureEmptyConstructors.ts | 0 .../scriptLexicalStructureItems.ts | 0 .../scriptLexicalStructureItemsExternalModules.ts | 0 ...tLexicalStructurePropertiesDefinedInConstructors.ts | 0 .../selfReferencedExternalModule2.ts | 0 .../signatureHelpInFunctionCall.ts | 0 .../signatureHelpNegativeTests.ts | 0 .../signatureHelpNegativeTests2.ts | 0 ...eHelpObjectCreationExpressionNoArgs_NotAvailable.ts | 0 .../signatureHelpWithInterfaceAsIdentifier.ts | 0 .../smartIndentAfterAlignedFunctionArgument.ts | 0 .../smartIndentAfterFatArrowVar.ts | 0 .../{fourslash_old => fourslash}/smartIndentClass.ts | 0 .../{fourslash_old => fourslash}/smartIndentEnum.ts | 0 .../smartIndentInsideBlockInsideCase.ts | 0 .../smartIndentInsideMultilineString.ts | 0 .../smartIndentInterface.ts | 0 .../{fourslash_old => fourslash}/smartIndentModule.ts | 0 .../smartIndentNestedModule.ts | 0 .../smartIndentNonterminatedArgumentListAtEOF.ts | 0 .../smartIndentNonterminatedIfStatementAtEOF.ts | 0 .../smartIndentOnFunctionParameters.ts | 0 .../smartIndentStatementFor.ts | 0 .../smartIndentStatementForIn.ts | 0 .../smartIndentStatementSwitch.ts | 0 .../smartIndentStatementTryCatchFinally.ts | 0 .../smartIndentStatementWith.ts | 0 .../spaceAfterConstructor.ts | 0 .../{fourslash_old => fourslash}/spaceAfterReturn.ts | 0 .../squiggleFunctionExpression.ts | 0 .../squiggleIllegalClassExtension.ts | 0 .../squiggleIllegalInterfaceExtension.ts | 0 .../squiggleIllegalSubclassOverride.ts | 0 .../squiggleUnclosedStringLiteral.ts | 0 .../{fourslash_old => fourslash}/superCallError0.ts | 0 .../superInDerivedTypeOfGenericWithStatics.ts | 0 .../{fourslash_old => fourslash}/switchIndenting.ts | 0 .../syntaxErrorAfterImport1.ts | 0 .../tabbingAfterNewlineInsertedBeforeWhile.ts | 0 .../toggleDuplicateFunctionDeclaration.ts | 0 .../typeAboveNumberLiteralExpressionStatement.ts | 0 .../{fourslash_old => fourslash}/typeArgCompletion.ts | 0 .../typeCheckAfterAddingGenericParameter.ts | 0 .../typeCheckExpression0.ts | 0 .../typeCheckGenericTypeLiteralArgument.ts | 0 .../typeCheckIndexSignature.ts | 0 .../typeCheckIndexerAccess1.ts | 0 .../typeCheckObjectInArrayLiteral.ts | 0 .../unclosedArrayErrorRecovery.ts | 0 .../unclosedCommentsInConstructor.ts | 0 .../unclosedFunctionErrorRecovery.ts | 0 .../unclosedFunctionErrorRecovery2.ts | 0 .../unclosedFunctionErrorRecovery3.ts | 0 .../unclosedMultilineStringLiteralErrorRecovery.ts | 0 .../unclosedStringLiteralErrorRecovery.ts | 0 .../unclosedStringLiteralErrorRecovery2.ts | 0 .../unclosedStringLiteralErrorRecovery3.ts | 0 .../unclosedStringLiteralErrorRecovery4.ts | 0 .../{fourslash_old => fourslash}/underscoreTyping1.ts | 0 .../unknownVariableErrorRecovery.ts | 0 .../updateToClassStatics.ts | 0 .../{fourslash_old => fourslash}/whiteSpaceTrimming.ts | 0 277 files changed, 5 insertions(+), 5 deletions(-) rename tests/cases/{fourslash_old => fourslash}/addDeclareToFunction.ts (100%) rename tests/cases/{fourslash_old => fourslash}/addDeclareToModule.ts (100%) rename tests/cases/{fourslash_old => fourslash}/addDuplicateSetter.ts (100%) rename tests/cases/{fourslash_old => fourslash}/addFunctionAboveMultiLineLambdaExpression.ts (100%) rename tests/cases/{fourslash_old => fourslash}/addFunctionInDuplicatedConstructorClassBody.ts (100%) rename tests/cases/{fourslash_old => fourslash}/addInterfaceMemberAboveClass.ts (100%) rename tests/cases/{fourslash_old => fourslash}/addInterfaceToNotSatisfyConstraint.ts (100%) rename tests/cases/{fourslash_old => fourslash}/addMemberToInterface.ts (100%) rename tests/cases/{fourslash_old => fourslash}/addMethodToInterface1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/addSignaturePartial.ts (100%) rename tests/cases/{fourslash_old => fourslash}/addVarToConstructor1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/aliasToVarUsedAsType.ts (100%) rename tests/cases/{fourslash_old => fourslash}/ambientVariablesWithSameName.ts (100%) rename tests/cases/{fourslash_old => fourslash}/argumentsAreAvailableAfterEditsAtEndOfFunction.ts (100%) rename tests/cases/{fourslash_old => fourslash}/argumentsIndexExpression.ts (100%) rename tests/cases/{fourslash_old => fourslash}/arrayCallAndConstructTypings.ts (100%) rename tests/cases/{fourslash_old => fourslash}/arrayConcatTypeCheck0.ts (100%) rename tests/cases/{fourslash_old => fourslash}/arrayConcatTypeCheck1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/arrayTypeMismatchIncrementalTypeCheck.ts (100%) rename tests/cases/{fourslash_old => fourslash}/assertContextualType.ts (100%) rename tests/cases/{fourslash_old => fourslash}/assignToExistingClass.ts (100%) rename tests/cases/{fourslash_old => fourslash}/brokenClassErrorRecovery.ts (100%) rename tests/cases/{fourslash_old => fourslash}/chainedFunctionFunctionArgIndent.ts (100%) rename tests/cases/{fourslash_old => fourslash}/chainedFunctionLambdaArgIndex.ts (100%) rename tests/cases/{fourslash_old => fourslash}/classInterfaceInsert.ts (100%) rename tests/cases/{fourslash_old => fourslash}/classRenamingErrorRecovery.ts (100%) rename tests/cases/{fourslash_old => fourslash}/cloduleAsBaseClass.ts (100%) rename tests/cases/{fourslash_old => fourslash}/closedCommentsInConstructor.ts (100%) rename tests/cases/{fourslash_old => fourslash}/commentsBlocks.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionInTypeOf2.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListAfterAnyType.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListAfterClassExtends.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListAfterInvalidCharacter.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListAfterNumericLiteral1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListAfterRegularExpressionLiteral1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListAfterStringLiteral1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListAndMemberListOnCommentedDot.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListAndMemberListOnCommentedLine.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListAndMemberListOnCommentedWhiteSpace.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListAtDeclarationOfParameterType.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListAtEOF.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListAtEOF1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListAtIdentifierDefinitionLocations.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListAtInvalidLocations.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListErrorRecovery.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListErrorRecovery2.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListForGenericInstance1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListFunctionMembers.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListInComments.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListInEmptyFile.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListInFatArrow.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListInFunctionDeclaration.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListInFunctionExpression.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListInObjectLiteral.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListInObjectLiteral2.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListInObjectLiteralThatIsParameterOfFunctionCall.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListInScope.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListKeywords.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListOfSplitInterface.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListOnAliasedModule.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListOnMethodParameterName.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListOnParamInClass.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListOnParamOfGenericType1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListOnPrivateVariableInModule.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListOnSuper.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListsThroughTransitiveBaseClasses.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completionListsThroughTransitiveBaseClasses2.ts (100%) rename tests/cases/{fourslash_old => fourslash}/completion_enum-members-with-invalid-identifiers-should-not-show-in-completion.ts (100%) rename tests/cases/{fourslash_old => fourslash}/consistenceOnIndentionsOfChainedFunctionCalls.ts (100%) rename tests/cases/{fourslash_old => fourslash}/consistentContextualTypeErrorsAfterEdits.ts (100%) rename tests/cases/{fourslash_old => fourslash}/constructorQuickInfo.ts (100%) rename tests/cases/{fourslash_old => fourslash}/contextuallyTypedFunctionExpressionGeneric1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/debuggerStatementIndent.ts (100%) rename tests/cases/{fourslash_old => fourslash}/declareFunction.ts (100%) rename tests/cases/{fourslash_old => fourslash}/deleteClassWithEnumPresent.ts (100%) rename tests/cases/{fourslash_old => fourslash}/deleteExtensionInReopenedInterface.ts (100%) rename tests/cases/{fourslash_old => fourslash}/deleteReopenedModule.ts (100%) rename tests/cases/{fourslash_old => fourslash}/deleteTypeParameter.ts (100%) rename tests/cases/{fourslash_old => fourslash}/duplicateClassModuleError0.ts (100%) rename tests/cases/{fourslash_old => fourslash}/duplicateFunctionImplementation.ts (100%) rename tests/cases/{fourslash_old => fourslash}/editLambdaArgToTypeParameter1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/emptyTypeArgumentList.ts (100%) rename tests/cases/{fourslash_old => fourslash}/enumAddition.ts (100%) rename tests/cases/{fourslash_old => fourslash}/enumUpdate1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/exportClauseErrorReporting0.ts (100%) rename tests/cases/{fourslash_old => fourslash}/exportEqualsInterfaceA.ts (100%) rename tests/cases/{fourslash_old => fourslash}/extendArrayInterface.ts (100%) rename tests/cases/{fourslash_old => fourslash}/failureToImplementClass.ts (100%) rename tests/cases/{fourslash_old => fourslash}/forIn.ts (100%) rename tests/cases/{fourslash_old => fourslash}/forceIndentAfterNewLineInsert.ts (100%) rename tests/cases/{fourslash_old => fourslash}/forwardReference.ts (100%) rename tests/cases/{fourslash_old => fourslash}/fsEditMarkerPositions.ts (100%) rename tests/cases/{fourslash_old => fourslash}/functionIndentation.ts (100%) rename tests/cases/{fourslash_old => fourslash}/functionRenamingErrorRecovery.ts (100%) rename tests/cases/{fourslash_old => fourslash}/functionTypes.ts (100%) rename tests/cases/{fourslash_old => fourslash}/generated/dummy.txt (100%) rename tests/cases/{fourslash_old => fourslash}/genericArityEnforcementAfterEdit.ts (100%) rename tests/cases/{fourslash_old => fourslash}/genericAssignmentCompat.ts (100%) rename tests/cases/{fourslash_old => fourslash}/genericCloduleCompletionList.ts (100%) rename tests/cases/{fourslash_old => fourslash}/genericFunctionWithGenericParams1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/genericInterfacePropertyInference1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/genericInterfacePropertyInference2.ts (100%) rename tests/cases/{fourslash_old => fourslash}/genericInterfaceWithInheritanceEdit1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/genericInterfacesWithConstraints1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/genericMethodParam.ts (100%) rename tests/cases/{fourslash_old => fourslash}/genericObjectBaseType.ts (100%) rename tests/cases/{fourslash_old => fourslash}/genericParameterHelp.ts (100%) rename tests/cases/{fourslash_old => fourslash}/genericRespecialization1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/genericSignaturesAreProperlyCleaned.ts (100%) rename tests/cases/{fourslash_old => fourslash}/genericTypeWithMultipleBases1MultiFile.ts (89%) rename tests/cases/{fourslash_old => fourslash}/getCompletionEntryDetails.ts (100%) rename tests/cases/{fourslash_old => fourslash}/getCompletionEntryDetails2.ts (100%) rename tests/cases/{fourslash_old => fourslash}/getImplementors1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/getImplementorsForFunction.ts (100%) rename tests/cases/{fourslash_old => fourslash}/getMatchingBracesNegativeCases.ts (100%) rename tests/cases/{fourslash_old => fourslash}/getNameOrDottedNameSpan.ts (100%) rename tests/cases/{fourslash_old => fourslash}/getOccurrencesOfAny.ts (100%) rename tests/cases/{fourslash_old => fourslash}/getTypeAtModuleExtends.ts (100%) rename tests/cases/{fourslash_old => fourslash}/globalCompletionListInsideObjectLiterals.ts (100%) rename tests/cases/{fourslash_old => fourslash}/goToDefinitionPrimitives.ts (100%) rename tests/cases/{fourslash_old => fourslash}/goToDefinitionSourceUnit.ts (100%) rename tests/cases/{fourslash_old => fourslash}/goToDefinitionUndefinedSymbols.ts (100%) rename tests/cases/{fourslash_old => fourslash}/identationAfterInterfaceCall.ts (100%) rename tests/cases/{fourslash_old => fourslash}/identifierErrorRecovery.ts (100%) rename tests/cases/{fourslash_old => fourslash}/importDeclPaste0.ts (100%) rename tests/cases/{fourslash_old => fourslash}/importValueUsedAsType.ts (100%) rename tests/cases/{fourslash_old => fourslash}/incompatibleOverride.ts (100%) rename tests/cases/{fourslash_old => fourslash}/incrementalResolveConstructorDeclaration.ts (100%) rename tests/cases/{fourslash_old => fourslash}/incrementalResolveFunctionPropertyAssignment.ts (100%) rename tests/cases/{fourslash_old => fourslash}/incrementalUpdateToClassImplementingGenericClass.ts (100%) rename tests/cases/{fourslash_old => fourslash}/indentAfterFunctionClosingBraces.ts (100%) rename tests/cases/{fourslash_old => fourslash}/indentAfterImport.ts (100%) rename tests/cases/{fourslash_old => fourslash}/indentation.ts (100%) rename tests/cases/{fourslash_old => fourslash}/indentationAfterModuleImport.ts (100%) rename tests/cases/{fourslash_old => fourslash}/indexSignatureWithoutAnnotation.ts (100%) rename tests/cases/{fourslash_old => fourslash}/inheritedModuleMembersForClodule2.ts (100%) rename tests/cases/{fourslash_old => fourslash}/insertArgumentBeforeOverloadedConstructor.ts (100%) rename tests/cases/{fourslash_old => fourslash}/insertInterfaceAndCheckTypeLiteralField.ts (100%) rename tests/cases/{fourslash_old => fourslash}/insertMethodCallAboveOthers.ts (100%) rename tests/cases/{fourslash_old => fourslash}/insertPublicBeforeSetter.ts (100%) rename tests/cases/{fourslash_old => fourslash}/insertReturnStatementInDuplicateIdentifierFunction.ts (100%) rename tests/cases/{fourslash_old => fourslash}/insertSecondTryCatchBlock.ts (100%) rename tests/cases/{fourslash_old => fourslash}/insertVarAfterEmptyTypeParamList.ts (100%) rename tests/cases/{fourslash_old => fourslash}/interfaceExtendsPrimitive.ts (100%) rename tests/cases/{fourslash_old => fourslash}/interfaceIndent.ts (100%) rename tests/cases/{fourslash_old => fourslash}/interfaceRecursiveInheritanceErrors0.ts (100%) rename tests/cases/{fourslash_old => fourslash}/interfaceRecursiveInheritanceErrors1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/invalidRestArgError.ts (100%) rename tests/cases/{fourslash_old => fourslash}/invertedCloduleAfterQuickInfo.ts (100%) rename tests/cases/{fourslash_old => fourslash}/invertedFunduleAfterQuickInfo.ts (100%) rename tests/cases/{fourslash_old => fourslash}/lambdaThisMembers.ts (100%) rename tests/cases/{fourslash_old => fourslash}/malformedObjectLiteral.ts (100%) rename tests/cases/{fourslash_old => fourslash}/memberConstructorEdits.ts (100%) rename tests/cases/{fourslash_old => fourslash}/memberListAfterSingleDot.ts (100%) rename tests/cases/{fourslash_old => fourslash}/memberListErrorRecovery.ts (100%) rename tests/cases/{fourslash_old => fourslash}/memberListInFunctionCall.ts (100%) rename tests/cases/{fourslash_old => fourslash}/memberListOfEnumInModule.ts (100%) rename tests/cases/{fourslash_old => fourslash}/memberListOfModuleAfterInvalidCharater.ts (100%) rename tests/cases/{fourslash_old => fourslash}/memberListOnConstructorType.ts (100%) rename tests/cases/{fourslash_old => fourslash}/memberOverloadEdits.ts (100%) rename tests/cases/{fourslash_old => fourslash}/memberlistOnDDot.ts (100%) rename tests/cases/{fourslash_old => fourslash}/mergedDeclarations1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/mergedDeclarations2.ts (100%) rename tests/cases/{fourslash_old => fourslash}/mispeltVariableForInLoopErrorRecovery.ts (100%) rename tests/cases/{fourslash_old => fourslash}/moduleEnumModule.ts (100%) rename tests/cases/{fourslash_old => fourslash}/moduleIndent.ts (100%) rename tests/cases/{fourslash_old => fourslash}/moduleMembersOfGenericType.ts (100%) rename tests/cases/{fourslash_old => fourslash}/moduleRenamingErrorRecovery.ts (100%) rename tests/cases/{fourslash_old => fourslash}/multiModuleClodule1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/multilineCommentBeforeOpenBrace.ts (100%) rename tests/cases/{fourslash_old => fourslash}/multipleExportAssignmentsErrorList0.ts (100%) rename tests/cases/{fourslash_old => fourslash}/navbar_contains-no-duplicates.ts (100%) rename tests/cases/{fourslash_old => fourslash}/noCompletionListOnCommentsInsideObjectLiterals.ts (100%) rename tests/cases/{fourslash_old => fourslash}/noQuickInfoInWhitespace.ts (100%) rename tests/cases/{fourslash_old => fourslash}/noSmartIndentInsideMultilineString.ts (100%) rename tests/cases/{fourslash_old => fourslash}/nonExistingImport.ts (100%) rename tests/cases/{fourslash_old => fourslash}/numberAssignement0.ts (100%) rename tests/cases/{fourslash_old => fourslash}/outliningForNonCompleteInterfaceDeclaration.ts (100%) rename tests/cases/{fourslash_old => fourslash}/overloadObjectLiteralCrash.ts (100%) rename tests/cases/{fourslash_old => fourslash}/parameterlessSetter.ts (100%) rename tests/cases/{fourslash_old => fourslash}/parenthesisFatArrows.ts (100%) rename tests/cases/{fourslash_old => fourslash}/paste.ts (100%) rename tests/cases/{fourslash_old => fourslash}/pasteLambdaOverModule.ts (100%) rename tests/cases/{fourslash_old => fourslash}/propertyDuplicateIdentifierError.ts (100%) rename tests/cases/{fourslash_old => fourslash}/publicBreak.ts (100%) rename tests/cases/{fourslash_old => fourslash}/pullFullDiffTypeParameterExtends0.ts (100%) rename tests/cases/{fourslash_old => fourslash}/quickInfoFromEmptyBlockComment.ts (100%) rename tests/cases/{fourslash_old => fourslash}/quickInfoInvalidLocations.ts (100%) rename tests/cases/{fourslash_old => fourslash}/quickInfoOfLablledForStatementIterator.ts (100%) rename tests/cases/{fourslash_old => fourslash}/quickInfoOnCircularTypes.ts (100%) rename tests/cases/{fourslash_old => fourslash}/quickInfoOnMergedInterfaces.ts (100%) rename tests/cases/{fourslash_old => fourslash}/quickInfoOnUnResolvedBaseConstructorSignature.ts (100%) rename tests/cases/{fourslash_old => fourslash}/quickinfoIsConsistent.ts (100%) rename tests/cases/{fourslash_old => fourslash}/recursiveGenerics2.ts (100%) rename tests/cases/{fourslash_old => fourslash}/recursiveInternalModuleImport.ts (100%) rename tests/cases/{fourslash_old => fourslash}/recursiveWrappedTypeParameters1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/referencesForNoContext.ts (100%) rename tests/cases/{fourslash_old => fourslash}/referencesInComment.ts (100%) rename tests/cases/{fourslash_old => fourslash}/regexDetection.ts (100%) rename tests/cases/{fourslash_old => fourslash}/regexErrorRecovery.ts (100%) rename tests/cases/{fourslash_old => fourslash}/removeDeclareFunctionExports.ts (100%) rename tests/cases/{fourslash_old => fourslash}/removeDeclareInModule.ts (100%) rename tests/cases/{fourslash_old => fourslash}/removeDeclareKeyword.ts (100%) rename tests/cases/{fourslash_old => fourslash}/removeDeclareParamTypeAnnotation.ts (100%) rename tests/cases/{fourslash_old => fourslash}/removeDuplicateIdentifier.ts (100%) rename tests/cases/{fourslash_old => fourslash}/removeExportFromInterfaceError0.ts (100%) rename tests/cases/{fourslash_old => fourslash}/removeExportFromInterfaceError1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/removeExportedClassFromReopenedModule.ts (100%) rename tests/cases/{fourslash_old => fourslash}/removeInterfaceExtendsClause.ts (100%) rename tests/cases/{fourslash_old => fourslash}/removeInterfaceUsedAsGenericTypeArgument.ts (100%) rename tests/cases/{fourslash_old => fourslash}/removeParameterBetweenCommentAndParameter.ts (100%) rename tests/cases/{fourslash_old => fourslash}/removeVarFromModuleWithReopenedEnums.ts (100%) rename tests/cases/{fourslash_old => fourslash}/renameModuleToVar.ts (100%) rename tests/cases/{fourslash_old => fourslash}/restParametersTypeValidation1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/returnRecursiveType.ts (100%) rename tests/cases/{fourslash_old => fourslash}/scriptLexicalStructureEmptyConstructors.ts (100%) rename tests/cases/{fourslash_old => fourslash}/scriptLexicalStructureItems.ts (100%) rename tests/cases/{fourslash_old => fourslash}/scriptLexicalStructureItemsExternalModules.ts (100%) rename tests/cases/{fourslash_old => fourslash}/scriptLexicalStructurePropertiesDefinedInConstructors.ts (100%) rename tests/cases/{fourslash_old => fourslash}/selfReferencedExternalModule2.ts (100%) rename tests/cases/{fourslash_old => fourslash}/signatureHelpInFunctionCall.ts (100%) rename tests/cases/{fourslash_old => fourslash}/signatureHelpNegativeTests.ts (100%) rename tests/cases/{fourslash_old => fourslash}/signatureHelpNegativeTests2.ts (100%) rename tests/cases/{fourslash_old => fourslash}/signatureHelpObjectCreationExpressionNoArgs_NotAvailable.ts (100%) rename tests/cases/{fourslash_old => fourslash}/signatureHelpWithInterfaceAsIdentifier.ts (100%) rename tests/cases/{fourslash_old => fourslash}/smartIndentAfterAlignedFunctionArgument.ts (100%) rename tests/cases/{fourslash_old => fourslash}/smartIndentAfterFatArrowVar.ts (100%) rename tests/cases/{fourslash_old => fourslash}/smartIndentClass.ts (100%) rename tests/cases/{fourslash_old => fourslash}/smartIndentEnum.ts (100%) rename tests/cases/{fourslash_old => fourslash}/smartIndentInsideBlockInsideCase.ts (100%) rename tests/cases/{fourslash_old => fourslash}/smartIndentInsideMultilineString.ts (100%) rename tests/cases/{fourslash_old => fourslash}/smartIndentInterface.ts (100%) rename tests/cases/{fourslash_old => fourslash}/smartIndentModule.ts (100%) rename tests/cases/{fourslash_old => fourslash}/smartIndentNestedModule.ts (100%) rename tests/cases/{fourslash_old => fourslash}/smartIndentNonterminatedArgumentListAtEOF.ts (100%) rename tests/cases/{fourslash_old => fourslash}/smartIndentNonterminatedIfStatementAtEOF.ts (100%) rename tests/cases/{fourslash_old => fourslash}/smartIndentOnFunctionParameters.ts (100%) rename tests/cases/{fourslash_old => fourslash}/smartIndentStatementFor.ts (100%) rename tests/cases/{fourslash_old => fourslash}/smartIndentStatementForIn.ts (100%) rename tests/cases/{fourslash_old => fourslash}/smartIndentStatementSwitch.ts (100%) rename tests/cases/{fourslash_old => fourslash}/smartIndentStatementTryCatchFinally.ts (100%) rename tests/cases/{fourslash_old => fourslash}/smartIndentStatementWith.ts (100%) rename tests/cases/{fourslash_old => fourslash}/spaceAfterConstructor.ts (100%) rename tests/cases/{fourslash_old => fourslash}/spaceAfterReturn.ts (100%) rename tests/cases/{fourslash_old => fourslash}/squiggleFunctionExpression.ts (100%) rename tests/cases/{fourslash_old => fourslash}/squiggleIllegalClassExtension.ts (100%) rename tests/cases/{fourslash_old => fourslash}/squiggleIllegalInterfaceExtension.ts (100%) rename tests/cases/{fourslash_old => fourslash}/squiggleIllegalSubclassOverride.ts (100%) rename tests/cases/{fourslash_old => fourslash}/squiggleUnclosedStringLiteral.ts (100%) rename tests/cases/{fourslash_old => fourslash}/superCallError0.ts (100%) rename tests/cases/{fourslash_old => fourslash}/superInDerivedTypeOfGenericWithStatics.ts (100%) rename tests/cases/{fourslash_old => fourslash}/switchIndenting.ts (100%) rename tests/cases/{fourslash_old => fourslash}/syntaxErrorAfterImport1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/tabbingAfterNewlineInsertedBeforeWhile.ts (100%) rename tests/cases/{fourslash_old => fourslash}/toggleDuplicateFunctionDeclaration.ts (100%) rename tests/cases/{fourslash_old => fourslash}/typeAboveNumberLiteralExpressionStatement.ts (100%) rename tests/cases/{fourslash_old => fourslash}/typeArgCompletion.ts (100%) rename tests/cases/{fourslash_old => fourslash}/typeCheckAfterAddingGenericParameter.ts (100%) rename tests/cases/{fourslash_old => fourslash}/typeCheckExpression0.ts (100%) rename tests/cases/{fourslash_old => fourslash}/typeCheckGenericTypeLiteralArgument.ts (100%) rename tests/cases/{fourslash_old => fourslash}/typeCheckIndexSignature.ts (100%) rename tests/cases/{fourslash_old => fourslash}/typeCheckIndexerAccess1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/typeCheckObjectInArrayLiteral.ts (100%) rename tests/cases/{fourslash_old => fourslash}/unclosedArrayErrorRecovery.ts (100%) rename tests/cases/{fourslash_old => fourslash}/unclosedCommentsInConstructor.ts (100%) rename tests/cases/{fourslash_old => fourslash}/unclosedFunctionErrorRecovery.ts (100%) rename tests/cases/{fourslash_old => fourslash}/unclosedFunctionErrorRecovery2.ts (100%) rename tests/cases/{fourslash_old => fourslash}/unclosedFunctionErrorRecovery3.ts (100%) rename tests/cases/{fourslash_old => fourslash}/unclosedMultilineStringLiteralErrorRecovery.ts (100%) rename tests/cases/{fourslash_old => fourslash}/unclosedStringLiteralErrorRecovery.ts (100%) rename tests/cases/{fourslash_old => fourslash}/unclosedStringLiteralErrorRecovery2.ts (100%) rename tests/cases/{fourslash_old => fourslash}/unclosedStringLiteralErrorRecovery3.ts (100%) rename tests/cases/{fourslash_old => fourslash}/unclosedStringLiteralErrorRecovery4.ts (100%) rename tests/cases/{fourslash_old => fourslash}/underscoreTyping1.ts (100%) rename tests/cases/{fourslash_old => fourslash}/unknownVariableErrorRecovery.ts (100%) rename tests/cases/{fourslash_old => fourslash}/updateToClassStatics.ts (100%) rename tests/cases/{fourslash_old => fourslash}/whiteSpaceTrimming.ts (100%) diff --git a/tests/cases/fourslash_old/addDeclareToFunction.ts b/tests/cases/fourslash/addDeclareToFunction.ts similarity index 100% rename from tests/cases/fourslash_old/addDeclareToFunction.ts rename to tests/cases/fourslash/addDeclareToFunction.ts diff --git a/tests/cases/fourslash_old/addDeclareToModule.ts b/tests/cases/fourslash/addDeclareToModule.ts similarity index 100% rename from tests/cases/fourslash_old/addDeclareToModule.ts rename to tests/cases/fourslash/addDeclareToModule.ts diff --git a/tests/cases/fourslash_old/addDuplicateSetter.ts b/tests/cases/fourslash/addDuplicateSetter.ts similarity index 100% rename from tests/cases/fourslash_old/addDuplicateSetter.ts rename to tests/cases/fourslash/addDuplicateSetter.ts diff --git a/tests/cases/fourslash_old/addFunctionAboveMultiLineLambdaExpression.ts b/tests/cases/fourslash/addFunctionAboveMultiLineLambdaExpression.ts similarity index 100% rename from tests/cases/fourslash_old/addFunctionAboveMultiLineLambdaExpression.ts rename to tests/cases/fourslash/addFunctionAboveMultiLineLambdaExpression.ts diff --git a/tests/cases/fourslash_old/addFunctionInDuplicatedConstructorClassBody.ts b/tests/cases/fourslash/addFunctionInDuplicatedConstructorClassBody.ts similarity index 100% rename from tests/cases/fourslash_old/addFunctionInDuplicatedConstructorClassBody.ts rename to tests/cases/fourslash/addFunctionInDuplicatedConstructorClassBody.ts diff --git a/tests/cases/fourslash_old/addInterfaceMemberAboveClass.ts b/tests/cases/fourslash/addInterfaceMemberAboveClass.ts similarity index 100% rename from tests/cases/fourslash_old/addInterfaceMemberAboveClass.ts rename to tests/cases/fourslash/addInterfaceMemberAboveClass.ts diff --git a/tests/cases/fourslash_old/addInterfaceToNotSatisfyConstraint.ts b/tests/cases/fourslash/addInterfaceToNotSatisfyConstraint.ts similarity index 100% rename from tests/cases/fourslash_old/addInterfaceToNotSatisfyConstraint.ts rename to tests/cases/fourslash/addInterfaceToNotSatisfyConstraint.ts diff --git a/tests/cases/fourslash_old/addMemberToInterface.ts b/tests/cases/fourslash/addMemberToInterface.ts similarity index 100% rename from tests/cases/fourslash_old/addMemberToInterface.ts rename to tests/cases/fourslash/addMemberToInterface.ts diff --git a/tests/cases/fourslash_old/addMethodToInterface1.ts b/tests/cases/fourslash/addMethodToInterface1.ts similarity index 100% rename from tests/cases/fourslash_old/addMethodToInterface1.ts rename to tests/cases/fourslash/addMethodToInterface1.ts diff --git a/tests/cases/fourslash_old/addSignaturePartial.ts b/tests/cases/fourslash/addSignaturePartial.ts similarity index 100% rename from tests/cases/fourslash_old/addSignaturePartial.ts rename to tests/cases/fourslash/addSignaturePartial.ts diff --git a/tests/cases/fourslash_old/addVarToConstructor1.ts b/tests/cases/fourslash/addVarToConstructor1.ts similarity index 100% rename from tests/cases/fourslash_old/addVarToConstructor1.ts rename to tests/cases/fourslash/addVarToConstructor1.ts diff --git a/tests/cases/fourslash_old/aliasToVarUsedAsType.ts b/tests/cases/fourslash/aliasToVarUsedAsType.ts similarity index 100% rename from tests/cases/fourslash_old/aliasToVarUsedAsType.ts rename to tests/cases/fourslash/aliasToVarUsedAsType.ts diff --git a/tests/cases/fourslash_old/ambientVariablesWithSameName.ts b/tests/cases/fourslash/ambientVariablesWithSameName.ts similarity index 100% rename from tests/cases/fourslash_old/ambientVariablesWithSameName.ts rename to tests/cases/fourslash/ambientVariablesWithSameName.ts diff --git a/tests/cases/fourslash_old/argumentsAreAvailableAfterEditsAtEndOfFunction.ts b/tests/cases/fourslash/argumentsAreAvailableAfterEditsAtEndOfFunction.ts similarity index 100% rename from tests/cases/fourslash_old/argumentsAreAvailableAfterEditsAtEndOfFunction.ts rename to tests/cases/fourslash/argumentsAreAvailableAfterEditsAtEndOfFunction.ts diff --git a/tests/cases/fourslash_old/argumentsIndexExpression.ts b/tests/cases/fourslash/argumentsIndexExpression.ts similarity index 100% rename from tests/cases/fourslash_old/argumentsIndexExpression.ts rename to tests/cases/fourslash/argumentsIndexExpression.ts diff --git a/tests/cases/fourslash_old/arrayCallAndConstructTypings.ts b/tests/cases/fourslash/arrayCallAndConstructTypings.ts similarity index 100% rename from tests/cases/fourslash_old/arrayCallAndConstructTypings.ts rename to tests/cases/fourslash/arrayCallAndConstructTypings.ts diff --git a/tests/cases/fourslash_old/arrayConcatTypeCheck0.ts b/tests/cases/fourslash/arrayConcatTypeCheck0.ts similarity index 100% rename from tests/cases/fourslash_old/arrayConcatTypeCheck0.ts rename to tests/cases/fourslash/arrayConcatTypeCheck0.ts diff --git a/tests/cases/fourslash_old/arrayConcatTypeCheck1.ts b/tests/cases/fourslash/arrayConcatTypeCheck1.ts similarity index 100% rename from tests/cases/fourslash_old/arrayConcatTypeCheck1.ts rename to tests/cases/fourslash/arrayConcatTypeCheck1.ts diff --git a/tests/cases/fourslash_old/arrayTypeMismatchIncrementalTypeCheck.ts b/tests/cases/fourslash/arrayTypeMismatchIncrementalTypeCheck.ts similarity index 100% rename from tests/cases/fourslash_old/arrayTypeMismatchIncrementalTypeCheck.ts rename to tests/cases/fourslash/arrayTypeMismatchIncrementalTypeCheck.ts diff --git a/tests/cases/fourslash_old/assertContextualType.ts b/tests/cases/fourslash/assertContextualType.ts similarity index 100% rename from tests/cases/fourslash_old/assertContextualType.ts rename to tests/cases/fourslash/assertContextualType.ts diff --git a/tests/cases/fourslash_old/assignToExistingClass.ts b/tests/cases/fourslash/assignToExistingClass.ts similarity index 100% rename from tests/cases/fourslash_old/assignToExistingClass.ts rename to tests/cases/fourslash/assignToExistingClass.ts diff --git a/tests/cases/fourslash_old/brokenClassErrorRecovery.ts b/tests/cases/fourslash/brokenClassErrorRecovery.ts similarity index 100% rename from tests/cases/fourslash_old/brokenClassErrorRecovery.ts rename to tests/cases/fourslash/brokenClassErrorRecovery.ts diff --git a/tests/cases/fourslash_old/chainedFunctionFunctionArgIndent.ts b/tests/cases/fourslash/chainedFunctionFunctionArgIndent.ts similarity index 100% rename from tests/cases/fourslash_old/chainedFunctionFunctionArgIndent.ts rename to tests/cases/fourslash/chainedFunctionFunctionArgIndent.ts diff --git a/tests/cases/fourslash_old/chainedFunctionLambdaArgIndex.ts b/tests/cases/fourslash/chainedFunctionLambdaArgIndex.ts similarity index 100% rename from tests/cases/fourslash_old/chainedFunctionLambdaArgIndex.ts rename to tests/cases/fourslash/chainedFunctionLambdaArgIndex.ts diff --git a/tests/cases/fourslash_old/classInterfaceInsert.ts b/tests/cases/fourslash/classInterfaceInsert.ts similarity index 100% rename from tests/cases/fourslash_old/classInterfaceInsert.ts rename to tests/cases/fourslash/classInterfaceInsert.ts diff --git a/tests/cases/fourslash_old/classRenamingErrorRecovery.ts b/tests/cases/fourslash/classRenamingErrorRecovery.ts similarity index 100% rename from tests/cases/fourslash_old/classRenamingErrorRecovery.ts rename to tests/cases/fourslash/classRenamingErrorRecovery.ts diff --git a/tests/cases/fourslash_old/cloduleAsBaseClass.ts b/tests/cases/fourslash/cloduleAsBaseClass.ts similarity index 100% rename from tests/cases/fourslash_old/cloduleAsBaseClass.ts rename to tests/cases/fourslash/cloduleAsBaseClass.ts diff --git a/tests/cases/fourslash_old/closedCommentsInConstructor.ts b/tests/cases/fourslash/closedCommentsInConstructor.ts similarity index 100% rename from tests/cases/fourslash_old/closedCommentsInConstructor.ts rename to tests/cases/fourslash/closedCommentsInConstructor.ts diff --git a/tests/cases/fourslash_old/commentsBlocks.ts b/tests/cases/fourslash/commentsBlocks.ts similarity index 100% rename from tests/cases/fourslash_old/commentsBlocks.ts rename to tests/cases/fourslash/commentsBlocks.ts diff --git a/tests/cases/fourslash_old/completionInTypeOf2.ts b/tests/cases/fourslash/completionInTypeOf2.ts similarity index 100% rename from tests/cases/fourslash_old/completionInTypeOf2.ts rename to tests/cases/fourslash/completionInTypeOf2.ts diff --git a/tests/cases/fourslash_old/completionListAfterAnyType.ts b/tests/cases/fourslash/completionListAfterAnyType.ts similarity index 100% rename from tests/cases/fourslash_old/completionListAfterAnyType.ts rename to tests/cases/fourslash/completionListAfterAnyType.ts diff --git a/tests/cases/fourslash_old/completionListAfterClassExtends.ts b/tests/cases/fourslash/completionListAfterClassExtends.ts similarity index 100% rename from tests/cases/fourslash_old/completionListAfterClassExtends.ts rename to tests/cases/fourslash/completionListAfterClassExtends.ts diff --git a/tests/cases/fourslash_old/completionListAfterInvalidCharacter.ts b/tests/cases/fourslash/completionListAfterInvalidCharacter.ts similarity index 100% rename from tests/cases/fourslash_old/completionListAfterInvalidCharacter.ts rename to tests/cases/fourslash/completionListAfterInvalidCharacter.ts diff --git a/tests/cases/fourslash_old/completionListAfterNumericLiteral1.ts b/tests/cases/fourslash/completionListAfterNumericLiteral1.ts similarity index 100% rename from tests/cases/fourslash_old/completionListAfterNumericLiteral1.ts rename to tests/cases/fourslash/completionListAfterNumericLiteral1.ts diff --git a/tests/cases/fourslash_old/completionListAfterRegularExpressionLiteral1.ts b/tests/cases/fourslash/completionListAfterRegularExpressionLiteral1.ts similarity index 100% rename from tests/cases/fourslash_old/completionListAfterRegularExpressionLiteral1.ts rename to tests/cases/fourslash/completionListAfterRegularExpressionLiteral1.ts diff --git a/tests/cases/fourslash_old/completionListAfterStringLiteral1.ts b/tests/cases/fourslash/completionListAfterStringLiteral1.ts similarity index 100% rename from tests/cases/fourslash_old/completionListAfterStringLiteral1.ts rename to tests/cases/fourslash/completionListAfterStringLiteral1.ts diff --git a/tests/cases/fourslash_old/completionListAndMemberListOnCommentedDot.ts b/tests/cases/fourslash/completionListAndMemberListOnCommentedDot.ts similarity index 100% rename from tests/cases/fourslash_old/completionListAndMemberListOnCommentedDot.ts rename to tests/cases/fourslash/completionListAndMemberListOnCommentedDot.ts diff --git a/tests/cases/fourslash_old/completionListAndMemberListOnCommentedLine.ts b/tests/cases/fourslash/completionListAndMemberListOnCommentedLine.ts similarity index 100% rename from tests/cases/fourslash_old/completionListAndMemberListOnCommentedLine.ts rename to tests/cases/fourslash/completionListAndMemberListOnCommentedLine.ts diff --git a/tests/cases/fourslash_old/completionListAndMemberListOnCommentedWhiteSpace.ts b/tests/cases/fourslash/completionListAndMemberListOnCommentedWhiteSpace.ts similarity index 100% rename from tests/cases/fourslash_old/completionListAndMemberListOnCommentedWhiteSpace.ts rename to tests/cases/fourslash/completionListAndMemberListOnCommentedWhiteSpace.ts diff --git a/tests/cases/fourslash_old/completionListAtDeclarationOfParameterType.ts b/tests/cases/fourslash/completionListAtDeclarationOfParameterType.ts similarity index 100% rename from tests/cases/fourslash_old/completionListAtDeclarationOfParameterType.ts rename to tests/cases/fourslash/completionListAtDeclarationOfParameterType.ts diff --git a/tests/cases/fourslash_old/completionListAtEOF.ts b/tests/cases/fourslash/completionListAtEOF.ts similarity index 100% rename from tests/cases/fourslash_old/completionListAtEOF.ts rename to tests/cases/fourslash/completionListAtEOF.ts diff --git a/tests/cases/fourslash_old/completionListAtEOF1.ts b/tests/cases/fourslash/completionListAtEOF1.ts similarity index 100% rename from tests/cases/fourslash_old/completionListAtEOF1.ts rename to tests/cases/fourslash/completionListAtEOF1.ts diff --git a/tests/cases/fourslash_old/completionListAtIdentifierDefinitionLocations.ts b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations.ts similarity index 100% rename from tests/cases/fourslash_old/completionListAtIdentifierDefinitionLocations.ts rename to tests/cases/fourslash/completionListAtIdentifierDefinitionLocations.ts diff --git a/tests/cases/fourslash_old/completionListAtInvalidLocations.ts b/tests/cases/fourslash/completionListAtInvalidLocations.ts similarity index 100% rename from tests/cases/fourslash_old/completionListAtInvalidLocations.ts rename to tests/cases/fourslash/completionListAtInvalidLocations.ts diff --git a/tests/cases/fourslash_old/completionListErrorRecovery.ts b/tests/cases/fourslash/completionListErrorRecovery.ts similarity index 100% rename from tests/cases/fourslash_old/completionListErrorRecovery.ts rename to tests/cases/fourslash/completionListErrorRecovery.ts diff --git a/tests/cases/fourslash_old/completionListErrorRecovery2.ts b/tests/cases/fourslash/completionListErrorRecovery2.ts similarity index 100% rename from tests/cases/fourslash_old/completionListErrorRecovery2.ts rename to tests/cases/fourslash/completionListErrorRecovery2.ts diff --git a/tests/cases/fourslash_old/completionListForGenericInstance1.ts b/tests/cases/fourslash/completionListForGenericInstance1.ts similarity index 100% rename from tests/cases/fourslash_old/completionListForGenericInstance1.ts rename to tests/cases/fourslash/completionListForGenericInstance1.ts diff --git a/tests/cases/fourslash_old/completionListFunctionMembers.ts b/tests/cases/fourslash/completionListFunctionMembers.ts similarity index 100% rename from tests/cases/fourslash_old/completionListFunctionMembers.ts rename to tests/cases/fourslash/completionListFunctionMembers.ts diff --git a/tests/cases/fourslash_old/completionListInComments.ts b/tests/cases/fourslash/completionListInComments.ts similarity index 100% rename from tests/cases/fourslash_old/completionListInComments.ts rename to tests/cases/fourslash/completionListInComments.ts diff --git a/tests/cases/fourslash_old/completionListInEmptyFile.ts b/tests/cases/fourslash/completionListInEmptyFile.ts similarity index 100% rename from tests/cases/fourslash_old/completionListInEmptyFile.ts rename to tests/cases/fourslash/completionListInEmptyFile.ts diff --git a/tests/cases/fourslash_old/completionListInFatArrow.ts b/tests/cases/fourslash/completionListInFatArrow.ts similarity index 100% rename from tests/cases/fourslash_old/completionListInFatArrow.ts rename to tests/cases/fourslash/completionListInFatArrow.ts diff --git a/tests/cases/fourslash_old/completionListInFunctionDeclaration.ts b/tests/cases/fourslash/completionListInFunctionDeclaration.ts similarity index 100% rename from tests/cases/fourslash_old/completionListInFunctionDeclaration.ts rename to tests/cases/fourslash/completionListInFunctionDeclaration.ts diff --git a/tests/cases/fourslash_old/completionListInFunctionExpression.ts b/tests/cases/fourslash/completionListInFunctionExpression.ts similarity index 100% rename from tests/cases/fourslash_old/completionListInFunctionExpression.ts rename to tests/cases/fourslash/completionListInFunctionExpression.ts diff --git a/tests/cases/fourslash_old/completionListInObjectLiteral.ts b/tests/cases/fourslash/completionListInObjectLiteral.ts similarity index 100% rename from tests/cases/fourslash_old/completionListInObjectLiteral.ts rename to tests/cases/fourslash/completionListInObjectLiteral.ts diff --git a/tests/cases/fourslash_old/completionListInObjectLiteral2.ts b/tests/cases/fourslash/completionListInObjectLiteral2.ts similarity index 100% rename from tests/cases/fourslash_old/completionListInObjectLiteral2.ts rename to tests/cases/fourslash/completionListInObjectLiteral2.ts diff --git a/tests/cases/fourslash_old/completionListInObjectLiteralThatIsParameterOfFunctionCall.ts b/tests/cases/fourslash/completionListInObjectLiteralThatIsParameterOfFunctionCall.ts similarity index 100% rename from tests/cases/fourslash_old/completionListInObjectLiteralThatIsParameterOfFunctionCall.ts rename to tests/cases/fourslash/completionListInObjectLiteralThatIsParameterOfFunctionCall.ts diff --git a/tests/cases/fourslash_old/completionListInScope.ts b/tests/cases/fourslash/completionListInScope.ts similarity index 100% rename from tests/cases/fourslash_old/completionListInScope.ts rename to tests/cases/fourslash/completionListInScope.ts diff --git a/tests/cases/fourslash_old/completionListKeywords.ts b/tests/cases/fourslash/completionListKeywords.ts similarity index 100% rename from tests/cases/fourslash_old/completionListKeywords.ts rename to tests/cases/fourslash/completionListKeywords.ts diff --git a/tests/cases/fourslash_old/completionListOfSplitInterface.ts b/tests/cases/fourslash/completionListOfSplitInterface.ts similarity index 100% rename from tests/cases/fourslash_old/completionListOfSplitInterface.ts rename to tests/cases/fourslash/completionListOfSplitInterface.ts diff --git a/tests/cases/fourslash_old/completionListOnAliasedModule.ts b/tests/cases/fourslash/completionListOnAliasedModule.ts similarity index 100% rename from tests/cases/fourslash_old/completionListOnAliasedModule.ts rename to tests/cases/fourslash/completionListOnAliasedModule.ts diff --git a/tests/cases/fourslash_old/completionListOnMethodParameterName.ts b/tests/cases/fourslash/completionListOnMethodParameterName.ts similarity index 100% rename from tests/cases/fourslash_old/completionListOnMethodParameterName.ts rename to tests/cases/fourslash/completionListOnMethodParameterName.ts diff --git a/tests/cases/fourslash_old/completionListOnParamInClass.ts b/tests/cases/fourslash/completionListOnParamInClass.ts similarity index 100% rename from tests/cases/fourslash_old/completionListOnParamInClass.ts rename to tests/cases/fourslash/completionListOnParamInClass.ts diff --git a/tests/cases/fourslash_old/completionListOnParamOfGenericType1.ts b/tests/cases/fourslash/completionListOnParamOfGenericType1.ts similarity index 100% rename from tests/cases/fourslash_old/completionListOnParamOfGenericType1.ts rename to tests/cases/fourslash/completionListOnParamOfGenericType1.ts diff --git a/tests/cases/fourslash_old/completionListOnPrivateVariableInModule.ts b/tests/cases/fourslash/completionListOnPrivateVariableInModule.ts similarity index 100% rename from tests/cases/fourslash_old/completionListOnPrivateVariableInModule.ts rename to tests/cases/fourslash/completionListOnPrivateVariableInModule.ts diff --git a/tests/cases/fourslash_old/completionListOnSuper.ts b/tests/cases/fourslash/completionListOnSuper.ts similarity index 100% rename from tests/cases/fourslash_old/completionListOnSuper.ts rename to tests/cases/fourslash/completionListOnSuper.ts diff --git a/tests/cases/fourslash_old/completionListsThroughTransitiveBaseClasses.ts b/tests/cases/fourslash/completionListsThroughTransitiveBaseClasses.ts similarity index 100% rename from tests/cases/fourslash_old/completionListsThroughTransitiveBaseClasses.ts rename to tests/cases/fourslash/completionListsThroughTransitiveBaseClasses.ts diff --git a/tests/cases/fourslash_old/completionListsThroughTransitiveBaseClasses2.ts b/tests/cases/fourslash/completionListsThroughTransitiveBaseClasses2.ts similarity index 100% rename from tests/cases/fourslash_old/completionListsThroughTransitiveBaseClasses2.ts rename to tests/cases/fourslash/completionListsThroughTransitiveBaseClasses2.ts diff --git a/tests/cases/fourslash_old/completion_enum-members-with-invalid-identifiers-should-not-show-in-completion.ts b/tests/cases/fourslash/completion_enum-members-with-invalid-identifiers-should-not-show-in-completion.ts similarity index 100% rename from tests/cases/fourslash_old/completion_enum-members-with-invalid-identifiers-should-not-show-in-completion.ts rename to tests/cases/fourslash/completion_enum-members-with-invalid-identifiers-should-not-show-in-completion.ts diff --git a/tests/cases/fourslash_old/consistenceOnIndentionsOfChainedFunctionCalls.ts b/tests/cases/fourslash/consistenceOnIndentionsOfChainedFunctionCalls.ts similarity index 100% rename from tests/cases/fourslash_old/consistenceOnIndentionsOfChainedFunctionCalls.ts rename to tests/cases/fourslash/consistenceOnIndentionsOfChainedFunctionCalls.ts diff --git a/tests/cases/fourslash_old/consistentContextualTypeErrorsAfterEdits.ts b/tests/cases/fourslash/consistentContextualTypeErrorsAfterEdits.ts similarity index 100% rename from tests/cases/fourslash_old/consistentContextualTypeErrorsAfterEdits.ts rename to tests/cases/fourslash/consistentContextualTypeErrorsAfterEdits.ts diff --git a/tests/cases/fourslash_old/constructorQuickInfo.ts b/tests/cases/fourslash/constructorQuickInfo.ts similarity index 100% rename from tests/cases/fourslash_old/constructorQuickInfo.ts rename to tests/cases/fourslash/constructorQuickInfo.ts diff --git a/tests/cases/fourslash_old/contextuallyTypedFunctionExpressionGeneric1.ts b/tests/cases/fourslash/contextuallyTypedFunctionExpressionGeneric1.ts similarity index 100% rename from tests/cases/fourslash_old/contextuallyTypedFunctionExpressionGeneric1.ts rename to tests/cases/fourslash/contextuallyTypedFunctionExpressionGeneric1.ts diff --git a/tests/cases/fourslash_old/debuggerStatementIndent.ts b/tests/cases/fourslash/debuggerStatementIndent.ts similarity index 100% rename from tests/cases/fourslash_old/debuggerStatementIndent.ts rename to tests/cases/fourslash/debuggerStatementIndent.ts diff --git a/tests/cases/fourslash_old/declareFunction.ts b/tests/cases/fourslash/declareFunction.ts similarity index 100% rename from tests/cases/fourslash_old/declareFunction.ts rename to tests/cases/fourslash/declareFunction.ts diff --git a/tests/cases/fourslash_old/deleteClassWithEnumPresent.ts b/tests/cases/fourslash/deleteClassWithEnumPresent.ts similarity index 100% rename from tests/cases/fourslash_old/deleteClassWithEnumPresent.ts rename to tests/cases/fourslash/deleteClassWithEnumPresent.ts diff --git a/tests/cases/fourslash_old/deleteExtensionInReopenedInterface.ts b/tests/cases/fourslash/deleteExtensionInReopenedInterface.ts similarity index 100% rename from tests/cases/fourslash_old/deleteExtensionInReopenedInterface.ts rename to tests/cases/fourslash/deleteExtensionInReopenedInterface.ts diff --git a/tests/cases/fourslash_old/deleteReopenedModule.ts b/tests/cases/fourslash/deleteReopenedModule.ts similarity index 100% rename from tests/cases/fourslash_old/deleteReopenedModule.ts rename to tests/cases/fourslash/deleteReopenedModule.ts diff --git a/tests/cases/fourslash_old/deleteTypeParameter.ts b/tests/cases/fourslash/deleteTypeParameter.ts similarity index 100% rename from tests/cases/fourslash_old/deleteTypeParameter.ts rename to tests/cases/fourslash/deleteTypeParameter.ts diff --git a/tests/cases/fourslash_old/duplicateClassModuleError0.ts b/tests/cases/fourslash/duplicateClassModuleError0.ts similarity index 100% rename from tests/cases/fourslash_old/duplicateClassModuleError0.ts rename to tests/cases/fourslash/duplicateClassModuleError0.ts diff --git a/tests/cases/fourslash_old/duplicateFunctionImplementation.ts b/tests/cases/fourslash/duplicateFunctionImplementation.ts similarity index 100% rename from tests/cases/fourslash_old/duplicateFunctionImplementation.ts rename to tests/cases/fourslash/duplicateFunctionImplementation.ts diff --git a/tests/cases/fourslash_old/editLambdaArgToTypeParameter1.ts b/tests/cases/fourslash/editLambdaArgToTypeParameter1.ts similarity index 100% rename from tests/cases/fourslash_old/editLambdaArgToTypeParameter1.ts rename to tests/cases/fourslash/editLambdaArgToTypeParameter1.ts diff --git a/tests/cases/fourslash_old/emptyTypeArgumentList.ts b/tests/cases/fourslash/emptyTypeArgumentList.ts similarity index 100% rename from tests/cases/fourslash_old/emptyTypeArgumentList.ts rename to tests/cases/fourslash/emptyTypeArgumentList.ts diff --git a/tests/cases/fourslash_old/enumAddition.ts b/tests/cases/fourslash/enumAddition.ts similarity index 100% rename from tests/cases/fourslash_old/enumAddition.ts rename to tests/cases/fourslash/enumAddition.ts diff --git a/tests/cases/fourslash_old/enumUpdate1.ts b/tests/cases/fourslash/enumUpdate1.ts similarity index 100% rename from tests/cases/fourslash_old/enumUpdate1.ts rename to tests/cases/fourslash/enumUpdate1.ts diff --git a/tests/cases/fourslash_old/exportClauseErrorReporting0.ts b/tests/cases/fourslash/exportClauseErrorReporting0.ts similarity index 100% rename from tests/cases/fourslash_old/exportClauseErrorReporting0.ts rename to tests/cases/fourslash/exportClauseErrorReporting0.ts diff --git a/tests/cases/fourslash_old/exportEqualsInterfaceA.ts b/tests/cases/fourslash/exportEqualsInterfaceA.ts similarity index 100% rename from tests/cases/fourslash_old/exportEqualsInterfaceA.ts rename to tests/cases/fourslash/exportEqualsInterfaceA.ts diff --git a/tests/cases/fourslash_old/extendArrayInterface.ts b/tests/cases/fourslash/extendArrayInterface.ts similarity index 100% rename from tests/cases/fourslash_old/extendArrayInterface.ts rename to tests/cases/fourslash/extendArrayInterface.ts diff --git a/tests/cases/fourslash_old/failureToImplementClass.ts b/tests/cases/fourslash/failureToImplementClass.ts similarity index 100% rename from tests/cases/fourslash_old/failureToImplementClass.ts rename to tests/cases/fourslash/failureToImplementClass.ts diff --git a/tests/cases/fourslash_old/forIn.ts b/tests/cases/fourslash/forIn.ts similarity index 100% rename from tests/cases/fourslash_old/forIn.ts rename to tests/cases/fourslash/forIn.ts diff --git a/tests/cases/fourslash_old/forceIndentAfterNewLineInsert.ts b/tests/cases/fourslash/forceIndentAfterNewLineInsert.ts similarity index 100% rename from tests/cases/fourslash_old/forceIndentAfterNewLineInsert.ts rename to tests/cases/fourslash/forceIndentAfterNewLineInsert.ts diff --git a/tests/cases/fourslash_old/forwardReference.ts b/tests/cases/fourslash/forwardReference.ts similarity index 100% rename from tests/cases/fourslash_old/forwardReference.ts rename to tests/cases/fourslash/forwardReference.ts diff --git a/tests/cases/fourslash_old/fsEditMarkerPositions.ts b/tests/cases/fourslash/fsEditMarkerPositions.ts similarity index 100% rename from tests/cases/fourslash_old/fsEditMarkerPositions.ts rename to tests/cases/fourslash/fsEditMarkerPositions.ts diff --git a/tests/cases/fourslash_old/functionIndentation.ts b/tests/cases/fourslash/functionIndentation.ts similarity index 100% rename from tests/cases/fourslash_old/functionIndentation.ts rename to tests/cases/fourslash/functionIndentation.ts diff --git a/tests/cases/fourslash_old/functionRenamingErrorRecovery.ts b/tests/cases/fourslash/functionRenamingErrorRecovery.ts similarity index 100% rename from tests/cases/fourslash_old/functionRenamingErrorRecovery.ts rename to tests/cases/fourslash/functionRenamingErrorRecovery.ts diff --git a/tests/cases/fourslash_old/functionTypes.ts b/tests/cases/fourslash/functionTypes.ts similarity index 100% rename from tests/cases/fourslash_old/functionTypes.ts rename to tests/cases/fourslash/functionTypes.ts diff --git a/tests/cases/fourslash_old/generated/dummy.txt b/tests/cases/fourslash/generated/dummy.txt similarity index 100% rename from tests/cases/fourslash_old/generated/dummy.txt rename to tests/cases/fourslash/generated/dummy.txt diff --git a/tests/cases/fourslash_old/genericArityEnforcementAfterEdit.ts b/tests/cases/fourslash/genericArityEnforcementAfterEdit.ts similarity index 100% rename from tests/cases/fourslash_old/genericArityEnforcementAfterEdit.ts rename to tests/cases/fourslash/genericArityEnforcementAfterEdit.ts diff --git a/tests/cases/fourslash_old/genericAssignmentCompat.ts b/tests/cases/fourslash/genericAssignmentCompat.ts similarity index 100% rename from tests/cases/fourslash_old/genericAssignmentCompat.ts rename to tests/cases/fourslash/genericAssignmentCompat.ts diff --git a/tests/cases/fourslash_old/genericCloduleCompletionList.ts b/tests/cases/fourslash/genericCloduleCompletionList.ts similarity index 100% rename from tests/cases/fourslash_old/genericCloduleCompletionList.ts rename to tests/cases/fourslash/genericCloduleCompletionList.ts diff --git a/tests/cases/fourslash_old/genericFunctionWithGenericParams1.ts b/tests/cases/fourslash/genericFunctionWithGenericParams1.ts similarity index 100% rename from tests/cases/fourslash_old/genericFunctionWithGenericParams1.ts rename to tests/cases/fourslash/genericFunctionWithGenericParams1.ts diff --git a/tests/cases/fourslash_old/genericInterfacePropertyInference1.ts b/tests/cases/fourslash/genericInterfacePropertyInference1.ts similarity index 100% rename from tests/cases/fourslash_old/genericInterfacePropertyInference1.ts rename to tests/cases/fourslash/genericInterfacePropertyInference1.ts diff --git a/tests/cases/fourslash_old/genericInterfacePropertyInference2.ts b/tests/cases/fourslash/genericInterfacePropertyInference2.ts similarity index 100% rename from tests/cases/fourslash_old/genericInterfacePropertyInference2.ts rename to tests/cases/fourslash/genericInterfacePropertyInference2.ts diff --git a/tests/cases/fourslash_old/genericInterfaceWithInheritanceEdit1.ts b/tests/cases/fourslash/genericInterfaceWithInheritanceEdit1.ts similarity index 100% rename from tests/cases/fourslash_old/genericInterfaceWithInheritanceEdit1.ts rename to tests/cases/fourslash/genericInterfaceWithInheritanceEdit1.ts diff --git a/tests/cases/fourslash_old/genericInterfacesWithConstraints1.ts b/tests/cases/fourslash/genericInterfacesWithConstraints1.ts similarity index 100% rename from tests/cases/fourslash_old/genericInterfacesWithConstraints1.ts rename to tests/cases/fourslash/genericInterfacesWithConstraints1.ts diff --git a/tests/cases/fourslash_old/genericMethodParam.ts b/tests/cases/fourslash/genericMethodParam.ts similarity index 100% rename from tests/cases/fourslash_old/genericMethodParam.ts rename to tests/cases/fourslash/genericMethodParam.ts diff --git a/tests/cases/fourslash_old/genericObjectBaseType.ts b/tests/cases/fourslash/genericObjectBaseType.ts similarity index 100% rename from tests/cases/fourslash_old/genericObjectBaseType.ts rename to tests/cases/fourslash/genericObjectBaseType.ts diff --git a/tests/cases/fourslash_old/genericParameterHelp.ts b/tests/cases/fourslash/genericParameterHelp.ts similarity index 100% rename from tests/cases/fourslash_old/genericParameterHelp.ts rename to tests/cases/fourslash/genericParameterHelp.ts diff --git a/tests/cases/fourslash_old/genericRespecialization1.ts b/tests/cases/fourslash/genericRespecialization1.ts similarity index 100% rename from tests/cases/fourslash_old/genericRespecialization1.ts rename to tests/cases/fourslash/genericRespecialization1.ts diff --git a/tests/cases/fourslash_old/genericSignaturesAreProperlyCleaned.ts b/tests/cases/fourslash/genericSignaturesAreProperlyCleaned.ts similarity index 100% rename from tests/cases/fourslash_old/genericSignaturesAreProperlyCleaned.ts rename to tests/cases/fourslash/genericSignaturesAreProperlyCleaned.ts diff --git a/tests/cases/fourslash_old/genericTypeWithMultipleBases1MultiFile.ts b/tests/cases/fourslash/genericTypeWithMultipleBases1MultiFile.ts similarity index 89% rename from tests/cases/fourslash_old/genericTypeWithMultipleBases1MultiFile.ts rename to tests/cases/fourslash/genericTypeWithMultipleBases1MultiFile.ts index e28e1aa0fc7..a2b32a6f383 100644 --- a/tests/cases/fourslash_old/genericTypeWithMultipleBases1MultiFile.ts +++ b/tests/cases/fourslash/genericTypeWithMultipleBases1MultiFile.ts @@ -4,20 +4,20 @@ ////interface iBaseScope { //// watch: () => void; ////} -// @Filename: genericTypeWithMultipleBases_1.ts +// @Filename: genericTypeWithMultipleBases_1.ts ////interface iMover { //// moveUp: () => void; ////} -// @Filename: genericTypeWithMultipleBases_2.ts +// @Filename: genericTypeWithMultipleBases_2.ts ////interface iScope extends iBaseScope, iMover { //// family: TModel; ////} -// @Filename: genericTypeWithMultipleBases_3.ts +// @Filename: genericTypeWithMultipleBases_3.ts ////var x: iScope; -// @Filename: genericTypeWithMultipleBases_4.ts +// @Filename: genericTypeWithMultipleBases_4.ts ////x./**/ goTo.marker(); verify.completionListContains('watch', '() => void'); verify.completionListContains('moveUp', '() => void'); -verify.completionListContains('family', 'TModel'); \ No newline at end of file +verify.completionListContains('family', 'number'); \ No newline at end of file diff --git a/tests/cases/fourslash_old/getCompletionEntryDetails.ts b/tests/cases/fourslash/getCompletionEntryDetails.ts similarity index 100% rename from tests/cases/fourslash_old/getCompletionEntryDetails.ts rename to tests/cases/fourslash/getCompletionEntryDetails.ts diff --git a/tests/cases/fourslash_old/getCompletionEntryDetails2.ts b/tests/cases/fourslash/getCompletionEntryDetails2.ts similarity index 100% rename from tests/cases/fourslash_old/getCompletionEntryDetails2.ts rename to tests/cases/fourslash/getCompletionEntryDetails2.ts diff --git a/tests/cases/fourslash_old/getImplementors1.ts b/tests/cases/fourslash/getImplementors1.ts similarity index 100% rename from tests/cases/fourslash_old/getImplementors1.ts rename to tests/cases/fourslash/getImplementors1.ts diff --git a/tests/cases/fourslash_old/getImplementorsForFunction.ts b/tests/cases/fourslash/getImplementorsForFunction.ts similarity index 100% rename from tests/cases/fourslash_old/getImplementorsForFunction.ts rename to tests/cases/fourslash/getImplementorsForFunction.ts diff --git a/tests/cases/fourslash_old/getMatchingBracesNegativeCases.ts b/tests/cases/fourslash/getMatchingBracesNegativeCases.ts similarity index 100% rename from tests/cases/fourslash_old/getMatchingBracesNegativeCases.ts rename to tests/cases/fourslash/getMatchingBracesNegativeCases.ts diff --git a/tests/cases/fourslash_old/getNameOrDottedNameSpan.ts b/tests/cases/fourslash/getNameOrDottedNameSpan.ts similarity index 100% rename from tests/cases/fourslash_old/getNameOrDottedNameSpan.ts rename to tests/cases/fourslash/getNameOrDottedNameSpan.ts diff --git a/tests/cases/fourslash_old/getOccurrencesOfAny.ts b/tests/cases/fourslash/getOccurrencesOfAny.ts similarity index 100% rename from tests/cases/fourslash_old/getOccurrencesOfAny.ts rename to tests/cases/fourslash/getOccurrencesOfAny.ts diff --git a/tests/cases/fourslash_old/getTypeAtModuleExtends.ts b/tests/cases/fourslash/getTypeAtModuleExtends.ts similarity index 100% rename from tests/cases/fourslash_old/getTypeAtModuleExtends.ts rename to tests/cases/fourslash/getTypeAtModuleExtends.ts diff --git a/tests/cases/fourslash_old/globalCompletionListInsideObjectLiterals.ts b/tests/cases/fourslash/globalCompletionListInsideObjectLiterals.ts similarity index 100% rename from tests/cases/fourslash_old/globalCompletionListInsideObjectLiterals.ts rename to tests/cases/fourslash/globalCompletionListInsideObjectLiterals.ts diff --git a/tests/cases/fourslash_old/goToDefinitionPrimitives.ts b/tests/cases/fourslash/goToDefinitionPrimitives.ts similarity index 100% rename from tests/cases/fourslash_old/goToDefinitionPrimitives.ts rename to tests/cases/fourslash/goToDefinitionPrimitives.ts diff --git a/tests/cases/fourslash_old/goToDefinitionSourceUnit.ts b/tests/cases/fourslash/goToDefinitionSourceUnit.ts similarity index 100% rename from tests/cases/fourslash_old/goToDefinitionSourceUnit.ts rename to tests/cases/fourslash/goToDefinitionSourceUnit.ts diff --git a/tests/cases/fourslash_old/goToDefinitionUndefinedSymbols.ts b/tests/cases/fourslash/goToDefinitionUndefinedSymbols.ts similarity index 100% rename from tests/cases/fourslash_old/goToDefinitionUndefinedSymbols.ts rename to tests/cases/fourslash/goToDefinitionUndefinedSymbols.ts diff --git a/tests/cases/fourslash_old/identationAfterInterfaceCall.ts b/tests/cases/fourslash/identationAfterInterfaceCall.ts similarity index 100% rename from tests/cases/fourslash_old/identationAfterInterfaceCall.ts rename to tests/cases/fourslash/identationAfterInterfaceCall.ts diff --git a/tests/cases/fourslash_old/identifierErrorRecovery.ts b/tests/cases/fourslash/identifierErrorRecovery.ts similarity index 100% rename from tests/cases/fourslash_old/identifierErrorRecovery.ts rename to tests/cases/fourslash/identifierErrorRecovery.ts diff --git a/tests/cases/fourslash_old/importDeclPaste0.ts b/tests/cases/fourslash/importDeclPaste0.ts similarity index 100% rename from tests/cases/fourslash_old/importDeclPaste0.ts rename to tests/cases/fourslash/importDeclPaste0.ts diff --git a/tests/cases/fourslash_old/importValueUsedAsType.ts b/tests/cases/fourslash/importValueUsedAsType.ts similarity index 100% rename from tests/cases/fourslash_old/importValueUsedAsType.ts rename to tests/cases/fourslash/importValueUsedAsType.ts diff --git a/tests/cases/fourslash_old/incompatibleOverride.ts b/tests/cases/fourslash/incompatibleOverride.ts similarity index 100% rename from tests/cases/fourslash_old/incompatibleOverride.ts rename to tests/cases/fourslash/incompatibleOverride.ts diff --git a/tests/cases/fourslash_old/incrementalResolveConstructorDeclaration.ts b/tests/cases/fourslash/incrementalResolveConstructorDeclaration.ts similarity index 100% rename from tests/cases/fourslash_old/incrementalResolveConstructorDeclaration.ts rename to tests/cases/fourslash/incrementalResolveConstructorDeclaration.ts diff --git a/tests/cases/fourslash_old/incrementalResolveFunctionPropertyAssignment.ts b/tests/cases/fourslash/incrementalResolveFunctionPropertyAssignment.ts similarity index 100% rename from tests/cases/fourslash_old/incrementalResolveFunctionPropertyAssignment.ts rename to tests/cases/fourslash/incrementalResolveFunctionPropertyAssignment.ts diff --git a/tests/cases/fourslash_old/incrementalUpdateToClassImplementingGenericClass.ts b/tests/cases/fourslash/incrementalUpdateToClassImplementingGenericClass.ts similarity index 100% rename from tests/cases/fourslash_old/incrementalUpdateToClassImplementingGenericClass.ts rename to tests/cases/fourslash/incrementalUpdateToClassImplementingGenericClass.ts diff --git a/tests/cases/fourslash_old/indentAfterFunctionClosingBraces.ts b/tests/cases/fourslash/indentAfterFunctionClosingBraces.ts similarity index 100% rename from tests/cases/fourslash_old/indentAfterFunctionClosingBraces.ts rename to tests/cases/fourslash/indentAfterFunctionClosingBraces.ts diff --git a/tests/cases/fourslash_old/indentAfterImport.ts b/tests/cases/fourslash/indentAfterImport.ts similarity index 100% rename from tests/cases/fourslash_old/indentAfterImport.ts rename to tests/cases/fourslash/indentAfterImport.ts diff --git a/tests/cases/fourslash_old/indentation.ts b/tests/cases/fourslash/indentation.ts similarity index 100% rename from tests/cases/fourslash_old/indentation.ts rename to tests/cases/fourslash/indentation.ts diff --git a/tests/cases/fourslash_old/indentationAfterModuleImport.ts b/tests/cases/fourslash/indentationAfterModuleImport.ts similarity index 100% rename from tests/cases/fourslash_old/indentationAfterModuleImport.ts rename to tests/cases/fourslash/indentationAfterModuleImport.ts diff --git a/tests/cases/fourslash_old/indexSignatureWithoutAnnotation.ts b/tests/cases/fourslash/indexSignatureWithoutAnnotation.ts similarity index 100% rename from tests/cases/fourslash_old/indexSignatureWithoutAnnotation.ts rename to tests/cases/fourslash/indexSignatureWithoutAnnotation.ts diff --git a/tests/cases/fourslash_old/inheritedModuleMembersForClodule2.ts b/tests/cases/fourslash/inheritedModuleMembersForClodule2.ts similarity index 100% rename from tests/cases/fourslash_old/inheritedModuleMembersForClodule2.ts rename to tests/cases/fourslash/inheritedModuleMembersForClodule2.ts diff --git a/tests/cases/fourslash_old/insertArgumentBeforeOverloadedConstructor.ts b/tests/cases/fourslash/insertArgumentBeforeOverloadedConstructor.ts similarity index 100% rename from tests/cases/fourslash_old/insertArgumentBeforeOverloadedConstructor.ts rename to tests/cases/fourslash/insertArgumentBeforeOverloadedConstructor.ts diff --git a/tests/cases/fourslash_old/insertInterfaceAndCheckTypeLiteralField.ts b/tests/cases/fourslash/insertInterfaceAndCheckTypeLiteralField.ts similarity index 100% rename from tests/cases/fourslash_old/insertInterfaceAndCheckTypeLiteralField.ts rename to tests/cases/fourslash/insertInterfaceAndCheckTypeLiteralField.ts diff --git a/tests/cases/fourslash_old/insertMethodCallAboveOthers.ts b/tests/cases/fourslash/insertMethodCallAboveOthers.ts similarity index 100% rename from tests/cases/fourslash_old/insertMethodCallAboveOthers.ts rename to tests/cases/fourslash/insertMethodCallAboveOthers.ts diff --git a/tests/cases/fourslash_old/insertPublicBeforeSetter.ts b/tests/cases/fourslash/insertPublicBeforeSetter.ts similarity index 100% rename from tests/cases/fourslash_old/insertPublicBeforeSetter.ts rename to tests/cases/fourslash/insertPublicBeforeSetter.ts diff --git a/tests/cases/fourslash_old/insertReturnStatementInDuplicateIdentifierFunction.ts b/tests/cases/fourslash/insertReturnStatementInDuplicateIdentifierFunction.ts similarity index 100% rename from tests/cases/fourslash_old/insertReturnStatementInDuplicateIdentifierFunction.ts rename to tests/cases/fourslash/insertReturnStatementInDuplicateIdentifierFunction.ts diff --git a/tests/cases/fourslash_old/insertSecondTryCatchBlock.ts b/tests/cases/fourslash/insertSecondTryCatchBlock.ts similarity index 100% rename from tests/cases/fourslash_old/insertSecondTryCatchBlock.ts rename to tests/cases/fourslash/insertSecondTryCatchBlock.ts diff --git a/tests/cases/fourslash_old/insertVarAfterEmptyTypeParamList.ts b/tests/cases/fourslash/insertVarAfterEmptyTypeParamList.ts similarity index 100% rename from tests/cases/fourslash_old/insertVarAfterEmptyTypeParamList.ts rename to tests/cases/fourslash/insertVarAfterEmptyTypeParamList.ts diff --git a/tests/cases/fourslash_old/interfaceExtendsPrimitive.ts b/tests/cases/fourslash/interfaceExtendsPrimitive.ts similarity index 100% rename from tests/cases/fourslash_old/interfaceExtendsPrimitive.ts rename to tests/cases/fourslash/interfaceExtendsPrimitive.ts diff --git a/tests/cases/fourslash_old/interfaceIndent.ts b/tests/cases/fourslash/interfaceIndent.ts similarity index 100% rename from tests/cases/fourslash_old/interfaceIndent.ts rename to tests/cases/fourslash/interfaceIndent.ts diff --git a/tests/cases/fourslash_old/interfaceRecursiveInheritanceErrors0.ts b/tests/cases/fourslash/interfaceRecursiveInheritanceErrors0.ts similarity index 100% rename from tests/cases/fourslash_old/interfaceRecursiveInheritanceErrors0.ts rename to tests/cases/fourslash/interfaceRecursiveInheritanceErrors0.ts diff --git a/tests/cases/fourslash_old/interfaceRecursiveInheritanceErrors1.ts b/tests/cases/fourslash/interfaceRecursiveInheritanceErrors1.ts similarity index 100% rename from tests/cases/fourslash_old/interfaceRecursiveInheritanceErrors1.ts rename to tests/cases/fourslash/interfaceRecursiveInheritanceErrors1.ts diff --git a/tests/cases/fourslash_old/invalidRestArgError.ts b/tests/cases/fourslash/invalidRestArgError.ts similarity index 100% rename from tests/cases/fourslash_old/invalidRestArgError.ts rename to tests/cases/fourslash/invalidRestArgError.ts diff --git a/tests/cases/fourslash_old/invertedCloduleAfterQuickInfo.ts b/tests/cases/fourslash/invertedCloduleAfterQuickInfo.ts similarity index 100% rename from tests/cases/fourslash_old/invertedCloduleAfterQuickInfo.ts rename to tests/cases/fourslash/invertedCloduleAfterQuickInfo.ts diff --git a/tests/cases/fourslash_old/invertedFunduleAfterQuickInfo.ts b/tests/cases/fourslash/invertedFunduleAfterQuickInfo.ts similarity index 100% rename from tests/cases/fourslash_old/invertedFunduleAfterQuickInfo.ts rename to tests/cases/fourslash/invertedFunduleAfterQuickInfo.ts diff --git a/tests/cases/fourslash_old/lambdaThisMembers.ts b/tests/cases/fourslash/lambdaThisMembers.ts similarity index 100% rename from tests/cases/fourslash_old/lambdaThisMembers.ts rename to tests/cases/fourslash/lambdaThisMembers.ts diff --git a/tests/cases/fourslash_old/malformedObjectLiteral.ts b/tests/cases/fourslash/malformedObjectLiteral.ts similarity index 100% rename from tests/cases/fourslash_old/malformedObjectLiteral.ts rename to tests/cases/fourslash/malformedObjectLiteral.ts diff --git a/tests/cases/fourslash_old/memberConstructorEdits.ts b/tests/cases/fourslash/memberConstructorEdits.ts similarity index 100% rename from tests/cases/fourslash_old/memberConstructorEdits.ts rename to tests/cases/fourslash/memberConstructorEdits.ts diff --git a/tests/cases/fourslash_old/memberListAfterSingleDot.ts b/tests/cases/fourslash/memberListAfterSingleDot.ts similarity index 100% rename from tests/cases/fourslash_old/memberListAfterSingleDot.ts rename to tests/cases/fourslash/memberListAfterSingleDot.ts diff --git a/tests/cases/fourslash_old/memberListErrorRecovery.ts b/tests/cases/fourslash/memberListErrorRecovery.ts similarity index 100% rename from tests/cases/fourslash_old/memberListErrorRecovery.ts rename to tests/cases/fourslash/memberListErrorRecovery.ts diff --git a/tests/cases/fourslash_old/memberListInFunctionCall.ts b/tests/cases/fourslash/memberListInFunctionCall.ts similarity index 100% rename from tests/cases/fourslash_old/memberListInFunctionCall.ts rename to tests/cases/fourslash/memberListInFunctionCall.ts diff --git a/tests/cases/fourslash_old/memberListOfEnumInModule.ts b/tests/cases/fourslash/memberListOfEnumInModule.ts similarity index 100% rename from tests/cases/fourslash_old/memberListOfEnumInModule.ts rename to tests/cases/fourslash/memberListOfEnumInModule.ts diff --git a/tests/cases/fourslash_old/memberListOfModuleAfterInvalidCharater.ts b/tests/cases/fourslash/memberListOfModuleAfterInvalidCharater.ts similarity index 100% rename from tests/cases/fourslash_old/memberListOfModuleAfterInvalidCharater.ts rename to tests/cases/fourslash/memberListOfModuleAfterInvalidCharater.ts diff --git a/tests/cases/fourslash_old/memberListOnConstructorType.ts b/tests/cases/fourslash/memberListOnConstructorType.ts similarity index 100% rename from tests/cases/fourslash_old/memberListOnConstructorType.ts rename to tests/cases/fourslash/memberListOnConstructorType.ts diff --git a/tests/cases/fourslash_old/memberOverloadEdits.ts b/tests/cases/fourslash/memberOverloadEdits.ts similarity index 100% rename from tests/cases/fourslash_old/memberOverloadEdits.ts rename to tests/cases/fourslash/memberOverloadEdits.ts diff --git a/tests/cases/fourslash_old/memberlistOnDDot.ts b/tests/cases/fourslash/memberlistOnDDot.ts similarity index 100% rename from tests/cases/fourslash_old/memberlistOnDDot.ts rename to tests/cases/fourslash/memberlistOnDDot.ts diff --git a/tests/cases/fourslash_old/mergedDeclarations1.ts b/tests/cases/fourslash/mergedDeclarations1.ts similarity index 100% rename from tests/cases/fourslash_old/mergedDeclarations1.ts rename to tests/cases/fourslash/mergedDeclarations1.ts diff --git a/tests/cases/fourslash_old/mergedDeclarations2.ts b/tests/cases/fourslash/mergedDeclarations2.ts similarity index 100% rename from tests/cases/fourslash_old/mergedDeclarations2.ts rename to tests/cases/fourslash/mergedDeclarations2.ts diff --git a/tests/cases/fourslash_old/mispeltVariableForInLoopErrorRecovery.ts b/tests/cases/fourslash/mispeltVariableForInLoopErrorRecovery.ts similarity index 100% rename from tests/cases/fourslash_old/mispeltVariableForInLoopErrorRecovery.ts rename to tests/cases/fourslash/mispeltVariableForInLoopErrorRecovery.ts diff --git a/tests/cases/fourslash_old/moduleEnumModule.ts b/tests/cases/fourslash/moduleEnumModule.ts similarity index 100% rename from tests/cases/fourslash_old/moduleEnumModule.ts rename to tests/cases/fourslash/moduleEnumModule.ts diff --git a/tests/cases/fourslash_old/moduleIndent.ts b/tests/cases/fourslash/moduleIndent.ts similarity index 100% rename from tests/cases/fourslash_old/moduleIndent.ts rename to tests/cases/fourslash/moduleIndent.ts diff --git a/tests/cases/fourslash_old/moduleMembersOfGenericType.ts b/tests/cases/fourslash/moduleMembersOfGenericType.ts similarity index 100% rename from tests/cases/fourslash_old/moduleMembersOfGenericType.ts rename to tests/cases/fourslash/moduleMembersOfGenericType.ts diff --git a/tests/cases/fourslash_old/moduleRenamingErrorRecovery.ts b/tests/cases/fourslash/moduleRenamingErrorRecovery.ts similarity index 100% rename from tests/cases/fourslash_old/moduleRenamingErrorRecovery.ts rename to tests/cases/fourslash/moduleRenamingErrorRecovery.ts diff --git a/tests/cases/fourslash_old/multiModuleClodule1.ts b/tests/cases/fourslash/multiModuleClodule1.ts similarity index 100% rename from tests/cases/fourslash_old/multiModuleClodule1.ts rename to tests/cases/fourslash/multiModuleClodule1.ts diff --git a/tests/cases/fourslash_old/multilineCommentBeforeOpenBrace.ts b/tests/cases/fourslash/multilineCommentBeforeOpenBrace.ts similarity index 100% rename from tests/cases/fourslash_old/multilineCommentBeforeOpenBrace.ts rename to tests/cases/fourslash/multilineCommentBeforeOpenBrace.ts diff --git a/tests/cases/fourslash_old/multipleExportAssignmentsErrorList0.ts b/tests/cases/fourslash/multipleExportAssignmentsErrorList0.ts similarity index 100% rename from tests/cases/fourslash_old/multipleExportAssignmentsErrorList0.ts rename to tests/cases/fourslash/multipleExportAssignmentsErrorList0.ts diff --git a/tests/cases/fourslash_old/navbar_contains-no-duplicates.ts b/tests/cases/fourslash/navbar_contains-no-duplicates.ts similarity index 100% rename from tests/cases/fourslash_old/navbar_contains-no-duplicates.ts rename to tests/cases/fourslash/navbar_contains-no-duplicates.ts diff --git a/tests/cases/fourslash_old/noCompletionListOnCommentsInsideObjectLiterals.ts b/tests/cases/fourslash/noCompletionListOnCommentsInsideObjectLiterals.ts similarity index 100% rename from tests/cases/fourslash_old/noCompletionListOnCommentsInsideObjectLiterals.ts rename to tests/cases/fourslash/noCompletionListOnCommentsInsideObjectLiterals.ts diff --git a/tests/cases/fourslash_old/noQuickInfoInWhitespace.ts b/tests/cases/fourslash/noQuickInfoInWhitespace.ts similarity index 100% rename from tests/cases/fourslash_old/noQuickInfoInWhitespace.ts rename to tests/cases/fourslash/noQuickInfoInWhitespace.ts diff --git a/tests/cases/fourslash_old/noSmartIndentInsideMultilineString.ts b/tests/cases/fourslash/noSmartIndentInsideMultilineString.ts similarity index 100% rename from tests/cases/fourslash_old/noSmartIndentInsideMultilineString.ts rename to tests/cases/fourslash/noSmartIndentInsideMultilineString.ts diff --git a/tests/cases/fourslash_old/nonExistingImport.ts b/tests/cases/fourslash/nonExistingImport.ts similarity index 100% rename from tests/cases/fourslash_old/nonExistingImport.ts rename to tests/cases/fourslash/nonExistingImport.ts diff --git a/tests/cases/fourslash_old/numberAssignement0.ts b/tests/cases/fourslash/numberAssignement0.ts similarity index 100% rename from tests/cases/fourslash_old/numberAssignement0.ts rename to tests/cases/fourslash/numberAssignement0.ts diff --git a/tests/cases/fourslash_old/outliningForNonCompleteInterfaceDeclaration.ts b/tests/cases/fourslash/outliningForNonCompleteInterfaceDeclaration.ts similarity index 100% rename from tests/cases/fourslash_old/outliningForNonCompleteInterfaceDeclaration.ts rename to tests/cases/fourslash/outliningForNonCompleteInterfaceDeclaration.ts diff --git a/tests/cases/fourslash_old/overloadObjectLiteralCrash.ts b/tests/cases/fourslash/overloadObjectLiteralCrash.ts similarity index 100% rename from tests/cases/fourslash_old/overloadObjectLiteralCrash.ts rename to tests/cases/fourslash/overloadObjectLiteralCrash.ts diff --git a/tests/cases/fourslash_old/parameterlessSetter.ts b/tests/cases/fourslash/parameterlessSetter.ts similarity index 100% rename from tests/cases/fourslash_old/parameterlessSetter.ts rename to tests/cases/fourslash/parameterlessSetter.ts diff --git a/tests/cases/fourslash_old/parenthesisFatArrows.ts b/tests/cases/fourslash/parenthesisFatArrows.ts similarity index 100% rename from tests/cases/fourslash_old/parenthesisFatArrows.ts rename to tests/cases/fourslash/parenthesisFatArrows.ts diff --git a/tests/cases/fourslash_old/paste.ts b/tests/cases/fourslash/paste.ts similarity index 100% rename from tests/cases/fourslash_old/paste.ts rename to tests/cases/fourslash/paste.ts diff --git a/tests/cases/fourslash_old/pasteLambdaOverModule.ts b/tests/cases/fourslash/pasteLambdaOverModule.ts similarity index 100% rename from tests/cases/fourslash_old/pasteLambdaOverModule.ts rename to tests/cases/fourslash/pasteLambdaOverModule.ts diff --git a/tests/cases/fourslash_old/propertyDuplicateIdentifierError.ts b/tests/cases/fourslash/propertyDuplicateIdentifierError.ts similarity index 100% rename from tests/cases/fourslash_old/propertyDuplicateIdentifierError.ts rename to tests/cases/fourslash/propertyDuplicateIdentifierError.ts diff --git a/tests/cases/fourslash_old/publicBreak.ts b/tests/cases/fourslash/publicBreak.ts similarity index 100% rename from tests/cases/fourslash_old/publicBreak.ts rename to tests/cases/fourslash/publicBreak.ts diff --git a/tests/cases/fourslash_old/pullFullDiffTypeParameterExtends0.ts b/tests/cases/fourslash/pullFullDiffTypeParameterExtends0.ts similarity index 100% rename from tests/cases/fourslash_old/pullFullDiffTypeParameterExtends0.ts rename to tests/cases/fourslash/pullFullDiffTypeParameterExtends0.ts diff --git a/tests/cases/fourslash_old/quickInfoFromEmptyBlockComment.ts b/tests/cases/fourslash/quickInfoFromEmptyBlockComment.ts similarity index 100% rename from tests/cases/fourslash_old/quickInfoFromEmptyBlockComment.ts rename to tests/cases/fourslash/quickInfoFromEmptyBlockComment.ts diff --git a/tests/cases/fourslash_old/quickInfoInvalidLocations.ts b/tests/cases/fourslash/quickInfoInvalidLocations.ts similarity index 100% rename from tests/cases/fourslash_old/quickInfoInvalidLocations.ts rename to tests/cases/fourslash/quickInfoInvalidLocations.ts diff --git a/tests/cases/fourslash_old/quickInfoOfLablledForStatementIterator.ts b/tests/cases/fourslash/quickInfoOfLablledForStatementIterator.ts similarity index 100% rename from tests/cases/fourslash_old/quickInfoOfLablledForStatementIterator.ts rename to tests/cases/fourslash/quickInfoOfLablledForStatementIterator.ts diff --git a/tests/cases/fourslash_old/quickInfoOnCircularTypes.ts b/tests/cases/fourslash/quickInfoOnCircularTypes.ts similarity index 100% rename from tests/cases/fourslash_old/quickInfoOnCircularTypes.ts rename to tests/cases/fourslash/quickInfoOnCircularTypes.ts diff --git a/tests/cases/fourslash_old/quickInfoOnMergedInterfaces.ts b/tests/cases/fourslash/quickInfoOnMergedInterfaces.ts similarity index 100% rename from tests/cases/fourslash_old/quickInfoOnMergedInterfaces.ts rename to tests/cases/fourslash/quickInfoOnMergedInterfaces.ts diff --git a/tests/cases/fourslash_old/quickInfoOnUnResolvedBaseConstructorSignature.ts b/tests/cases/fourslash/quickInfoOnUnResolvedBaseConstructorSignature.ts similarity index 100% rename from tests/cases/fourslash_old/quickInfoOnUnResolvedBaseConstructorSignature.ts rename to tests/cases/fourslash/quickInfoOnUnResolvedBaseConstructorSignature.ts diff --git a/tests/cases/fourslash_old/quickinfoIsConsistent.ts b/tests/cases/fourslash/quickinfoIsConsistent.ts similarity index 100% rename from tests/cases/fourslash_old/quickinfoIsConsistent.ts rename to tests/cases/fourslash/quickinfoIsConsistent.ts diff --git a/tests/cases/fourslash_old/recursiveGenerics2.ts b/tests/cases/fourslash/recursiveGenerics2.ts similarity index 100% rename from tests/cases/fourslash_old/recursiveGenerics2.ts rename to tests/cases/fourslash/recursiveGenerics2.ts diff --git a/tests/cases/fourslash_old/recursiveInternalModuleImport.ts b/tests/cases/fourslash/recursiveInternalModuleImport.ts similarity index 100% rename from tests/cases/fourslash_old/recursiveInternalModuleImport.ts rename to tests/cases/fourslash/recursiveInternalModuleImport.ts diff --git a/tests/cases/fourslash_old/recursiveWrappedTypeParameters1.ts b/tests/cases/fourslash/recursiveWrappedTypeParameters1.ts similarity index 100% rename from tests/cases/fourslash_old/recursiveWrappedTypeParameters1.ts rename to tests/cases/fourslash/recursiveWrappedTypeParameters1.ts diff --git a/tests/cases/fourslash_old/referencesForNoContext.ts b/tests/cases/fourslash/referencesForNoContext.ts similarity index 100% rename from tests/cases/fourslash_old/referencesForNoContext.ts rename to tests/cases/fourslash/referencesForNoContext.ts diff --git a/tests/cases/fourslash_old/referencesInComment.ts b/tests/cases/fourslash/referencesInComment.ts similarity index 100% rename from tests/cases/fourslash_old/referencesInComment.ts rename to tests/cases/fourslash/referencesInComment.ts diff --git a/tests/cases/fourslash_old/regexDetection.ts b/tests/cases/fourslash/regexDetection.ts similarity index 100% rename from tests/cases/fourslash_old/regexDetection.ts rename to tests/cases/fourslash/regexDetection.ts diff --git a/tests/cases/fourslash_old/regexErrorRecovery.ts b/tests/cases/fourslash/regexErrorRecovery.ts similarity index 100% rename from tests/cases/fourslash_old/regexErrorRecovery.ts rename to tests/cases/fourslash/regexErrorRecovery.ts diff --git a/tests/cases/fourslash_old/removeDeclareFunctionExports.ts b/tests/cases/fourslash/removeDeclareFunctionExports.ts similarity index 100% rename from tests/cases/fourslash_old/removeDeclareFunctionExports.ts rename to tests/cases/fourslash/removeDeclareFunctionExports.ts diff --git a/tests/cases/fourslash_old/removeDeclareInModule.ts b/tests/cases/fourslash/removeDeclareInModule.ts similarity index 100% rename from tests/cases/fourslash_old/removeDeclareInModule.ts rename to tests/cases/fourslash/removeDeclareInModule.ts diff --git a/tests/cases/fourslash_old/removeDeclareKeyword.ts b/tests/cases/fourslash/removeDeclareKeyword.ts similarity index 100% rename from tests/cases/fourslash_old/removeDeclareKeyword.ts rename to tests/cases/fourslash/removeDeclareKeyword.ts diff --git a/tests/cases/fourslash_old/removeDeclareParamTypeAnnotation.ts b/tests/cases/fourslash/removeDeclareParamTypeAnnotation.ts similarity index 100% rename from tests/cases/fourslash_old/removeDeclareParamTypeAnnotation.ts rename to tests/cases/fourslash/removeDeclareParamTypeAnnotation.ts diff --git a/tests/cases/fourslash_old/removeDuplicateIdentifier.ts b/tests/cases/fourslash/removeDuplicateIdentifier.ts similarity index 100% rename from tests/cases/fourslash_old/removeDuplicateIdentifier.ts rename to tests/cases/fourslash/removeDuplicateIdentifier.ts diff --git a/tests/cases/fourslash_old/removeExportFromInterfaceError0.ts b/tests/cases/fourslash/removeExportFromInterfaceError0.ts similarity index 100% rename from tests/cases/fourslash_old/removeExportFromInterfaceError0.ts rename to tests/cases/fourslash/removeExportFromInterfaceError0.ts diff --git a/tests/cases/fourslash_old/removeExportFromInterfaceError1.ts b/tests/cases/fourslash/removeExportFromInterfaceError1.ts similarity index 100% rename from tests/cases/fourslash_old/removeExportFromInterfaceError1.ts rename to tests/cases/fourslash/removeExportFromInterfaceError1.ts diff --git a/tests/cases/fourslash_old/removeExportedClassFromReopenedModule.ts b/tests/cases/fourslash/removeExportedClassFromReopenedModule.ts similarity index 100% rename from tests/cases/fourslash_old/removeExportedClassFromReopenedModule.ts rename to tests/cases/fourslash/removeExportedClassFromReopenedModule.ts diff --git a/tests/cases/fourslash_old/removeInterfaceExtendsClause.ts b/tests/cases/fourslash/removeInterfaceExtendsClause.ts similarity index 100% rename from tests/cases/fourslash_old/removeInterfaceExtendsClause.ts rename to tests/cases/fourslash/removeInterfaceExtendsClause.ts diff --git a/tests/cases/fourslash_old/removeInterfaceUsedAsGenericTypeArgument.ts b/tests/cases/fourslash/removeInterfaceUsedAsGenericTypeArgument.ts similarity index 100% rename from tests/cases/fourslash_old/removeInterfaceUsedAsGenericTypeArgument.ts rename to tests/cases/fourslash/removeInterfaceUsedAsGenericTypeArgument.ts diff --git a/tests/cases/fourslash_old/removeParameterBetweenCommentAndParameter.ts b/tests/cases/fourslash/removeParameterBetweenCommentAndParameter.ts similarity index 100% rename from tests/cases/fourslash_old/removeParameterBetweenCommentAndParameter.ts rename to tests/cases/fourslash/removeParameterBetweenCommentAndParameter.ts diff --git a/tests/cases/fourslash_old/removeVarFromModuleWithReopenedEnums.ts b/tests/cases/fourslash/removeVarFromModuleWithReopenedEnums.ts similarity index 100% rename from tests/cases/fourslash_old/removeVarFromModuleWithReopenedEnums.ts rename to tests/cases/fourslash/removeVarFromModuleWithReopenedEnums.ts diff --git a/tests/cases/fourslash_old/renameModuleToVar.ts b/tests/cases/fourslash/renameModuleToVar.ts similarity index 100% rename from tests/cases/fourslash_old/renameModuleToVar.ts rename to tests/cases/fourslash/renameModuleToVar.ts diff --git a/tests/cases/fourslash_old/restParametersTypeValidation1.ts b/tests/cases/fourslash/restParametersTypeValidation1.ts similarity index 100% rename from tests/cases/fourslash_old/restParametersTypeValidation1.ts rename to tests/cases/fourslash/restParametersTypeValidation1.ts diff --git a/tests/cases/fourslash_old/returnRecursiveType.ts b/tests/cases/fourslash/returnRecursiveType.ts similarity index 100% rename from tests/cases/fourslash_old/returnRecursiveType.ts rename to tests/cases/fourslash/returnRecursiveType.ts diff --git a/tests/cases/fourslash_old/scriptLexicalStructureEmptyConstructors.ts b/tests/cases/fourslash/scriptLexicalStructureEmptyConstructors.ts similarity index 100% rename from tests/cases/fourslash_old/scriptLexicalStructureEmptyConstructors.ts rename to tests/cases/fourslash/scriptLexicalStructureEmptyConstructors.ts diff --git a/tests/cases/fourslash_old/scriptLexicalStructureItems.ts b/tests/cases/fourslash/scriptLexicalStructureItems.ts similarity index 100% rename from tests/cases/fourslash_old/scriptLexicalStructureItems.ts rename to tests/cases/fourslash/scriptLexicalStructureItems.ts diff --git a/tests/cases/fourslash_old/scriptLexicalStructureItemsExternalModules.ts b/tests/cases/fourslash/scriptLexicalStructureItemsExternalModules.ts similarity index 100% rename from tests/cases/fourslash_old/scriptLexicalStructureItemsExternalModules.ts rename to tests/cases/fourslash/scriptLexicalStructureItemsExternalModules.ts diff --git a/tests/cases/fourslash_old/scriptLexicalStructurePropertiesDefinedInConstructors.ts b/tests/cases/fourslash/scriptLexicalStructurePropertiesDefinedInConstructors.ts similarity index 100% rename from tests/cases/fourslash_old/scriptLexicalStructurePropertiesDefinedInConstructors.ts rename to tests/cases/fourslash/scriptLexicalStructurePropertiesDefinedInConstructors.ts diff --git a/tests/cases/fourslash_old/selfReferencedExternalModule2.ts b/tests/cases/fourslash/selfReferencedExternalModule2.ts similarity index 100% rename from tests/cases/fourslash_old/selfReferencedExternalModule2.ts rename to tests/cases/fourslash/selfReferencedExternalModule2.ts diff --git a/tests/cases/fourslash_old/signatureHelpInFunctionCall.ts b/tests/cases/fourslash/signatureHelpInFunctionCall.ts similarity index 100% rename from tests/cases/fourslash_old/signatureHelpInFunctionCall.ts rename to tests/cases/fourslash/signatureHelpInFunctionCall.ts diff --git a/tests/cases/fourslash_old/signatureHelpNegativeTests.ts b/tests/cases/fourslash/signatureHelpNegativeTests.ts similarity index 100% rename from tests/cases/fourslash_old/signatureHelpNegativeTests.ts rename to tests/cases/fourslash/signatureHelpNegativeTests.ts diff --git a/tests/cases/fourslash_old/signatureHelpNegativeTests2.ts b/tests/cases/fourslash/signatureHelpNegativeTests2.ts similarity index 100% rename from tests/cases/fourslash_old/signatureHelpNegativeTests2.ts rename to tests/cases/fourslash/signatureHelpNegativeTests2.ts diff --git a/tests/cases/fourslash_old/signatureHelpObjectCreationExpressionNoArgs_NotAvailable.ts b/tests/cases/fourslash/signatureHelpObjectCreationExpressionNoArgs_NotAvailable.ts similarity index 100% rename from tests/cases/fourslash_old/signatureHelpObjectCreationExpressionNoArgs_NotAvailable.ts rename to tests/cases/fourslash/signatureHelpObjectCreationExpressionNoArgs_NotAvailable.ts diff --git a/tests/cases/fourslash_old/signatureHelpWithInterfaceAsIdentifier.ts b/tests/cases/fourslash/signatureHelpWithInterfaceAsIdentifier.ts similarity index 100% rename from tests/cases/fourslash_old/signatureHelpWithInterfaceAsIdentifier.ts rename to tests/cases/fourslash/signatureHelpWithInterfaceAsIdentifier.ts diff --git a/tests/cases/fourslash_old/smartIndentAfterAlignedFunctionArgument.ts b/tests/cases/fourslash/smartIndentAfterAlignedFunctionArgument.ts similarity index 100% rename from tests/cases/fourslash_old/smartIndentAfterAlignedFunctionArgument.ts rename to tests/cases/fourslash/smartIndentAfterAlignedFunctionArgument.ts diff --git a/tests/cases/fourslash_old/smartIndentAfterFatArrowVar.ts b/tests/cases/fourslash/smartIndentAfterFatArrowVar.ts similarity index 100% rename from tests/cases/fourslash_old/smartIndentAfterFatArrowVar.ts rename to tests/cases/fourslash/smartIndentAfterFatArrowVar.ts diff --git a/tests/cases/fourslash_old/smartIndentClass.ts b/tests/cases/fourslash/smartIndentClass.ts similarity index 100% rename from tests/cases/fourslash_old/smartIndentClass.ts rename to tests/cases/fourslash/smartIndentClass.ts diff --git a/tests/cases/fourslash_old/smartIndentEnum.ts b/tests/cases/fourslash/smartIndentEnum.ts similarity index 100% rename from tests/cases/fourslash_old/smartIndentEnum.ts rename to tests/cases/fourslash/smartIndentEnum.ts diff --git a/tests/cases/fourslash_old/smartIndentInsideBlockInsideCase.ts b/tests/cases/fourslash/smartIndentInsideBlockInsideCase.ts similarity index 100% rename from tests/cases/fourslash_old/smartIndentInsideBlockInsideCase.ts rename to tests/cases/fourslash/smartIndentInsideBlockInsideCase.ts diff --git a/tests/cases/fourslash_old/smartIndentInsideMultilineString.ts b/tests/cases/fourslash/smartIndentInsideMultilineString.ts similarity index 100% rename from tests/cases/fourslash_old/smartIndentInsideMultilineString.ts rename to tests/cases/fourslash/smartIndentInsideMultilineString.ts diff --git a/tests/cases/fourslash_old/smartIndentInterface.ts b/tests/cases/fourslash/smartIndentInterface.ts similarity index 100% rename from tests/cases/fourslash_old/smartIndentInterface.ts rename to tests/cases/fourslash/smartIndentInterface.ts diff --git a/tests/cases/fourslash_old/smartIndentModule.ts b/tests/cases/fourslash/smartIndentModule.ts similarity index 100% rename from tests/cases/fourslash_old/smartIndentModule.ts rename to tests/cases/fourslash/smartIndentModule.ts diff --git a/tests/cases/fourslash_old/smartIndentNestedModule.ts b/tests/cases/fourslash/smartIndentNestedModule.ts similarity index 100% rename from tests/cases/fourslash_old/smartIndentNestedModule.ts rename to tests/cases/fourslash/smartIndentNestedModule.ts diff --git a/tests/cases/fourslash_old/smartIndentNonterminatedArgumentListAtEOF.ts b/tests/cases/fourslash/smartIndentNonterminatedArgumentListAtEOF.ts similarity index 100% rename from tests/cases/fourslash_old/smartIndentNonterminatedArgumentListAtEOF.ts rename to tests/cases/fourslash/smartIndentNonterminatedArgumentListAtEOF.ts diff --git a/tests/cases/fourslash_old/smartIndentNonterminatedIfStatementAtEOF.ts b/tests/cases/fourslash/smartIndentNonterminatedIfStatementAtEOF.ts similarity index 100% rename from tests/cases/fourslash_old/smartIndentNonterminatedIfStatementAtEOF.ts rename to tests/cases/fourslash/smartIndentNonterminatedIfStatementAtEOF.ts diff --git a/tests/cases/fourslash_old/smartIndentOnFunctionParameters.ts b/tests/cases/fourslash/smartIndentOnFunctionParameters.ts similarity index 100% rename from tests/cases/fourslash_old/smartIndentOnFunctionParameters.ts rename to tests/cases/fourslash/smartIndentOnFunctionParameters.ts diff --git a/tests/cases/fourslash_old/smartIndentStatementFor.ts b/tests/cases/fourslash/smartIndentStatementFor.ts similarity index 100% rename from tests/cases/fourslash_old/smartIndentStatementFor.ts rename to tests/cases/fourslash/smartIndentStatementFor.ts diff --git a/tests/cases/fourslash_old/smartIndentStatementForIn.ts b/tests/cases/fourslash/smartIndentStatementForIn.ts similarity index 100% rename from tests/cases/fourslash_old/smartIndentStatementForIn.ts rename to tests/cases/fourslash/smartIndentStatementForIn.ts diff --git a/tests/cases/fourslash_old/smartIndentStatementSwitch.ts b/tests/cases/fourslash/smartIndentStatementSwitch.ts similarity index 100% rename from tests/cases/fourslash_old/smartIndentStatementSwitch.ts rename to tests/cases/fourslash/smartIndentStatementSwitch.ts diff --git a/tests/cases/fourslash_old/smartIndentStatementTryCatchFinally.ts b/tests/cases/fourslash/smartIndentStatementTryCatchFinally.ts similarity index 100% rename from tests/cases/fourslash_old/smartIndentStatementTryCatchFinally.ts rename to tests/cases/fourslash/smartIndentStatementTryCatchFinally.ts diff --git a/tests/cases/fourslash_old/smartIndentStatementWith.ts b/tests/cases/fourslash/smartIndentStatementWith.ts similarity index 100% rename from tests/cases/fourslash_old/smartIndentStatementWith.ts rename to tests/cases/fourslash/smartIndentStatementWith.ts diff --git a/tests/cases/fourslash_old/spaceAfterConstructor.ts b/tests/cases/fourslash/spaceAfterConstructor.ts similarity index 100% rename from tests/cases/fourslash_old/spaceAfterConstructor.ts rename to tests/cases/fourslash/spaceAfterConstructor.ts diff --git a/tests/cases/fourslash_old/spaceAfterReturn.ts b/tests/cases/fourslash/spaceAfterReturn.ts similarity index 100% rename from tests/cases/fourslash_old/spaceAfterReturn.ts rename to tests/cases/fourslash/spaceAfterReturn.ts diff --git a/tests/cases/fourslash_old/squiggleFunctionExpression.ts b/tests/cases/fourslash/squiggleFunctionExpression.ts similarity index 100% rename from tests/cases/fourslash_old/squiggleFunctionExpression.ts rename to tests/cases/fourslash/squiggleFunctionExpression.ts diff --git a/tests/cases/fourslash_old/squiggleIllegalClassExtension.ts b/tests/cases/fourslash/squiggleIllegalClassExtension.ts similarity index 100% rename from tests/cases/fourslash_old/squiggleIllegalClassExtension.ts rename to tests/cases/fourslash/squiggleIllegalClassExtension.ts diff --git a/tests/cases/fourslash_old/squiggleIllegalInterfaceExtension.ts b/tests/cases/fourslash/squiggleIllegalInterfaceExtension.ts similarity index 100% rename from tests/cases/fourslash_old/squiggleIllegalInterfaceExtension.ts rename to tests/cases/fourslash/squiggleIllegalInterfaceExtension.ts diff --git a/tests/cases/fourslash_old/squiggleIllegalSubclassOverride.ts b/tests/cases/fourslash/squiggleIllegalSubclassOverride.ts similarity index 100% rename from tests/cases/fourslash_old/squiggleIllegalSubclassOverride.ts rename to tests/cases/fourslash/squiggleIllegalSubclassOverride.ts diff --git a/tests/cases/fourslash_old/squiggleUnclosedStringLiteral.ts b/tests/cases/fourslash/squiggleUnclosedStringLiteral.ts similarity index 100% rename from tests/cases/fourslash_old/squiggleUnclosedStringLiteral.ts rename to tests/cases/fourslash/squiggleUnclosedStringLiteral.ts diff --git a/tests/cases/fourslash_old/superCallError0.ts b/tests/cases/fourslash/superCallError0.ts similarity index 100% rename from tests/cases/fourslash_old/superCallError0.ts rename to tests/cases/fourslash/superCallError0.ts diff --git a/tests/cases/fourslash_old/superInDerivedTypeOfGenericWithStatics.ts b/tests/cases/fourslash/superInDerivedTypeOfGenericWithStatics.ts similarity index 100% rename from tests/cases/fourslash_old/superInDerivedTypeOfGenericWithStatics.ts rename to tests/cases/fourslash/superInDerivedTypeOfGenericWithStatics.ts diff --git a/tests/cases/fourslash_old/switchIndenting.ts b/tests/cases/fourslash/switchIndenting.ts similarity index 100% rename from tests/cases/fourslash_old/switchIndenting.ts rename to tests/cases/fourslash/switchIndenting.ts diff --git a/tests/cases/fourslash_old/syntaxErrorAfterImport1.ts b/tests/cases/fourslash/syntaxErrorAfterImport1.ts similarity index 100% rename from tests/cases/fourslash_old/syntaxErrorAfterImport1.ts rename to tests/cases/fourslash/syntaxErrorAfterImport1.ts diff --git a/tests/cases/fourslash_old/tabbingAfterNewlineInsertedBeforeWhile.ts b/tests/cases/fourslash/tabbingAfterNewlineInsertedBeforeWhile.ts similarity index 100% rename from tests/cases/fourslash_old/tabbingAfterNewlineInsertedBeforeWhile.ts rename to tests/cases/fourslash/tabbingAfterNewlineInsertedBeforeWhile.ts diff --git a/tests/cases/fourslash_old/toggleDuplicateFunctionDeclaration.ts b/tests/cases/fourslash/toggleDuplicateFunctionDeclaration.ts similarity index 100% rename from tests/cases/fourslash_old/toggleDuplicateFunctionDeclaration.ts rename to tests/cases/fourslash/toggleDuplicateFunctionDeclaration.ts diff --git a/tests/cases/fourslash_old/typeAboveNumberLiteralExpressionStatement.ts b/tests/cases/fourslash/typeAboveNumberLiteralExpressionStatement.ts similarity index 100% rename from tests/cases/fourslash_old/typeAboveNumberLiteralExpressionStatement.ts rename to tests/cases/fourslash/typeAboveNumberLiteralExpressionStatement.ts diff --git a/tests/cases/fourslash_old/typeArgCompletion.ts b/tests/cases/fourslash/typeArgCompletion.ts similarity index 100% rename from tests/cases/fourslash_old/typeArgCompletion.ts rename to tests/cases/fourslash/typeArgCompletion.ts diff --git a/tests/cases/fourslash_old/typeCheckAfterAddingGenericParameter.ts b/tests/cases/fourslash/typeCheckAfterAddingGenericParameter.ts similarity index 100% rename from tests/cases/fourslash_old/typeCheckAfterAddingGenericParameter.ts rename to tests/cases/fourslash/typeCheckAfterAddingGenericParameter.ts diff --git a/tests/cases/fourslash_old/typeCheckExpression0.ts b/tests/cases/fourslash/typeCheckExpression0.ts similarity index 100% rename from tests/cases/fourslash_old/typeCheckExpression0.ts rename to tests/cases/fourslash/typeCheckExpression0.ts diff --git a/tests/cases/fourslash_old/typeCheckGenericTypeLiteralArgument.ts b/tests/cases/fourslash/typeCheckGenericTypeLiteralArgument.ts similarity index 100% rename from tests/cases/fourslash_old/typeCheckGenericTypeLiteralArgument.ts rename to tests/cases/fourslash/typeCheckGenericTypeLiteralArgument.ts diff --git a/tests/cases/fourslash_old/typeCheckIndexSignature.ts b/tests/cases/fourslash/typeCheckIndexSignature.ts similarity index 100% rename from tests/cases/fourslash_old/typeCheckIndexSignature.ts rename to tests/cases/fourslash/typeCheckIndexSignature.ts diff --git a/tests/cases/fourslash_old/typeCheckIndexerAccess1.ts b/tests/cases/fourslash/typeCheckIndexerAccess1.ts similarity index 100% rename from tests/cases/fourslash_old/typeCheckIndexerAccess1.ts rename to tests/cases/fourslash/typeCheckIndexerAccess1.ts diff --git a/tests/cases/fourslash_old/typeCheckObjectInArrayLiteral.ts b/tests/cases/fourslash/typeCheckObjectInArrayLiteral.ts similarity index 100% rename from tests/cases/fourslash_old/typeCheckObjectInArrayLiteral.ts rename to tests/cases/fourslash/typeCheckObjectInArrayLiteral.ts diff --git a/tests/cases/fourslash_old/unclosedArrayErrorRecovery.ts b/tests/cases/fourslash/unclosedArrayErrorRecovery.ts similarity index 100% rename from tests/cases/fourslash_old/unclosedArrayErrorRecovery.ts rename to tests/cases/fourslash/unclosedArrayErrorRecovery.ts diff --git a/tests/cases/fourslash_old/unclosedCommentsInConstructor.ts b/tests/cases/fourslash/unclosedCommentsInConstructor.ts similarity index 100% rename from tests/cases/fourslash_old/unclosedCommentsInConstructor.ts rename to tests/cases/fourslash/unclosedCommentsInConstructor.ts diff --git a/tests/cases/fourslash_old/unclosedFunctionErrorRecovery.ts b/tests/cases/fourslash/unclosedFunctionErrorRecovery.ts similarity index 100% rename from tests/cases/fourslash_old/unclosedFunctionErrorRecovery.ts rename to tests/cases/fourslash/unclosedFunctionErrorRecovery.ts diff --git a/tests/cases/fourslash_old/unclosedFunctionErrorRecovery2.ts b/tests/cases/fourslash/unclosedFunctionErrorRecovery2.ts similarity index 100% rename from tests/cases/fourslash_old/unclosedFunctionErrorRecovery2.ts rename to tests/cases/fourslash/unclosedFunctionErrorRecovery2.ts diff --git a/tests/cases/fourslash_old/unclosedFunctionErrorRecovery3.ts b/tests/cases/fourslash/unclosedFunctionErrorRecovery3.ts similarity index 100% rename from tests/cases/fourslash_old/unclosedFunctionErrorRecovery3.ts rename to tests/cases/fourslash/unclosedFunctionErrorRecovery3.ts diff --git a/tests/cases/fourslash_old/unclosedMultilineStringLiteralErrorRecovery.ts b/tests/cases/fourslash/unclosedMultilineStringLiteralErrorRecovery.ts similarity index 100% rename from tests/cases/fourslash_old/unclosedMultilineStringLiteralErrorRecovery.ts rename to tests/cases/fourslash/unclosedMultilineStringLiteralErrorRecovery.ts diff --git a/tests/cases/fourslash_old/unclosedStringLiteralErrorRecovery.ts b/tests/cases/fourslash/unclosedStringLiteralErrorRecovery.ts similarity index 100% rename from tests/cases/fourslash_old/unclosedStringLiteralErrorRecovery.ts rename to tests/cases/fourslash/unclosedStringLiteralErrorRecovery.ts diff --git a/tests/cases/fourslash_old/unclosedStringLiteralErrorRecovery2.ts b/tests/cases/fourslash/unclosedStringLiteralErrorRecovery2.ts similarity index 100% rename from tests/cases/fourslash_old/unclosedStringLiteralErrorRecovery2.ts rename to tests/cases/fourslash/unclosedStringLiteralErrorRecovery2.ts diff --git a/tests/cases/fourslash_old/unclosedStringLiteralErrorRecovery3.ts b/tests/cases/fourslash/unclosedStringLiteralErrorRecovery3.ts similarity index 100% rename from tests/cases/fourslash_old/unclosedStringLiteralErrorRecovery3.ts rename to tests/cases/fourslash/unclosedStringLiteralErrorRecovery3.ts diff --git a/tests/cases/fourslash_old/unclosedStringLiteralErrorRecovery4.ts b/tests/cases/fourslash/unclosedStringLiteralErrorRecovery4.ts similarity index 100% rename from tests/cases/fourslash_old/unclosedStringLiteralErrorRecovery4.ts rename to tests/cases/fourslash/unclosedStringLiteralErrorRecovery4.ts diff --git a/tests/cases/fourslash_old/underscoreTyping1.ts b/tests/cases/fourslash/underscoreTyping1.ts similarity index 100% rename from tests/cases/fourslash_old/underscoreTyping1.ts rename to tests/cases/fourslash/underscoreTyping1.ts diff --git a/tests/cases/fourslash_old/unknownVariableErrorRecovery.ts b/tests/cases/fourslash/unknownVariableErrorRecovery.ts similarity index 100% rename from tests/cases/fourslash_old/unknownVariableErrorRecovery.ts rename to tests/cases/fourslash/unknownVariableErrorRecovery.ts diff --git a/tests/cases/fourslash_old/updateToClassStatics.ts b/tests/cases/fourslash/updateToClassStatics.ts similarity index 100% rename from tests/cases/fourslash_old/updateToClassStatics.ts rename to tests/cases/fourslash/updateToClassStatics.ts diff --git a/tests/cases/fourslash_old/whiteSpaceTrimming.ts b/tests/cases/fourslash/whiteSpaceTrimming.ts similarity index 100% rename from tests/cases/fourslash_old/whiteSpaceTrimming.ts rename to tests/cases/fourslash/whiteSpaceTrimming.ts From a6e87cd9ec67bd9db75309da22907ea60396fd53 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Jul 2014 12:02:42 -0700 Subject: [PATCH 53/59] enable fourslash tests by default --- src/harness/runner.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/harness/runner.ts b/src/harness/runner.ts index accf41684c0..9f1ae0e90a9 100644 --- a/src/harness/runner.ts +++ b/src/harness/runner.ts @@ -97,9 +97,8 @@ if (runners.length === 0) { } //// language services - // TODO: Re-enable Fourslash runner - // runners.push(new FourslashRunner()); - // runners.push(new GeneratedFourslashRunner()); + runners.push(new FourslashRunner()); + //runners.push(new GeneratedFourslashRunner()); } sys.newLine = '\r\n'; From 7faad38c8425b18d6bc738690ec10b100b0be0c3 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Jul 2014 12:02:57 -0700 Subject: [PATCH 54/59] remove unused interface --- src/compiler/checker.ts | 1 - src/compiler/types.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ab32682c90a..994b00abae6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -87,7 +87,6 @@ module ts { getTypeOfExpression: getTypeOfExpression, typeToString: typeToString, symbolToString: symbolToString, - writeTypeToTextWriter: writeTypeToTextWriter, getAugmentedPropertiesOfApparentType: getAugmentedPropertiesOfApparentType }; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 05e2ce641c0..6ca6035a968 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -602,7 +602,6 @@ module ts { getTypeOfExpression(node: Expression, contextualType?: Type, contextualMapper?: TypeMapper): Type; typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string; symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string; - writeTypeToTextWriter(type: Type, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter): void; getAugmentedPropertiesOfApparentType(type: Type): Symbol[]; } From 648af3801afb8953e0772f9237663ec6617111d1 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Jul 2014 12:35:26 -0700 Subject: [PATCH 55/59] react to changes after rebase --- src/harness/fourslash.ts | 2 +- tests/cases/fourslash/underscoreTyping1.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index ac11fecbd3f..9a1f97395a0 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -424,6 +424,7 @@ module FourSlash { this.scenarioActions.push(''); if (actual !== expected) { + this.printErrorLog(false, errors); var errorMsg = "Actual number of errors (" + actual + ") does not match expected number (" + expected + ")"; Harness.IO.log(errorMsg); throw new Error(errorMsg); @@ -1894,7 +1895,6 @@ module FourSlash { { unitName: fileName, content: Harness.IO.readFile(fileName) } ]; harnessCompiler.addInputFiles(filesToAdd); - harnessCompiler.compile(); var emitterIOHost: Harness.Compiler.IEmitterIOHost = { writeFile: (path: string, contents: string, writeByteOrderMark: boolean) => fsOutput.Write(contents), diff --git a/tests/cases/fourslash/underscoreTyping1.ts b/tests/cases/fourslash/underscoreTyping1.ts index 06e8b979079..d4556e07f74 100644 --- a/tests/cases/fourslash/underscoreTyping1.ts +++ b/tests/cases/fourslash/underscoreTyping1.ts @@ -18,4 +18,4 @@ //// } goTo.position(0); -verify.numberOfErrorsInCurrentFile(3); +verify.numberOfErrorsInCurrentFile(2); From f5091c226fe159997050c489700848663adbaca3 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Jul 2014 15:03:35 -0700 Subject: [PATCH 56/59] Use correct casing for file references --- src/services/services.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 14581c0c3d6..f0be2fa0c25 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -6,9 +6,9 @@ /// /// -/// -/// -/// +/// +/// +/// /// /// /// @@ -21,7 +21,7 @@ /// /// /// -/// +/// /// /// From 990669972a20ca06358ae98c22d672f45d0fbbb8 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Jul 2014 15:28:25 -0700 Subject: [PATCH 57/59] update error positions after rebase --- tests/cases/fourslash/errorConsistency.ts | 2 +- tests/cases/fourslash/genericAssignmentCompat.ts | 2 +- tests/cases/fourslash/squiggleFunctionExpression.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/cases/fourslash/errorConsistency.ts b/tests/cases/fourslash/errorConsistency.ts index ab910b4cf68..3d17870f3b4 100644 --- a/tests/cases/fourslash/errorConsistency.ts +++ b/tests/cases/fourslash/errorConsistency.ts @@ -4,7 +4,7 @@ ////val(f: (t: T) => U): Int; ////} ////declare var v1: Int; -////var /*1*/v2: Int = v1/*2*/; +////var /*1*/v2/*2*/: Int = v1; goTo.eof(); verify.errorExistsBetweenMarkers("1", "2"); diff --git a/tests/cases/fourslash/genericAssignmentCompat.ts b/tests/cases/fourslash/genericAssignmentCompat.ts index f80870baf21..c9d547147b1 100644 --- a/tests/cases/fourslash/genericAssignmentCompat.ts +++ b/tests/cases/fourslash/genericAssignmentCompat.ts @@ -8,7 +8,7 @@ //// //// declare var v1: Int; //// -//// var /*1*/v2: Int = v1/*2*/; +//// var /*1*/v2/*2*/: Int = v1; verify.errorExistsBetweenMarkers("1", "2"); verify.numberOfErrorsInCurrentFile(1); \ No newline at end of file diff --git a/tests/cases/fourslash/squiggleFunctionExpression.ts b/tests/cases/fourslash/squiggleFunctionExpression.ts index efd4b6bafec..3477f31db3a 100644 --- a/tests/cases/fourslash/squiggleFunctionExpression.ts +++ b/tests/cases/fourslash/squiggleFunctionExpression.ts @@ -1,7 +1,7 @@ /// ////function takesCallback(callback: (n) => any) { } -////takesCallback(function inner(n) { var /*1*/k: string = 10/*2*/; }); +////takesCallback(function inner(n) { var /*1*/k/*2*/: string = 10; }); verify.errorExistsBetweenMarkers("1", "2"); verify.not.errorExistsBeforeMarker("1"); From 0a206d8855c3667c6ca3723a034bad18c653d333 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 30 Jul 2014 14:46:33 -0700 Subject: [PATCH 58/59] Respond to code review comments: * Change comment to say "noresolve=false" in shims.ts https://github.com/Microsoft/TypeScript/commit/05eeba5bc95f9a39ceb9c17b5674ed7135d74aed * Switch newline to "\r\n" https://github.com/Microsoft/TypeScript/commit/9395eeaedbb4279480c306f88e7916fa9694de31 * Use hasOwnProperty for Map types https://github.com/Microsoft/TypeScript/commit/212c18460281cac5b5be5239d45f7d04212f62d8 * Switch "s" to "S" in typescriptServices.ts filename https://github.com/Microsoft/TypeScript/commit/9061e58dffbeaf3f72cee1c6ca6d8fc0b98b1ea5 * Change method names in Node to be more detailed --- Jakefile | 2 +- src/compiler/core.ts | 4 + src/services/compiler/bloomFilter.ts | 2 +- .../getScriptLexicalStructureWalker.ts | 6 +- src/services/services.ts | 88 ++++++++++++------- src/services/shims.ts | 2 +- 6 files changed, 68 insertions(+), 36 deletions(-) diff --git a/Jakefile b/Jakefile index d738359e221..a36c3f4a9d7 100644 --- a/Jakefile +++ b/Jakefile @@ -231,7 +231,7 @@ task("generate-diagnostics", [diagnosticInfoMapTs]) var tcFile = path.join(builtLocalDirectory, "tc.js"); compileFile(tcFile, compilerSources, [builtLocalDirectory, copyright].concat(compilerSources), [copyright], /*useBuiltCompiler:*/ false); -var tcServicesFile = path.join(builtLocalDirectory, "typescriptservices.js"); +var tcServicesFile = path.join(builtLocalDirectory, "typescriptServices.js"); compileFile(tcServicesFile, servicesSources, [builtLocalDirectory, copyright].concat(servicesSources), [copyright], /*useBuiltCompiler:*/ true); // Local target to build the compiler and services diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 824aaca5a46..2aa6ae6e9a7 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -142,6 +142,10 @@ module ts { return result; } + export function lookUp(map: Map, key: string): T { + return hasProperty(map, key) ? map[key] : undefined; + } + export function mapToArray(map: Map): T[] { var result: T[] = []; for (var id in map) result.push(map[id]); diff --git a/src/services/compiler/bloomFilter.ts b/src/services/compiler/bloomFilter.ts index 8b0e3674e09..44d72bf5bfa 100644 --- a/src/services/compiler/bloomFilter.ts +++ b/src/services/compiler/bloomFilter.ts @@ -83,7 +83,7 @@ module TypeScript { public addKeys(keys: ts.Map) { for (var name in keys) { - if (keys[name]) { + if (ts.lookUp(keys, name)) { this.add(name); } } diff --git a/src/services/getScriptLexicalStructureWalker.ts b/src/services/getScriptLexicalStructureWalker.ts index df182d3b404..b42f34fa927 100644 --- a/src/services/getScriptLexicalStructureWalker.ts +++ b/src/services/getScriptLexicalStructureWalker.ts @@ -34,7 +34,7 @@ module TypeScript.Services { var parentScope = this.currentScope; this.parentScopes.push(parentScope); - var scope = parentScope.childScopes[key]; + var scope = ts.lookUp(parentScope.childScopes, key); if (!scope) { scope = this.createScope() parentScope.childScopes[key] = scope; @@ -76,7 +76,7 @@ module TypeScript.Services { private createItem(node: TypeScript.ISyntaxNode, modifiers: ISyntaxToken[], kind: string, name: string): void { var key = kind + "+" + name; - if (this.currentScope.items[key] !== undefined) { + if (ts.lookUp(this.currentScope.items, key) !== undefined) { this.addAdditionalSpan(node, key); return; } @@ -100,7 +100,7 @@ module TypeScript.Services { node: TypeScript.ISyntaxNode, key: string) { - var item = this.currentScope.items[key] + var item = ts.lookUp(this.currentScope.items, key); Debug.assert(item !== undefined); var start = TypeScript.start(node); diff --git a/src/services/services.ts b/src/services/services.ts index f0be2fa0c25..c3359b1004c 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -32,8 +32,12 @@ module ts { getChildCount(): number; getChildAt(index: number): Node; getChildren(): Node[]; + getStart(): number; + getFullStart(): number; + getEnd(): number; + getWidth(): number; getFullWidth(): number; - getTriviaWidth(): number; + getLeadingTriviaWidth(): number; getFullText(): string; getFirstToken(): Node; getLastToken(): Node; @@ -91,16 +95,28 @@ module ts { return node; } - public getTextPos(): number { + public getStart(): number { return getTokenPosOfNode(this); } - - public getFullWidth(): number { - return this.end - this.pos; + + public getFullStart(): number { + return this.pos; } - public getTriviaWidth(): number { - return getTokenPosOfNode(this) - this.pos; + public getEnd(): number { + return this.end; + } + + public getWidth(): number { + return this.getStart() - this.getEnd(); + } + + public getFullWidth(): number { + return this.end - this.getFullStart(); + } + + public getLeadingTriviaWidth(): number { + return this.getStart() - this.pos; } public getFullText(): string { @@ -919,40 +935,48 @@ module ts { return this._compilationSettings; } + public getEntry(filename: string): HostFileInformation { + filename = TypeScript.switchToForwardSlashes(filename); + return lookUp(this.filenameToEntry, filename); + } + public contains(filename: string): boolean { - return !!this.filenameToEntry[TypeScript.switchToForwardSlashes(filename)]; + return !!this.getEntry(filename); } public getHostfilename(filename: string) { - var hostCacheEntry = this.filenameToEntry[TypeScript.switchToForwardSlashes(filename)]; + var hostCacheEntry = this.getEntry(filename); if (hostCacheEntry) { return hostCacheEntry.filename; } return filename; } - public getfilenames(): string[] { + public getFilenames(): string[] { var fileNames: string[] = []; - for (var id in this.filenameToEntry) { - fileNames.push(id); - } + + forEachKey(this.filenameToEntry, key => { + if (hasProperty(this.filenameToEntry, key)) + fileNames.push(key); + }); + return fileNames; } public getVersion(filename: string): number { - return this.filenameToEntry[TypeScript.switchToForwardSlashes(filename)].version; + return this.getEntry(filename).version; } public isOpen(filename: string): boolean { - return this.filenameToEntry[TypeScript.switchToForwardSlashes(filename)].isOpen; + return this.getEntry(filename).isOpen; } public getByteOrderMark(filename: string): ByteOrderMark { - return this.filenameToEntry[TypeScript.switchToForwardSlashes(filename)].byteOrderMark; + return this.getEntry(filename).byteOrderMark; } public getScriptSnapshot(filename: string): TypeScript.IScriptSnapshot { - var file = this.filenameToEntry[TypeScript.switchToForwardSlashes(filename)]; + var file = this.getEntry(filename); if (!file.sourceText) { file.sourceText = this.host.getScriptSnapshot(file.filename); } @@ -1117,7 +1141,7 @@ module ts { function getBucketForCompilationSettings(settings: CompilerOptions, createIfMissing: boolean): Map { var key = getKeyFromCompilationSettings(settings); - var bucket = buckets[key]; + var bucket = lookUp(buckets, key); if (!bucket && createIfMissing) { buckets[key] = bucket = {}; } @@ -1126,7 +1150,7 @@ module ts { function reportStats() { var bucketInfoArray = Object.keys(buckets).filter(name => name && name.charAt(0) === '_').map(name => { - var entries = buckets[name]; + var entries = lookUp(buckets, name); var documents: { name: string; refCount: number; references: string[]; }[] = []; for (var i in entries) { var entry = entries[i]; @@ -1152,7 +1176,7 @@ module ts { referencedFiles: string[]= []): Document { var bucket = getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ true); - var entry = bucket[filename]; + var entry = lookUp(bucket, filename); if (!entry) { var document = createDocument(compilationSettings, filename, scriptSnapshot, byteOrderMark, version, isOpen, referencedFiles); @@ -1179,7 +1203,7 @@ module ts { var bucket = getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ false); Debug.assert(bucket); - var entry = bucket[filename]; + var entry = lookUp(bucket, filename); Debug.assert(entry); if (entry.document.isOpen() === isOpen && entry.document.getVersion() === version) { @@ -1194,7 +1218,7 @@ module ts { var bucket = getBucketForCompilationSettings(compilationSettings, false); Debug.assert(bucket); - var entry = bucket[filename]; + var entry = lookUp(bucket, filename); entry.refCount--; Debug.assert(entry.refCount >= 0); @@ -1229,10 +1253,14 @@ module ts { TypeScript.LocalizedDiagnosticMessages = host.getLocalizedDiagnosticMessages(); } + function getDocument(filename: string): Document { + return lookUp(documentsByName, filename); + } + function createCompilerHost(): CompilerHost { return { getSourceFile: (filename, languageVersion) => { - var document = documentsByName[filename]; + var document = getDocument(filename); Debug.assert(!!document, "document can not be undefined"); @@ -1241,7 +1269,7 @@ module ts { getCancellationToken: () => cancellationToken, getCanonicalFileName: (filename) => useCaseSensitivefilenames ? filename : filename.toLowerCase(), useCaseSensitiveFileNames: () => useCaseSensitivefilenames, - getNewLine: () => "\n", + getNewLine: () => "\r\n", // Need something that doesn't depend on sys.ts here getDefaultLibFilename: (): string => { throw Error("TOD:: getDefaultLibfilename"); @@ -1292,7 +1320,7 @@ module ts { // Now, for every file the host knows about, either add the file (if the compiler // doesn't know about it.). Or notify the compiler about any changes (if it does // know about it.) - var hostfilenames = hostCache.getfilenames(); + var hostfilenames = hostCache.getFilenames(); for (var i = 0, n = hostfilenames.length; i < n; i++) { var filename = hostfilenames[i]; @@ -1301,7 +1329,7 @@ module ts { var isOpen = hostCache.isOpen(filename); var scriptSnapshot = hostCache.getScriptSnapshot(filename); - var document: Document = documentsByName[filename]; + var document: Document = getDocument(filename); if (document) { // // If the document is the same, assume no update @@ -1564,7 +1592,7 @@ module ts { filename = TypeScript.switchToForwardSlashes(filename); - var document = documentsByName[filename]; + var document = getDocument(filename); var sourceUnit = document.getSourceUnit(); if (isCompletionListBlocker(document.getSyntaxTree().sourceUnit(), position)) { @@ -1706,7 +1734,7 @@ module ts { return undefined; } - var symbol = activeCompletionSession.symbols[entryName]; + var symbol = lookUp(activeCompletionSession.symbols, entryName); if (symbol) { var type = session.typeChecker.getTypeOfSymbol(symbol); Debug.assert(type, "Could not find type for symbol"); @@ -1739,7 +1767,7 @@ module ts { // find the child that has this for (var i = 0, n = current.getChildCount(); i < n; i++) { var child = current.getChildAt(i); - if (getTokenPosOfNode(child) <= position && position < child.end) { + if (child.getStart() <= position && position < child.getEnd()) { current = child; continue outer; } @@ -1824,7 +1852,7 @@ module ts { synchronizeHostData(); filename = TypeScript.switchToForwardSlashes(filename); - var document = documentsByName[filename]; + var document = getDocument(filename); var node = getNodeAtPosition(document.getSourceFile(), position); if (!node) return undefined; diff --git a/src/services/shims.ts b/src/services/shims.ts index 8debe8f973b..f02b9b62088 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -331,7 +331,7 @@ module ts { /// TODO: this should be pushed into VS. /// We can not ask the LS instance to resolve, as this will lead to asking the host about files it does not know about, - /// something it is not desinged to handle. for now make sure we never get a noresolve=true. + /// something it is not desinged to handle. for now make sure we never get a "noresolve == false". /// This value should not matter, as the host runs resolution logic independentlly options.noResolve = true; From 732ffc0d5d442af197fc27f8a759fa311fc1a186 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 31 Jul 2014 19:04:55 -0700 Subject: [PATCH 59/59] More changes to address code review comments --- src/compiler/checker.ts | 2 +- src/services/services.ts | 47 +++++++++++----------------------------- 2 files changed, 14 insertions(+), 35 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1799f19c380..6097e3337dd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6198,7 +6198,7 @@ module ts { // True if the given identifier is part of a type reference function isTypeReferenceIdentifier(identifier: Identifier): boolean { var node: Node = identifier; - while (node.parent && node.parent.kind === SyntaxKind.QualifiedName) node = node.parent; + if (node.parent && node.parent.kind === SyntaxKind.QualifiedName) node = node.parent; return node.parent && node.parent.kind === SyntaxKind.TypeReference; } diff --git a/src/services/services.ts b/src/services/services.ts index c3359b1004c..1c60f2c6ba0 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -108,7 +108,7 @@ module ts { } public getWidth(): number { - return this.getStart() - this.getEnd(); + return this.getEnd() - this.getStart(); } public getFullWidth(): number { @@ -1235,6 +1235,16 @@ module ts { }; } + // A cache of completion entries for keywords, these do not change between sessions + var keywordCompletions:CompletionEntry[] = []; + for (var i = SyntaxKind.FirstKeyword; i <= SyntaxKind.LastKeyword; i++) { + keywordCompletions.push({ + name: tokenToString(i), + kind: ScriptElementKind.keyword, + kindModifiers: ScriptElementKindModifier.none + }); + } + export function createLanguageService(host: LanguageServiceHost, documentRegistry: DocumentRegistry): LanguageService { var syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host); var formattingRulesProvider: TypeScript.Services.Formatting.RulesProvider; @@ -1246,7 +1256,6 @@ module ts { var documentRegistry = documentRegistry; var cancellationToken = new CancellationTokenObject(host.getCancellationToken()); var activeCompletionSession: CompletionSession; // The current active completion session, used to get the completion entry details - var keywordCompletions = getKeywordCompletionEntries(); // A cache of completion entries for keywords, these do not change between sessions // Check if the localized messages json is set, otherwise query the host for it if (!TypeScript.LocalizedDiagnosticMessages) { @@ -1301,7 +1310,8 @@ module ts { // If the language version changed, then that affects what types of things we parse. So // we have to dump all syntax trees. // TODO: handle propagateEnumConstants - var settingsChangeAffectsSyntax = oldSettings.target !== compilationSettings.target; + // TODO: is module still needed + var settingsChangeAffectsSyntax = oldSettings.target !== compilationSettings.target || oldSettings.module !== compilationSettings.module; var changesInCompilationSettingsAffectSyntax = oldSettings && compilationSettings && !compareDataObjects(oldSettings, compilationSettings) && settingsChangeAffectsSyntax; @@ -1423,37 +1433,6 @@ module ts { }; } - function getKeywordCompletionEntries(): CompletionEntry[] { - var keywords = [ - "break", - "case", "catch", "class", "constructor", "continue", - "debugger", "declare", "default", "delete", "do", - "else", "enum", "export", "extends", - "false", "finally", "for", "function", - "get", - "if","implements", "import", "in", "instanceof", "interface", - "module", - "new", "null", - "private", "public", - "require","return", - "set", "static", "super", "switch", - "this", "throw", "true", "try", "typeof", - "var", - "while","with", - ]; - - var result: CompletionEntry[] = []; - forEach(keywords, (keyword) => { - result.push({ - name: keyword, - kind: ScriptElementKind.keyword, - kindModifiers: ScriptElementKindModifier.none - }); - }); - - return result; - } - function getCompletionsAtPosition(filename: string, position: number, isMemberCompletion: boolean) { function getCompletionEntriesFromSymbols(symbols: Symbol[], session: CompletionSession): void { forEach(symbols, (symbol) => {