@soundscript/soundscript 0.1.16 → 0.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/json.js +1 -1
- package/numerics.js +4 -4
- package/package.json +6 -6
- package/project-transform/src/checker/rules/flow.js +16 -3
- package/project-transform/src/checker/rules/flow.ts +20 -3
- package/project-transform/src/checker/rules/unsound_syntax.js +0 -3
- package/project-transform/src/checker/rules/unsound_syntax.ts +0 -4
- package/project-transform/src/cli.js +1 -1
- package/project-transform/src/cli.ts +1 -1
- package/project-transform/src/compiler/compile_project.js +75 -9
- package/project-transform/src/compiler/compile_project.ts +121 -7
- package/project-transform/src/compiler/ir.ts +19 -1
- package/project-transform/src/compiler/lower.js +10335 -1477
- package/project-transform/src/compiler/lower.ts +16826 -4074
- package/project-transform/src/compiler/toolchain.js +36 -4
- package/project-transform/src/compiler/toolchain.ts +36 -4
- package/project-transform/src/compiler/wasm_js_host_runtime.js +134 -0
- package/project-transform/src/compiler/wasm_js_host_runtime.ts +146 -0
- package/project-transform/src/compiler/wat_arrays.js +4 -1
- package/project-transform/src/compiler/wat_arrays.ts +5 -1
- package/project-transform/src/compiler/wat_emitter.js +1497 -311
- package/project-transform/src/compiler/wat_emitter.ts +2971 -1017
- package/project-transform/src/compiler/wat_tagged.js +5 -0
- package/project-transform/src/compiler/wat_tagged.ts +5 -0
- package/project-transform/src/compiler_generator_runner.js +2139 -19
- package/project-transform/src/compiler_generator_runner.ts +2143 -20
- package/project-transform/src/compiler_promise_runner.js +4615 -636
- package/project-transform/src/compiler_promise_runner.ts +4703 -659
- package/project-transform/src/compiler_test_helpers.js +0 -579
- package/project-transform/src/compiler_test_helpers.ts +0 -648
- package/project-transform/src/frontend/macro_expander.js +4 -6
- package/project-transform/src/frontend/macro_expander.ts +4 -6
- package/project-transform/src/frontend/macro_operand_semantics.js +124 -1
- package/project-transform/src/frontend/macro_operand_semantics.ts +230 -6
- package/project-transform/src/frontend/macro_resolver.js +2 -2
- package/project-transform/src/frontend/macro_resolver.ts +2 -1
- package/project-transform/src/frontend/project_macro_support.js +29 -5
- package/project-transform/src/frontend/project_macro_support.ts +46 -10
|
@@ -1572,15 +1572,13 @@ export function expandPreparedProgramWithFileRegistries(
|
|
|
1572
1572
|
>,
|
|
1573
1573
|
preserveMissingExpanders = false,
|
|
1574
1574
|
annotateExpansions = false,
|
|
1575
|
+
sourceFiles = preparedProgram.program.getSourceFiles(),
|
|
1575
1576
|
): ReadonlyMap<string, ts.SourceFile> {
|
|
1576
|
-
const
|
|
1577
|
+
const nonDeclarationSourceFiles = sourceFiles.filter((sourceFile) => !sourceFile.isDeclarationFile);
|
|
1578
|
+
const collected = collectResolvedMacroPlaceholders(preparedProgram, nonDeclarationSourceFiles);
|
|
1577
1579
|
const expandedFiles = new Map<string, ts.SourceFile>();
|
|
1578
1580
|
|
|
1579
|
-
for (const sourceFile of
|
|
1580
|
-
if (sourceFile.isDeclarationFile) {
|
|
1581
|
-
continue;
|
|
1582
|
-
}
|
|
1583
|
-
|
|
1581
|
+
for (const sourceFile of nonDeclarationSourceFiles) {
|
|
1584
1582
|
const fileRegistries = registriesByFile.get(sourceFile.fileName);
|
|
1585
1583
|
const advancedRegistry = fileRegistries?.advancedRegistry ?? new Map();
|
|
1586
1584
|
const registry = fileRegistries?.registry ?? new Map();
|
|
@@ -4,6 +4,7 @@ import { createPreparedProgram, mapProgramPositionToSource, mapSourcePositionToP
|
|
|
4
4
|
import { rewriteMacroSource } from './macro_rewrite.js';
|
|
5
5
|
import { createMacroSemantics } from './macro_semantics.js';
|
|
6
6
|
const COMPLETION_PLACEHOLDER_IDENTIFIER = '__sts_completion_target';
|
|
7
|
+
const sharedExprOperandFileSourceCache = new WeakMap();
|
|
7
8
|
function isNestedMacroHoverTarget(value) {
|
|
8
9
|
return 'kind' in value;
|
|
9
10
|
}
|
|
@@ -22,6 +23,18 @@ function getExprArgumentSpan(invocation, index) {
|
|
|
22
23
|
const argument = invocation.argumentSpans[index];
|
|
23
24
|
return argument?.kind === 'ExprArg' ? argument.span : undefined;
|
|
24
25
|
}
|
|
26
|
+
function exprArgumentContainsNestedMacroInvocation(fileName, originalText, exprSpan, nestedRegistries) {
|
|
27
|
+
const sourceFile = ts.createSourceFile(fileName, originalText, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
|
|
28
|
+
const importPrelude = sourceFile.statements
|
|
29
|
+
.filter(ts.isImportDeclaration)
|
|
30
|
+
.map((statement) => statement.getText(sourceFile))
|
|
31
|
+
.join('\n');
|
|
32
|
+
const operandText = originalText.slice(exprSpan.start, exprSpan.end);
|
|
33
|
+
const probeSourceText = importPrelude.length > 0
|
|
34
|
+
? `${importPrelude}\nconst __sts_nested_probe = ${operandText};\n`
|
|
35
|
+
: `const __sts_nested_probe = ${operandText};\n`;
|
|
36
|
+
return rewriteMacroSource(fileName, probeSourceText, nestedRegistries.siteKindsBySpecifier ?? new Map(), getAlwaysAvailableBuiltinMacroSiteKinds()).replacements.length > 0;
|
|
37
|
+
}
|
|
25
38
|
function _getExpressionArgumentSpan(invocation, expressionArgumentIndex) {
|
|
26
39
|
const expressionArguments = invocation.argumentSpans.filter((argument) => argument.kind === 'ExprArg');
|
|
27
40
|
return expressionArguments[expressionArgumentIndex]?.span;
|
|
@@ -287,6 +300,7 @@ function expandNestedOperandSource(preparedProgram, resolved, patchedText, neste
|
|
|
287
300
|
};
|
|
288
301
|
const finalProgram = ts.createProgram({
|
|
289
302
|
host: overrideHost,
|
|
303
|
+
oldProgram: nestedPreparedProgram.program,
|
|
290
304
|
options: nestedPreparedProgram.options,
|
|
291
305
|
rootNames: nestedPreparedProgram.rootNames.map((fileName) => nestedPreparedProgram.toProgramFileName(fileName)),
|
|
292
306
|
});
|
|
@@ -407,6 +421,95 @@ function findExpressionAtSpan(sourceFile, start, end) {
|
|
|
407
421
|
visit(sourceFile);
|
|
408
422
|
return found;
|
|
409
423
|
}
|
|
424
|
+
function sharedExprOperandFileSourceCacheKey(rewrittenProgramFileName, index) {
|
|
425
|
+
return `${rewrittenProgramFileName}\0${index}`;
|
|
426
|
+
}
|
|
427
|
+
function buildSharedExprOperandFileSource(preparedProgram, preparedFile, sourceFileName, index, nestedRegistries) {
|
|
428
|
+
const rewrittenProgramFileName = preparedProgram.toProgramFileName(sourceFileName);
|
|
429
|
+
const replacements = [];
|
|
430
|
+
for (const replacement of preparedFile.rewriteResult.replacements) {
|
|
431
|
+
const invocation = preparedFile.rewriteResult.macrosById.get(replacement.id);
|
|
432
|
+
if (!invocation) {
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
const exprSpan = getExprArgumentSpan(invocation, index);
|
|
436
|
+
if (!exprSpan) {
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
if (exprArgumentContainsNestedMacroInvocation(sourceFileName, preparedFile.originalText, exprSpan, nestedRegistries)) {
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
const operandText = preparedFile.originalText.slice(exprSpan.start, exprSpan.end);
|
|
443
|
+
replacements.push({
|
|
444
|
+
id: replacement.id,
|
|
445
|
+
end: mapStageOnePositionToProgram(preparedFile, replacement.rewrittenSpan.end),
|
|
446
|
+
operandText,
|
|
447
|
+
start: mapStageOnePositionToProgram(preparedFile, replacement.rewrittenSpan.start),
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
replacements.sort((left, right) => left.start - right.start);
|
|
451
|
+
if (replacements.length === 0) {
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
let patchedText = '';
|
|
455
|
+
let cursor = 0;
|
|
456
|
+
const spansByPlaceholderId = new Map();
|
|
457
|
+
for (const replacement of replacements) {
|
|
458
|
+
patchedText += preparedFile.rewrittenText.slice(cursor, replacement.start);
|
|
459
|
+
const patchedStart = patchedText.length;
|
|
460
|
+
patchedText += replacement.operandText;
|
|
461
|
+
spansByPlaceholderId.set(replacement.id, {
|
|
462
|
+
end: patchedStart + replacement.operandText.length,
|
|
463
|
+
fileName: sourceFileName,
|
|
464
|
+
start: patchedStart,
|
|
465
|
+
});
|
|
466
|
+
cursor = replacement.end;
|
|
467
|
+
}
|
|
468
|
+
patchedText += preparedFile.rewrittenText.slice(cursor);
|
|
469
|
+
const overrideHost = {
|
|
470
|
+
...preparedProgram.preparedHost.host,
|
|
471
|
+
getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile) {
|
|
472
|
+
if (fileName === rewrittenProgramFileName) {
|
|
473
|
+
return ts.createSourceFile(fileName, patchedText, languageVersion, true);
|
|
474
|
+
}
|
|
475
|
+
return preparedProgram.preparedHost.host.getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile);
|
|
476
|
+
},
|
|
477
|
+
readFile(fileName) {
|
|
478
|
+
if (fileName === rewrittenProgramFileName) {
|
|
479
|
+
return patchedText;
|
|
480
|
+
}
|
|
481
|
+
return preparedProgram.preparedHost.host.readFile(fileName);
|
|
482
|
+
},
|
|
483
|
+
};
|
|
484
|
+
const patchedProgram = ts.createProgram({
|
|
485
|
+
host: overrideHost,
|
|
486
|
+
oldProgram: preparedProgram.program,
|
|
487
|
+
options: preparedProgram.options,
|
|
488
|
+
rootNames: preparedProgram.rootNames.map((fileName) => preparedProgram.toProgramFileName(fileName)),
|
|
489
|
+
});
|
|
490
|
+
const patchedSourceFile = patchedProgram.getSourceFile(rewrittenProgramFileName);
|
|
491
|
+
if (!patchedSourceFile) {
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
|
+
return {
|
|
495
|
+
semantics: createMacroSemantics(patchedProgram),
|
|
496
|
+
sourceFile: patchedSourceFile,
|
|
497
|
+
spansByPlaceholderId,
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
function getSharedExprOperandFileSource(preparedProgram, preparedFile, sourceFileName, index, nestedRegistries) {
|
|
501
|
+
let programCache = sharedExprOperandFileSourceCache.get(preparedProgram);
|
|
502
|
+
if (!programCache) {
|
|
503
|
+
programCache = new Map();
|
|
504
|
+
sharedExprOperandFileSourceCache.set(preparedProgram, programCache);
|
|
505
|
+
}
|
|
506
|
+
const rewrittenProgramFileName = preparedProgram.toProgramFileName(sourceFileName);
|
|
507
|
+
const cacheKey = sharedExprOperandFileSourceCacheKey(rewrittenProgramFileName, index);
|
|
508
|
+
if (!programCache.has(cacheKey)) {
|
|
509
|
+
programCache.set(cacheKey, buildSharedExprOperandFileSource(preparedProgram, preparedFile, sourceFileName, index, nestedRegistries));
|
|
510
|
+
}
|
|
511
|
+
return programCache.get(cacheKey) ?? null;
|
|
512
|
+
}
|
|
410
513
|
function findDeepestNodeContainingPosition(node, position) {
|
|
411
514
|
if (position < node.getFullStart() || position >= node.getEnd()) {
|
|
412
515
|
return undefined;
|
|
@@ -438,6 +541,7 @@ function createPatchedMacroSource(preparedProgram, resolved, replacementText) {
|
|
|
438
541
|
};
|
|
439
542
|
const patchedProgram = ts.createProgram({
|
|
440
543
|
host: overrideHost,
|
|
544
|
+
oldProgram: preparedProgram.program,
|
|
441
545
|
options: preparedProgram.options,
|
|
442
546
|
rootNames: preparedProgram.rootNames.map((fileName) => preparedProgram.toProgramFileName(fileName)),
|
|
443
547
|
});
|
|
@@ -747,11 +851,29 @@ export function resolveExprArgumentOperand(preparedProgram, resolved, index, nes
|
|
|
747
851
|
const replacement = resolved.placeholder.replacement;
|
|
748
852
|
const preparedFile = resolved.placeholder.preparedFile;
|
|
749
853
|
const operandText = preparedFile.originalText.slice(exprSpan.start, exprSpan.end);
|
|
750
|
-
const nestedExpansion =
|
|
854
|
+
const nestedExpansion = exprArgumentContainsNestedMacroInvocation(resolved.placeholder.invocation.fileName, preparedFile.originalText, exprSpan, nestedRegistries)
|
|
855
|
+
? materializeNestedOperandExpansion(preparedProgram, resolved, operandText, nestedRegistries) ?? { expressionText: operandText, preludeTexts: [] }
|
|
856
|
+
: { expressionText: operandText, preludeTexts: [] };
|
|
751
857
|
if (!nestedExpansion) {
|
|
752
858
|
return null;
|
|
753
859
|
}
|
|
754
860
|
const expandedText = nestedExpansion.expressionText;
|
|
861
|
+
if (nestedExpansion.preludeTexts.length === 0 && expandedText === operandText) {
|
|
862
|
+
const sharedSource = getSharedExprOperandFileSource(preparedProgram, preparedFile, resolved.placeholder.invocation.fileName, index, nestedRegistries);
|
|
863
|
+
const sharedSpan = sharedSource?.spansByPlaceholderId.get(resolved.placeholder.id);
|
|
864
|
+
if (sharedSource && sharedSpan) {
|
|
865
|
+
const patchedExpression = findExpressionAtSpan(sharedSource.sourceFile, sharedSpan.start, sharedSpan.end);
|
|
866
|
+
if (patchedExpression) {
|
|
867
|
+
return {
|
|
868
|
+
expandedText,
|
|
869
|
+
preludeTexts: nestedExpansion.preludeTexts,
|
|
870
|
+
node: patchedExpression,
|
|
871
|
+
semantics: sharedSource.semantics,
|
|
872
|
+
sourceFile: sharedSource.sourceFile,
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
755
877
|
const containingStatement = findContainingStatement(resolved.callExpression);
|
|
756
878
|
const programReplacementStart = mapStageOnePositionToProgram(preparedFile, replacement.rewrittenSpan.start);
|
|
757
879
|
const programReplacementEnd = mapStageOnePositionToProgram(preparedFile, replacement.rewrittenSpan.end);
|
|
@@ -787,6 +909,7 @@ export function resolveExprArgumentOperand(preparedProgram, resolved, index, nes
|
|
|
787
909
|
};
|
|
788
910
|
const patchedProgram = ts.createProgram({
|
|
789
911
|
host: overrideHost,
|
|
912
|
+
oldProgram: preparedProgram.program,
|
|
790
913
|
options: preparedProgram.options,
|
|
791
914
|
rootNames: preparedProgram.rootNames.map((fileName) => preparedProgram.toProgramFileName(fileName)),
|
|
792
915
|
});
|
|
@@ -30,6 +30,12 @@ export interface ResolvedExprArgumentOperand {
|
|
|
30
30
|
|
|
31
31
|
export interface ResolvedPrimaryExprOperand extends ResolvedExprArgumentOperand {}
|
|
32
32
|
|
|
33
|
+
interface SharedExprOperandFileSource {
|
|
34
|
+
semantics: ReturnType<typeof createMacroSemantics>;
|
|
35
|
+
sourceFile: ts.SourceFile;
|
|
36
|
+
spansByPlaceholderId: ReadonlyMap<number, SourceSpan>;
|
|
37
|
+
}
|
|
38
|
+
|
|
33
39
|
export interface MaterializedMacroMappingSegment {
|
|
34
40
|
generatedEnd: number;
|
|
35
41
|
generatedStart: number;
|
|
@@ -73,6 +79,10 @@ export interface NestedMacroHoverTarget {
|
|
|
73
79
|
}
|
|
74
80
|
|
|
75
81
|
const COMPLETION_PLACEHOLDER_IDENTIFIER = '__sts_completion_target';
|
|
82
|
+
const sharedExprOperandFileSourceCache = new WeakMap<
|
|
83
|
+
PreparedProgram,
|
|
84
|
+
Map<string, SharedExprOperandFileSource | null>
|
|
85
|
+
>();
|
|
76
86
|
|
|
77
87
|
function isNestedMacroHoverTarget(
|
|
78
88
|
value: MaterializedMacroHoverRegion | NestedMacroHoverTarget,
|
|
@@ -106,6 +116,36 @@ function getExprArgumentSpan(
|
|
|
106
116
|
return argument?.kind === 'ExprArg' ? argument.span : undefined;
|
|
107
117
|
}
|
|
108
118
|
|
|
119
|
+
function exprArgumentContainsNestedMacroInvocation(
|
|
120
|
+
fileName: string,
|
|
121
|
+
originalText: string,
|
|
122
|
+
exprSpan: SourceSpan,
|
|
123
|
+
nestedRegistries: NestedMacroRegistries,
|
|
124
|
+
): boolean {
|
|
125
|
+
const sourceFile = ts.createSourceFile(
|
|
126
|
+
fileName,
|
|
127
|
+
originalText,
|
|
128
|
+
ts.ScriptTarget.Latest,
|
|
129
|
+
true,
|
|
130
|
+
ts.ScriptKind.TSX,
|
|
131
|
+
);
|
|
132
|
+
const importPrelude = sourceFile.statements
|
|
133
|
+
.filter(ts.isImportDeclaration)
|
|
134
|
+
.map((statement) => statement.getText(sourceFile))
|
|
135
|
+
.join('\n');
|
|
136
|
+
const operandText = originalText.slice(exprSpan.start, exprSpan.end);
|
|
137
|
+
const probeSourceText = importPrelude.length > 0
|
|
138
|
+
? `${importPrelude}\nconst __sts_nested_probe = ${operandText};\n`
|
|
139
|
+
: `const __sts_nested_probe = ${operandText};\n`;
|
|
140
|
+
|
|
141
|
+
return rewriteMacroSource(
|
|
142
|
+
fileName,
|
|
143
|
+
probeSourceText,
|
|
144
|
+
nestedRegistries.siteKindsBySpecifier ?? new Map(),
|
|
145
|
+
getAlwaysAvailableBuiltinMacroSiteKinds(),
|
|
146
|
+
).replacements.length > 0;
|
|
147
|
+
}
|
|
148
|
+
|
|
109
149
|
function _getExpressionArgumentSpan(
|
|
110
150
|
invocation: ParsedMacroInvocation,
|
|
111
151
|
expressionArgumentIndex: number,
|
|
@@ -507,6 +547,7 @@ function expandNestedOperandSource(
|
|
|
507
547
|
};
|
|
508
548
|
const finalProgram = ts.createProgram({
|
|
509
549
|
host: overrideHost,
|
|
550
|
+
oldProgram: nestedPreparedProgram.program,
|
|
510
551
|
options: nestedPreparedProgram.options,
|
|
511
552
|
rootNames: nestedPreparedProgram.rootNames.map((fileName) =>
|
|
512
553
|
nestedPreparedProgram.toProgramFileName(fileName)
|
|
@@ -733,6 +774,153 @@ function findExpressionAtSpan(
|
|
|
733
774
|
return found;
|
|
734
775
|
}
|
|
735
776
|
|
|
777
|
+
function sharedExprOperandFileSourceCacheKey(
|
|
778
|
+
rewrittenProgramFileName: string,
|
|
779
|
+
index: number,
|
|
780
|
+
): string {
|
|
781
|
+
return `${rewrittenProgramFileName}\0${index}`;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
function buildSharedExprOperandFileSource(
|
|
785
|
+
preparedProgram: PreparedProgram,
|
|
786
|
+
preparedFile: PreparedSourceFile,
|
|
787
|
+
sourceFileName: string,
|
|
788
|
+
index: number,
|
|
789
|
+
nestedRegistries: NestedMacroRegistries,
|
|
790
|
+
): SharedExprOperandFileSource | null {
|
|
791
|
+
const rewrittenProgramFileName = preparedProgram.toProgramFileName(sourceFileName);
|
|
792
|
+
const replacements: Array<{ end: number; id: number; operandText: string; start: number }> = [];
|
|
793
|
+
for (const replacement of preparedFile.rewriteResult.replacements) {
|
|
794
|
+
const invocation = preparedFile.rewriteResult.macrosById.get(replacement.id);
|
|
795
|
+
if (!invocation) {
|
|
796
|
+
continue;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
const exprSpan = getExprArgumentSpan(invocation, index);
|
|
800
|
+
if (!exprSpan) {
|
|
801
|
+
continue;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
if (
|
|
805
|
+
exprArgumentContainsNestedMacroInvocation(
|
|
806
|
+
sourceFileName,
|
|
807
|
+
preparedFile.originalText,
|
|
808
|
+
exprSpan,
|
|
809
|
+
nestedRegistries,
|
|
810
|
+
)
|
|
811
|
+
) {
|
|
812
|
+
continue;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
const operandText = preparedFile.originalText.slice(exprSpan.start, exprSpan.end);
|
|
816
|
+
replacements.push({
|
|
817
|
+
id: replacement.id,
|
|
818
|
+
end: mapStageOnePositionToProgram(preparedFile, replacement.rewrittenSpan.end),
|
|
819
|
+
operandText,
|
|
820
|
+
start: mapStageOnePositionToProgram(preparedFile, replacement.rewrittenSpan.start),
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
replacements.sort((left, right) => left.start - right.start);
|
|
824
|
+
|
|
825
|
+
if (replacements.length === 0) {
|
|
826
|
+
return null;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
let patchedText = '';
|
|
830
|
+
let cursor = 0;
|
|
831
|
+
const spansByPlaceholderId = new Map<number, SourceSpan>();
|
|
832
|
+
for (const replacement of replacements) {
|
|
833
|
+
patchedText += preparedFile.rewrittenText.slice(cursor, replacement.start);
|
|
834
|
+
const patchedStart = patchedText.length;
|
|
835
|
+
patchedText += replacement.operandText;
|
|
836
|
+
spansByPlaceholderId.set(replacement.id, {
|
|
837
|
+
end: patchedStart + replacement.operandText.length,
|
|
838
|
+
fileName: sourceFileName,
|
|
839
|
+
start: patchedStart,
|
|
840
|
+
});
|
|
841
|
+
cursor = replacement.end;
|
|
842
|
+
}
|
|
843
|
+
patchedText += preparedFile.rewrittenText.slice(cursor);
|
|
844
|
+
|
|
845
|
+
const overrideHost: ts.CompilerHost = {
|
|
846
|
+
...preparedProgram.preparedHost.host,
|
|
847
|
+
getSourceFile(
|
|
848
|
+
fileName: string,
|
|
849
|
+
languageVersion: ts.ScriptTarget | ts.CreateSourceFileOptions,
|
|
850
|
+
onError?: (message: string) => void,
|
|
851
|
+
shouldCreateNewSourceFile?: boolean,
|
|
852
|
+
): ts.SourceFile | undefined {
|
|
853
|
+
if (fileName === rewrittenProgramFileName) {
|
|
854
|
+
return ts.createSourceFile(fileName, patchedText, languageVersion, true);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
return preparedProgram.preparedHost.host.getSourceFile(
|
|
858
|
+
fileName,
|
|
859
|
+
languageVersion,
|
|
860
|
+
onError,
|
|
861
|
+
shouldCreateNewSourceFile,
|
|
862
|
+
);
|
|
863
|
+
},
|
|
864
|
+
readFile(fileName: string): string | undefined {
|
|
865
|
+
if (fileName === rewrittenProgramFileName) {
|
|
866
|
+
return patchedText;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
return preparedProgram.preparedHost.host.readFile(fileName);
|
|
870
|
+
},
|
|
871
|
+
};
|
|
872
|
+
|
|
873
|
+
const patchedProgram = ts.createProgram({
|
|
874
|
+
host: overrideHost,
|
|
875
|
+
oldProgram: preparedProgram.program,
|
|
876
|
+
options: preparedProgram.options,
|
|
877
|
+
rootNames: preparedProgram.rootNames.map((fileName) =>
|
|
878
|
+
preparedProgram.toProgramFileName(fileName)
|
|
879
|
+
),
|
|
880
|
+
});
|
|
881
|
+
const patchedSourceFile = patchedProgram.getSourceFile(rewrittenProgramFileName);
|
|
882
|
+
if (!patchedSourceFile) {
|
|
883
|
+
return null;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
return {
|
|
887
|
+
semantics: createMacroSemantics(patchedProgram),
|
|
888
|
+
sourceFile: patchedSourceFile,
|
|
889
|
+
spansByPlaceholderId,
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
function getSharedExprOperandFileSource(
|
|
894
|
+
preparedProgram: PreparedProgram,
|
|
895
|
+
preparedFile: PreparedSourceFile,
|
|
896
|
+
sourceFileName: string,
|
|
897
|
+
index: number,
|
|
898
|
+
nestedRegistries: NestedMacroRegistries,
|
|
899
|
+
): SharedExprOperandFileSource | null {
|
|
900
|
+
let programCache = sharedExprOperandFileSourceCache.get(preparedProgram);
|
|
901
|
+
if (!programCache) {
|
|
902
|
+
programCache = new Map();
|
|
903
|
+
sharedExprOperandFileSourceCache.set(preparedProgram, programCache);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
const rewrittenProgramFileName = preparedProgram.toProgramFileName(sourceFileName);
|
|
907
|
+
const cacheKey = sharedExprOperandFileSourceCacheKey(rewrittenProgramFileName, index);
|
|
908
|
+
if (!programCache.has(cacheKey)) {
|
|
909
|
+
programCache.set(
|
|
910
|
+
cacheKey,
|
|
911
|
+
buildSharedExprOperandFileSource(
|
|
912
|
+
preparedProgram,
|
|
913
|
+
preparedFile,
|
|
914
|
+
sourceFileName,
|
|
915
|
+
index,
|
|
916
|
+
nestedRegistries,
|
|
917
|
+
),
|
|
918
|
+
);
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
return programCache.get(cacheKey) ?? null;
|
|
922
|
+
}
|
|
923
|
+
|
|
736
924
|
function findDeepestNodeContainingPosition(node: ts.Node, position: number): ts.Node | undefined {
|
|
737
925
|
if (position < node.getFullStart() || position >= node.getEnd()) {
|
|
738
926
|
return undefined;
|
|
@@ -805,6 +993,7 @@ function createPatchedMacroSource(
|
|
|
805
993
|
|
|
806
994
|
const patchedProgram = ts.createProgram({
|
|
807
995
|
host: overrideHost,
|
|
996
|
+
oldProgram: preparedProgram.program,
|
|
808
997
|
options: preparedProgram.options,
|
|
809
998
|
rootNames: preparedProgram.rootNames.map((fileName) =>
|
|
810
999
|
preparedProgram.toProgramFileName(fileName)
|
|
@@ -1325,16 +1514,50 @@ export function resolveExprArgumentOperand(
|
|
|
1325
1514
|
const replacement = resolved.placeholder.replacement;
|
|
1326
1515
|
const preparedFile = resolved.placeholder.preparedFile;
|
|
1327
1516
|
const operandText = preparedFile.originalText.slice(exprSpan.start, exprSpan.end);
|
|
1328
|
-
const nestedExpansion =
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1517
|
+
const nestedExpansion = exprArgumentContainsNestedMacroInvocation(
|
|
1518
|
+
resolved.placeholder.invocation.fileName,
|
|
1519
|
+
preparedFile.originalText,
|
|
1520
|
+
exprSpan,
|
|
1521
|
+
nestedRegistries,
|
|
1522
|
+
)
|
|
1523
|
+
? materializeNestedOperandExpansion(
|
|
1524
|
+
preparedProgram,
|
|
1525
|
+
resolved,
|
|
1526
|
+
operandText,
|
|
1527
|
+
nestedRegistries,
|
|
1528
|
+
) ?? { expressionText: operandText, preludeTexts: [] as readonly string[] }
|
|
1529
|
+
: { expressionText: operandText, preludeTexts: [] as readonly string[] };
|
|
1334
1530
|
if (!nestedExpansion) {
|
|
1335
1531
|
return null;
|
|
1336
1532
|
}
|
|
1337
1533
|
const expandedText = nestedExpansion.expressionText;
|
|
1534
|
+
if (nestedExpansion.preludeTexts.length === 0 && expandedText === operandText) {
|
|
1535
|
+
const sharedSource = getSharedExprOperandFileSource(
|
|
1536
|
+
preparedProgram,
|
|
1537
|
+
preparedFile,
|
|
1538
|
+
resolved.placeholder.invocation.fileName,
|
|
1539
|
+
index,
|
|
1540
|
+
nestedRegistries,
|
|
1541
|
+
);
|
|
1542
|
+
const sharedSpan = sharedSource?.spansByPlaceholderId.get(resolved.placeholder.id);
|
|
1543
|
+
if (sharedSource && sharedSpan) {
|
|
1544
|
+
const patchedExpression = findExpressionAtSpan(
|
|
1545
|
+
sharedSource.sourceFile,
|
|
1546
|
+
sharedSpan.start,
|
|
1547
|
+
sharedSpan.end,
|
|
1548
|
+
);
|
|
1549
|
+
if (patchedExpression) {
|
|
1550
|
+
return {
|
|
1551
|
+
expandedText,
|
|
1552
|
+
preludeTexts: nestedExpansion.preludeTexts,
|
|
1553
|
+
node: patchedExpression,
|
|
1554
|
+
semantics: sharedSource.semantics,
|
|
1555
|
+
sourceFile: sharedSource.sourceFile,
|
|
1556
|
+
};
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1338
1561
|
const containingStatement = findContainingStatement(resolved.callExpression);
|
|
1339
1562
|
const programReplacementStart = mapStageOnePositionToProgram(
|
|
1340
1563
|
preparedFile,
|
|
@@ -1397,6 +1620,7 @@ export function resolveExprArgumentOperand(
|
|
|
1397
1620
|
|
|
1398
1621
|
const patchedProgram = ts.createProgram({
|
|
1399
1622
|
host: overrideHost,
|
|
1623
|
+
oldProgram: preparedProgram.program,
|
|
1400
1624
|
options: preparedProgram.options,
|
|
1401
1625
|
rootNames: preparedProgram.rootNames.map((fileName) =>
|
|
1402
1626
|
preparedProgram.toProgramFileName(fileName)
|
|
@@ -41,9 +41,9 @@ export function resolveMacroPlaceholdersInSourceFile(sourceFile, placeholderInde
|
|
|
41
41
|
visit(sourceFile);
|
|
42
42
|
return resolved;
|
|
43
43
|
}
|
|
44
|
-
export function collectResolvedMacroPlaceholders(preparedProgram) {
|
|
44
|
+
export function collectResolvedMacroPlaceholders(preparedProgram, sourceFiles = preparedProgram.program.getSourceFiles()) {
|
|
45
45
|
const placeholderIndex = preparedProgram.placeholderIndex();
|
|
46
|
-
const collected =
|
|
46
|
+
const collected = sourceFiles
|
|
47
47
|
.filter((sourceFile) => !sourceFile.isDeclarationFile)
|
|
48
48
|
.flatMap((sourceFile) => {
|
|
49
49
|
const sourceFileName = preparedProgram.toSourceFileName(sourceFile.fileName);
|
|
@@ -90,9 +90,10 @@ export function resolveMacroPlaceholdersInSourceFile(
|
|
|
90
90
|
|
|
91
91
|
export function collectResolvedMacroPlaceholders(
|
|
92
92
|
preparedProgram: MacroResolverPreparedProgram,
|
|
93
|
+
sourceFiles = preparedProgram.program.getSourceFiles(),
|
|
93
94
|
): CollectedResolvedMacroPlaceholder[] {
|
|
94
95
|
const placeholderIndex = preparedProgram.placeholderIndex();
|
|
95
|
-
const collected =
|
|
96
|
+
const collected = sourceFiles
|
|
96
97
|
.filter((sourceFile) => !sourceFile.isDeclarationFile)
|
|
97
98
|
.flatMap((sourceFile) => {
|
|
98
99
|
const sourceFileName = preparedProgram.toSourceFileName(sourceFile.fileName);
|
|
@@ -1233,6 +1233,17 @@ export function createProjectMacroEnvironment(preparedProgram, builtinDefinition
|
|
|
1233
1233
|
return cached;
|
|
1234
1234
|
}
|
|
1235
1235
|
const macroNames = macroNamesForFile(sourceFile);
|
|
1236
|
+
if (macroNames.size === 0) {
|
|
1237
|
+
const emptyBindings = {
|
|
1238
|
+
advancedRegistry: new Map(),
|
|
1239
|
+
definitions: new Map(),
|
|
1240
|
+
importedBindingUsage: new Map(),
|
|
1241
|
+
registry: new Map(),
|
|
1242
|
+
siteKindsBySpecifier: new Map(),
|
|
1243
|
+
};
|
|
1244
|
+
bindingsByFile.set(sourceFile.fileName, emptyBindings);
|
|
1245
|
+
return emptyBindings;
|
|
1246
|
+
}
|
|
1236
1247
|
const definitions = new Map();
|
|
1237
1248
|
const registry = new Map();
|
|
1238
1249
|
const advancedRegistry = new Map();
|
|
@@ -1372,7 +1383,18 @@ export function createProjectMacroEnvironment(preparedProgram, builtinDefinition
|
|
|
1372
1383
|
const registriesByFile = new Map();
|
|
1373
1384
|
const bindingUsageByFile = new Map();
|
|
1374
1385
|
const hasBindingsByFile = new Map();
|
|
1386
|
+
const expandedFiles = new Map();
|
|
1387
|
+
const macroSourceFiles = [];
|
|
1375
1388
|
for (const sourceFile of sourceFiles) {
|
|
1389
|
+
const macroNames = macroNamesForFile(sourceFile);
|
|
1390
|
+
if (macroNames.size === 0) {
|
|
1391
|
+
const sourceFileName = preparedProgram.toSourceFileName(sourceFile.fileName);
|
|
1392
|
+
const preparedSource = preparedProgram.preparedHost.getPreparedSourceFile(sourceFileName);
|
|
1393
|
+
expandedFiles.set(sourceFile.fileName, preparedSource
|
|
1394
|
+
? ts.createSourceFile(sourceFile.fileName, preparedSource.originalText, preparedProgram.options.target ?? ts.ScriptTarget.Latest, true, scriptKindForHostFile(sourceFile.fileName))
|
|
1395
|
+
: sourceFile);
|
|
1396
|
+
continue;
|
|
1397
|
+
}
|
|
1376
1398
|
const bindings = bindingsForSourceFile(sourceFile);
|
|
1377
1399
|
registriesByFile.set(sourceFile.fileName, {
|
|
1378
1400
|
registry: bindings.registry,
|
|
@@ -1381,21 +1403,23 @@ export function createProjectMacroEnvironment(preparedProgram, builtinDefinition
|
|
|
1381
1403
|
});
|
|
1382
1404
|
bindingUsageByFile.set(sourceFile.fileName, bindings.importedBindingUsage);
|
|
1383
1405
|
hasBindingsByFile.set(sourceFile.fileName, hasResolvedMacroBindings(bindings));
|
|
1406
|
+
macroSourceFiles.push(sourceFile);
|
|
1384
1407
|
}
|
|
1385
|
-
const expanded =
|
|
1386
|
-
|
|
1408
|
+
const expanded = macroSourceFiles.length > 0
|
|
1409
|
+
? expandPreparedProgramWithFileRegistries(preparedProgram, registriesByFile, preserveMissingExpanders, annotateExpansions, macroSourceFiles)
|
|
1410
|
+
: new Map();
|
|
1387
1411
|
for (const [fileName, sourceFile] of expanded.entries()) {
|
|
1388
1412
|
if (!hasBindingsByFile.get(fileName)) {
|
|
1389
1413
|
const sourceFileName = preparedProgram.toSourceFileName(fileName);
|
|
1390
1414
|
const preparedSource = preparedProgram.preparedHost.getPreparedSourceFile(sourceFileName);
|
|
1391
|
-
|
|
1415
|
+
expandedFiles.set(fileName, preparedSource
|
|
1392
1416
|
? ts.createSourceFile(fileName, preparedSource.originalText, preparedProgram.options.target ?? ts.ScriptTarget.Latest, true, scriptKindForHostFile(fileName))
|
|
1393
1417
|
: sourceFile);
|
|
1394
1418
|
continue;
|
|
1395
1419
|
}
|
|
1396
|
-
|
|
1420
|
+
expandedFiles.set(fileName, stripCompileTimeOnlyImportedBindings(sourceFile, bindingUsageByFile.get(fileName) ?? new Map(), preserveRemovedImportStatements));
|
|
1397
1421
|
}
|
|
1398
|
-
return
|
|
1422
|
+
return expandedFiles;
|
|
1399
1423
|
},
|
|
1400
1424
|
};
|
|
1401
1425
|
}
|
|
@@ -1895,6 +1895,18 @@ export function createProjectMacroEnvironment(
|
|
|
1895
1895
|
}
|
|
1896
1896
|
|
|
1897
1897
|
const macroNames = macroNamesForFile(sourceFile);
|
|
1898
|
+
if (macroNames.size === 0) {
|
|
1899
|
+
const emptyBindings = {
|
|
1900
|
+
advancedRegistry: new Map<string, AdvancedMacroExpander>(),
|
|
1901
|
+
definitions: new Map<string, MacroDefinition>(),
|
|
1902
|
+
importedBindingUsage: new Map<string, ImportedBindingUsage>(),
|
|
1903
|
+
registry: new Map<string, RewriteMacroExpander>(),
|
|
1904
|
+
siteKindsBySpecifier: new Map<string, Map<string, ImportedMacroSiteKind>>(),
|
|
1905
|
+
};
|
|
1906
|
+
bindingsByFile.set(sourceFile.fileName, emptyBindings);
|
|
1907
|
+
return emptyBindings;
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1898
1910
|
const definitions = new Map<string, MacroDefinition>();
|
|
1899
1911
|
const registry = new Map<string, RewriteMacroExpander>();
|
|
1900
1912
|
const advancedRegistry = new Map<string, AdvancedMacroExpander>();
|
|
@@ -2084,8 +2096,29 @@ export function createProjectMacroEnvironment(
|
|
|
2084
2096
|
>();
|
|
2085
2097
|
const bindingUsageByFile = new Map<string, ReadonlyMap<string, ImportedBindingUsage>>();
|
|
2086
2098
|
const hasBindingsByFile = new Map<string, boolean>();
|
|
2099
|
+
const expandedFiles = new Map<string, ts.SourceFile>();
|
|
2100
|
+
const macroSourceFiles: ts.SourceFile[] = [];
|
|
2087
2101
|
|
|
2088
2102
|
for (const sourceFile of sourceFiles) {
|
|
2103
|
+
const macroNames = macroNamesForFile(sourceFile);
|
|
2104
|
+
if (macroNames.size === 0) {
|
|
2105
|
+
const sourceFileName = preparedProgram.toSourceFileName(sourceFile.fileName);
|
|
2106
|
+
const preparedSource = preparedProgram.preparedHost.getPreparedSourceFile(sourceFileName);
|
|
2107
|
+
expandedFiles.set(
|
|
2108
|
+
sourceFile.fileName,
|
|
2109
|
+
preparedSource
|
|
2110
|
+
? ts.createSourceFile(
|
|
2111
|
+
sourceFile.fileName,
|
|
2112
|
+
preparedSource.originalText,
|
|
2113
|
+
preparedProgram.options.target ?? ts.ScriptTarget.Latest,
|
|
2114
|
+
true,
|
|
2115
|
+
scriptKindForHostFile(sourceFile.fileName),
|
|
2116
|
+
)
|
|
2117
|
+
: sourceFile,
|
|
2118
|
+
);
|
|
2119
|
+
continue;
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2089
2122
|
const bindings = bindingsForSourceFile(sourceFile);
|
|
2090
2123
|
registriesByFile.set(sourceFile.fileName, {
|
|
2091
2124
|
registry: bindings.registry,
|
|
@@ -2094,20 +2127,23 @@ export function createProjectMacroEnvironment(
|
|
|
2094
2127
|
});
|
|
2095
2128
|
bindingUsageByFile.set(sourceFile.fileName, bindings.importedBindingUsage);
|
|
2096
2129
|
hasBindingsByFile.set(sourceFile.fileName, hasResolvedMacroBindings(bindings));
|
|
2130
|
+
macroSourceFiles.push(sourceFile);
|
|
2097
2131
|
}
|
|
2098
2132
|
|
|
2099
|
-
const expanded =
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2133
|
+
const expanded = macroSourceFiles.length > 0
|
|
2134
|
+
? expandPreparedProgramWithFileRegistries(
|
|
2135
|
+
preparedProgram,
|
|
2136
|
+
registriesByFile,
|
|
2137
|
+
preserveMissingExpanders,
|
|
2138
|
+
annotateExpansions,
|
|
2139
|
+
macroSourceFiles,
|
|
2140
|
+
)
|
|
2141
|
+
: new Map<string, ts.SourceFile>();
|
|
2106
2142
|
for (const [fileName, sourceFile] of expanded.entries()) {
|
|
2107
2143
|
if (!hasBindingsByFile.get(fileName)) {
|
|
2108
2144
|
const sourceFileName = preparedProgram.toSourceFileName(fileName);
|
|
2109
2145
|
const preparedSource = preparedProgram.preparedHost.getPreparedSourceFile(sourceFileName);
|
|
2110
|
-
|
|
2146
|
+
expandedFiles.set(
|
|
2111
2147
|
fileName,
|
|
2112
2148
|
preparedSource
|
|
2113
2149
|
? ts.createSourceFile(
|
|
@@ -2122,7 +2158,7 @@ export function createProjectMacroEnvironment(
|
|
|
2122
2158
|
continue;
|
|
2123
2159
|
}
|
|
2124
2160
|
|
|
2125
|
-
|
|
2161
|
+
expandedFiles.set(
|
|
2126
2162
|
fileName,
|
|
2127
2163
|
stripCompileTimeOnlyImportedBindings(
|
|
2128
2164
|
sourceFile,
|
|
@@ -2131,7 +2167,7 @@ export function createProjectMacroEnvironment(
|
|
|
2131
2167
|
),
|
|
2132
2168
|
);
|
|
2133
2169
|
}
|
|
2134
|
-
return
|
|
2170
|
+
return expandedFiles;
|
|
2135
2171
|
},
|
|
2136
2172
|
};
|
|
2137
2173
|
}
|