Fixed issue with transform flag computation in binder, and emitTokenText when the position is synthesized.

This commit is contained in:
Ron Buckton 2015-09-14 13:34:42 -07:00
parent dd998b981f
commit 36fad618f6
8 changed files with 636 additions and 583 deletions

View file

@ -101,7 +101,7 @@ namespace ts {
let symbolCount = 0;
let Symbol = objectAllocator.getSymbolConstructor();
let classifiableNames: Map<string> = {};
let transformFlags: TransformFlags;
let subtreeTransformFlags: TransformFlags;
let skipTransformFlagAggregation: boolean;
if (!file.locals) {
@ -817,10 +817,10 @@ namespace ts {
function aggregateTransformFlagsAnd<T>(cbNode: (node: Node) => T, node: Node): T {
if (!skipTransformFlagAggregation) {
let saveTransformFlags = transformFlags;
transformFlags = 0;
let savedSubtreeTransformFlags = subtreeTransformFlags;
subtreeTransformFlags = 0;
let result = cbNode(node);
transformFlags = saveTransformFlags | computeTransformFlagsForNode(node, transformFlags);
subtreeTransformFlags = savedSubtreeTransformFlags | (computeTransformFlagsForNode(node, subtreeTransformFlags) & ~TransformFlags.NodeExcludes);
return result;
}

View file

@ -203,6 +203,21 @@ namespace ts {
return result;
}
export function skip<T>(array: T[], count: number) {
if (array) {
return count === 0 ? array : array.slice(count);
}
return undefined;
}
export function take<T>(array: T[], count: number) {
if (array) {
return count === array.length ? array : array.slice(0, count);
}
return undefined;
}
export function append<T>(to: T[], ...values: T[]): T[] {
let result: T[];
if (to) {

View file

@ -512,7 +512,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
return tokenEndPos;
}
else {
emitTokenText(tokenKind, startPos, emitFn);
return emitTokenText(tokenKind, startPos, emitFn);
}
}
@ -799,7 +799,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
else {
write(tokenString);
}
return startPos + tokenString.length;
return positionIsSynthesized(startPos) ? -1 : startPos + tokenString.length;
}
function emitOptional(prefix: string, node: Node) {
@ -5038,7 +5038,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
}
function emitClassLikeDeclarationBelowES6(node: ClassLikeDeclaration) {
Debug.assert(!compilerOptions.experimentalTransforms, "This function should not be called when using '--experimentalTransforms'.");
// Debug.assert(!compilerOptions.experimentalTransforms, "This function should not be called when using '--experimentalTransforms'.");
verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node);
if (node.kind === SyntaxKind.ClassDeclaration) {
@ -5723,7 +5723,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
}
function emitEnumDeclaration(node: EnumDeclaration) {
Debug.assert(!compilerOptions.experimentalTransforms, "This function should not be called when using '--experimentalTransforms'.");
// Debug.assert(!compilerOptions.experimentalTransforms, "This function should not be called when using '--experimentalTransforms'.");
verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node);
// const enums are completely erased during compilation.
@ -5845,7 +5845,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
}
function emitModuleDeclaration(node: ModuleDeclaration) {
Debug.assert(!compilerOptions.experimentalTransforms, "This function should not be called when using '--experimentalTransforms'.");
// Debug.assert(!compilerOptions.experimentalTransforms, "This function should not be called when using '--experimentalTransforms'.");
verifyStackBehavior(StackBehavior.NodeIsOnTopOfStack, node);

View file

@ -7,409 +7,407 @@ namespace ts {
return nodeConstructors[kind] || (nodeConstructors[kind] = objectAllocator.getNodeConstructor(kind));
}
// export function createNode<T extends Node>(kind: SyntaxKind): T {
// return createNode<T>(kind);
// }
export function setNodeFlags<T extends Node>(node: T, flags: NodeFlags): T {
if (!node || flags === undefined) {
return node;
}
node.flags = flags;
return node;
}
export function setTextRange<T extends TextRange>(node: T, range: TextRange): T {
if (!node || !range) {
return node;
}
node.pos = range.pos;
node.end = range.end;
return node;
}
export function setModifiers<T extends Node>(node: T, modifiers: Node[]): T {
if (modifiers) {
node.modifiers = createModifiersArray(modifiers);
node.flags |= node.modifiers.flags;
}
return node;
}
// // @internal
// export namespace factory {
export function setNodeFlags<T extends Node>(node: T, flags: NodeFlags): T {
if (!node || flags === undefined) {
return node;
}
export function setOriginalNode<T extends Node>(node: T, original: Node): T {
node.original = node;
return node;
}
export function attachCommentRanges<T extends Node>(node: T, leadingCommentRanges: CommentRange[], trailingCommentRanges?: CommentRange[]): T {
(<SynthesizedNode>node).leadingCommentRanges = leadingCommentRanges;
(<SynthesizedNode>node).trailingCommentRanges = trailingCommentRanges;
return node;
}
export function startOnNewLine<T extends Node>(node: T): T {
(<SynthesizedNode>node).startsOnNewLine = true;
return node;
}
export function updateFrom<T extends Node>(oldNode: T, newNode: T): T {
let flags = oldNode.flags;
if (oldNode.modifiers) {
flags &= ~oldNode.modifiers.flags;
}
if (newNode.modifiers) {
flags |= newNode.modifiers.flags;
}
newNode.flags = flags;
newNode.original = oldNode;
newNode.pos = oldNode.pos;
newNode.end = oldNode.end;
//mergeCommentRanges(oldNode, newNode);
return newNode;
}
function mergeCommentRanges(oldNode: Node, newNode: Node) {
if ((<SynthesizedNode>oldNode).leadingCommentRanges && !(<SynthesizedNode>newNode).leadingCommentRanges) {
(<SynthesizedNode>newNode).leadingCommentRanges = (<SynthesizedNode>oldNode).leadingCommentRanges;
}
if ((<SynthesizedNode>oldNode).trailingCommentRanges && !(<SynthesizedNode>newNode).trailingCommentRanges) {
(<SynthesizedNode>newNode).trailingCommentRanges = (<SynthesizedNode>oldNode).trailingCommentRanges;
}
}
export function cloneNodeArray<T extends Node>(array: NodeArray<T>): NodeArray<T> {
return array ? createNodeArray(array.slice(0), /*location*/ array) : undefined;
}
export function createNode<T extends Node>(kind: SyntaxKind, location?: TextRange, flags?: NodeFlags): T {
let node = <T>new (getNodeConstructor(kind))();
if (location) {
node.pos = location.pos;
node.end = location.end;
}
if (flags) {
node.flags = flags;
return node;
}
export function setTextRange<T extends TextRange>(node: T, range: TextRange): T {
if (!node || !range) {
return node;
}
node.pos = range.pos;
node.end = range.end;
return node;
return node;
}
export function createNodeArray<T extends Node>(elements?: T[], location?: TextRange) {
let nodes = <NodeArray<T>>(elements || []);
if (location) {
nodes.pos = location.pos;
nodes.end = location.end;
}
else if (nodes.pos === undefined) {
nodes.pos = -1;
nodes.end = -1;
}
export function setModifiers<T extends Node>(node: T, modifiers: Node[]): T {
if (modifiers) {
node.modifiers = createModifiersArray(modifiers);
node.flags |= node.modifiers.flags;
}
return node;
}
export function attachCommentRanges<T extends Node>(node: T, leadingCommentRanges: CommentRange[], trailingCommentRanges?: CommentRange[]): T {
(<SynthesizedNode>node).leadingCommentRanges = leadingCommentRanges;
(<SynthesizedNode>node).trailingCommentRanges = trailingCommentRanges;
return node;
}
return nodes;
}
export function startOnNewLine<T extends Node>(node: T): T {
(<SynthesizedNode>node).startsOnNewLine = true;
return node;
}
export function updateFrom<T extends Node>(oldNode: T, newNode: T): T {
let flags = oldNode.flags;
if (oldNode.modifiers) {
flags &= ~oldNode.modifiers.flags;
}
if (newNode.modifiers) {
flags |= newNode.modifiers.flags;
}
newNode.flags = flags;
newNode.original = oldNode;
newNode.pos = oldNode.pos;
newNode.end = oldNode.end;
//mergeCommentRanges(oldNode, newNode);
return newNode;
}
function mergeCommentRanges(oldNode: Node, newNode: Node) {
if ((<SynthesizedNode>oldNode).leadingCommentRanges && !(<SynthesizedNode>newNode).leadingCommentRanges) {
(<SynthesizedNode>newNode).leadingCommentRanges = (<SynthesizedNode>oldNode).leadingCommentRanges;
}
if ((<SynthesizedNode>oldNode).trailingCommentRanges && !(<SynthesizedNode>newNode).trailingCommentRanges) {
(<SynthesizedNode>newNode).trailingCommentRanges = (<SynthesizedNode>oldNode).trailingCommentRanges;
}
}
export function cloneNodeArray<T extends Node>(array: NodeArray<T>): NodeArray<T> {
return array ? createNodeArray(array.slice(0), /*location*/ array) : undefined;
}
export function createNode<T extends Node>(kind: SyntaxKind, location?: TextRange, flags?: NodeFlags): T {
let node = <T>new (getNodeConstructor(kind))();
if (location) {
node.pos = location.pos;
node.end = location.end;
}
if (flags) {
node.flags = flags;
}
return node;
}
export function createNodeArray<T extends Node>(elements?: T[], location?: TextRange) {
let nodes = <NodeArray<T>>(elements || []);
if (location) {
nodes.pos = location.pos;
nodes.end = location.end;
}
else if (nodes.pos === undefined) {
nodes.pos = -1;
nodes.end = -1;
}
return nodes;
}
export function createModifiersArray(elements?: Node[], location?: TextRange) {
let modifiers = <ModifiersArray>createNodeArray(elements || [], location);
if (modifiers.flags === undefined) {
let flags = 0;
for (let modifier of modifiers) {
flags |= modifierToFlag(modifier.kind);
}
modifiers.flags = flags;
}
return modifiers;
}
// export function createSourceFileNode(): SourceFile {
// let node = <SourceFile>createNode(SyntaxKind.SourceFile);
// return node;
// }
// export function updateSourceFileNode(node: SourceFile, statements: NodeArray<Statement>, endOfFileToken: Node): SourceFile {
// if (statements !== node.statements || endOfFileToken !== node.endOfFileToken) {
// let newNode = createNode<SourceFile>(SyntaxKind.SourceFile);
// newNode.statements = statements;
// newNode.endOfFileToken = endOfFileToken;
// return updateFrom(node, newNode);
// }
// return node;
// }
export function createNumericLiteral2(value: number, location?: TextRange, flags?: NodeFlags): LiteralExpression {
let node = createNumericLiteral(String(value), location, flags);
return node;
}
export function createPropertyAccessExpression2(expression: Expression, name: Identifier, location?: TextRange, flags?: NodeFlags) {
return createPropertyAccessExpression(parenthesizeForAccess(expression), createNode(SyntaxKind.DotToken), name, location, flags);
}
export function createPropertyAccessExpression3(expression: Expression, name: string, location?: TextRange, flags?: NodeFlags) {
return createPropertyAccessExpression(parenthesizeForAccess(expression), createNode(SyntaxKind.DotToken), createIdentifier(name), location, flags);
}
export function makeSynthesized<TNode extends Node>(node: TNode): TNode {
return nodeIsSynthesized(node) ? node : cloneNode(node);
}
export function parenthesizeForBinary(expr: Expression, operator: SyntaxKind) {
// When diagnosing whether the expression needs parentheses, the decision should be based
// on the innermost expression in a chain of nested type assertions.
while (expr.kind === SyntaxKind.TypeAssertionExpression || expr.kind === SyntaxKind.AsExpression) {
expr = (<AssertionExpression>expr).expression;
}
// If the resulting expression is already parenthesized, we do not need to do any further processing.
if (isParenthesizedExpression(expr)) {
return expr;
}
let exprPrecedence = getExpressionPrecedence(expr);
let operatorPrecedence = getBinaryOperatorPrecedence(operator);
if (exprPrecedence < operatorPrecedence) {
// lower precedence, the expression needs parenthesis
return createParenthesizedExpression(expr);
}
else {
// higher precedence.
return expr;
}
}
export function parenthesizeForAccess(expr: Expression): LeftHandSideExpression {
// When diagnosing whether the expression needs parentheses, the decision should be based
// on the innermost expression in a chain of nested type assertions.
while (expr.kind === SyntaxKind.TypeAssertionExpression || expr.kind === SyntaxKind.AsExpression) {
expr = (<AssertionExpression>expr).expression;
export function createModifiersArray(elements?: Node[], location?: TextRange) {
let modifiers = <ModifiersArray>createNodeArray(elements || [], location);
if (modifiers.flags === undefined) {
let flags = 0;
for (let modifier of modifiers) {
flags |= modifierToFlag(modifier.kind);
}
// isLeftHandSideExpression is almost the correct criterion for when it is not necessary
// to parenthesize the expression before a dot. The known exceptions are:
//
// NewExpression:
// new C.x -> not the same as (new C).x
// NumberLiteral
// 1.x -> not the same as (1).x
//
if (isLeftHandSideExpression(expr) &&
expr.kind !== SyntaxKind.NewExpression &&
expr.kind !== SyntaxKind.NumericLiteral) {
modifiers.flags = flags;
}
return <LeftHandSideExpression>expr;
}
return modifiers;
}
// export function createSourceFileNode(): SourceFile {
// let node = <SourceFile>createNode(SyntaxKind.SourceFile);
// return node;
// }
// export function updateSourceFileNode(node: SourceFile, statements: NodeArray<Statement>, endOfFileToken: Node): SourceFile {
// if (statements !== node.statements || endOfFileToken !== node.endOfFileToken) {
// let newNode = createNode<SourceFile>(SyntaxKind.SourceFile);
// newNode.statements = statements;
// newNode.endOfFileToken = endOfFileToken;
// return updateFrom(node, newNode);
// }
// return node;
// }
export function createNumericLiteral2(value: number, location?: TextRange, flags?: NodeFlags): LiteralExpression {
let node = createNumericLiteral(String(value), location, flags);
return node;
}
export function createPropertyAccessExpression2(expression: Expression, name: Identifier, location?: TextRange, flags?: NodeFlags) {
return createPropertyAccessExpression(parenthesizeForAccess(expression), createNode(SyntaxKind.DotToken), name, location, flags);
}
export function createPropertyAccessExpression3(expression: Expression, name: string, location?: TextRange, flags?: NodeFlags) {
return createPropertyAccessExpression(parenthesizeForAccess(expression), createNode(SyntaxKind.DotToken), createIdentifier(name), location, flags);
}
export function makeSynthesized<TNode extends Node>(node: TNode): TNode {
return nodeIsSynthesized(node) ? node : cloneNode(node);
}
export function parenthesizeForBinary(expr: Expression, operator: SyntaxKind) {
// When diagnosing whether the expression needs parentheses, the decision should be based
// on the innermost expression in a chain of nested type assertions.
while (expr.kind === SyntaxKind.TypeAssertionExpression || expr.kind === SyntaxKind.AsExpression) {
expr = (<AssertionExpression>expr).expression;
}
// If the resulting expression is already parenthesized, we do not need to do any further processing.
if (isParenthesizedExpression(expr)) {
return expr;
}
let exprPrecedence = getExpressionPrecedence(expr);
let operatorPrecedence = getBinaryOperatorPrecedence(operator);
if (exprPrecedence < operatorPrecedence) {
// lower precedence, the expression needs parenthesis
return createParenthesizedExpression(expr);
}
else {
// higher precedence.
return expr;
}
}
export function createCallExpression2(expression: Expression, _arguments?: Expression[], location?: TextRange, flags?: NodeFlags) {
return createCallExpression(parenthesizeForAccess(expression), undefined, _arguments, location, flags);
}
export function createObjectLiteralExpression2(properties?: ObjectLiteralElement[]) {
return createObjectLiteralExpression(undefined, undefined, createNodeArray(properties));
}
export function createAssignmentExpression(left: Expression, right: Expression) {
return createBinaryExpression2(left, SyntaxKind.EqualsToken, right);
}
export function createStrictEqualityExpression(left: Expression, right: Expression) {
return createBinaryExpression2(left, SyntaxKind.EqualsEqualsEqualsToken, right);
}
export function createStrictInequalityExpression(left: Expression, right: Expression) {
return createBinaryExpression2(left, SyntaxKind.ExclamationEqualsEqualsToken, right);
}
export function createLogicalAndExpression(left: Expression, right: Expression) {
return createBinaryExpression2(left, SyntaxKind.AmpersandAmpersandToken, right);
}
export function createLogicalOrExpression(left: Expression, right: Expression) {
return createBinaryExpression2(left, SyntaxKind.BarBarToken, right);
}
export function createCommaExpression(left: Expression, right: Expression) {
return createBinaryExpression2(left, SyntaxKind.CommaToken, right);
export function parenthesizeForAccess(expr: Expression): LeftHandSideExpression {
// When diagnosing whether the expression needs parentheses, the decision should be based
// on the innermost expression in a chain of nested type assertions.
while (expr.kind === SyntaxKind.TypeAssertionExpression || expr.kind === SyntaxKind.AsExpression) {
expr = (<AssertionExpression>expr).expression;
}
export function createBinaryExpression2(left: Expression, operator: SyntaxKind, right: Expression) {
return createBinaryExpression(parenthesizeForBinary(left, operator), createNode(operator), parenthesizeForBinary(right, operator));
}
export function createConditionalExpression2(condition: Expression, whenTrue: Expression, whenFalse: Expression, location?: TextRange, flags?: NodeFlags) {
return createConditionalExpression(condition, createNode(SyntaxKind.QuestionToken), whenTrue, createNode(SyntaxKind.ColonToken), whenFalse, location, flags);
}
export function createParameter2(name: BindingPattern | Identifier, initializer?: Expression, location?: TextRange, flags?: NodeFlags) {
return createParameter(undefined, undefined, undefined, name, undefined, undefined, initializer, location, flags);
}
export function createRestParameter(name: Identifier, location?: TextRange, flags?: NodeFlags) {
return createParameter(undefined, undefined, createNode(SyntaxKind.DotDotDotToken), name, undefined, undefined, undefined, location, flags);
}
export function createVariableDeclaration2(name: Identifier | BindingPattern, initializer?: Expression, location?: TextRange, flags?: NodeFlags) {
return createVariableDeclaration(name, undefined, initializer, location, flags);
}
export function createVariableStatement2(declarationList: VariableDeclarationList, location?: TextRange, flags?: NodeFlags) {
return createVariableStatement(undefined, undefined, declarationList, location, flags);
}
export function createSimpleLetStatement(name: Identifier, initializer: Expression, location?: TextRange, exported?: boolean) {
let varDecl = createVariableDeclaration2(name, initializer);
let varDeclList = createVariableDeclarationList([varDecl], undefined, NodeFlags.Let);
let varStmt = createVariableStatement2(varDeclList, location, exported ? NodeFlags.Export : 0);
return varStmt;
}
export function createExportDefaultStatement(expression: Expression): ExportAssignment {
return createExportAssignment(undefined, undefined, expression);
}
function createClassHeritageClauses(baseTypeNode: ExpressionWithTypeArguments) {
return baseTypeNode ? [createHeritageClause(SyntaxKind.ExtendsKeyword, [baseTypeNode])] : undefined;
// isLeftHandSideExpression is almost the correct criterion for when it is not necessary
// to parenthesize the expression before a dot. The known exceptions are:
//
// NewExpression:
// new C.x -> not the same as (new C).x
// NumberLiteral
// 1.x -> not the same as (1).x
//
if (isLeftHandSideExpression(expr) &&
expr.kind !== SyntaxKind.NewExpression &&
expr.kind !== SyntaxKind.NumericLiteral) {
return <LeftHandSideExpression>expr;
}
export function createClassDeclaration2(name: Identifier, baseTypeNode: ExpressionWithTypeArguments, members: ClassElement[], location?: TextRange, flags?: NodeFlags): ClassDeclaration {
return createClassDeclaration(undefined, undefined, name, undefined, createClassHeritageClauses(baseTypeNode), members, location, flags);
}
return createParenthesizedExpression(expr);
}
export function createClassExpression2(name: Identifier, baseTypeNode: ExpressionWithTypeArguments, members: ClassElement[]): ClassExpression {
return createClassExpression(undefined, undefined, name, undefined, createClassHeritageClauses(baseTypeNode), members);
}
export function createCallExpression2(expression: Expression, _arguments?: Expression[], location?: TextRange, flags?: NodeFlags) {
return createCallExpression(parenthesizeForAccess(expression), undefined, _arguments, location, flags);
}
export function createClassExpression3(baseTypeNode: ExpressionWithTypeArguments, members: ClassElement[]): ClassExpression {
return createClassExpression2(undefined, baseTypeNode, members);
}
export function createConstructor2(parameters: Array<ParameterDeclaration>, body: Block, location?: TextRange, flags?: NodeFlags): ConstructorDeclaration {
return createConstructor(undefined, undefined, parameters, undefined, body, location, flags);
}
export function createObjectLiteralExpression2(properties?: ObjectLiteralElement[]) {
return createObjectLiteralExpression(undefined, undefined, createNodeArray(properties));
}
export function createMethodDeclaration2(name: PropertyName, parameters: Array<ParameterDeclaration>, body: Block, location?: TextRange, flags?: NodeFlags): MethodDeclaration {
return createMethodDeclaration(undefined, undefined, undefined, name, undefined, parameters, undefined, body, location, flags);
}
export function createAssignmentExpression(left: Expression, right: Expression) {
return createBinaryExpression2(left, SyntaxKind.EqualsToken, right);
}
export function createGetAccessor2(name: PropertyName, parameters: Array<ParameterDeclaration>, body: Block, location?: TextRange, flags?: NodeFlags): GetAccessorDeclaration {
return createGetAccessor(undefined, undefined, name, parameters, undefined, body, location, flags);
}
export function createStrictEqualityExpression(left: Expression, right: Expression) {
return createBinaryExpression2(left, SyntaxKind.EqualsEqualsEqualsToken, right);
}
export function createSetAccessor2(name: PropertyName, parameters: Array<ParameterDeclaration>, body: Block, location?: TextRange, flags?: NodeFlags): SetAccessorDeclaration {
return createSetAccessor(undefined, undefined, name, parameters, undefined, body, location, flags);
}
export function createFunctionDeclaration2(name: Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange, flags?: NodeFlags) {
return createFunctionDeclaration(undefined, undefined, undefined, name, undefined, parameters, undefined, body, location, flags);
}
export function createFunctionDeclaration3(asteriskToken: Node, name: Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange, flags?: NodeFlags) {
return createFunctionDeclaration(undefined, undefined, asteriskToken, name, undefined, parameters, undefined, body, location, flags);
}
export function createFunctionExpression2(name: Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange, flags?: NodeFlags) {
return createFunctionExpression(undefined, undefined, undefined, name, undefined, parameters, undefined, body, location, flags);
}
export function createFunctionExpression3(asteriskToken: Node, name: Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange, flags?: NodeFlags) {
return createFunctionExpression(undefined, undefined, asteriskToken, name, undefined, parameters, undefined, body, location, flags);
}
export function createArrowFunction2(parameters: ParameterDeclaration[], body: Block | Expression, location?: TextRange, flags?: NodeFlags) {
return createArrowFunction(undefined, undefined, undefined, parameters, undefined, createNode(SyntaxKind.EqualsGreaterThanToken), body, location, flags);
}
export function createStrictInequalityExpression(left: Expression, right: Expression) {
return createBinaryExpression2(left, SyntaxKind.ExclamationEqualsEqualsToken, right);
}
export function createGeneratorFunctionExpression(parameters: ParameterDeclaration[], body: Block, location?: TextRange, flags?: NodeFlags) {
return createFunctionExpression(undefined, undefined, createNode(SyntaxKind.AsteriskToken), undefined, undefined, parameters, undefined, body, location, flags);
}
export function createVoidZeroExpression(location?: TextRange, flags?: NodeFlags): VoidExpression {
return createVoidExpression(createNumericLiteral2(0), location, flags);
}
export function createPropertyOrElementAccessExpression(expression: Expression, propName: Identifier | LiteralExpression, location?: TextRange, flags?: NodeFlags): LeftHandSideExpression {
return isIdentifier(propName)
? createPropertyAccessExpression2(expression, makeSynthesized(propName), location, flags)
: createElementAccessExpression2(expression, makeSynthesized(propName), location, flags);
}
export function createElementAccessExpression2(expression: Expression, argumentExpression: Expression, location?: TextRange, flags?: NodeFlags): ElementAccessExpression {
return createElementAccessExpression(parenthesizeForAccess(expression), argumentExpression, location, flags);
}
export function createLogicalAndExpression(left: Expression, right: Expression) {
return createBinaryExpression2(left, SyntaxKind.AmpersandAmpersandToken, right);
}
export function createElementAccessExpression3(expression: Expression, index: number, location?: TextRange, flags?: NodeFlags): ElementAccessExpression {
return createElementAccessExpression2(expression, createNumericLiteral2(index), location, flags);
}
export function createLogicalOrExpression(left: Expression, right: Expression) {
return createBinaryExpression2(left, SyntaxKind.BarBarToken, right);
}
export function createSliceCall(value: Expression, sliceIndex: number, location?: TextRange, flags?: NodeFlags): CallExpression {
return createCallExpression2(createPropertyAccessExpression3(value, "slice"), [createNumericLiteral2(sliceIndex)], location, flags);
}
export function createApplyCall(target: Expression, thisArg: Expression, _arguments: Expression, location?: TextRange, flags?: NodeFlags) {
return createCallExpression2(createPropertyAccessExpression3(target, "apply"), [thisArg, _arguments], location, flags);
}
export function createCommaExpression(left: Expression, right: Expression) {
return createBinaryExpression2(left, SyntaxKind.CommaToken, right);
}
export function createExtendsHelperCall(name: Identifier) {
return createCallExpression2(createIdentifier("__extends"), [name, createIdentifier("_super")]);
}
export function createAwaiterHelperCall(hasLexicalArguments: boolean, promiseConstructor: EntityName | Expression, body: Block) {
let argumentsExpr = hasLexicalArguments ? createIdentifier("arguments") : createVoidZeroExpression();
let promiseExpr = promiseConstructor ? convertEntityNameToExpression(promiseConstructor) : createIdentifier("Promise");
return createCallExpression2(createIdentifier("__awaiter"), [createThisKeyword(), argumentsExpr, promiseExpr, createGeneratorFunctionExpression([], body)]);
}
function convertEntityNameToExpression(node: EntityName | Expression): Expression {
return isQualifiedName(node) ? createPropertyAccessExpression2(convertEntityNameToExpression(node.left), cloneNode(node.right)) : cloneNode(node);
}
export function createDecorateHelperCall(decoratorExpressions: Expression[], target: Expression, memberName?: Expression, descriptor?: Expression) {
return createCallExpression2(createIdentifier("__decorate"), append([createArrayLiteralExpression(decoratorExpressions), target], memberName, descriptor));
}
export function createParamHelperCall(parameterIndex: number, decoratorExpression: Expression) {
return createCallExpression2(createIdentifier("__param"), [createNumericLiteral2(parameterIndex), decoratorExpression]);
}
export function createMetadataHelperCall(metadataKey: string, metadataValue: Expression) {
return createCallExpression2(createIdentifier("__metadata"), [createStringLiteral(metadataKey), metadataValue]);
}
export function createBinaryExpression2(left: Expression, operator: SyntaxKind, right: Expression) {
return createBinaryExpression(parenthesizeForBinary(left, operator), createNode(operator), parenthesizeForBinary(right, operator));
}
export function createDefinePropertyCall(target: Expression, memberName: Expression, descriptor: Expression) {
return createCallExpression2(createPropertyAccessExpression3(createIdentifier("Object"), "defineProperty"), [target, memberName, descriptor]);
}
export function createGetOwnPropertyDescriptorCall(target: Expression, memberName: Expression) {
return createCallExpression2(createPropertyAccessExpression3(createIdentifier("Object"), "getOwnPropertyDescriptor"), [target, memberName]);
}
export function createDefaultValueCheck(value: Expression, defaultValue: Expression, ensureIdentifier: (value: Expression) => Expression, location?: TextRange, flags?: NodeFlags): Expression {
// The value expression will be evaluated twice, so for anything but a simple identifier
// we need to generate a temporary variable
value = ensureIdentifier(value);
export function createConditionalExpression2(condition: Expression, whenTrue: Expression, whenFalse: Expression, location?: TextRange, flags?: NodeFlags) {
return createConditionalExpression(condition, createNode(SyntaxKind.QuestionToken), whenTrue, createNode(SyntaxKind.ColonToken), whenFalse, location, flags);
}
export function createParameter2(name: BindingPattern | Identifier, initializer?: Expression, location?: TextRange, flags?: NodeFlags) {
return createParameter(undefined, undefined, undefined, name, undefined, undefined, initializer, location, flags);
}
export function createRestParameter(name: Identifier, location?: TextRange, flags?: NodeFlags) {
return createParameter(undefined, undefined, createNode(SyntaxKind.DotDotDotToken), name, undefined, undefined, undefined, location, flags);
}
export function createVariableDeclaration2(name: Identifier | BindingPattern, initializer?: Expression, location?: TextRange, flags?: NodeFlags) {
return createVariableDeclaration(name, undefined, initializer, location, flags);
}
export function createVariableStatement2(declarationList: VariableDeclarationList, location?: TextRange, flags?: NodeFlags) {
return createVariableStatement(undefined, undefined, declarationList, location, flags);
}
export function createSimpleLetStatement(name: Identifier, initializer: Expression, location?: TextRange, exported?: boolean) {
let varDecl = createVariableDeclaration2(name, initializer);
let varDeclList = createVariableDeclarationList([varDecl], undefined, NodeFlags.Let);
let varStmt = createVariableStatement2(varDeclList, location, exported ? NodeFlags.Export : 0);
return varStmt;
}
export function createExportDefaultStatement(expression: Expression): ExportAssignment {
return createExportAssignment(undefined, undefined, expression);
}
function createClassHeritageClauses(baseTypeNode: ExpressionWithTypeArguments) {
return baseTypeNode ? [createHeritageClause(SyntaxKind.ExtendsKeyword, [baseTypeNode])] : undefined;
}
export function createClassDeclaration2(name: Identifier, baseTypeNode: ExpressionWithTypeArguments, members: ClassElement[], location?: TextRange, flags?: NodeFlags): ClassDeclaration {
return createClassDeclaration(undefined, undefined, name, undefined, createClassHeritageClauses(baseTypeNode), members, location, flags);
}
export function createClassExpression2(name: Identifier, baseTypeNode: ExpressionWithTypeArguments, members: ClassElement[]): ClassExpression {
return createClassExpression(undefined, undefined, name, undefined, createClassHeritageClauses(baseTypeNode), members);
}
export function createClassExpression3(baseTypeNode: ExpressionWithTypeArguments, members: ClassElement[]): ClassExpression {
return createClassExpression2(undefined, baseTypeNode, members);
}
export function createConstructor2(parameters: Array<ParameterDeclaration>, body: Block, location?: TextRange, flags?: NodeFlags): ConstructorDeclaration {
return createConstructor(undefined, undefined, parameters, undefined, body, location, flags);
}
export function createMethodDeclaration2(name: PropertyName, parameters: Array<ParameterDeclaration>, body: Block, location?: TextRange, flags?: NodeFlags): MethodDeclaration {
return createMethodDeclaration(undefined, undefined, undefined, name, undefined, parameters, undefined, body, location, flags);
}
export function createGetAccessor2(name: PropertyName, parameters: Array<ParameterDeclaration>, body: Block, location?: TextRange, flags?: NodeFlags): GetAccessorDeclaration {
return createGetAccessor(undefined, undefined, name, parameters, undefined, body, location, flags);
}
export function createSetAccessor2(name: PropertyName, parameters: Array<ParameterDeclaration>, body: Block, location?: TextRange, flags?: NodeFlags): SetAccessorDeclaration {
return createSetAccessor(undefined, undefined, name, parameters, undefined, body, location, flags);
}
export function createFunctionDeclaration2(name: Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange, flags?: NodeFlags) {
return createFunctionDeclaration(undefined, undefined, undefined, name, undefined, parameters, undefined, body, location, flags);
}
export function createFunctionDeclaration3(asteriskToken: Node, name: Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange, flags?: NodeFlags) {
return createFunctionDeclaration(undefined, undefined, asteriskToken, name, undefined, parameters, undefined, body, location, flags);
}
export function createFunctionExpression2(name: Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange, flags?: NodeFlags) {
return createFunctionExpression(undefined, undefined, undefined, name, undefined, parameters, undefined, body, location, flags);
}
export function createFunctionExpression3(asteriskToken: Node, name: Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange, flags?: NodeFlags) {
return createFunctionExpression(undefined, undefined, asteriskToken, name, undefined, parameters, undefined, body, location, flags);
}
export function createArrowFunction2(parameters: ParameterDeclaration[], body: Block | Expression, location?: TextRange, flags?: NodeFlags) {
return createArrowFunction(undefined, undefined, undefined, parameters, undefined, createNode(SyntaxKind.EqualsGreaterThanToken), body, location, flags);
}
export function createGeneratorFunctionExpression(parameters: ParameterDeclaration[], body: Block, location?: TextRange, flags?: NodeFlags) {
return createFunctionExpression(undefined, undefined, createNode(SyntaxKind.AsteriskToken), undefined, undefined, parameters, undefined, body, location, flags);
}
export function createVoidZeroExpression(location?: TextRange, flags?: NodeFlags): VoidExpression {
return createVoidExpression(createNumericLiteral2(0), location, flags);
}
export function createPropertyOrElementAccessExpression(expression: Expression, propName: Identifier | LiteralExpression, location?: TextRange, flags?: NodeFlags): LeftHandSideExpression {
return isIdentifier(propName)
? createPropertyAccessExpression2(expression, makeSynthesized(propName), location, flags)
: createElementAccessExpression2(expression, makeSynthesized(propName), location, flags);
}
export function createElementAccessExpression2(expression: Expression, argumentExpression: Expression, location?: TextRange, flags?: NodeFlags): ElementAccessExpression {
return createElementAccessExpression(parenthesizeForAccess(expression), argumentExpression, location, flags);
}
export function createElementAccessExpression3(expression: Expression, index: number, location?: TextRange, flags?: NodeFlags): ElementAccessExpression {
return createElementAccessExpression2(expression, createNumericLiteral2(index), location, flags);
}
export function createSliceCall(value: Expression, sliceIndex: number, location?: TextRange, flags?: NodeFlags): CallExpression {
return createCallExpression2(createPropertyAccessExpression3(value, "slice"), [createNumericLiteral2(sliceIndex)], location, flags);
}
export function createApplyCall(target: Expression, thisArg: Expression, _arguments: Expression, location?: TextRange, flags?: NodeFlags) {
return createCallExpression2(createPropertyAccessExpression3(target, "apply"), [thisArg, _arguments], location, flags);
}
export function createExtendsHelperCall(name: Identifier) {
return createCallExpression2(createIdentifier("__extends"), [name, createIdentifier("_super")]);
}
export function createAwaiterHelperCall(hasLexicalArguments: boolean, promiseConstructor: EntityName | Expression, body: Block) {
let argumentsExpr = hasLexicalArguments ? createIdentifier("arguments") : createVoidZeroExpression();
let promiseExpr = promiseConstructor ? convertEntityNameToExpression(promiseConstructor) : createIdentifier("Promise");
return createCallExpression2(createIdentifier("__awaiter"), [createThisKeyword(), argumentsExpr, promiseExpr, createGeneratorFunctionExpression([], body)]);
}
function convertEntityNameToExpression(node: EntityName | Expression): Expression {
return isQualifiedName(node) ? createPropertyAccessExpression2(convertEntityNameToExpression(node.left), cloneNode(node.right)) : cloneNode(node);
}
export function createDecorateHelperCall(decoratorExpressions: Expression[], target: Expression, memberName?: Expression, descriptor?: Expression) {
return createCallExpression2(createIdentifier("__decorate"), append([createArrayLiteralExpression(decoratorExpressions), target], memberName, descriptor));
}
export function createParamHelperCall(parameterIndex: number, decoratorExpression: Expression) {
return createCallExpression2(createIdentifier("__param"), [createNumericLiteral2(parameterIndex), decoratorExpression]);
}
export function createMetadataHelperCall(metadataKey: string, metadataValue: Expression) {
return createCallExpression2(createIdentifier("__metadata"), [createStringLiteral(metadataKey), metadataValue]);
}
export function createDefinePropertyCall(target: Expression, memberName: Expression, descriptor: Expression) {
return createCallExpression2(createPropertyAccessExpression3(createIdentifier("Object"), "defineProperty"), [target, memberName, descriptor]);
}
export function createGetOwnPropertyDescriptorCall(target: Expression, memberName: Expression) {
return createCallExpression2(createPropertyAccessExpression3(createIdentifier("Object"), "getOwnPropertyDescriptor"), [target, memberName]);
}
export function createDefaultValueCheck(value: Expression, defaultValue: Expression, ensureIdentifier: (value: Expression) => Expression, location?: TextRange, flags?: NodeFlags): Expression {
// The value expression will be evaluated twice, so for anything but a simple identifier
// we need to generate a temporary variable
value = ensureIdentifier(value);
// <value> === void 0 ? <defaultValue> : <value>
return createConditionalExpression2(createStrictEqualityExpression(value, createVoidZeroExpression()), defaultValue, value, location, flags);
}
// <value> === void 0 ? <defaultValue> : <value>
return createConditionalExpression2(createStrictEqualityExpression(value, createVoidZeroExpression()), defaultValue, value, location, flags);
}
export function createMemberAccessForPropertyName(target: Expression, memberName: PropertyName, location?: TextRange, flags?: NodeFlags): MemberExpression {
return isIdentifier(memberName)
? createPropertyAccessExpression2(target, cloneNode(memberName), location, flags)
: isComputedPropertyName(memberName)
? createElementAccessExpression2(target, cloneNode(memberName.expression), location, flags)
: createElementAccessExpression2(target, cloneNode(memberName), location, flags);
}
export function inlineExpressions(expressions: Expression[]) {
return reduceLeft(expressions, createCommaExpression);
}
// }
export function createMemberAccessForPropertyName(target: Expression, memberName: PropertyName, location?: TextRange, flags?: NodeFlags): MemberExpression {
return isIdentifier(memberName)
? createPropertyAccessExpression2(target, cloneNode(memberName), location, flags)
: isComputedPropertyName(memberName)
? createElementAccessExpression2(target, cloneNode(memberName.expression), location, flags)
: createElementAccessExpression2(target, cloneNode(memberName), location, flags);
}
export function inlineExpressions(expressions: Expression[]) {
return reduceLeft(expressions, createCommaExpression);
}
export function isDeclarationStatement(node: Node): node is DeclarationStatement {
if (node) {
switch (node.kind) {
@ -426,6 +424,6 @@ namespace ts {
return true;
}
}
return false;
return false;
}
}

View file

@ -1,6 +1,6 @@
/// <reference path="factory.ts" />
/// <reference path="transform.generated.ts" />
const FORCE_TRANSFORMS = false;
const FORCE_TRANSFORMS = true;
/* @internal */
namespace ts {
@ -16,6 +16,7 @@ namespace ts {
* @param subtreeFlags Transform flags computed for this node's subtree
*/
export function computeTransformFlagsForNode(node: Node, subtreeFlags: TransformFlags) {
Debug.assert((subtreeFlags & TransformFlags.NodeExcludes) == 0, "Subtree includes a `ThisNode...` flag.");
let transformFlags: TransformFlags;
// Mark transformations needed for each node
@ -260,12 +261,45 @@ namespace ts {
return transform.runTransformationChain(statements, chain, _compilerOptions, _currentSourceFile, _resolver, _generatedNameSet, _nodeToGeneratedName);
}
export const enum VisitorFlags {
export const enum PipelineFlags {
LexicalEnvironment = 1 << 1,
StatementOrBlock = 1 << 2,
//ExpressionOrBlock = 1 << 3,
}
// interface Transformer {
// getEmitResolver(): EmitResolver;
// getCompilerOptions(): CompilerOptions;
// makeUniqueName(baseName: string): string;
// getGeneratedNameForNode(node: Node): Identifier;
// nodeHasGeneratedName(node: Node): boolean;
// createUniqueIdentifier(baseName: string): Identifier;
// createTempVariable(loopVariable: boolean): Identifier;
// declareLocal(baseName?: string): Identifier;
// hoistVariableDeclaration(name: Identifier): void;
// hoistFunctionDeclaration(func: FunctionDeclaration): void;
// createParentNavigator(): ParentNavigator;
// getParentNode(): Node;
// getCurrentNode(): Node;
// findAncestorNode<T extends Node>(match: (node: Node) => node is T): T;
// findAncestorNode(match: (node: Node) => boolean): Node;
// getDeclarationName(node: DeclarationStatement): Identifier;
// getDeclarationName(node: ClassExpression): Identifier;
// getDeclarationName(node: Declaration): DeclarationName;
// getClassMemberPrefix(node: ClassLikeDeclaration, member: ClassElement): Expression;
// pipeNode<TIn extends Node, TOut extends Node>(input: TIn, pipeline: Pipeline<TIn, TOut>, output: PipelineOutput<TOut>, flags?: PipelineFlags): void;
// pipeNodes<TIn extends Node, TOut extends Node>(input: TIn[], pipeline: Pipeline<TIn, TOut>, output: PipelineOutput<TOut>, flags?: PipelineFlags): void;
// emitNode<TIn extends Node, TOut extends Node>(input: TIn, pipeline: Pipeline<TIn, TOut>, output: TOut[], flags?: PipelineFlags, nodeTest?: NodeTest<TOut>): void;
// emitNodes<TIn extends Node, TOut extends Node>(input: TIn[], pipeline: Pipeline<TIn, TOut>, output: TOut[], flags?: PipelineFlags, nodeTest?: NodeTest<TOut>): void;
// visitNode<T extends Node>(input: T, pipeline: Pipeline<Node, Node>, flags?: PipelineFlags, nodeTest?: NodeTest<T>): T;
// visitNode<T extends Node>(input: T, pipeline: Pipeline<T, T>, flags?: PipelineFlags, nodeTest?: NodeTest<T>): T;
// visitNode<TIn extends Node, TOut extends Node>(input: TIn, pipeline: Pipeline<TIn, TOut>, flags?: PipelineFlags, nodeTest?: NodeTest<TOut>): TOut;
// visitNodes<T extends Node>(input: T[], pipeline: Pipeline<Node, Node>, flags?: PipelineFlags, nodeTest?: NodeTest<T>): NodeArray<T>;
// visitNodes<T extends Node>(input: T[], pipeline: Pipeline<T, T>, flags?: PipelineFlags, nodeTest?: NodeTest<T>): NodeArray<T>;
// visitNodes<TIn extends Node, TOut extends Node>(input: TIn[], pipeline: Pipeline<TIn, TOut>, flags?: PipelineFlags, nodeTest?: NodeTest<TOut>): NodeArray<TOut>;
// accept<T extends Node>(node: T, pipeline: Pipeline<T, T>, write: PipelineOutput<T>): void;
// }
export namespace transform {
// Flags enum to track count of temp variables and a few dedicated names
const enum TempFlags {
@ -467,6 +501,10 @@ namespace ts {
return nodeStack.createParentNavigator();
}
export function getRootNode(): SourceFile {
return currentSourceFile;
}
export function getCurrentNode(): Node {
return nodeStack.getNode();
}
@ -666,7 +704,7 @@ namespace ts {
return updatedNode;
}
function readNodeArray(flags: VisitorFlags): NodeArray<Node> {
function readNodeArray(): NodeArray<Node> {
if (updatedNodes) {
return createNodeArray(updatedNodes, /*location*/ <NodeArray<Node>>originalNodes);
}
@ -686,7 +724,7 @@ namespace ts {
* This function also manages when new lexical environments are introduced, and tracks temporary
* variables and hoisted variable and function declarations.
*/
function pipeOneOrMany<TIn extends Node, TOut extends Node>(inputNode: TIn, inputNodes: TIn[], pipeline: Visitor, output: (node: TOut) => void, flags: VisitorFlags): void {
function pipeOneOrMany<TIn extends Node, TOut extends Node>(inputNode: TIn, inputNodes: TIn[], pipeline: Visitor, output: (node: TOut) => void, flags: PipelineFlags): void {
if (!inputNode && !inputNodes) {
return;
}
@ -698,7 +736,7 @@ namespace ts {
// If we are starting a new lexical environment, we need to reinitialize the lexical
// environment state as well
if (flags & VisitorFlags.LexicalEnvironment) {
if (flags & PipelineFlags.LexicalEnvironment) {
savedTempFlags = tempFlags;
savedHoistedVariableDeclarations = hoistedVariableDeclarations;
savedHoistedFunctionDeclarations = hoistedFunctionDeclarations;
@ -733,7 +771,7 @@ namespace ts {
// If we established a new lexical environment, we need to write any hoisted variables or
// function declarations to the end of the output.
if (flags & VisitorFlags.LexicalEnvironment) {
if (flags & PipelineFlags.LexicalEnvironment) {
if (hoistedVariableDeclarations) {
var stmt = createVariableStatement2(createVariableDeclarationList(hoistedVariableDeclarations));
output(<TOut><Node>stmt);
@ -751,7 +789,7 @@ namespace ts {
}
}
function emitOne<TIn extends Node, TOut extends Node>(input: TIn, pipeline: Pipeline<TIn, TOut>, flags: VisitorFlags, nodeTest: NodeTest<TOut>): TOut {
function emitOne<TIn extends Node, TOut extends Node>(input: TIn, pipeline: Pipeline<TIn, TOut>, flags: PipelineFlags, nodeTest: NodeTest<TOut>): TOut {
if (!input) {
return undefined;
}
@ -766,7 +804,7 @@ namespace ts {
updatedNode = undefined;
nodeTestCallback = nodeTest;
writeNodeWithOrWithoutNodeTest = nodeTest ? writeNodeWithNodeTest : writeNodeWithoutNodeTest;
writeNodeFastOrSlow = flags & VisitorFlags.StatementOrBlock ? writeNodeFastOrSlow = writeStatementOrBlockSlow : writeNodeFastOrSlow = writeNodeSlow;
writeNodeFastOrSlow = flags & PipelineFlags.StatementOrBlock ? writeStatementOrBlockSlow : writeNodeSlow;
// Pipe the input node into the output
pipeOneOrMany<TIn, TOut>(input, undefined, pipeline, writeNode, flags);
@ -783,7 +821,7 @@ namespace ts {
return result;
}
function emitOneOrMany<TIn extends Node, TOut extends Node>(inputNode: TIn, inputNodes: TIn[], pipeline: Pipeline<TIn, TOut>, output: TOut[], flags: VisitorFlags, nodeTest: (node: Node) => node is TOut): NodeArray<TOut> {
function emitOneOrMany<TIn extends Node, TOut extends Node>(inputNode: TIn, inputNodes: TIn[], pipeline: Pipeline<TIn, TOut>, output: TOut[], flags: PipelineFlags, nodeTest: (node: Node) => node is TOut): NodeArray<TOut> {
// Exit early if we have nothing to do
if (!inputNode && !inputNodes) {
return undefined;
@ -809,7 +847,7 @@ namespace ts {
pipeOneOrMany<TIn, TOut>(inputNode, inputNodes, pipeline, writeNode, flags);
// Read the output array
output = <NodeArray<TOut>>readNodeArray(flags);
output = <NodeArray<TOut>>readNodeArray();
// Restore previous environment
offsetWritten = savedOffsetWritten;
@ -863,7 +901,7 @@ namespace ts {
* @param output The callback passed to `visitor` to write each visited node.
* @param flags Flags that affect the pipeline.
*/
export function pipeNode<TIn extends Node, TOut extends Node>(input: TIn, pipeline: Pipeline<TIn, TOut>, output: PipelineOutput<TOut>, flags?: VisitorFlags): void {
export function pipeNode<TIn extends Node, TOut extends Node>(input: TIn, pipeline: Pipeline<TIn, TOut>, output: PipelineOutput<TOut>, flags?: PipelineFlags): void {
pipeOneOrMany(input, undefined, pipeline, output, flags);
}
@ -874,7 +912,7 @@ namespace ts {
* @param output The callback passed to `visitor` to write each visited node.
* @param flags Flags that affect the pipeline.
*/
export function pipeNodes<TIn extends Node, TOut extends Node>(input: TIn[], pipeline: Pipeline<TIn, TOut>, output: PipelineOutput<TOut>, flags?: VisitorFlags): void {
export function pipeNodes<TIn extends Node, TOut extends Node>(input: TIn[], pipeline: Pipeline<TIn, TOut>, output: PipelineOutput<TOut>, flags?: PipelineFlags): void {
pipeOneOrMany(undefined, input, pipeline, output, flags);
}
@ -885,10 +923,14 @@ namespace ts {
* @param output The destination node array to which to write the results from visiting each node.
* @param flags Flags that affect the pipeline.
*/
export function emitNode<TIn extends Node, TOut extends Node>(input: TIn, pipeline: Pipeline<TIn, TOut>, output: TOut[], flags?: VisitorFlags, nodeTest?: NodeTest<TOut>): void {
export function emitNode<TIn extends Node, TOut extends Node>(input: TIn, pipeline: Pipeline<TIn, TOut>, output: TOut[], flags?: PipelineFlags, nodeTest?: NodeTest<TOut>): void {
emitOneOrMany(input, undefined, pipeline, output, flags, nodeTest);
}
export function flatMapNode<TIn extends Node, TOut extends Node>(input: TIn, pipeline: Pipeline<TIn, TOut>, flags?: PipelineFlags, nodeTest?: NodeTest<TOut>): NodeArray<TOut> {
return emitOneOrMany(input, undefined, pipeline, [], flags, nodeTest);
}
/**
* Writes the result from visiting each node from an input source to an output node array.
* @param input The source nodes to visit.
@ -896,32 +938,32 @@ namespace ts {
* @param output The destination node array to which to write the results from visiting each node.
* @param flags Flags that affect the pipeline.
*/
export function emitNodes<TIn extends Node, TOut extends Node>(input: TIn[], pipeline: Pipeline<TIn, TOut>, output: TOut[], flags?: VisitorFlags, nodeTest?: NodeTest<TOut>): void {
export function emitNodes<TIn extends Node, TOut extends Node>(input: TIn[], pipeline: Pipeline<TIn, TOut>, output: TOut[], flags?: PipelineFlags, nodeTest?: NodeTest<TOut>): void {
emitOneOrMany(undefined, input, pipeline, output, flags, nodeTest);
}
export function visitNode<T extends Node>(node: T, visitor: Visitor, flags?: VisitorFlags): T;
export function visitNode<TIn extends Node, TOut extends Node>(node: TIn, visitor: Pipeline<TIn, TOut>, flags?: VisitorFlags, nodeTest?: NodeTest<TOut>): TOut;
export function visitNode<TIn extends Node, TOut extends Node>(node: TIn, visitor: Pipeline<TIn, TOut>, flags?: VisitorFlags, nodeTest?: NodeTest<TOut>): TOut {
export function visitNode<T extends Node>(node: T, visitor: Visitor, flags?: PipelineFlags): T;
export function visitNode<TIn extends Node, TOut extends Node>(node: TIn, visitor: Pipeline<TIn, TOut>, flags?: PipelineFlags, nodeTest?: NodeTest<TOut>): TOut;
export function visitNode<TIn extends Node, TOut extends Node>(node: TIn, visitor: Pipeline<TIn, TOut>, flags?: PipelineFlags, nodeTest?: NodeTest<TOut>): TOut {
return emitOne(node, visitor, flags, nodeTest);
}
export function visitStatement(node: Statement, visitor: Visitor, flags?: VisitorFlags) {
return emitOne<Statement, Statement>(node, visitor, flags | VisitorFlags.StatementOrBlock, undefined);
export function visitStatement(node: Statement, visitor: Visitor, flags?: PipelineFlags) {
return emitOne<Statement, Statement>(node, visitor, flags | PipelineFlags.StatementOrBlock, undefined);
}
export function visitNodes<T extends Node>(nodes: T[], pipeline: Visitor, flags?: VisitorFlags): NodeArray<T>;
export function visitNodes<TIn extends Node, TOut extends Node>(nodes: TIn[], pipeline: Pipeline<TIn, TOut>, flags?: VisitorFlags, nodeTest?: NodeTest<TOut>): NodeArray<TOut>;
export function visitNodes<TIn extends Node, TOut extends Node>(nodes: TIn[], pipeline: Pipeline<TIn, TOut>, flags?: VisitorFlags, nodeTest?: NodeTest<TOut>): NodeArray<TOut> {
export function visitNodes<T extends Node>(nodes: T[], pipeline: Visitor, flags?: PipelineFlags): NodeArray<T>;
export function visitNodes<TIn extends Node, TOut extends Node>(nodes: TIn[], pipeline: Pipeline<TIn, TOut>, flags?: PipelineFlags, nodeTest?: NodeTest<TOut>): NodeArray<TOut>;
export function visitNodes<TIn extends Node, TOut extends Node>(nodes: TIn[], pipeline: Pipeline<TIn, TOut>, flags?: PipelineFlags, nodeTest?: NodeTest<TOut>): NodeArray<TOut> {
return emitOneOrMany<TIn, TOut>(undefined, nodes, pipeline, undefined, flags, nodeTest);
}
export function visitNewLexicalEnvironment(node: LexicalEnvironmentBody, pipeline: Visitor): LexicalEnvironmentBody {
if (isBlock(node)) {
return updateBlock(node, visitNodes<Statement, Statement>(node.statements, pipeline, VisitorFlags.LexicalEnvironment));
return updateBlock(node, visitNodes<Statement, Statement>(node.statements, pipeline, PipelineFlags.LexicalEnvironment));
}
else if (isModuleBlock(node)) {
return updateModuleBlock(node, visitNodes<Statement, Statement>(node.statements, pipeline, VisitorFlags.LexicalEnvironment));
return updateModuleBlock(node, visitNodes<Statement, Statement>(node.statements, pipeline, PipelineFlags.LexicalEnvironment));
}
else if (isExpressionNode(node)) {
return visitExpressionFunctionBodyInNewLexicalEnvironment(node, pipeline);

View file

@ -2,7 +2,7 @@
/*@internal*/
namespace ts.transform {
export function toES5(statements: NodeArray<Statement>) {
return visitNodes(statements, transformNode, VisitorFlags.LexicalEnvironment);
return visitNodes(statements, transformNode, PipelineFlags.LexicalEnvironment);
}
/**
@ -41,7 +41,7 @@ namespace ts.transform {
accept(node, transformNode, write);
}
else {
return write(node);
write(node);
}
}
@ -153,7 +153,7 @@ namespace ts.transform {
let body = createBlock([]);
if (constructor) {
emitNode(constructor, transformConstructor, body.statements, VisitorFlags.LexicalEnvironment);
emitNode(constructor, transformConstructor, body.statements, PipelineFlags.LexicalEnvironment);
}
else if (baseTypeNode) {
let superCall = createDefaultSuperCall();
@ -402,7 +402,7 @@ namespace ts.transform {
function transformMethodDeclaration(node: ClassLikeDeclaration, member: MethodDeclaration, write: (node: Statement) => void): void {
let prefix = getClassMemberPrefix(node, member);
let propExpr = getMemberAccessForPropertyName(node, member);
let funcExpr = rewriteFunctionExpression(member, /*name*/ undefined, /*location*/ undefined);
let funcExpr = transformFunctionLikeExpressionToFunctionExpression(member, /*name*/ undefined, /*location*/ undefined);
let assignExpr = createAssignmentExpression(propExpr, funcExpr);
let assignStmt = createExpressionStatement(assignExpr, /*location*/ member);
startOnNewLine(assignStmt);
@ -415,7 +415,7 @@ namespace ts.transform {
let name = getExpressionForPropertyName(firstAccessor);
let descriptorExpr = createObjectLiteralExpression2();
if (accessors.getAccessor) {
let funcExpr = rewriteFunctionExpression(accessors.getAccessor, /*name*/ undefined, /*location*/ accessors.getAccessor);
let funcExpr = transformFunctionLikeExpressionToFunctionExpression(accessors.getAccessor, /*name*/ undefined, /*location*/ accessors.getAccessor);
let getName = createIdentifier("get");
let getProp = createPropertyAssignment(getName, funcExpr);
startOnNewLine(getProp);
@ -423,7 +423,7 @@ namespace ts.transform {
}
if (accessors.setAccessor) {
let funcExpr = rewriteFunctionExpression(accessors.setAccessor, /*name*/ undefined, /*location*/ accessors.setAccessor);
let funcExpr = transformFunctionLikeExpressionToFunctionExpression(accessors.setAccessor, /*name*/ undefined, /*location*/ accessors.setAccessor);
let setName = createIdentifier("set");
let setProp = createPropertyAssignment(setName, funcExpr);
startOnNewLine(setProp);
@ -447,32 +447,19 @@ namespace ts.transform {
}
function transformFunctionExpression(node: FunctionExpression, write: (node: Expression) => void): void {
write(rewriteFunctionExpression(node, node.name, /*location*/ node));
write(transformFunctionLikeExpressionToFunctionExpression(node, node.name, /*location*/ node));
}
function rewriteFunctionExpression(node: FunctionLikeDeclaration, name: Identifier, location: TextRange): FunctionExpression {
function transformFunctionLikeExpressionToFunctionExpression(node: FunctionLikeDeclaration, name: Identifier, location: TextRange): FunctionExpression {
let parameters = visitNodes(node.parameters, transformNode);
let body = createBlock([], node.body);
emitNode(node, transformFunctionBody, body.statements, VisitorFlags.LexicalEnvironment);
return createFunctionExpression2(name, parameters, body, location);
let statements = flatMapNode(node, transformFunctionBody, PipelineFlags.LexicalEnvironment);
return createFunctionExpression2(name, parameters, createBlock(statements), location);
}
function transformFunctionDeclaration(node: FunctionDeclaration, write: (node: Statement) => void): void {
let parameters = visitNodes(node.parameters, transformNode);
let body = createBlock([], node.body);
emitNode(node, transformFunctionBody, body.statements, VisitorFlags.LexicalEnvironment);
write(createFunctionDeclaration2(node.name, parameters, body, /*location*/ node));
}
function transformToFunctionLikeDeclaration<T extends FunctionLikeDeclaration>(node: FunctionLikeDeclaration, name: Identifier, location: TextRange,
createfn: (name: DeclarationName, parameters: ParameterDeclaration[], body: Block, location: TextRange) => T): T {
let parameters = visitNodes(node.parameters, transformNode);
let newBody = createBlock([], /*location*/ isBlock(node.body) ? node.body : undefined);
emitNode(node, transformFunctionBody, newBody.statements, VisitorFlags.LexicalEnvironment);
let func = createfn(name, parameters, newBody, location);
return func;
let statements = flatMapNode(node, transformFunctionBody, PipelineFlags.LexicalEnvironment);
write(createFunctionDeclaration2(node.name, parameters, createBlock(statements), /*location*/ node));
}
function transformFunctionBody(node: FunctionLikeDeclaration, write: (node: Statement) => void) {

View file

@ -4,6 +4,9 @@ namespace ts.transform {
let resolver: EmitResolver;
let compilerOptions: CompilerOptions;
let languageVersion: ScriptTarget;
let currentLexicalEnvironment: SourceFile | FunctionLikeDeclaration | ModuleDeclaration
let currentModuleDeclaration: ModuleDeclaration;
let currentClassLikeDeclaration: ClassLikeDeclaration;
let currentBaseTypeNode: ExpressionWithTypeArguments;
let currentConstructor: ConstructorDeclaration;
let currentParametersWithPropertyAssignments: ParameterDeclaration[];
@ -13,7 +16,8 @@ namespace ts.transform {
resolver = getEmitResolver();
compilerOptions = getCompilerOptions();
languageVersion = compilerOptions.target || ScriptTarget.ES3;
return visitNodes(statements, transformNode, VisitorFlags.LexicalEnvironment);
currentLexicalEnvironment = getRootNode();
return visitNodes(statements, transformNode, PipelineFlags.LexicalEnvironment);
}
/**
@ -33,11 +37,7 @@ namespace ts.transform {
* If no part of this node or its subtree requires transformation, the node
* is returned, unchanged.
*/
function transformNode<T extends Node>(node: T, write: (node: T) => void): void {
if (!node) {
return;
}
function transformNode(node: Node, write: (node: Node) => void): void {
// Debug.assert(
// !needsTransform(node, TransformFlags.ThisNodeNeedsTransformToES7),
// "Cannot transform node with post-ES7 syntax.");
@ -54,10 +54,6 @@ namespace ts.transform {
}
function transformModuleElement(node: Node, write: (node: Node) => void): void {
if (!node) {
return;
}
if (node.flags & NodeFlags.Export) {
transformNodeWorker(node, write);
}
@ -165,11 +161,11 @@ namespace ts.transform {
//
// TypeScript heritage clause extensions include:
// - `implements` clause
return transformHeritageClause(<HeritageClause>node, write);
return visitHeritageClause(<HeritageClause>node, write);
case SyntaxKind.ExpressionWithTypeArguments:
// TypeScript supports type arguments on an expression in an `extends` heritage clause.
return transformExpressionWithTypeArguments(<ExpressionWithTypeArguments>node, write);
return visitExpressionWithTypeArguments(<ExpressionWithTypeArguments>node, write);
case SyntaxKind.MethodDeclaration:
// TypeScript method declarations may be 'async', and may have decorators, modifiers
@ -247,31 +243,30 @@ namespace ts.transform {
* @param node The node to transform.
*/
function transformClassDeclaration(node: ClassDeclaration, write: (node: Statement) => void) {
let baseTypeNode = visitAndGetClassExtendsHeritageClauseElement(node);
let classMembers: ClassElement[] = [];
let constructor = transformConstructor(node, baseTypeNode);
if (constructor) {
classMembers.push(constructor);
}
let savedCurrentBaseTypeNode = currentBaseTypeNode;
let savedCurrentClassLikeDeclaration = currentClassLikeDeclaration;
currentClassLikeDeclaration = node;
currentBaseTypeNode = getAndVisitClassExtendsHeritageClauseElement(node);
let classMembers: ClassElement[] = [];
emitNode(node, emitConstructor, classMembers);
emitNodes(node.members, transformNode, classMembers);
if (nodeIsDecorated(node)) {
// If the class has been decorated, we need to emit the class as part of a `let` declaration
// to avoid the pitfalls of the doubly-bound class name.
let classExpr = createClassExpression3(baseTypeNode, classMembers);
let classExpr = createClassExpression3(currentBaseTypeNode, classMembers);
let varStmt = createSimpleLetStatement(getDeclarationName(node), classExpr, /*location*/ node, isTopLevelNonDefaultExport(node));
varStmt.original = node;
write(varStmt);
write(setOriginalNode(varStmt, node));
}
else {
let exportFlags = isNamespaceLevelExport(node) ? undefined : node.flags & (NodeFlags.Export | NodeFlags.Default);
let classDecl = createClassDeclaration2(getDeclarationName(node), baseTypeNode, classMembers, /*location*/ node, exportFlags);
classDecl.original = node;
write(classDecl);
let classDecl = createClassDeclaration2(getDeclarationName(node), currentBaseTypeNode, classMembers, /*location*/ node, exportFlags);
write(setOriginalNode(classDecl, node));
}
transformPropertyDeclarationsToStatements(node, getInitializedProperties(node, /*isStatic*/ true), write);
pipeNodes(getInitializedProperties(node, /*isStatic*/ true), transformPropertyDeclarationToStatement, write);
transformDecoratorsOfMembers(node, /*isStatic*/ false, write);
transformDecoratorsOfMembers(node, /*isStatic*/ true, write);
transformDecoratorsOfConstructor(node, write);
@ -282,79 +277,47 @@ namespace ts.transform {
else if (isTopLevelDefaultExport(node) && nodeIsDecorated(node)) {
write(createExportDefaultStatement(getDeclarationName(node)));
}
currentClassLikeDeclaration = savedCurrentClassLikeDeclaration;
currentBaseTypeNode = savedCurrentBaseTypeNode;
}
function transformClassExpression(node: ClassExpression, write: (node: LeftHandSideExpression) => void) {
let baseTypeNode = visitAndGetClassExtendsHeritageClauseElement(node);
let classMembers: ClassElement[] = [];
let constructor = transformConstructor(node, baseTypeNode);
if (constructor) {
classMembers.push(constructor);
}
let savedCurrentClassLikeDeclaration = currentClassLikeDeclaration;
let savedCurrentBaseTypeNode = currentBaseTypeNode;
currentClassLikeDeclaration = node;
currentBaseTypeNode = getAndVisitClassExtendsHeritageClauseElement(node);
let classMembers: ClassElement[] = [];
emitNode(node, emitConstructor, classMembers);
emitNodes(node.members, transformNode, classMembers);
let classExpr = createClassExpression2(getDeclarationName(node), baseTypeNode, classMembers);
let classExpr = createClassExpression2(getDeclarationName(node), currentBaseTypeNode, classMembers);
let staticPropertyAssignments = getInitializedProperties(node, /*isStatic*/ true);
if (staticPropertyAssignments) {
let expressions: Expression[] = [];
let tempVar = declareLocal();
let cacheExpr = createAssignmentExpression(tempVar, classExpr);
expressions.push(cacheExpr);
transformPropertyDeclarationsToExpressions(node, staticPropertyAssignments, expressions);
expressions.push(createAssignmentExpression(tempVar, classExpr));
emitNodes(staticPropertyAssignments, transformPropertyDeclarationToExpression, expressions);
expressions.push(tempVar);
write(createParenthesizedExpression(inlineExpressions(expressions)));
}
else {
write(classExpr);
}
currentClassLikeDeclaration = savedCurrentClassLikeDeclaration;
currentBaseTypeNode = savedCurrentBaseTypeNode;
}
function visitAndGetClassExtendsHeritageClauseElement(node: ClassLikeDeclaration) {
let heritageClauses = visitNodes(node.heritageClauses, transformNode);
function getAndVisitClassExtendsHeritageClauseElement(node: ClassLikeDeclaration) {
let heritageClauses = visitNodes(node.heritageClauses, visitHeritageClause);
let extendsClause = heritageClauses && firstOrUndefined(heritageClauses);
let baseTypeNode = extendsClause && firstOrUndefined(extendsClause.types);
return baseTypeNode;
}
function isTopLevelExport(node: Node) {
return !!(node.flags & NodeFlags.Export) && isSourceFile(getParentNode());
}
function isTopLevelDefaultExport(node: Node) {
return isTopLevelExport(node) && !!(node.flags & NodeFlags.Default);
}
function isTopLevelNonDefaultExport(node: Node) {
return isTopLevelExport(node) && !(node.flags & NodeFlags.Default);
}
function isNamespaceLevelExport(node: Node) {
return !!(node.flags & NodeFlags.Export) && !isSourceFile(getParentNode());
}
function getContainingModule(): ModuleDeclaration {
return findAncestorNode(isModuleDeclaration);
}
function getContainingModuleName(): Identifier {
let container = findAncestorNode(isModuleDeclaration);
return container ? getGeneratedNameForNode(container) : createIdentifier("exports");
}
function getModuleMemberName(node: Declaration): Expression {
let name = <Identifier>getDeclarationName(node);
Debug.assert(isIdentifier(name));
if (getCombinedNodeFlags(transform) & NodeFlags.Export) {
let container = getContainingModuleName();
let propExpr = createPropertyAccessExpression2(container, name);
return propExpr;
}
return name;
}
function transformConstructor(node: ClassLikeDeclaration, baseTypeNode: ExpressionWithTypeArguments) {
function emitConstructor(node: ClassLikeDeclaration, write: (node: ClassElement) => void): void {
// Check if we have a property assignment inside class declaration.
// If there is a property assignment, we need to emit constructor whether users define it or not
// If there is no property assignment, we can omit constructor if users do not define it
@ -365,117 +328,92 @@ namespace ts.transform {
// For target ES6 and above, if there is no property assignment
// do not emit constructor in class declaration.
if (!parameterPropertyAssignments && !instancePropertyAssignments) {
return constructor;
write(constructor);
return;
}
let parameters: ParameterDeclaration[] = [];
if (constructor) {
emitNodes(constructor.parameters, transformNode, parameters);
}
else if (baseTypeNode) {
else if (currentBaseTypeNode) {
parameters.push(createRestParameter(createIdentifier("args"), /*location*/ undefined, NodeFlags.GeneratedRest));
}
let statements: Statement[] = [];
let savedCurrentBaseTypeNode = currentBaseTypeNode;
let savedCurrentConstructor = currentConstructor;
let savedCurrentParametersWithPropertyAssignments = currentParametersWithPropertyAssignments;
let savedCurrentInstancePropertyAssignments = currentInstancePropertyAssignments;
emitNode(node, emitConstructorBody, statements, VisitorFlags.LexicalEnvironment, isStatementNode);
let statements = flatMapNode(node, emitConstructorBody, PipelineFlags.LexicalEnvironment)
write(createConstructor2(parameters, createBlock(statements), /*location*/ constructor));
currentBaseTypeNode = savedCurrentBaseTypeNode;
currentConstructor = savedCurrentConstructor;
currentParametersWithPropertyAssignments = savedCurrentParametersWithPropertyAssignments;
currentInstancePropertyAssignments = savedCurrentInstancePropertyAssignments;
return createConstructor2(parameters, createBlock(statements), /*location*/ constructor);
}
function emitConstructorBody(node: ClassLikeDeclaration, write: (node: Statement) => void) {
let baseTypeNode = currentBaseTypeNode;
let constructor = currentConstructor;
let parameterPropertyAssignments = currentParametersWithPropertyAssignments;
let instancePropertyAssignments = currentInstancePropertyAssignments;
let superCall: ExpressionStatement;
if (constructor) {
if (baseTypeNode) {
superCall = findInitialSuperCall(constructor);
if (currentConstructor) {
if (currentBaseTypeNode) {
superCall = findInitialSuperCall(currentConstructor);
if (superCall) {
write(superCall);
}
}
if (parameterPropertyAssignments) {
for (let parameter of parameterPropertyAssignments) {
let name = <Identifier>cloneNode(parameter.name);
let thisExpr = createThisKeyword();
let propExpr = createPropertyAccessExpression2(thisExpr, name);
let assignExpr = createAssignmentExpression(propExpr, name);
let assignStmt = createExpressionStatement(assignExpr);
startOnNewLine(assignStmt);
write(assignStmt);
}
}
pipeNodes(currentParametersWithPropertyAssignments, emitParameterPropertyAssignment, write);
}
else if (baseTypeNode) {
let superExpr = createSuperKeyword();
let argsName = createIdentifier("args");
let spreadExpr = createSpreadElementExpression(argsName);
let callExpr = createCallExpression2(superExpr, [spreadExpr]);
let callStmt = createExpressionStatement(callExpr, /*location*/ undefined, NodeFlags.GeneratedSuper);
startOnNewLine(callStmt);
write(callStmt);
else if (currentBaseTypeNode) {
let callExpr = createCallExpression2(createSuperKeyword(), [createSpreadElementExpression(createIdentifier("args"))]);
write(startOnNewLine(createExpressionStatement(callExpr, /*location*/ undefined, NodeFlags.GeneratedSuper)));
}
transformPropertyDeclarationsToStatements(node, instancePropertyAssignments, write);
pipeNodes(currentInstancePropertyAssignments, transformPropertyDeclarationToStatement, write);
if (constructor) {
let bodyStatements = constructor.body.statements;
pipeNodes(superCall ? bodyStatements.slice(1) : bodyStatements, transformNode, write);
if (currentConstructor) {
pipeNodes(skip(currentConstructor.body.statements, superCall ? 1 : 0), transformNode, write);
}
}
function transformHeritageClause(node: HeritageClause, write: (node: HeritageClause) => void) {
function emitParameterPropertyAssignment(node: ParameterDeclaration, write: (node: Statement) => void) {
let name = <Identifier>cloneNode(node.name);
let propExpr = createPropertyAccessExpression2(createThisKeyword(), name);
let assignExpr = createAssignmentExpression(propExpr, name);
write(startOnNewLine(createExpressionStatement(assignExpr)));
}
function visitHeritageClause(node: HeritageClause, write: (node: HeritageClause) => void) {
if (node.token === SyntaxKind.ExtendsKeyword) {
write(updateHeritageClause(node, visitNodes(node.types, transformNode)));
write(updateHeritageClause(node, take(visitNodes(node.types, visitExpressionWithTypeArguments), 1)));
}
}
function transformExpressionWithTypeArguments(node: ExpressionWithTypeArguments, write: (node: ExpressionWithTypeArguments) => void) {
function visitExpressionWithTypeArguments(node: ExpressionWithTypeArguments, write: (node: ExpressionWithTypeArguments) => void) {
write(updateExpressionWithTypeArguments(node, visitNode(node.expression, transformNode), /*typeArguments*/ undefined));
}
function transformPropertyDeclarationsToStatements(node: ClassLikeDeclaration, properties: PropertyDeclaration[], write: (node: Statement) => void) {
if (!properties) {
return;
}
for (let property of properties) {
write(createExpressionStatement(transformPropertyDeclaration(node, property), /*location*/ property));
}
function transformPropertyDeclarationToStatement(node: PropertyDeclaration, write: (node: Statement) => void): void {
transformPropertyDeclarationToExpressionOrStatement(node, undefined, write);
}
function transformPropertyDeclarationsToExpressions(node: ClassLikeDeclaration, properties: PropertyDeclaration[], expressions: Expression[]) {
if (!properties) {
return;
}
for (let property of properties) {
let propertyAssignment = transformPropertyDeclaration(node, property, /*location*/ property);
expressions.push(propertyAssignment);
}
function transformPropertyDeclarationToExpression(node: PropertyDeclaration, write: (node: Expression) => void): void {
transformPropertyDeclarationToExpressionOrStatement(node, write, undefined);
}
function transformPropertyDeclaration(node: ClassLikeDeclaration, property: PropertyDeclaration, location?: TextRange): Expression {
let isStatic = (property.flags & NodeFlags.Static) !== 0;
let target = isStatic ? getDeclarationName(node) : createThisKeyword();
let name = transformPropertyName(property);
let left = createMemberAccessForPropertyName(target, name, /*location*/ property.name);
let initializer = visitNode(property.initializer, transformNode);
function transformPropertyDeclarationToExpressionOrStatement(node: PropertyDeclaration, writeExpression: (node: Expression) => void, writeStatement: (node: Statement) => void): void {
let isStatic = (node.flags & NodeFlags.Static) !== 0;
let target = isStatic ? getDeclarationName(currentClassLikeDeclaration) : createThisKeyword();
let left = createMemberAccessForPropertyName(target, transformPropertyName(node), /*location*/ node.name);
let initializer = visitNode(node.initializer, transformNode);
let assignExpr = createAssignmentExpression(left, initializer);
setTextRange(assignExpr, location);
return assignExpr;
setTextRange(assignExpr, node);
if (writeExpression) {
writeExpression(assignExpr);
}
else {
writeStatement(createExpressionStatement(assignExpr));
}
}
// emitter.ts:4074
@ -707,10 +645,7 @@ namespace ts.transform {
}
function transformVariableStatement(node: VariableStatement, write: (node: Statement) => void) {
// TODO(rbuckton): transform namespace exports for a variable declaration list
// Debug.assert(isNamespaceLevelExport(node), "Should only reach here for exported variables." + node.declarationList.declarations[0].name);
// pipeNode(node.declarationList, write, transformVariableDeclarationListToExpressionStatement);
return accept(node, transformNode, write);
pipeNode(node.declarationList, transformVariableDeclarationListToExpressionStatement, write);
}
function transformVariableDeclarationListToExpressionStatement(node: VariableDeclarationList, write: (node: Statement) => void) {
@ -752,22 +687,56 @@ namespace ts.transform {
}
function transformObjectBindingPatternToExpression(node: ObjectBindingPattern, write: (node: Expression) => void) {
Debug.fail("not implemented");
let properties: ObjectLiteralElement[] = [];
let properties = visitNodes<BindingElement, ObjectLiteralElement>(node.elements, transformBindingElementToObjectLiteralElement);
write(createObjectLiteralExpression2(properties));
}
function transformBindingElementToObjectLiteralElement(node: BindingElement, write: (node: ObjectLiteralElement) => void) {
let propertyName = node.propertyName || <Identifier>node.name;
let name = node.name;
let expr = isBindingPattern(name)
? visitNode<BindingPattern, Expression>(name, transformBindingPatternToExpression)
: getModuleMemberName(node);
let initializer = visitNode(node.initializer, transformNode);
if (initializer) {
expr = createAssignmentExpression(expr, initializer);
}
write(createPropertyAssignment(propertyName, expr));
}
function transformArrayBindingPatternToExpression(node: ArrayBindingPattern, write: (node: Expression) => void) {
Debug.fail("not implemented");
let elements: Expression[] = [];
let elements = visitNodes<BindingElement, Expression>(node.elements, transformBindingElementToExpression);
write(createArrayLiteralExpression(elements));
}
function transformBindingElementToExpression(node: BindingElement, write: (node: Expression) => void) {
let name = node.name;
let expr = isBindingPattern(name)
? visitNode<BindingPattern, Expression>(name, transformBindingPatternToExpression)
: getModuleMemberName(node);
let initializer = visitNode(node.initializer, transformNode);
if (initializer) {
expr = createAssignmentExpression(expr, initializer);
}
if (node.dotDotDotToken) {
expr = createSpreadElementExpression(expr);
}
write(expr);
}
function transformModuleDeclaration(node: ModuleDeclaration, write: (node: Statement) => void) {
if (!shouldEmitModuleDeclaration(node)) {
return;
}
let savedCurrentModuleDeclaration = currentModuleDeclaration;
currentModuleDeclaration = node;
let location = node;
if (!isModuleMergedWithClass(node)) {
let exportFlags = isTopLevelExport(node) ? NodeFlags.Export : undefined;
@ -784,7 +753,7 @@ namespace ts.transform {
let body = node.body;
let moduleBody: Block;
if (isModuleBlock(body)) {
moduleBody = createBlock(visitNodes(body.statements, transformModuleElement));
moduleBody = createBlock(visitNodes(body.statements, transformModuleElement, PipelineFlags.LexicalEnvironment));
}
else {
let inner = visitStatement(body, transformNode);
@ -804,8 +773,9 @@ namespace ts.transform {
let callExpr = createCallExpression2(parenExpr, [moduleParam]);
let callStmt = createExpressionStatement(callExpr, location, NodeFlags.GeneratedNamespace);
callStmt.original = node;
write(callStmt);
write(setOriginalNode(callStmt, node));
currentModuleDeclaration = savedCurrentModuleDeclaration;
}
function shouldEmitModuleDeclaration(node: ModuleDeclaration) {
@ -1382,4 +1352,41 @@ namespace ts.transform {
let conditionalExpr = createConditionalExpression2(equalityExpr, globalSymbolName, globalObjectName);
return conditionalExpr;
}
function isTopLevelExport(node: Node) {
return !!(node.flags & NodeFlags.Export) && isSourceFile(getParentNode());
}
function isTopLevelDefaultExport(node: Node) {
return isTopLevelExport(node) && !!(node.flags & NodeFlags.Default);
}
function isTopLevelNonDefaultExport(node: Node) {
return isTopLevelExport(node) && !(node.flags & NodeFlags.Default);
}
function isNamespaceLevelExport(node: Node) {
return !!(node.flags & NodeFlags.Export) && !isSourceFile(getParentNode());
}
function getContainingModule(): ModuleDeclaration {
return findAncestorNode(isModuleDeclaration);
}
function getContainingModuleName(): Identifier {
let container = findAncestorNode(isModuleDeclaration);
return container ? getGeneratedNameForNode(container) : createIdentifier("exports");
}
function getModuleMemberName(node: Declaration): Expression {
let name = <Identifier>getDeclarationName(node);
Debug.assert(isIdentifier(name));
if (getCombinedNodeFlags(transform) & NodeFlags.Export) {
let container = getContainingModuleName();
let propExpr = createPropertyAccessExpression2(container, name);
return propExpr;
}
return name;
}
}

View file

@ -892,6 +892,10 @@ namespace ts {
type?: TypeNode;
initializer?: Expression;
}
export interface PropertyLikeDeclaration extends Declaration {
name: PropertyName;
}
export interface BindingPattern extends Node {
elements: NodeArray<BindingElement>;