Skip to content

Commit fa430ae

Browse files
committed
Allow emitBinary to use state machine for comments/sourcemaps
1 parent 7f49931 commit fa430ae

File tree

1 file changed

+93
-15
lines changed

1 file changed

+93
-15
lines changed

src/compiler/emitter.ts

Lines changed: 93 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,15 +1202,15 @@ namespace ts {
12021202
function emitWithContext<T extends Node>(node: T, emitCallback: (node: T) => void) {
12031203
onBeforeEmitNode?.(node);
12041204

1205+
const emitFlags = getEmitFlags(node);
12051206
const savedPreserveSourceNewlines = preserveSourceNewlines;
1206-
if (preserveSourceNewlines && !!(getEmitFlags(node) & EmitFlags.IgnoreSourceNewlines)) {
1207+
if (preserveSourceNewlines && (emitFlags & EmitFlags.IgnoreSourceNewlines)) {
12071208
preserveSourceNewlines = false;
12081209
}
12091210

12101211
const savedContainerPos = containerPos;
12111212
const savedContainerEnd = containerEnd;
12121213
const savedDeclarationListContainerEnd = declarationListContainerEnd;
1213-
const emitFlags = getEmitFlags(node);
12141214
const commentRange = shouldEmitComments(node) ? getCommentRange(node) : undefined;
12151215
const sourceMapRange = shouldEmitSourceMaps(node) ? getSourceMapRange(node) : undefined;
12161216

@@ -2520,7 +2520,62 @@ namespace ts {
25202520
}
25212521

25222522
function createEmitBinaryExpression() {
2523-
return createBinaryExpressionWalker(noop, maybePipelineEmitExpression, onOperator, maybePipelineEmitExpression, onExit, identity);
2523+
class EmitBinaryExpressionState {
2524+
nested = false;
2525+
preserveSourceNewlines: boolean | undefined = undefined;
2526+
containerPos = -1;
2527+
containerEnd = -1;
2528+
declarationListContainerEnd = -1;
2529+
emitFlags = EmitFlags.None;
2530+
commentRange: TextRange | undefined = undefined;
2531+
sourceMapRange: SourceMapRange | undefined = undefined;
2532+
}
2533+
2534+
return createBinaryExpressionWalker(onEnter, maybeEmitExpression, onOperator, maybeEmitExpression, onExit, identity);
2535+
2536+
function onEnter(node: BinaryExpression, prev: EmitBinaryExpressionState | undefined) {
2537+
const state = new EmitBinaryExpressionState();
2538+
if (prev) {
2539+
// `prev` is only defined when recuring. We can use this fact to indicate
2540+
// we are entering into a nested binary expression and can replicate the
2541+
// leading comment and sourcemap emit performed by `emitWithContext`.
2542+
state.nested = true;
2543+
onBeforeEmitNode?.(node);
2544+
2545+
state.emitFlags = getEmitFlags(node);
2546+
state.preserveSourceNewlines = preserveSourceNewlines;
2547+
if (preserveSourceNewlines && (state.emitFlags & EmitFlags.IgnoreSourceNewlines)) {
2548+
preserveSourceNewlines = false;
2549+
}
2550+
2551+
state.containerPos = containerPos;
2552+
state.containerEnd = containerEnd;
2553+
state.declarationListContainerEnd = declarationListContainerEnd;
2554+
state.commentRange = shouldEmitComments(node) ? getCommentRange(node) : undefined;
2555+
state.sourceMapRange = shouldEmitSourceMaps(node) ? getSourceMapRange(node) : undefined;
2556+
2557+
// Emit leading comments
2558+
if (state.commentRange) {
2559+
emitLeadingCommentsOfNode(node, state.emitFlags, state.commentRange.pos, state.commentRange.end);
2560+
if (state.emitFlags & EmitFlags.NoNestedComments) {
2561+
commentsDisabled = true;
2562+
}
2563+
}
2564+
2565+
// Emit leading sourcemap
2566+
if (state.sourceMapRange) {
2567+
const source = state.sourceMapRange.source || sourceMapSource;
2568+
if ((state.emitFlags & EmitFlags.NoLeadingSourceMap) === 0
2569+
&& state.sourceMapRange.pos >= 0) {
2570+
emitSourcePos(state.sourceMapRange.source || sourceMapSource, skipSourceTrivia(source, state.sourceMapRange.pos));
2571+
}
2572+
if (state.emitFlags & EmitFlags.NoNestedSourceMaps) {
2573+
sourceMapsDisabled = true;
2574+
}
2575+
}
2576+
}
2577+
return state;
2578+
}
25242579

25252580
function onOperator(operatorToken: BinaryOperatorToken, _: unknown, node: BinaryExpression) {
25262581
const isCommaOperator = operatorToken.kind !== SyntaxKind.CommaToken;
@@ -2533,25 +2588,48 @@ namespace ts {
25332588
writeLinesAndIndent(linesAfterOperator, /*writeSpaceIfNotIndenting*/ true);
25342589
}
25352590

2536-
function onExit(node: BinaryExpression) {
2591+
function onExit(node: BinaryExpression, state: EmitBinaryExpressionState) {
25372592
const linesBeforeOperator = getLinesBetweenNodes(node, node.left, node.operatorToken);
25382593
const linesAfterOperator = getLinesBetweenNodes(node, node.operatorToken, node.right);
25392594
decreaseIndentIf(linesBeforeOperator, linesAfterOperator);
2540-
}
25412595

2542-
function maybePipelineEmitExpression(next: Expression) {
2543-
// Then actually do the work of emitting the node `next` returned by the prior state
2544-
// The following section should be identical to `pipelineEmit` save it assumes EmitHint.Expression and offloads
2545-
// binary expression handling, where possible, to the contained work queue
2596+
if (state.nested) {
2597+
// If we are marked as nested, we are recurring. We can use this fact to indicate
2598+
// we are exiting from a nested binary expression and can replicate the trailing
2599+
// comment and sourcemap emit performed by `emitWithContext`.
25462600

2547-
if (!shouldEmitComments(next) && !shouldEmitSourceMaps(next) && isBinaryExpression(next)) {
2548-
// If the target pipeline phase is emit directly, and the next node's also a binary expression,
2549-
// skip all the intermediate indirection and push the expression directly onto the work stack
2550-
return next;
2601+
// Emit trailing sourcemap
2602+
if (state.sourceMapRange) {
2603+
if (state.emitFlags & EmitFlags.NoNestedSourceMaps) {
2604+
sourceMapsDisabled = false;
2605+
}
2606+
if ((state.emitFlags & EmitFlags.NoTrailingSourceMap) === 0
2607+
&& state.sourceMapRange.end >= 0) {
2608+
emitSourcePos(state.sourceMapRange.source || sourceMapSource, state.sourceMapRange.end);
2609+
}
2610+
}
2611+
2612+
// Emit trailing comments
2613+
if (state.commentRange) {
2614+
if (state.emitFlags & EmitFlags.NoNestedComments) {
2615+
commentsDisabled = false;
2616+
}
2617+
emitTrailingCommentsOfNode(node, state.emitFlags, state.commentRange.pos, state.commentRange.end, state.containerPos, state.containerEnd, state.declarationListContainerEnd);
2618+
}
2619+
2620+
onAfterEmitNode?.(node);
2621+
2622+
preserveSourceNewlines = state.preserveSourceNewlines;
25512623
}
2552-
else {
2553-
emit(next);
2624+
}
2625+
2626+
function maybeEmitExpression(next: Expression) {
2627+
// Push a new frame for binary expressions, otherwise emit all other expressions.
2628+
if (isBinaryExpression(next)) {
2629+
return next;
25542630
}
2631+
2632+
emit(next);
25552633
}
25562634
}
25572635

0 commit comments

Comments
 (0)