Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Reduce stack depth due to substitution
  • Loading branch information
rbuckton committed Feb 9, 2017
commit a295aa8fd1934b43e8f26e41da2550656e615209
26 changes: 11 additions & 15 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ namespace ts {

// transform hooks
onEmitNode: transform.emitNodeWithNotification,
onSubstituteNode: transform.emitNodeWithSubstitution,
substituteNode: transform.substituteNode,

// sourcemap hooks
onEmitSourceMapOfNode: sourceMap.emitNodeWithSourceMap,
Expand Down Expand Up @@ -198,7 +198,7 @@ namespace ts {
onEmitNode,
onEmitHelpers,
onSetSourceFile,
onSubstituteNode,
substituteNode,
} = handlers;

const newLine = getNewLineCharacter(printerOptions);
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
}
Expand All @@ -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);
Expand Down Expand Up @@ -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));
}
}

Expand Down Expand Up @@ -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);
Expand Down
13 changes: 4 additions & 9 deletions src/compiler/transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ namespace ts {

return {
transformed,
emitNodeWithSubstitution,
substituteNode,
emitNodeWithNotification,
dispose
};
Expand Down Expand Up @@ -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;
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/transformers/es2015.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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);
}
}

Expand Down
2 changes: 0 additions & 2 deletions src/compiler/transformers/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
16 changes: 6 additions & 10 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions src/compiler/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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;

Expand Down
2 changes: 1 addition & 1 deletion src/harness/unittests/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down