Skip to content

Commit bfb8933

Browse files
committed
Refactored emit pipeline.
1 parent c1ee534 commit bfb8933

File tree

11 files changed

+310
-306
lines changed

11 files changed

+310
-306
lines changed

src/compiler/comments.ts

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace ts {
55
export interface CommentWriter {
66
reset(): void;
77
setSourceFile(sourceFile: SourceFile): void;
8-
emitNodeWithComments(node: Node, emitCallback: (node: Node) => void): void;
8+
emitNodeWithComments(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void;
99
emitBodyWithDetachedComments(node: Node, detachedRange: TextRange, emitCallback: (node: Node) => void): void;
1010
emitTrailingCommentsOfPosition(pos: number): void;
1111
}
@@ -34,9 +34,9 @@ namespace ts {
3434
emitTrailingCommentsOfPosition,
3535
};
3636

37-
function emitNodeWithComments(node: Node, emitCallback: (node: Node) => void) {
37+
function emitNodeWithComments(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) {
3838
if (disabled) {
39-
emitCallback(node);
39+
emitCallback(emitContext, node);
4040
return;
4141
}
4242

@@ -46,10 +46,12 @@ namespace ts {
4646
if ((pos < 0 && end < 0) || (pos === end)) {
4747
// Both pos and end are synthesized, so just emit the node without comments.
4848
if (emitFlags & EmitFlags.NoNestedComments) {
49-
disableCommentsAndEmit(node, emitCallback);
49+
disabled = true;
50+
emitCallback(emitContext, node);
51+
disabled = false;
5052
}
5153
else {
52-
emitCallback(node);
54+
emitCallback(emitContext, node);
5355
}
5456
}
5557
else {
@@ -91,10 +93,12 @@ namespace ts {
9193
}
9294

9395
if (emitFlags & EmitFlags.NoNestedComments) {
94-
disableCommentsAndEmit(node, emitCallback);
96+
disabled = true;
97+
emitCallback(emitContext, node);
98+
disabled = false;
9599
}
96100
else {
97-
emitCallback(node);
101+
emitCallback(emitContext, node);
98102
}
99103

100104
if (extendedDiagnostics) {
@@ -137,8 +141,10 @@ namespace ts {
137141
performance.measure("commentTime", "preEmitBodyWithDetachedComments");
138142
}
139143

140-
if (emitFlags & EmitFlags.NoNestedComments) {
141-
disableCommentsAndEmit(node, emitCallback);
144+
if (emitFlags & EmitFlags.NoNestedComments && !disabled) {
145+
disabled = true;
146+
emitCallback(node);
147+
disabled = false;
142148
}
143149
else {
144150
emitCallback(node);
@@ -284,17 +290,6 @@ namespace ts {
284290
detachedCommentsInfo = undefined;
285291
}
286292

287-
function disableCommentsAndEmit(node: Node, emitCallback: (node: Node) => void): void {
288-
if (disabled) {
289-
emitCallback(node);
290-
}
291-
else {
292-
disabled = true;
293-
emitCallback(node);
294-
disabled = false;
295-
}
296-
}
297-
298293
function hasDetachedComments(pos: number) {
299294
return detachedCommentsInfo !== undefined && lastOrUndefined(detachedCommentsInfo).nodePos === pos;
300295
}

src/compiler/emitter.ts

Lines changed: 99 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -229,33 +229,27 @@ const _super = (function (geti, seti) {
229229
let isOwnFileEmit: boolean;
230230
let emitSkipped = false;
231231

232-
performance.mark("beforeTransform");
232+
const sourceFiles = getSourceFilesToEmit(host, targetSourceFile);
233233

234234
// Transform the source files
235-
const transformed = transformFiles(
236-
resolver,
237-
host,
238-
getSourceFilesToEmit(host, targetSourceFile),
239-
transformers);
240-
241-
performance.measure("transformTime", "beforeTransform");
242-
243-
// Extract helpers from the result
235+
performance.mark("beforeTransform");
244236
const {
237+
transformed,
245238
emitNodeWithSubstitution,
246239
emitNodeWithNotification
247-
} = transformed;
248-
249-
performance.mark("beforePrint");
240+
} = transformFiles(resolver, host, sourceFiles, transformers);
241+
performance.measure("transformTime", "beforeTransform");
250242

251243
// Emit each output file
252-
forEachTransformedEmitFile(host, transformed.getSourceFiles(), emitFile);
253-
254-
// Clean up after transformation
255-
transformed.dispose();
256-
244+
performance.mark("beforePrint");
245+
forEachTransformedEmitFile(host, transformed, emitFile);
257246
performance.measure("printTime", "beforePrint");
258247

248+
// Clean up emit nodes on parse tree
249+
for (const sourceFile of sourceFiles) {
250+
disposeEmitNodes(sourceFile);
251+
}
252+
259253
return {
260254
emitSkipped,
261255
diagnostics: emitterDiagnostics.getDiagnostics(),
@@ -346,111 +340,137 @@ const _super = (function (geti, seti) {
346340
currentFileIdentifiers = node.identifiers;
347341
sourceMap.setSourceFile(node);
348342
comments.setSourceFile(node);
349-
emitNodeWithNotification(node, emitWithSubstitution);
343+
pipelineEmitWithNotification(EmitContext.SourceFile, node);
350344
}
351345

352346
/**
353347
* Emits a node.
354348
*/
355349
function emit(node: Node) {
356-
emitNodeWithNotification(node, emitWithComments);
350+
pipelineEmitWithNotification(EmitContext.Unspecified, node);
357351
}
358352

359353
/**
360-
* Emits a node with comments.
361-
*
362-
* NOTE: Do not call this method directly. It is part of the emit pipeline
363-
* and should only be called indirectly from emit.
354+
* Emits an IdentifierName.
364355
*/
365-
function emitWithComments(node: Node) {
366-
emitNodeWithComments(node, emitWithSourceMap);
356+
function emitIdentifierName(node: Identifier) {
357+
pipelineEmitWithNotification(EmitContext.IdentifierName, node);
367358
}
368359

369360
/**
370-
* Emits a node with source maps.
371-
*
372-
* NOTE: Do not call this method directly. It is part of the emit pipeline
373-
* and should only be called indirectly from emitWithComments.
361+
* Emits an expression node.
374362
*/
375-
function emitWithSourceMap(node: Node) {
376-
emitNodeWithSourceMap(node, emitWithSubstitution);
363+
function emitExpression(node: Expression) {
364+
pipelineEmitWithNotification(EmitContext.Expression, node);
377365
}
378366

379367
/**
380-
* Emits a node with possible substitution.
368+
* Emits a node with possible notification.
381369
*
382370
* NOTE: Do not call this method directly. It is part of the emit pipeline
383-
* and should only be called indirectly from emitWithSourceMap or
384-
* emitIdentifierNameWithComments.
371+
* and should only be called from printSourceFile, emit, emitExpression, or
372+
* emitIdentifierName.
385373
*/
386-
function emitWithSubstitution(node: Node) {
387-
emitNodeWithSubstitution(node, /*isExpression*/ false, emitWorker);
374+
function pipelineEmitWithNotification(emitContext: EmitContext, node: Node) {
375+
emitNodeWithNotification(emitContext, node, pipelineEmitWithComments);
388376
}
389377

390378
/**
391-
* Emits an IdentifierName.
379+
* Emits a node with comments.
380+
*
381+
* NOTE: Do not call this method directly. It is part of the emit pipeline
382+
* and should only be called indirectly from pipelineEmitWithNotification.
392383
*/
393-
function emitIdentifierName(node: Identifier) {
394-
if (node) {
395-
emitNodeWithNotification(node, emitIdentifierNameWithComments);
384+
function pipelineEmitWithComments(emitContext: EmitContext, node: Node) {
385+
// Do not emit comments for SourceFile
386+
if (emitContext === EmitContext.SourceFile) {
387+
pipelineEmitWithSourceMap(emitContext, node);
388+
return;
396389
}
390+
391+
emitNodeWithComments(emitContext, node, pipelineEmitWithSourceMap);
397392
}
398393

399394
/**
400-
* Emits an IdentifierName with possible comments.
395+
* Emits a node with source maps.
401396
*
402397
* NOTE: Do not call this method directly. It is part of the emit pipeline
403-
* and should only be called indirectly from emitIdentifierName.
398+
* and should only be called indirectly from pipelineEmitWithComments.
404399
*/
405-
function emitIdentifierNameWithComments(node: Identifier) {
406-
emitNodeWithComments(node, emitWithSubstitution);
400+
function pipelineEmitWithSourceMap(emitContext: EmitContext, node: Node) {
401+
// Do not emit source mappings for SourceFile or IdentifierName
402+
if (emitContext === EmitContext.SourceFile
403+
|| emitContext === EmitContext.IdentifierName) {
404+
pipelineEmitWithSubstitution(emitContext, node);
405+
return;
406+
}
407+
408+
emitNodeWithSourceMap(emitContext, node, pipelineEmitWithSubstitution);
407409
}
408410

409411
/**
410-
* Emits an expression node.
412+
* Emits a node with possible substitution.
413+
*
414+
* NOTE: Do not call this method directly. It is part of the emit pipeline
415+
* and should only be called indirectly from pipelineEmitWithSourceMap or
416+
* pipelineEmitInUnspecifiedContext (when pickign a more specific context).
411417
*/
412-
function emitExpression(node: Expression) {
413-
emitNodeWithNotification(node, emitExpressionWithComments);
418+
function pipelineEmitWithSubstitution(emitContext: EmitContext, node: Node) {
419+
emitNodeWithSubstitution(emitContext, node, pipelineEmitForContext);
414420
}
415421

416422
/**
417-
* Emits an expression with comments.
423+
* Emits a node.
418424
*
419-
* NOTE: Do not call this method directly. It is part of the emitExpression pipeline
420-
* and should only be called indirectly from emitExpression.
425+
* NOTE: Do not call this method directly. It is part of the emit pipeline
426+
* and should only be called indirectly from pipelineEmitWithSubstitution.
421427
*/
422-
function emitExpressionWithComments(node: Expression) {
423-
emitNodeWithComments(node, emitExpressionWithSourceMap);
428+
function pipelineEmitForContext(emitContext: EmitContext, node: Node): void {
429+
switch (emitContext) {
430+
case EmitContext.SourceFile: return pipelineEmitInSourceFileContext(node);
431+
case EmitContext.IdentifierName: return pipelineEmitInIdentifierNameContext(node);
432+
case EmitContext.Unspecified: return pipelineEmitInUnspecifiedContext(node);
433+
case EmitContext.Expression: return pipelineEmitInExpressionContext(node);
434+
}
424435
}
425436

426437
/**
427-
* Emits an expression with possible source maps.
438+
* Emits a node in the SourceFile EmitContext.
428439
*
429-
* NOTE: Do not call this method directly. It is part of the emitExpression pipeline
430-
* and should only be called indirectly from emitExpressionWithComments.
440+
* NOTE: Do not call this method directly. It is part of the emit pipeline
441+
* and should only be called indirectly from pipelineEmitForContext.
431442
*/
432-
function emitExpressionWithSourceMap(node: Expression) {
433-
emitNodeWithSourceMap(node, emitExpressionWithSubstitution);
443+
function pipelineEmitInSourceFileContext(node: Node): void {
444+
const kind = node.kind;
445+
switch (kind) {
446+
// Top-level nodes
447+
case SyntaxKind.SourceFile:
448+
return emitSourceFile(<SourceFile>node);
449+
}
434450
}
435451

436452
/**
437-
* Emits an expression with possible substitution.
453+
* Emits a node in the IdentifierName EmitContext.
438454
*
439-
* NOTE: Do not call this method directly. It is part of the emitExpression pipeline
440-
* and should only be called indirectly from emitExpressionWithSourceMap or
441-
* from emitWorker.
455+
* NOTE: Do not call this method directly. It is part of the emit pipeline
456+
* and should only be called indirectly from pipelineEmitForContext.
442457
*/
443-
function emitExpressionWithSubstitution(node: Expression) {
444-
emitNodeWithSubstitution(node, /*isExpression*/ true, emitExpressionWorker);
458+
function pipelineEmitInIdentifierNameContext(node: Node): void {
459+
const kind = node.kind;
460+
switch (kind) {
461+
// Identifiers
462+
case SyntaxKind.Identifier:
463+
return emitIdentifier(<Identifier>node);
464+
}
445465
}
446466

447467
/**
448-
* Emits a node.
468+
* Emits a node in the Unspecified EmitContext.
449469
*
450470
* NOTE: Do not call this method directly. It is part of the emit pipeline
451-
* and should only be called indirectly from emitNodeWithSubstitution.
471+
* and should only be called indirectly from pipelineEmitForContext.
452472
*/
453-
function emitWorker(node: Node): void {
473+
function pipelineEmitInUnspecifiedContext(node: Node): void {
454474
const kind = node.kind;
455475
switch (kind) {
456476
// Pseudo-literals
@@ -486,7 +506,8 @@ const _super = (function (geti, seti) {
486506
case SyntaxKind.StringKeyword:
487507
case SyntaxKind.SymbolKeyword:
488508
case SyntaxKind.GlobalKeyword:
489-
return emitTokenNode(node);
509+
writeTokenText(kind);
510+
return;
490511

491512
// Parse tree nodes
492513

@@ -691,27 +712,24 @@ const _super = (function (geti, seti) {
691712
case SyntaxKind.EnumMember:
692713
return emitEnumMember(<EnumMember>node);
693714

694-
// Top-level nodes
695-
case SyntaxKind.SourceFile:
696-
return emitSourceFile(<SourceFile>node);
697-
698715
// JSDoc nodes (ignored)
699-
700716
// Transformation nodes (ignored)
701717
}
702718

719+
// If the node is an expression, try to emit it as an expression with
720+
// substitution.
703721
if (isExpression(node)) {
704-
return emitExpressionWithSubstitution(node);
722+
return pipelineEmitWithSubstitution(EmitContext.Expression, node);
705723
}
706724
}
707725

708726
/**
709-
* Emits an expression.
727+
* Emits a node in the Expression EmitContext.
710728
*
711-
* NOTE: Do not call this method directly. It is part of the emitExpression pipeline
712-
* and should only be called indirectly from emitExpressionWithNotification.
729+
* NOTE: Do not call this method directly. It is part of the emit pipeline
730+
* and should only be called indirectly from pipelineEmitForContext.
713731
*/
714-
function emitExpressionWorker(node: Node) {
732+
function pipelineEmitInExpressionContext(node: Node): void {
715733
const kind = node.kind;
716734
switch (kind) {
717735
// Literals
@@ -733,7 +751,8 @@ const _super = (function (geti, seti) {
733751
case SyntaxKind.SuperKeyword:
734752
case SyntaxKind.TrueKeyword:
735753
case SyntaxKind.ThisKeyword:
736-
return emitTokenNode(node);
754+
writeTokenText(kind);
755+
return;
737756

738757
// Expressions
739758
case SyntaxKind.ArrayLiteralExpression:
@@ -2444,15 +2463,7 @@ const _super = (function (geti, seti) {
24442463
function writeTokenText(token: SyntaxKind, pos?: number) {
24452464
const tokenString = tokenToString(token);
24462465
write(tokenString);
2447-
return positionIsSynthesized(pos) ? -1 : pos + tokenString.length;
2448-
}
2449-
2450-
function emitTokenNode(node: Node) {
2451-
emitNodeWithSourceMap(node, emitTokenNodeWorker);
2452-
}
2453-
2454-
function emitTokenNodeWorker(node: Node) {
2455-
writeTokenText(node.kind);
2466+
return pos < 0 ? pos : pos + tokenString.length;
24562467
}
24572468

24582469
function increaseIndentIf(value: boolean, valueToWriteWhenNotIndenting?: string) {

0 commit comments

Comments
 (0)