Skip to content

Commit 12cd0bf

Browse files
committed
Remove EmitHelperState, general helper cleanup.
1 parent 5f5b117 commit 12cd0bf

File tree

13 files changed

+725
-620
lines changed

13 files changed

+725
-620
lines changed

src/compiler/factory.ts

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,23 +1695,8 @@ namespace ts {
16951695

16961696
// Helpers
16971697

1698-
export interface EmitHelperState {
1699-
currentSourceFile: SourceFile;
1700-
compilerOptions: CompilerOptions;
1701-
requestedHelpers?: EmitHelper[];
1702-
}
1703-
1704-
export function getHelperName(helperState: EmitHelperState, name: string) {
1705-
const externalHelpersModuleName = getOrCreateExternalHelpersModuleName(helperState.currentSourceFile, helperState.compilerOptions);
1706-
return externalHelpersModuleName
1707-
? createPropertyAccess(externalHelpersModuleName, name)
1708-
: createIdentifier(name);
1709-
}
1710-
1711-
export function requestEmitHelper(helperState: EmitHelperState, helper: EmitHelper) {
1712-
if (!contains(helperState.requestedHelpers, helper)) {
1713-
helperState.requestedHelpers = append(helperState.requestedHelpers, helper);
1714-
}
1698+
export function getHelperName(name: string) {
1699+
return setEmitFlags(createIdentifier(name), EmitFlags.HelperName | EmitFlags.AdviseOnEmitNode);
17151700
}
17161701

17171702
export interface CallBinding {
@@ -2061,6 +2046,10 @@ namespace ts {
20612046

20622047
// Utilities
20632048

2049+
export function convertToFunctionBody(node: ConciseBody) {
2050+
return isBlock(node) ? node : createBlock([createReturn(node, /*location*/ node)], /*location*/ node);
2051+
}
2052+
20642053
function isUseStrictPrologue(node: ExpressionStatement): boolean {
20652054
return (node.expression as StringLiteral).text === "use strict";
20662055
}
@@ -2110,6 +2099,13 @@ namespace ts {
21102099
return statementOffset;
21112100
}
21122101

2102+
export function startsWithUseStrict(statements: Statement[]) {
2103+
const firstStatement = firstOrUndefined(statements);
2104+
return firstStatement !== undefined
2105+
&& isPrologueDirective(firstStatement)
2106+
&& isUseStrictPrologue(firstStatement);
2107+
}
2108+
21132109
/**
21142110
* Ensures "use strict" directive is added
21152111
*
@@ -2606,7 +2602,7 @@ namespace ts {
26062602
*
26072603
* @param node The node.
26082604
*/
2609-
function getOrCreateEmitNode(node: Node) {
2605+
export function getOrCreateEmitNode(node: Node) {
26102606
if (!node.emitNode) {
26112607
if (isParseTreeNode(node)) {
26122608
// To avoid holding onto transformation artifacts, we keep track of any
@@ -2735,14 +2731,25 @@ namespace ts {
27352731
return emitNode && emitNode.externalHelpersModuleName;
27362732
}
27372733

2738-
export function getOrCreateExternalHelpersModuleName(node: SourceFile, compilerOptions: CompilerOptions) {
2734+
export function getOrCreateExternalHelpersModuleNameIfNeeded(node: SourceFile, compilerOptions: CompilerOptions) {
27392735
if (compilerOptions.importHelpers && (isExternalModule(node) || compilerOptions.isolatedModules)) {
2740-
const parseNode = getOriginalNode(node, isSourceFile);
2741-
const emitNode = getOrCreateEmitNode(parseNode);
2742-
return emitNode.externalHelpersModuleName || (emitNode.externalHelpersModuleName = createUniqueName(externalHelpersModuleNameText));
2736+
const externalHelpersModuleName = getExternalHelpersModuleName(node);
2737+
if (externalHelpersModuleName) {
2738+
return externalHelpersModuleName;
2739+
}
2740+
2741+
const helpers = getEmitHelpers(node);
2742+
if (helpers) {
2743+
for (const helper of helpers) {
2744+
if (!helper.scoped) {
2745+
const parseNode = getOriginalNode(node, isSourceFile);
2746+
const emitNode = getOrCreateEmitNode(parseNode);
2747+
return emitNode.externalHelpersModuleName || (emitNode.externalHelpersModuleName = createUniqueName(externalHelpersModuleNameText));
2748+
}
2749+
}
2750+
}
27432751
}
27442752
}
2745-
27462753
/**
27472754
* Adds an EmitHelper to a node.
27482755
*/
@@ -2930,7 +2937,7 @@ namespace ts {
29302937
hasExportStarsToExportValues: boolean; // whether this module contains export*
29312938
}
29322939

2933-
export function collectExternalModuleInfo(sourceFile: SourceFile, resolver: EmitResolver): ExternalModuleInfo {
2940+
export function collectExternalModuleInfo(sourceFile: SourceFile, resolver: EmitResolver, compilerOptions: CompilerOptions): ExternalModuleInfo {
29342941
const externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[] = [];
29352942
const exportSpecifiers = createMap<ExportSpecifier[]>();
29362943
const exportedBindings = createMap<Identifier[]>();
@@ -2940,7 +2947,7 @@ namespace ts {
29402947
let exportEquals: ExportAssignment = undefined;
29412948
let hasExportStarsToExportValues = false;
29422949

2943-
const externalHelpersModuleName = getExternalHelpersModuleName(sourceFile);
2950+
const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(sourceFile, compilerOptions);
29442951
const externalHelpersImportDeclaration = externalHelpersModuleName && createImportDeclaration(
29452952
/*decorators*/ undefined,
29462953
/*modifiers*/ undefined,

src/compiler/transformer.ts

Lines changed: 71 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -26,84 +26,6 @@ namespace ts {
2626
EmitNotifications = 1 << 1,
2727
}
2828

29-
export interface TransformationResult {
30-
/**
31-
* Gets the transformed source files.
32-
*/
33-
transformed: SourceFile[];
34-
35-
/**
36-
* Emits the substitute for a node, if one is available; otherwise, emits the node.
37-
*
38-
* @param emitContext The current emit context.
39-
* @param node The node to substitute.
40-
* @param emitCallback A callback used to emit the node or its substitute.
41-
*/
42-
emitNodeWithSubstitution(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void;
43-
44-
/**
45-
* Emits a node with possible notification.
46-
*
47-
* @param emitContext The current emit context.
48-
* @param node The node to emit.
49-
* @param emitCallback A callback used to emit the node.
50-
*/
51-
emitNodeWithNotification(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void;
52-
}
53-
54-
export interface TransformationContext extends LexicalEnvironment {
55-
getCompilerOptions(): CompilerOptions;
56-
getEmitResolver(): EmitResolver;
57-
getEmitHost(): EmitHost;
58-
59-
/**
60-
* Hoists a function declaration to the containing scope.
61-
*/
62-
hoistFunctionDeclaration(node: FunctionDeclaration): void;
63-
64-
/**
65-
* Hoists a variable declaration to the containing scope.
66-
*/
67-
hoistVariableDeclaration(node: Identifier): void;
68-
69-
/**
70-
* Enables expression substitutions in the pretty printer for the provided SyntaxKind.
71-
*/
72-
enableSubstitution(kind: SyntaxKind): void;
73-
74-
/**
75-
* Determines whether expression substitutions are enabled for the provided node.
76-
*/
77-
isSubstitutionEnabled(node: Node): boolean;
78-
79-
/**
80-
* Hook used by transformers to substitute expressions just before they
81-
* are emitted by the pretty printer.
82-
*/
83-
onSubstituteNode?: (emitContext: EmitContext, node: Node) => Node;
84-
85-
/**
86-
* Enables before/after emit notifications in the pretty printer for the provided
87-
* SyntaxKind.
88-
*/
89-
enableEmitNotification(kind: SyntaxKind): void;
90-
91-
/**
92-
* Determines whether before/after emit notifications should be raised in the pretty
93-
* printer when it emits a node.
94-
*/
95-
isEmitNotificationEnabled(node: Node): boolean;
96-
97-
/**
98-
* Hook used to allow transformers to capture state before or after
99-
* the printer emits a node.
100-
*/
101-
onEmitNode?: (emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) => void;
102-
}
103-
104-
/* @internal */
105-
export type Transformer = (context: TransformationContext) => (node: SourceFile) => SourceFile;
106-
10729
export function getTransformers(compilerOptions: CompilerOptions) {
10830
const jsx = compilerOptions.jsx;
10931
const languageVersion = getEmitScriptTarget(compilerOptions);
@@ -149,25 +71,33 @@ namespace ts {
14971
* @param transforms An array of Transformers.
15072
*/
15173
export function transformFiles(resolver: EmitResolver, host: EmitHost, sourceFiles: SourceFile[], transformers: Transformer[]): TransformationResult {
152-
const lexicalEnvironmentVariableDeclarationsStack: VariableDeclaration[][] = [];
153-
const lexicalEnvironmentFunctionDeclarationsStack: FunctionDeclaration[][] = [];
15474
const enabledSyntaxKindFeatures = new Array<SyntaxKindFeatureFlags>(SyntaxKind.Count);
15575

76+
let scopeModificationDisabled = false;
77+
78+
let lexicalEnvironmentVariableDeclarations: VariableDeclaration[];
79+
let lexicalEnvironmentFunctionDeclarations: FunctionDeclaration[];
80+
let lexicalEnvironmentVariableDeclarationsStack: VariableDeclaration[][] = [];
81+
let lexicalEnvironmentFunctionDeclarationsStack: FunctionDeclaration[][] = [];
15682
let lexicalEnvironmentStackOffset = 0;
157-
let hoistedVariableDeclarations: VariableDeclaration[];
158-
let hoistedFunctionDeclarations: FunctionDeclaration[];
159-
let lexicalEnvironmentDisabled: boolean;
83+
let lexicalEnvironmentSuspended = false;
84+
85+
let emitHelpers: EmitHelper[];
16086

16187
// The transformation context is provided to each transformer as part of transformer
16288
// initialization.
16389
const context: TransformationContext = {
16490
getCompilerOptions: () => host.getCompilerOptions(),
16591
getEmitResolver: () => resolver,
16692
getEmitHost: () => host,
167-
hoistVariableDeclaration,
168-
hoistFunctionDeclaration,
16993
startLexicalEnvironment,
94+
suspendLexicalEnvironment,
95+
resumeLexicalEnvironment,
17096
endLexicalEnvironment,
97+
hoistVariableDeclaration,
98+
hoistFunctionDeclaration,
99+
requestEmitHelper,
100+
readEmitHelpers,
171101
onSubstituteNode: (_emitContext, node) => node,
172102
enableSubstitution,
173103
isSubstitutionEnabled,
@@ -183,7 +113,7 @@ namespace ts {
183113
const transformed = map(sourceFiles, transformSourceFile);
184114

185115
// Disable modification of the lexical environment.
186-
lexicalEnvironmentDisabled = true;
116+
scopeModificationDisabled = true;
187117

188118
return {
189119
transformed,
@@ -278,64 +208,80 @@ namespace ts {
278208
* Records a hoisted variable declaration for the provided name within a lexical environment.
279209
*/
280210
function hoistVariableDeclaration(name: Identifier): void {
281-
Debug.assert(!lexicalEnvironmentDisabled, "Cannot modify the lexical environment during the print phase.");
211+
Debug.assert(!scopeModificationDisabled, "Cannot modify the lexical environment during the print phase.");
282212
const decl = createVariableDeclaration(name);
283-
if (!hoistedVariableDeclarations) {
284-
hoistedVariableDeclarations = [decl];
213+
if (!lexicalEnvironmentVariableDeclarations) {
214+
lexicalEnvironmentVariableDeclarations = [decl];
285215
}
286216
else {
287-
hoistedVariableDeclarations.push(decl);
217+
lexicalEnvironmentVariableDeclarations.push(decl);
288218
}
289219
}
290220

291221
/**
292222
* Records a hoisted function declaration within a lexical environment.
293223
*/
294224
function hoistFunctionDeclaration(func: FunctionDeclaration): void {
295-
Debug.assert(!lexicalEnvironmentDisabled, "Cannot modify the lexical environment during the print phase.");
296-
if (!hoistedFunctionDeclarations) {
297-
hoistedFunctionDeclarations = [func];
225+
Debug.assert(!scopeModificationDisabled, "Cannot modify the lexical environment during the print phase.");
226+
if (!lexicalEnvironmentFunctionDeclarations) {
227+
lexicalEnvironmentFunctionDeclarations = [func];
298228
}
299229
else {
300-
hoistedFunctionDeclarations.push(func);
230+
lexicalEnvironmentFunctionDeclarations.push(func);
301231
}
302232
}
303233

234+
/** Suspends the current lexical environment, usually after visiting a parameter list. */
235+
function suspendLexicalEnvironment(): void {
236+
Debug.assert(!scopeModificationDisabled, "Cannot suspend a lexical environment during the print phase.");
237+
Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is already suspended.");
238+
lexicalEnvironmentSuspended = true;
239+
}
240+
241+
/** Resumes a suspended lexical environment, usually before visiting a function body. */
242+
function resumeLexicalEnvironment(): void {
243+
Debug.assert(!scopeModificationDisabled, "Cannot resume a lexical environment during the print phase.");
244+
Debug.assert(lexicalEnvironmentSuspended, "Lexical environment is not suspended suspended.");
245+
lexicalEnvironmentSuspended = false;
246+
}
247+
304248
/**
305249
* Starts a new lexical environment. Any existing hoisted variable or function declarations
306250
* are pushed onto a stack, and the related storage variables are reset.
307251
*/
308252
function startLexicalEnvironment(): void {
309-
Debug.assert(!lexicalEnvironmentDisabled, "Cannot start a lexical environment during the print phase.");
253+
Debug.assert(!scopeModificationDisabled, "Cannot start a lexical environment during the print phase.");
254+
Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is suspended.");
310255

311256
// Save the current lexical environment. Rather than resizing the array we adjust the
312257
// stack size variable. This allows us to reuse existing array slots we've
313258
// already allocated between transformations to avoid allocation and GC overhead during
314259
// transformation.
315-
lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset] = hoistedVariableDeclarations;
316-
lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset] = hoistedFunctionDeclarations;
260+
lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentVariableDeclarations;
261+
lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentFunctionDeclarations;
317262
lexicalEnvironmentStackOffset++;
318-
hoistedVariableDeclarations = undefined;
319-
hoistedFunctionDeclarations = undefined;
263+
lexicalEnvironmentVariableDeclarations = undefined;
264+
lexicalEnvironmentFunctionDeclarations = undefined;
320265
}
321266

322267
/**
323268
* Ends a lexical environment. The previous set of hoisted declarations are restored and
324269
* any hoisted declarations added in this environment are returned.
325270
*/
326271
function endLexicalEnvironment(): Statement[] {
327-
Debug.assert(!lexicalEnvironmentDisabled, "Cannot end a lexical environment during the print phase.");
272+
Debug.assert(!scopeModificationDisabled, "Cannot end a lexical environment during the print phase.");
273+
Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is suspended.");
328274

329275
let statements: Statement[];
330-
if (hoistedVariableDeclarations || hoistedFunctionDeclarations) {
331-
if (hoistedFunctionDeclarations) {
332-
statements = [...hoistedFunctionDeclarations];
276+
if (lexicalEnvironmentVariableDeclarations || lexicalEnvironmentFunctionDeclarations) {
277+
if (lexicalEnvironmentFunctionDeclarations) {
278+
statements = [...lexicalEnvironmentFunctionDeclarations];
333279
}
334280

335-
if (hoistedVariableDeclarations) {
281+
if (lexicalEnvironmentVariableDeclarations) {
336282
const statement = createVariableStatement(
337283
/*modifiers*/ undefined,
338-
createVariableDeclarationList(hoistedVariableDeclarations)
284+
createVariableDeclarationList(lexicalEnvironmentVariableDeclarations)
339285
);
340286

341287
if (!statements) {
@@ -349,9 +295,27 @@ namespace ts {
349295

350296
// Restore the previous lexical environment.
351297
lexicalEnvironmentStackOffset--;
352-
hoistedVariableDeclarations = lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset];
353-
hoistedFunctionDeclarations = lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset];
298+
lexicalEnvironmentVariableDeclarations = lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset];
299+
lexicalEnvironmentFunctionDeclarations = lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset];
300+
if (lexicalEnvironmentStackOffset === 0) {
301+
lexicalEnvironmentVariableDeclarationsStack = [];
302+
lexicalEnvironmentFunctionDeclarationsStack = [];
303+
}
304+
354305
return statements;
355306
}
307+
308+
function requestEmitHelper(helper: EmitHelper): void {
309+
Debug.assert(!scopeModificationDisabled, "Cannot modify the lexical environment during the print phase.");
310+
Debug.assert(!helper.scoped, "Cannot request a scoped emit helper.");
311+
emitHelpers = append(emitHelpers, helper);
312+
}
313+
314+
function readEmitHelpers(): EmitHelper[] | undefined {
315+
Debug.assert(!scopeModificationDisabled, "Cannot modify the lexical environment during the print phase.");
316+
const helpers = emitHelpers;
317+
emitHelpers = undefined;
318+
return helpers;
319+
}
356320
}
357321
}

0 commit comments

Comments
 (0)