Reduce stack depth due to substitution

This commit is contained in:
Ron Buckton 2017-02-09 13:10:17 -08:00
parent 3b20d82ba6
commit a295aa8fd1
7 changed files with 27 additions and 42 deletions

View File

@ -37,7 +37,7 @@ namespace ts {
// transform hooks
onEmitNode: transform.emitNodeWithNotification,
onSubstituteNode: transform.emitNodeWithSubstitution,
substituteNode: transform.substituteNode,
// sourcemap hooks
onEmitSourceMapOfNode: sourceMap.emitNodeWithSourceMap,
@ -198,7 +198,7 @@ namespace ts {
onEmitNode,
onEmitHelpers,
onSetSourceFile,
onSubstituteNode,
substituteNode,
} = handlers;
const newLine = getNewLineCharacter(printerOptions);
@ -327,8 +327,8 @@ namespace ts {
setWriter(/*output*/ undefined);
}
function emit(node: Node, hint = EmitHint.Unspecified) {
pipelineEmitWithNotification(hint, node);
function emit(node: Node) {
pipelineEmitWithNotification(EmitHint.Unspecified, node);
}
function emitIdentifierName(node: Identifier) {
@ -349,6 +349,7 @@ namespace ts {
}
function pipelineEmitWithComments(hint: EmitHint, node: Node) {
node = trySubstituteNode(hint, node);
if (emitNodeWithComments && hint !== EmitHint.SourceFile) {
emitNodeWithComments(hint, node, pipelineEmitWithSourceMap);
}
@ -359,16 +360,7 @@ namespace ts {
function pipelineEmitWithSourceMap(hint: EmitHint, node: Node) {
if (onEmitSourceMapOfNode && hint !== EmitHint.SourceFile && hint !== EmitHint.IdentifierName) {
onEmitSourceMapOfNode(hint, node, pipelineEmitWithSubstitution);
}
else {
pipelineEmitWithSubstitution(hint, node);
}
}
function pipelineEmitWithSubstitution(hint: EmitHint, node: Node) {
if (onSubstituteNode) {
onSubstituteNode(hint, node, pipelineEmitWithHint);
onEmitSourceMapOfNode(hint, node, pipelineEmitWithHint);
}
else {
pipelineEmitWithHint(hint, node);
@ -634,7 +626,7 @@ namespace ts {
// If the node is an expression, try to emit it as an expression with
// substitution.
if (isExpression(node)) {
return pipelineEmitWithSubstitution(EmitHint.Expression, node);
return pipelineEmitExpression(trySubstituteNode(EmitHint.Expression, node));
}
}
@ -731,6 +723,10 @@ namespace ts {
}
}
function trySubstituteNode(hint: EmitHint, node: Node) {
return node && substituteNode && substituteNode(hint, node) || node;
}
function emitBodyIndirect(node: Node, elements: NodeArray<Node>, emitCallback: (node: Node) => void): void {
if (emitBodyWithDetachedComments) {
emitBodyWithDetachedComments(node, elements, emitCallback);

View File

@ -159,7 +159,7 @@ namespace ts {
return {
transformed,
emitNodeWithSubstitution,
substituteNode,
emitNodeWithNotification,
dispose
};
@ -191,14 +191,9 @@ namespace ts {
* @param node The node to emit.
* @param emitCallback The callback used to emit the node or its substitute.
*/
function emitNodeWithSubstitution(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
Debug.assert(state < TransformationState.Disposed, "Cannot invoke TransformationResult callbacks after the result is disposed.");
if (node) {
if (isSubstitutionEnabled(node)) {
node = onSubstituteNode(hint, node) || node;
}
emitCallback(hint, node);
}
function substituteNode(hint: EmitHint, node: Node) {
Debug.assert(state < TransformationState.Disposed, "Cannot substitute a node after the result is disposed.");
return node && isSubstitutionEnabled(node) && onSubstituteNode(hint, node) || node;
}
/**

View File

@ -3549,7 +3549,7 @@ namespace ts {
if (enabledSubstitutions & ES2015SubstitutionFlags.BlockScopedBindings) {
const original = getParseTreeNode(node, isIdentifier);
if (original && isNameOfDeclarationWithCollidingName(original)) {
return getGeneratedNameForNode(original);
return setTextRange(getGeneratedNameForNode(original), node);
}
}
@ -3602,7 +3602,7 @@ namespace ts {
if (enabledSubstitutions & ES2015SubstitutionFlags.BlockScopedBindings) {
const declaration = resolver.getReferencedDeclarationWithCollidingName(node);
if (declaration) {
return getGeneratedNameForNode(declaration.name);
return setTextRange(getGeneratedNameForNode(declaration.name), node);
}
}

View File

@ -3322,8 +3322,6 @@ namespace ts {
: getTextOfNode(node.argumentExpression);
addSyntheticTrailingComment(substitute, SyntaxKind.MultiLineCommentTrivia, ` ${propertyName} `);
// wrap the substituted node so that it emits its own comments.
return createPartiallyEmittedExpression(substitute);
}
return substitute;

View File

@ -3901,13 +3901,12 @@
diagnostics?: Diagnostic[];
/**
* Emits the substitute for a node, if one is available; otherwise, emits the node.
* Gets a substitute for a node, if one is available; otherwise, returns the original node.
*
* @param hint A hint as to the intended usage of the node.
* @param node The node to substitute.
* @param emitCallback A callback used to emit the node or its substitute.
*/
emitNodeWithSubstitution(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
substituteNode(hint: EmitHint, node: Node): Node;
/**
* Emits a node with possible notification.
@ -3998,23 +3997,20 @@
/**
* A hook used by the Printer to perform just-in-time substitution of a node. This is
* primarily used by node transformations that need to substitute one node for another,
* such as replacing `myExportedVar` with `exports.myExportedVar`. A compatible
* implementation **must** invoke `emitCallback` eith the provided `hint` and either
* the provided `node`, or its substitute.
* such as replacing `myExportedVar` with `exports.myExportedVar`.
* @param hint A hint indicating the intended purpose of the node.
* @param node The node to emit.
* @param emitCallback A callback that, when invoked, will emit the node.
* @example
* ```ts
* var printer = createPrinter(printerOptions, {
* onSubstituteNode(hint, node, emitCallback) {
* substituteNode(hint, node) {
* // perform substitution if necessary...
* emitCallback(hint, node);
* return node;
* }
* });
* ```
*/
onSubstituteNode?(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
substituteNode?(hint: EmitHint, node: Node): Node;
/*@internal*/ onEmitSourceMapOfNode?: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void;
/*@internal*/ onEmitSourceMapOfToken?: (node: Node, token: SyntaxKind, pos: number, emitCallback: (token: SyntaxKind, pos: number) => number) => number;
/*@internal*/ onEmitSourceMapOfPosition?: (pos: number) => void;

View File

@ -709,7 +709,7 @@ namespace ts {
return node ? f(initial, node) : initial;
}
function reduceNodeArray<T>(nodes: Node[], f: (memo: T, nodes: Node[]) => T, initial: T) {
function reduceNodeArray<T>(nodes: NodeArray<Node>, f: (memo: T, nodes: NodeArray<Node>) => T, initial: T) {
return nodes ? f(initial, nodes) : initial;
}
@ -721,12 +721,12 @@ namespace ts {
* @param initial The initial value to supply to the reduction.
* @param f The callback function
*/
export function reduceEachChild<T>(node: Node, initial: T, cbNode: (memo: T, node: Node) => T, cbNodeArray?: (memo: T, nodes: Node[]) => T): T {
export function reduceEachChild<T>(node: Node, initial: T, cbNode: (memo: T, node: Node) => T, cbNodeArray?: (memo: T, nodes: NodeArray<Node>) => T): T {
if (node === undefined) {
return initial;
}
const reduceNodes: (nodes: Node[], f: (memo: T, node: Node | Node[]) => T, initial: T) => T = cbNodeArray ? reduceNodeArray : reduceLeft;
const reduceNodes: (nodes: NodeArray<Node>, f: (memo: T, node: Node | NodeArray<Node>) => T, initial: T) => T = cbNodeArray ? reduceNodeArray : reduceLeft;
const cbNodes = cbNodeArray || cbNode;
const kind = node.kind;

View File

@ -9,7 +9,7 @@ namespace ts {
const transformed = transform(createSourceFile("source.ts", source, ScriptTarget.ES2015), transformers);
const printer = createPrinter({ newLine: NewLineKind.CarriageReturnLineFeed }, {
onEmitNode: transformed.emitNodeWithNotification,
onSubstituteNode: transformed.emitNodeWithSubstitution
substituteNode: transformed.substituteNode
});
const result = printer.printBundle(createBundle(transformed.transformed));
transformed.dispose();