diff --git a/Jakefile.js b/Jakefile.js
index 889d7cf6299..1f6120ef64a 100644
--- a/Jakefile.js
+++ b/Jakefile.js
@@ -31,9 +31,9 @@ if (process.env.path !== undefined) {
}
var compilerSources = [
+ "types.ts",
"core.ts",
"sys.ts",
- "types.ts",
"scanner.ts",
"factory.ts",
"factory.generated.ts",
@@ -60,6 +60,8 @@ var servicesSources = [
"sys.ts",
"types.ts",
"scanner.ts",
+ "factory.ts",
+ "factory.generated.ts",
"parser.ts",
"utilities.ts",
"binder.ts",
diff --git a/scripts/processTypes.ts b/scripts/processTypes.ts
index 0ba68803e7d..f8928d58ae0 100644
--- a/scripts/processTypes.ts
+++ b/scripts/processTypes.ts
@@ -404,8 +404,6 @@ function generateFactory(outputFile: string) {
let writer = createLineWrappingTextWriter(host.getNewLine(), columnWrap);
writer.write(`// `);
writer.writeLine();
- writer.write(`/// `);
- writer.writeLine();
writer.write(`/// `);
writer.writeLine();
writer.write(`namespace ts {`);
diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts
index 29d7e6b43eb..7c1000b7a84 100644
--- a/src/compiler/emitter.ts
+++ b/src/compiler/emitter.ts
@@ -2814,9 +2814,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
return;
}
- let parentNode = nodeStack.getParent();
emitToken(SyntaxKind.OpenBraceToken, node.pos);
increaseIndent();
+
+ let parentNode = nodeStack.getParent();
scopeEmitStart(parentNode);
if (node.kind === SyntaxKind.ModuleBlock) {
Debug.assert(parentNode.kind === SyntaxKind.ModuleDeclaration);
diff --git a/src/compiler/factory.generated.ts b/src/compiler/factory.generated.ts
index 24c4d4b41fc..56073b6de1c 100644
--- a/src/compiler/factory.generated.ts
+++ b/src/compiler/factory.generated.ts
@@ -1,5 +1,4 @@
//
-///
///
namespace ts {
export namespace factory {
@@ -2889,6 +2888,9 @@ namespace ts {
export function isEnumMember(node: Node): node is EnumMember {
return node && node.kind === SyntaxKind.EnumMember;
}
+ export function isSourceFile(node: Node): node is SourceFile {
+ return node && node.kind === SyntaxKind.SourceFile;
+ }
export function isJSDocTypeExpression(node: Node): node is JSDocTypeExpression {
return node && node.kind === SyntaxKind.JSDocTypeExpression;
}
@@ -3187,6 +3189,7 @@ namespace ts {
case SyntaxKind.JSDocReturnTag:
case SyntaxKind.JSDocTypeTag:
case SyntaxKind.JSDocParameterTag:
+ case SyntaxKind.SourceFile:
return true;
}
}
diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts
index bde56323a04..1276fea83b3 100644
--- a/src/compiler/factory.ts
+++ b/src/compiler/factory.ts
@@ -10,7 +10,7 @@ namespace ts {
export function createNode(kind: SyntaxKind): T {
return factory.createNode(kind);
}
-
+
// @internal
export namespace factory {
export function setNodeFlags(node: T, flags: NodeFlags): T {
@@ -129,6 +129,16 @@ namespace ts {
return node;
}
+ export function updateSourceFile(node: SourceFile, statements: NodeArray, endOfFileToken: Node): SourceFile {
+ if (statements !== node.statements || endOfFileToken !== node.endOfFileToken) {
+ let newNode = createSourceFile();
+ newNode.statements = statements;
+ newNode.endOfFileToken = endOfFileToken;
+ return updateFrom(node, newNode);
+ }
+ return node;
+ }
+
export function createNumericLiteral2(value: number, location?: TextRange, flags?: NodeFlags): LiteralExpression {
let node = factory.createNumericLiteral(String(value), location, flags);
return node;
diff --git a/src/compiler/transform.generated.ts b/src/compiler/transform.generated.ts
index 0b479aded50..2a284b835bf 100644
--- a/src/compiler/transform.generated.ts
+++ b/src/compiler/transform.generated.ts
@@ -600,6 +600,11 @@ namespace ts.transform {
node,
visitNode((node).name, visitor),
visitNode((node).initializer, visitor)));
+ case SyntaxKind.SourceFile:
+ return write(factory.updateSourceFile(
+ node,
+ >visitNodes((node).statements, visitor),
+ (node).endOfFileToken));
case SyntaxKind.JSDocTypeExpression:
return write(factory.updateJSDocTypeExpression(
node,
diff --git a/src/compiler/transform.ts b/src/compiler/transform.ts
index ed1e2bbf062..999bcc1a76a 100644
--- a/src/compiler/transform.ts
+++ b/src/compiler/transform.ts
@@ -4,14 +4,6 @@ const FORCE_TRANSFORMS = false;
/* @internal */
namespace ts {
-
- // Flags enum to track count of temp variables and a few dedicated names
- const enum TempFlags {
- Auto = 0x00000000, // No preferred name
- CountMask = 0x0FFFFFFF, // Temp variable counter
- _i = 0x10000000, // Use/preference flag for '_i'
- }
-
/**
* Computes the transform flags for a node, given the transform flags of its subtree
* @param node The node to analyze
@@ -261,8 +253,23 @@ namespace ts {
_compilerOptions: CompilerOptions, _currentSourceFile: SourceFile, _resolver: EmitResolver, _generatedNameSet: Map, _nodeToGeneratedName: string[]) {
return transform.runTransformationChain(statements, chain, _compilerOptions, _currentSourceFile, _resolver, _generatedNameSet, _nodeToGeneratedName);
}
-
+
+ export type Visitor = (input: Node, output: (node: Node) => void) => void;
+
+ export const enum VisitorFlags {
+ NewLexicalEnvironment = 1 << 1,
+ PreserveStack = 1 << 2,
+ ReturnUndefinedIfEmpty = 1 << 3,
+ }
+
export namespace transform {
+ // Flags enum to track count of temp variables and a few dedicated names
+ const enum TempFlags {
+ Auto = 0x00000000, // No preferred name
+ CountMask = 0x0FFFFFFF, // Temp variable counter
+ _i = 0x10000000, // Use/preference flag for '_i'
+ }
+
let transformationRunning: boolean;
let transformFlags: TransformFlags;
let generatedNameSet: Map;
@@ -277,10 +284,7 @@ namespace ts {
let resolver: EmitResolver;
// node stack
- let nodeStackSize: number;
- let ancestorStack: Node[];
- let parentNode: Node;
- let currentNode: Node;
+ let nodeStack: NodeStack;
// single node transform
let updatedNode: Node;
@@ -315,9 +319,8 @@ namespace ts {
generatedNameSet = _generatedNameSet;
nodeToGeneratedName = _nodeToGeneratedName;
nodeToGeneratedIdentifier = [];
- ancestorStack = [];
- nodeStackSize = 1;
- currentNode = _currentSourceFile;
+ nodeStack = createNodeStack();
+ nodeStack.pushNode(_currentSourceFile);
transformationRunning = true;
}
@@ -329,18 +332,14 @@ namespace ts {
generatedNameSet = undefined;
nodeToGeneratedName = undefined;
nodeToGeneratedIdentifier = undefined;
- ancestorStack = undefined;
- nodeStackSize = undefined;
- currentNode = undefined;
+ nodeStack = undefined;
transformationRunning = false;
}
-
-
// Return the next available name in the pattern _a ... _z, _0, _1, ...
// TempFlags._i or TempFlags._n may be used to express a preference for that dedicated name.
// Note that names generated by makeTempVariableName and makeUniqueName will never conflict.
- export function makeTempVariableName(flags: TempFlags): string {
+ function makeTempVariableName(flags: TempFlags): string {
if (flags && !(tempFlags & flags)) {
let name = flags === TempFlags._i ? "_i" : "_n";
if (isUniqueName(name)) {
@@ -458,21 +457,6 @@ namespace ts {
return makeUniqueName("class");
}
- function pushNode(node: Node): void {
- nodeStackSize++;
- if (nodeStackSize > 2) {
- ancestorStack.push(parentNode);
- }
- parentNode = currentNode;
- currentNode = node;
- }
-
- function popNode(): void {
- currentNode = parentNode;
- parentNode = nodeStackSize > 2 ? ancestorStack.pop() : undefined;
- nodeStackSize--;
- }
-
export function getEmitResolver(): EmitResolver {
return resolver;
}
@@ -481,32 +465,22 @@ namespace ts {
return compilerOptions;
}
+ export function createParentNavigator(): ParentNavigator {
+ return nodeStack.createParentNavigator();
+ }
+
export function getCurrentNode(): Node {
- return currentNode;
+ return nodeStack.getNode();
}
export function getParentNode(): Node {
- return parentNode;
+ return nodeStack.getParent();
}
- export function peekNode(offset: number): Node {
- switch (offset) {
- case 0: return currentNode;
- case 1: return parentNode;
- default: return nodeStackSize > 2 ? ancestorStack[nodeStackSize - 1 - offset] : undefined;
- }
- }
-
export function findAncestorNode(match: (node: Node) => node is T): T;
export function findAncestorNode(match: (node: Node) => boolean): Node;
export function findAncestorNode(match: (node: Node) => boolean) {
- for (let i = 1; i < nodeStackSize; i++) {
- let node = peekNode(i);
- if (match(node)) {
- return node;
- }
- }
- return undefined;
+ return nodeStack.findAncestorNode(match);
}
export function getDeclarationName(node: DeclarationStatement): Identifier;
@@ -698,12 +672,12 @@ namespace ts {
updatedNodes.push(node);
}
- function readNodeArray(returnUndefinedIfEmpty?: boolean): NodeArray {
+ function readNodeArray(flags: VisitorFlags): NodeArray {
if (updatedNodes) {
return factory.createNodeArray(updatedNodes, /*location*/ >originalNodes);
}
else if (offsetWritten !== originalNodes.length) {
- if (offsetWritten === 0 && returnUndefinedIfEmpty) {
+ if (offsetWritten === 0 && (flags & VisitorFlags.ReturnUndefinedIfEmpty)) {
return undefined;
}
else {
@@ -715,31 +689,42 @@ namespace ts {
}
}
- type Visitor = (input: Node, output: (node: Node) => void) => void;
-
- function pipeOne(input: Node, output: (node: Node) => void, visitor: Visitor): void {
- pushNode(input);
- visitor(input, output);
- popNode();
- }
-
- function pipeMany(input: Node[], output: (node: Node) => void, visitor: Visitor): void {
- // For perf reasons, we push `undefined` as the current node and set it to the correct
- // value for each iteration of the loop below. This avoids excessive push and pop
- // operations on `ancestorStack`.
- pushNode(/*node*/ undefined);
-
- // Visit each input node
- for (let i = 0, l = input.length; i < l; ++i) {
- currentNode = input[i];
- visitor(currentNode, output);
+ function pipeOne(input: Node, output: (node: Node) => void, visitor: Visitor, flags: VisitorFlags): void {
+ if (!(flags & VisitorFlags.PreserveStack)) {
+ nodeStack.pushNode(input);
+ visitor(input, output);
+ nodeStack.popNode();
+ }
+ else {
+ visitor(input, output);
}
-
- // For the perf reasons mentioned above, we pop the current node at the end of the loop.
- popNode();
}
- function pipeOneOrMany(input: T, output: (node: Node) => void, visitor: Visitor, newLexicalEnvironment: boolean, pipe: (input: T, output: (node: Node) => void, visitor: Visitor) => void): void {
+ function pipeMany(input: Node[], output: (node: Node) => void, visitor: Visitor, flags: VisitorFlags): void {
+ if (!(flags & VisitorFlags.PreserveStack)) {
+ // For perf reasons, we push `undefined` as the current node and set it to the correct
+ // value for each iteration of the loop below. This avoids excessive push and pop
+ // operations on `ancestorStack`.
+ nodeStack.pushNode(/*node*/ undefined);
+
+ // Visit each input node
+ for (let i = 0, l = input.length; i < l; ++i) {
+ let currentNode = input[i];
+ nodeStack.setNode(currentNode);
+ visitor(currentNode, output);
+ }
+
+ // For the perf reasons mentioned above, we pop the current node at the end of the loop.
+ nodeStack.popNode();
+ }
+ else {
+ for (let node of input) {
+ visitor(node, output);
+ }
+ }
+ }
+
+ function pipeOneOrMany(input: T, output: (node: Node) => void, visitor: Visitor, flags: VisitorFlags, pipe: (input: T, output: (node: Node) => void, visitor: Visitor, flags: VisitorFlags) => void): void {
if (!input) {
return;
}
@@ -751,7 +736,7 @@ namespace ts {
// If we are starting a new lexical environment, we need to reinitialize the lexical
// environment state as well
- if (newLexicalEnvironment) {
+ if (flags & VisitorFlags.NewLexicalEnvironment) {
savedTempFlags = tempFlags;
savedHoistedVariableDeclarations = hoistedVariableDeclarations;
savedHoistedFunctionDeclarations = hoistedFunctionDeclarations;
@@ -761,11 +746,11 @@ namespace ts {
hoistedFunctionDeclarations = undefined;
}
- pipe(input, output, visitor);
+ pipe(input, output, visitor, flags & ~VisitorFlags.NewLexicalEnvironment);
// If we established a new lexical environment, we need to write any hoisted variables or
// function declarations to the end of the output.
- if (newLexicalEnvironment) {
+ if (flags & VisitorFlags.NewLexicalEnvironment) {
if (hoistedVariableDeclarations) {
output(factory.createVariableStatement2(
factory.createVariableDeclarationList(
@@ -793,8 +778,8 @@ namespace ts {
* @param visitor The callback to execute as we visit each node in the source.
* @param newLexicalEnvironment A value that indicates whether this pipeline starts a new lexical environment.
*/
- export function pipeNode(input: Node, output: (node: Node) => void, visitor: Visitor, newLexicalEnvironment?: boolean): void {
- pipeOneOrMany(input, output, visitor, newLexicalEnvironment, pipeOne);
+ export function pipeNode(input: Node, output: (node: Node) => void, visitor: Visitor, flags?: VisitorFlags): void {
+ pipeOneOrMany(input, output, visitor, flags, pipeOne);
}
/**
@@ -804,11 +789,11 @@ namespace ts {
* @param visitor The callback to execute as we visit each node in the source.
* @param newLexicalEnvironment A value that indicates whether this pipeline starts a new lexical environment.
*/
- export function pipeNodes(input: Node[], output: (node: Node) => void, visitor: Visitor, newLexicalEnvironment?: boolean): void {
- pipeOneOrMany(input, output, visitor, newLexicalEnvironment, pipeMany);
+ export function pipeNodes(input: Node[], output: (node: Node) => void, visitor: Visitor, flags?: VisitorFlags): void {
+ pipeOneOrMany(input, output, visitor, flags, pipeMany);
}
- function emitOneOrMany(input: T, output: Node[], visitor: Visitor, newLexicalEnvironment: boolean, pipe: (input: T, output: (node: Node) => void, visitor: Visitor, newLexicalEnvironment: boolean) => void): void {
+ function emitOneOrMany(input: T, output: Node[], visitor: Visitor, flags: VisitorFlags, pipe: (input: T, output: (node: Node) => void, visitor: Visitor, flags: VisitorFlags) => void): void {
// Exit early if we have nothing to do
if (!input) {
return;
@@ -826,7 +811,7 @@ namespace ts {
offsetWritten = 0;
writeNodeToNodeArrayFastOrSlow = writeNodeToNodeArrayFast;
- pipe(input, writeNodeToNodeArray, visitor, newLexicalEnvironment);
+ pipe(input, writeNodeToNodeArray, visitor, flags | VisitorFlags.PreserveStack);
// Restore previous environment
originalNodes = savedOriginalNodes;
@@ -842,8 +827,8 @@ namespace ts {
* @param visitor The callback to execute as we visit each node in the source.
* @param newLexicalEnvironment A value that indicates whether this pipeline starts a new lexical environment.
*/
- export function emitNode(input: Node, output: Node[], visitor: (input: Node, write: (output: Node) => void) => void, newLexicalEnvironment?: boolean): void {
- emitOneOrMany(input, output, visitor, newLexicalEnvironment, pipeOne);
+ export function emitNode(input: Node, output: Node[], visitor: (input: Node, write: (output: Node) => void) => void, flags?: VisitorFlags): void {
+ emitOneOrMany(input, output, visitor, flags, pipeOne);
}
/**
@@ -853,13 +838,15 @@ namespace ts {
* @param visitor The callback to execute as we visit each node in the source.
* @param newLexicalEnvironment A value that indicates whether this pipeline starts a new lexical environment.
*/
- export function emitNodes(input: Node[], output: Node[], visitor: (input: Node, write: (output: Node) => void) => void, newLexicalEnvironment?: boolean): void {
- emitOneOrMany(input, output, visitor, newLexicalEnvironment, pipeMany);
+ export function emitNodes(input: Node[], output: Node[], visitor: (input: Node, write: (output: Node) => void) => void, flags?: VisitorFlags): void {
+ emitOneOrMany(input, output, visitor, flags, pipeMany);
}
- export function visitNode(node: T, visitor: (input: Node, write: (node: Node) => void) => void): T {
+ export function visitNode(node: T, visitor: (input: Node, write: (node: Node) => void) => void, flags?: VisitorFlags): T;
+ export function visitNode(node: TIn, visitor: (input: TIn, write: (node: TOut) => void) => void, flags?: VisitorFlags): TOut;
+ export function visitNode(node: TIn, visitor: (input: TIn, write: (node: TOut) => void) => void, flags?: VisitorFlags): TOut {
if (!node) {
- return node;
+ return undefined;
}
let savedUpdatedNode = updatedNode;
@@ -867,16 +854,16 @@ namespace ts {
updatedNode = undefined;
writeNodeFastOrSlow = writeNodeSlow;
- pipeNode(node, writeNode, visitor);
+ pipeNode(node, writeNode, visitor, flags);
- let visited = readNode();
+ let visited = readNode();
updatedNode = savedUpdatedNode;
writeNodeFastOrSlow = savedWriteOneNode;
return visited;
}
- export function visitStatement(node: Statement, visitor: (input: Node, write: (node: Node) => void) => void) {
+ export function visitStatement(node: Statement, visitor: (input: Node, write: (node: Node) => void) => void, flags?: VisitorFlags) {
if (!node) {
return node;
}
@@ -889,7 +876,7 @@ namespace ts {
updatedBlock = undefined;
writeStatementFastOrSlow = writeStatementSlow;
- pipeNode(node, writeStatement, visitor);
+ pipeNode(node, writeStatement, visitor, flags);
let visited = readStatement();
updatedStatement = savedUpdatedStatement;
@@ -899,10 +886,9 @@ namespace ts {
return visited;
}
- export function visitNodes(nodes: Statement[], visitor: (input: Node, output: (node: Node) => void) => void, newLexicalEnvironment: boolean): NodeArray;
- export function visitNodes(nodes: T[], visitor: (input: Node, output: (node: Node) => void) => void): NodeArray;
- export function visitNodes(nodes: TIn[], visitor: (input: TIn, output: (node: TOut) => void) => void, newLexicalEnvironment?: boolean, returnUndefinedIfEmpty?: boolean): NodeArray;
- export function visitNodes(nodes: TIn[], visitor: (input: TIn, output: (node: TOut) => void) => void, newLexicalEnvironment?: boolean, returnUndefinedIfEmpty?: boolean): NodeArray {
+ export function visitNodes(nodes: T[], visitor: (input: Node, output: (node: Node) => void) => void, flags?: VisitorFlags): NodeArray;
+ export function visitNodes(nodes: TIn[], visitor: (input: TIn, output: (node: TOut) => void) => void, flags?: VisitorFlags): NodeArray;
+ export function visitNodes(nodes: TIn[], visitor: (input: TIn, output: (node: TOut) => void) => void, flags?: VisitorFlags): NodeArray {
// Exit early if we have nothing to do
if (!nodes) {
return undefined;
@@ -921,9 +907,9 @@ namespace ts {
writeNodeToNodeArrayFastOrSlow = writeNodeToNodeArraySlow;
// Pipe each node from input into output
- pipeNodes(originalNodes, writeNodeToNodeArray, visitor, newLexicalEnvironment);
+ pipeNodes(originalNodes, writeNodeToNodeArray, visitor, flags);
- let visited = readNodeArray(returnUndefinedIfEmpty);
+ let visited = readNodeArray(flags);
// Restore previous environment
originalNodes = savedOriginalNodes;
@@ -973,13 +959,13 @@ namespace ts {
case SyntaxKind.Block:
return factory.updateBlock(
node,
- visitNodes((node).statements, visitor, /*newLexicalEnvironment*/ true)
+ visitNodes((node).statements, visitor, VisitorFlags.NewLexicalEnvironment)
);
case SyntaxKind.ModuleBlock:
return factory.updateModuleBlock(
node,
- visitNodes((node).statements, visitor, /*newLexicalEnvironment*/ true)
+ visitNodes((node).statements, visitor, VisitorFlags.NewLexicalEnvironment)
);
default:
diff --git a/src/compiler/transforms/es5.ts b/src/compiler/transforms/es5.ts
index 21e5dc434d4..b26b05ec300 100644
--- a/src/compiler/transforms/es5.ts
+++ b/src/compiler/transforms/es5.ts
@@ -2,7 +2,7 @@
/*@internal*/
namespace ts.transform {
export function toES5(statements: NodeArray) {
- return visitNodes(statements, transformNode, /*newLexicalEnvironment*/ true);
+ return visitNodes(statements, transformNode, VisitorFlags.NewLexicalEnvironment);
}
/**
@@ -153,7 +153,7 @@ namespace ts.transform {
let body = factory.createBlock([]);
if (constructor) {
- emitNode(constructor, body.statements, transformConstructor, /*newLexicalEnvironment*/ true);
+ emitNode(constructor, body.statements, transformConstructor, VisitorFlags.NewLexicalEnvironment);
}
else if (baseTypeNode) {
let superCall = createDefaultSuperCall();
@@ -453,14 +453,14 @@ namespace ts.transform {
function rewriteFunctionExpression(node: FunctionLikeDeclaration, name: Identifier, location: TextRange): FunctionExpression {
let parameters = visitNodes(node.parameters, transformNode);
let body = factory.createBlock([], node.body);
- emitNode(node, body.statements, transformFunctionBody, /*newLexicalEnvironment*/ true);
+ emitNode(node, body.statements, transformFunctionBody, VisitorFlags.NewLexicalEnvironment);
return factory.createFunctionExpression2(name, parameters, body, location);
}
function transformFunctionDeclaration(node: FunctionDeclaration, write: (node: Statement) => void): void {
let parameters = visitNodes(node.parameters, transformNode);
let body = factory.createBlock([], node.body);
- emitNode(node, body.statements, transformFunctionBody, /*newLexicalEnvironment*/ true);
+ emitNode(node, body.statements, transformFunctionBody, VisitorFlags.NewLexicalEnvironment);
write(factory.createFunctionDeclaration2(node.name, parameters, body, /*location*/ node));
}
@@ -469,7 +469,7 @@ namespace ts.transform {
let parameters = visitNodes(node.parameters, transformNode);
let newBody = factory.createBlock([], /*location*/ isBlock(node.body) ? node.body : undefined);
- emitNode(node, newBody.statements, transformFunctionBody, /*newLexicalEnvironment*/ true);
+ emitNode(node, newBody.statements, transformFunctionBody, VisitorFlags.NewLexicalEnvironment);
let func = createfn(name, parameters, newBody, location);
return func;
@@ -526,7 +526,7 @@ namespace ts.transform {
}
function transformThisKeyword(node: LeftHandSideExpression): LeftHandSideExpression {
- let container = getThisContainer(node, /*includeArrowFunctions*/ true);
+ let container = getThisContainer(transform, /*includeArrowFunctions*/ true);
if (isArrowFunction(container)) {
let thisName = factory.createIdentifier("_this");
return thisName;
diff --git a/src/compiler/transforms/es6.ts b/src/compiler/transforms/es6.ts
index ee725760316..c04cd7d607a 100644
--- a/src/compiler/transforms/es6.ts
+++ b/src/compiler/transforms/es6.ts
@@ -9,7 +9,7 @@ namespace ts.transform {
resolver = getEmitResolver();
compilerOptions = getCompilerOptions();
languageVersion = compilerOptions.target || ScriptTarget.ES3;
- return visitNodes(statements, transformNode, /*newLexicalEnvironment*/ true);
+ return visitNodes(statements, transformNode, VisitorFlags.NewLexicalEnvironment);
}
/**
@@ -74,24 +74,6 @@ namespace ts.transform {
}
switch (node.kind) {
- // case SyntaxKind.Block:
- // case SyntaxKind.ModuleBlock:
- // case SyntaxKind.CaseClause:
- // case SyntaxKind.DefaultClause:
- // // These nodes contain statement lists which may need to be expanded to include multiple statements...
- // // See NodeArraywrite in transform.ts for approach
-
- // case SyntaxKind.DoStatement:
- // case SyntaxKind.WhileStatement:
- // case SyntaxKind.ForStatement:
- // case SyntaxKind.ForInStatement:
- // case SyntaxKind.ForOfStatement:
- // case SyntaxKind.IfStatement:
- // case SyntaxKind.LabeledStatement:
- // case SyntaxKind.WithStatement:
- // // These nodes contain single statement nodes that may need to be switched to a block if a child node needs multiple statements...
- // // See Statementwrite in transform.ts for approach
-
case SyntaxKind.PublicKeyword:
case SyntaxKind.PrivateKeyword:
case SyntaxKind.ProtectedKeyword:
@@ -100,6 +82,7 @@ namespace ts.transform {
case SyntaxKind.ConstKeyword:
case SyntaxKind.DeclareKeyword:
// TypeScript accessibility modifiers are elided.
+ return;
case SyntaxKind.ArrayType:
case SyntaxKind.TupleType:
@@ -118,31 +101,37 @@ namespace ts.transform {
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
// TypeScript type nodes are elided.
+ return;
case SyntaxKind.IndexSignature:
// TypeScript index signatures are elided.
+ return;
case SyntaxKind.Decorator:
// TypeScript decorators are elided. They will be emitted as part of transformClassDeclaration.
+ return;
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.TypeAliasDeclaration:
// TypeScript type-only declarations are elided
+ return;
case SyntaxKind.PropertyDeclaration:
// TypeScript property declarations are elided.
+ return;
case SyntaxKind.IndexSignature:
// TypeScript index signatures are elided.
+ return;
case SyntaxKind.Constructor:
// TypeScript constructors are elided. The constructor of a class will be
// reordered to the start of the member list in `transformClassDeclaration`.
+ return;
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.TypeAliasDeclaration:
// TypeScript interfaces and type aliases are elided.
-
return;
case SyntaxKind.ClassDeclaration:
@@ -233,9 +222,9 @@ namespace ts.transform {
// TypeScript 'await' expressions must be transformed.
return transformAwaitExpression(node, write);
- // case SyntaxKind.VariableStatement:
- // // TypeScript namespace exports for variable statements must be transformed.
- // return transformVariableStatement(node, write);
+ case SyntaxKind.VariableStatement:
+ // TypeScript namespace exports for variable statements must be transformed.
+ return transformVariableStatement(node, write);
case SyntaxKind.ModuleDeclaration:
// TypeScript namespace declarations must be transformed.
@@ -362,7 +351,7 @@ namespace ts.transform {
let name = getDeclarationName(node);
Debug.assert(isIdentifier(name));
- if (getCombinedNodeFlags(node) & NodeFlags.Export) {
+ if (getCombinedNodeFlags(transform) & NodeFlags.Export) {
let container = getContainingModuleName();
let propExpr = factory.createPropertyAccessExpression2(container, name);
return propExpr;
@@ -788,16 +777,27 @@ namespace ts.transform {
}
function transformVariableDeclarationList(node: VariableDeclarationList, write: (node: Statement) => void) {
- let expressions = visitNodes(node.declarations, transformVariableDeclaration, /*newLexicalEnvironment*/ false, /*returnUndefinedIfEmpty*/ true);
- if (expressions) {
+ let expressions: Expression[] = [];
+ emitNodes(node.declarations, expressions, transformVariableDeclaration);
+
+ if (expressions.length) {
let exprStmt = factory.createExpressionStatement(factory.inlineExpressions(expressions));
write(exprStmt);
}
}
function transformVariableDeclaration(node: VariableDeclaration, write: (node: Expression) => void) {
- if (isBindingPattern(node.name)) {
- Debug.fail("Transform not yet supported.");
+ if (!node.initializer) {
+ return;
+ }
+
+ let name = node.name;
+ if (isBindingPattern(name)) {
+ let expr = visitNode(name, transformBindingPatternToExpression);
+ let initializer = visitNode(node.initializer, transformNode);
+ let assignExpr = factory.createAssignmentExpression(expr, initializer);
+ let parenExpr = factory.createParenthesizedExpression(assignExpr);
+ write(parenExpr);
}
else {
let name = getModuleMemberName(node);
@@ -806,6 +806,27 @@ namespace ts.transform {
write(assignExpr);
}
}
+
+ function transformBindingPatternToExpression(node: BindingPattern, write: (node: Expression) => void) {
+ switch (node.kind) {
+ case SyntaxKind.ObjectBindingPattern:
+ return transformObjectBindingPatternToExpression(node, write);
+
+ case SyntaxKind.ArrayBindingPattern:
+ return transformArrayBindingPatternToExpression(node, write);
+ }
+ }
+
+ function transformObjectBindingPatternToExpression(node: ObjectBindingPattern, write: (node: Expression) => void) {
+ let properties: ObjectLiteralElement[] = [];
+
+ write(factory.createObjectLiteralExpression2(properties));
+ }
+
+ function transformArrayBindingPatternToExpression(node: ArrayBindingPattern, write: (node: Expression) => void) {
+ let elements: Expression[] = [];
+ write(factory.createArrayLiteralExpression(elements));
+ }
function transformModuleDeclaration(node: ModuleDeclaration, write: (node: Statement) => void) {
if (!shouldEmitModuleDeclaration(node)) {
diff --git a/src/compiler/types.ts b/src/compiler/types.ts
index d6323e42d03..513b1d80be1 100644
--- a/src/compiler/types.ts
+++ b/src/compiler/types.ts
@@ -1830,8 +1830,10 @@ namespace ts {
}
// Source files are declarations when they are external modules.
- // @kind(SyntaxKind.SourceFile)
- // @factoryhidden
+ // @kind(SyntaxKind.SourceFile, { create: false, update: false })
+ // @factoryhidden("decorators")
+ // @factoryhidden("modifiers")
+ // @factoryhidden("name")
export interface SourceFile extends Declaration {
statements: NodeArray;
endOfFileToken: Node;
@@ -1861,6 +1863,7 @@ namespace ts {
languageVersion: ScriptTarget;
// The first node that causes this file to be an external module
+ // @factoryhidden
/* @internal */ externalModuleIndicator: Node;
/* @internal */ isDefaultLib: boolean;
diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts
index 3fa30cddb18..a5f52303230 100644
--- a/src/compiler/utilities.ts
+++ b/src/compiler/utilities.ts
@@ -391,7 +391,7 @@ namespace ts {
return flags;
}
-
+
export function isConst(navigable: ParentNavigable): boolean {
return !!(getCombinedNodeFlags(navigable) & NodeFlags.Const);
}
@@ -717,7 +717,7 @@ namespace ts {
break;
case SyntaxKind.Decorator:
// Decorators are always applied outside of the body of a class or method.
- if (nav.getParent().kind === SyntaxKind.Parameter && isClassElement(nav.getGrandparent())) {
+ if (isParameter(nav.getParent()) && isClassElement(nav.getGrandparent())) {
// If the decorator's parent is a Parameter, we resolve the this container from
// the grandparent class declaration.
nav.moveToParent();
@@ -773,7 +773,8 @@ namespace ts {
break;
case SyntaxKind.Decorator:
// Decorators are always applied outside of the body of a class or method.
- if (nav.getParent().kind === SyntaxKind.Parameter && isClassElement(nav.getGrandparent())) {
+ if (isParameter(nav.getParent())
+ && isClassElement(nav.getGrandparent())) {
// If the decorator's parent is a Parameter, we resolve the this container from
// the grandparent class declaration.
nav.moveToParent();
diff --git a/src/services/services.ts b/src/services/services.ts
index 27bc4ae36cb..cb5860d8c9f 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -225,7 +225,7 @@ namespace ts {
public getText(sourceFile?: SourceFile): string {
return (sourceFile || this.getSourceFile()).text.substring(this.getStart(), this.getEnd());
}
-
+
private addSyntheticNodes(nodes: Node[], pos: number, end: number): number {
scanner.setTextPos(pos);
while (pos < end) {