@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.
Files changed (38) hide show
  1. package/json.js +1 -1
  2. package/numerics.js +4 -4
  3. package/package.json +6 -6
  4. package/project-transform/src/checker/rules/flow.js +16 -3
  5. package/project-transform/src/checker/rules/flow.ts +20 -3
  6. package/project-transform/src/checker/rules/unsound_syntax.js +0 -3
  7. package/project-transform/src/checker/rules/unsound_syntax.ts +0 -4
  8. package/project-transform/src/cli.js +1 -1
  9. package/project-transform/src/cli.ts +1 -1
  10. package/project-transform/src/compiler/compile_project.js +75 -9
  11. package/project-transform/src/compiler/compile_project.ts +121 -7
  12. package/project-transform/src/compiler/ir.ts +19 -1
  13. package/project-transform/src/compiler/lower.js +10335 -1477
  14. package/project-transform/src/compiler/lower.ts +16826 -4074
  15. package/project-transform/src/compiler/toolchain.js +36 -4
  16. package/project-transform/src/compiler/toolchain.ts +36 -4
  17. package/project-transform/src/compiler/wasm_js_host_runtime.js +134 -0
  18. package/project-transform/src/compiler/wasm_js_host_runtime.ts +146 -0
  19. package/project-transform/src/compiler/wat_arrays.js +4 -1
  20. package/project-transform/src/compiler/wat_arrays.ts +5 -1
  21. package/project-transform/src/compiler/wat_emitter.js +1497 -311
  22. package/project-transform/src/compiler/wat_emitter.ts +2971 -1017
  23. package/project-transform/src/compiler/wat_tagged.js +5 -0
  24. package/project-transform/src/compiler/wat_tagged.ts +5 -0
  25. package/project-transform/src/compiler_generator_runner.js +2139 -19
  26. package/project-transform/src/compiler_generator_runner.ts +2143 -20
  27. package/project-transform/src/compiler_promise_runner.js +4615 -636
  28. package/project-transform/src/compiler_promise_runner.ts +4703 -659
  29. package/project-transform/src/compiler_test_helpers.js +0 -579
  30. package/project-transform/src/compiler_test_helpers.ts +0 -648
  31. package/project-transform/src/frontend/macro_expander.js +4 -6
  32. package/project-transform/src/frontend/macro_expander.ts +4 -6
  33. package/project-transform/src/frontend/macro_operand_semantics.js +124 -1
  34. package/project-transform/src/frontend/macro_operand_semantics.ts +230 -6
  35. package/project-transform/src/frontend/macro_resolver.js +2 -2
  36. package/project-transform/src/frontend/macro_resolver.ts +2 -1
  37. package/project-transform/src/frontend/project_macro_support.js +29 -5
  38. package/project-transform/src/frontend/project_macro_support.ts +46 -10
package/json.js CHANGED
@@ -12,7 +12,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
12
12
  var _JsonLikeParser_instances, _JsonLikeParser_index, _JsonLikeParser_text, _JsonLikeParser_consumeKeyword, _JsonLikeParser_parseArray, _JsonLikeParser_parseNumber, _JsonLikeParser_parseObject, _JsonLikeParser_parseString, _JsonLikeParser_consumeDigits, _JsonLikeParser_skipWhitespace, _JsonLikeParser_isDigit, _JsonLikeParser_error;
13
13
  import { Failure } from '@soundscript/soundscript/failures';
14
14
  import { isErr, resultOf } from '@soundscript/soundscript/result';
15
- import { F32, F64, format as formatNumeric, I8, I16, I32, I64, isNumeric, toHostNumber, U8, U16, U32, U64, } from './numerics.sts';
15
+ import { F32, F64, format as formatNumeric, I8, I16, I32, I64, isNumeric, toHostNumber, U8, U16, U32, U64, } from './numerics.js';
16
16
  const MAX_SAFE_INTEGER_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);
17
17
  const MIN_SAFE_INTEGER_BIGINT = BigInt(Number.MIN_SAFE_INTEGER);
18
18
  export class JsonParseFailure extends Failure {
package/numerics.js CHANGED
@@ -10,10 +10,10 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
12
  var _MachineNumericBox_key, _MachineNumericBox_payload;
13
- import { fromCompare } from './compare.sts';
14
- import { Failure } from './failures.sts';
15
- import { fromHashEq, stringHash } from './hash.sts';
16
- import { err, ok } from './result.sts';
13
+ import { fromCompare } from './compare.js';
14
+ import { Failure } from './failures.js';
15
+ import { fromHashEq, stringHash } from './hash.js';
16
+ import { err, ok } from './result.js';
17
17
  export class NumericOverflowFailure extends Failure {
18
18
  constructor(leaf, operation) {
19
19
  super(`Checked ${operation} overflowed for ${leaf}.`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soundscript/soundscript",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "license": "ISC",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -232,11 +232,11 @@
232
232
  "typescript": "5.9.3"
233
233
  },
234
234
  "optionalDependencies": {
235
- "@soundscript/cli-darwin-arm64": "0.1.16",
236
- "@soundscript/cli-darwin-x64": "0.1.16",
237
- "@soundscript/cli-linux-arm64": "0.1.16",
238
- "@soundscript/cli-linux-x64": "0.1.16",
239
- "@soundscript/cli-win32-x64": "0.1.16"
235
+ "@soundscript/cli-darwin-arm64": "0.1.17",
236
+ "@soundscript/cli-darwin-x64": "0.1.17",
237
+ "@soundscript/cli-linux-arm64": "0.1.17",
238
+ "@soundscript/cli-linux-x64": "0.1.17",
239
+ "@soundscript/cli-win32-x64": "0.1.17"
240
240
  },
241
241
  "repository": {
242
242
  "type": "git",
@@ -3,6 +3,7 @@ import { SOUND_DIAGNOSTIC_CODES, SOUND_DIAGNOSTIC_MESSAGES } from '../engine/dia
3
3
  import { getNodeDiagnosticRange, } from '../diagnostics.js';
4
4
  import { getFlowChildRegionStructure, getFlowRegionStructure, materializeConditionStructures, } from './flow_facts.js';
5
5
  import { cloneState, FLOW_FACT_ENVIRONMENT, isFunctionLikeWithBody, prepareChildRegionState, recordExecutedExpressionAliases, recordVariableAliases, statementAffectsNarrow, } from './flow_invalidation.js';
6
+ import { isConstLocalBindingPath } from './flow_shared.js';
6
7
  import { isInsideSyntheticErrorNormalizationHelper } from './generated_helpers.js';
7
8
  function boundaryKindLabel(kind) {
8
9
  switch (kind) {
@@ -114,6 +115,15 @@ function findInvalidation(context, statement, activeFacts, state) {
114
115
  }
115
116
  return undefined;
116
117
  }
118
+ function factRequiresBoundaryInvalidation(fact) {
119
+ if (fact.path.segments.length !== 0 || !isConstLocalBindingPath(fact.path)) {
120
+ return true;
121
+ }
122
+ return fact.kind !== 'discriminantLiteral' &&
123
+ fact.kind !== 'nonNull' &&
124
+ fact.kind !== 'truthy' &&
125
+ fact.kind !== 'typeof';
126
+ }
117
127
  function analyzeStatements(context, regionNode, statements, state, diagnostics, inheritedFacts = [], options = {}) {
118
128
  const region = regionNode ? getFlowRegionStructure(context, regionNode, statements, options) : {
119
129
  entries: statements.map((statement) => ({
@@ -134,7 +144,8 @@ function analyzeStatements(context, regionNode, statements, state, diagnostics,
134
144
  boundaryKind: classifyBoundaryKind(sequentialAnalysis.invalidatingNode),
135
145
  }));
136
146
  }
137
- const activeSequentialFacts = [...inheritedFacts, ...sequentialAnalysis.facts];
147
+ const activeSequentialFacts = [...inheritedFacts, ...sequentialAnalysis.facts]
148
+ .filter(factRequiresBoundaryInvalidation);
138
149
  const invalidatingNode = findInvalidation(context, statement, activeSequentialFacts, state);
139
150
  if (invalidatingNode) {
140
151
  diagnostics.push(createDiagnostic(context, invalidatingNode));
@@ -187,7 +198,8 @@ function analyzeRootRegion(context, regionNode, statements, diagnostics) {
187
198
  export function runFlowRules(context) {
188
199
  const diagnostics = [];
189
200
  context.forEachSourceFile((sourceFile) => {
190
- analyzeRootRegion(context, sourceFile, sourceFile.statements.filter((statement) => !context.isGeneratedNode(statement)), diagnostics);
201
+ const rootStatements = sourceFile.statements.filter((statement) => !context.isGeneratedNode(statement));
202
+ analyzeRootRegion(context, sourceFile, rootStatements, diagnostics);
191
203
  context.traverse(sourceFile, (node) => {
192
204
  if (!isFunctionLikeWithBody(node)) {
193
205
  return;
@@ -195,7 +207,8 @@ export function runFlowRules(context) {
195
207
  if (isInsideSyntheticErrorNormalizationHelper(node)) {
196
208
  return;
197
209
  }
198
- analyzeRootRegion(context, ts.isBlock(node.body) ? node.body : undefined, getRootStatements(node.body).filter((statement) => !context.isGeneratedNode(statement)), diagnostics);
210
+ const bodyStatements = getRootStatements(node.body).filter((statement) => !context.isGeneratedNode(statement));
211
+ analyzeRootRegion(context, ts.isBlock(node.body) ? node.body : undefined, bodyStatements, diagnostics);
199
212
  });
200
213
  });
201
214
  return diagnostics;
@@ -25,6 +25,7 @@ import {
25
25
  recordVariableAliases,
26
26
  statementAffectsNarrow,
27
27
  } from './flow_invalidation.ts';
28
+ import { isConstLocalBindingPath } from './flow_shared.ts';
28
29
  import { isInsideSyntheticErrorNormalizationHelper } from './generated_helpers.ts';
29
30
 
30
31
  type InvalidationBoundaryKind =
@@ -181,6 +182,19 @@ function findInvalidation(
181
182
  return undefined;
182
183
  }
183
184
 
185
+ function factRequiresBoundaryInvalidation(
186
+ fact: FlowFact<NormalizedPath>,
187
+ ): boolean {
188
+ if (fact.path.segments.length !== 0 || !isConstLocalBindingPath(fact.path)) {
189
+ return true;
190
+ }
191
+
192
+ return fact.kind !== 'discriminantLiteral' &&
193
+ fact.kind !== 'nonNull' &&
194
+ fact.kind !== 'truthy' &&
195
+ fact.kind !== 'typeof';
196
+ }
197
+
184
198
  function analyzeStatements(
185
199
  context: AnalysisContext,
186
200
  regionNode: ts.Node | undefined,
@@ -218,7 +232,8 @@ function analyzeStatements(
218
232
  }),
219
233
  );
220
234
  }
221
- const activeSequentialFacts = [...inheritedFacts, ...sequentialAnalysis.facts];
235
+ const activeSequentialFacts = [...inheritedFacts, ...sequentialAnalysis.facts]
236
+ .filter(factRequiresBoundaryInvalidation);
222
237
  const invalidatingNode = findInvalidation(context, statement, activeSequentialFacts, state);
223
238
  if (invalidatingNode) {
224
239
  diagnostics.push(createDiagnostic(context, invalidatingNode));
@@ -305,10 +320,11 @@ export function runFlowRules(context: AnalysisContext): SoundDiagnostic[] {
305
320
  const diagnostics: SoundDiagnostic[] = [];
306
321
 
307
322
  context.forEachSourceFile((sourceFile) => {
323
+ const rootStatements = sourceFile.statements.filter((statement) => !context.isGeneratedNode(statement));
308
324
  analyzeRootRegion(
309
325
  context,
310
326
  sourceFile,
311
- sourceFile.statements.filter((statement) => !context.isGeneratedNode(statement)),
327
+ rootStatements,
312
328
  diagnostics,
313
329
  );
314
330
 
@@ -320,10 +336,11 @@ export function runFlowRules(context: AnalysisContext): SoundDiagnostic[] {
320
336
  return;
321
337
  }
322
338
 
339
+ const bodyStatements = getRootStatements(node.body).filter((statement) => !context.isGeneratedNode(statement));
323
340
  analyzeRootRegion(
324
341
  context,
325
342
  ts.isBlock(node.body) ? node.body : undefined,
326
- getRootStatements(node.body).filter((statement) => !context.isGeneratedNode(statement)),
343
+ bodyStatements,
327
344
  diagnostics,
328
345
  );
329
346
  });
@@ -1583,9 +1583,6 @@ function getUnsupportedFeatureDiagnostic(context, node) {
1583
1583
  return unsupportedFeature(node.expression, 'prototypeMutation');
1584
1584
  }
1585
1585
  }
1586
- if (ts.isForInStatement(node)) {
1587
- return unsupportedFeature(node, 'forIn');
1588
- }
1589
1586
  if (ts.isLabeledStatement(node)) {
1590
1587
  return unsupportedFeature(node.label, 'labeledStatement');
1591
1588
  }
@@ -2381,10 +2381,6 @@ function getUnsupportedFeatureDiagnostic(
2381
2381
  }
2382
2382
  }
2383
2383
 
2384
- if (ts.isForInStatement(node)) {
2385
- return unsupportedFeature(node, 'forIn');
2386
- }
2387
-
2388
2384
  if (ts.isLabeledStatement(node)) {
2389
2385
  return unsupportedFeature(node.label, 'labeledStatement');
2390
2386
  }
@@ -11,7 +11,7 @@ import { createTempDirectory, fileExistsSync, makeDirectory, readStdinText, remo
11
11
  import { materializeRuntimeGraph, } from './runtime/materialize.js';
12
12
  import { runProgram } from './run_program.js';
13
13
  import { projectEditorFile } from './editor_projection.js';
14
- export const VERSION = '0.1.16';
14
+ export const VERSION = '0.1.17';
15
15
  const FINDINGS_EXIT_CODE = 1;
16
16
  const CLI_FAILURE_EXIT_CODE = 2;
17
17
  function createCliDiagnostic(code, message, filePath, details) {
@@ -59,7 +59,7 @@ import {
59
59
  import { runProgram, type RunProgramOptions, type RunProgramResult } from './run_program.ts';
60
60
  import { projectEditorFile } from './editor_projection.ts';
61
61
 
62
- export const VERSION = '0.1.16';
62
+ export const VERSION = '0.1.17';
63
63
  const FINDINGS_EXIT_CODE = 1;
64
64
  const CLI_FAILURE_EXIT_CODE = 2;
65
65
 
@@ -2,14 +2,14 @@ import ts from 'typescript';
2
2
  import { dirname, relative } from '../platform/path.js';
3
3
  import { createAnnotationLookup } from '../annotation_syntax.js';
4
4
  import { createSoundStdlibCompilerHost } from '../bundled/sound_stdlib.js';
5
- import { formatDiagnostics, getNodeDiagnosticRange, hasErrorDiagnostics, toMergedDiagnostic, } from '../checker/diagnostics.js';
5
+ import { formatDiagnostics, getNodeDiagnosticRange, hasErrorDiagnostics, remapDiagnosticFilePaths, toMergedDiagnostic, } from '../checker/diagnostics.js';
6
6
  import { COMPILER_DIAGNOSTIC_CODES, COMPILER_DIAGNOSTIC_MESSAGES, } from '../checker/engine/diagnostic_codes.js';
7
7
  import { createAnalysisContext } from '../checker/engine/context.js';
8
8
  import { runSoundAnalysis } from '../checker/rules/index.js';
9
9
  import { runUniversalPolicyAnalysis } from '../checker/rules/universal.js';
10
10
  import { collectSoundscriptRootNames, getConfigFileParsingDiagnostics, loadConfig, } from '../config.js';
11
11
  import { createBuiltinExpandedProgram } from '../frontend/builtin_macro_support.js';
12
- import { getLineAndCharacterOfPosition, mapProgramEnclosingRangeToSource, toSourceFileName, } from '../frontend/project_frontend.js';
12
+ import { getLineAndCharacterOfPosition, getPositionOfLineAndCharacter, mapProgramEnclosingRangeToSource, toSourceFileName, } from '../frontend/project_frontend.js';
13
13
  import { CompilerUnsupportedError } from './errors.js';
14
14
  import { lowerProgramToCompilerIR, validateHonestHeapBoundarySurfaces } from './lower.js';
15
15
  import { CompilerToolchainError, packageCompilerOutput, } from './toolchain.js';
@@ -57,6 +57,72 @@ function createCompilerDiagnosticForNode(node, overrides) {
57
57
  ...getNodeDiagnosticRange(node),
58
58
  };
59
59
  }
60
+ function remapDiagnostics(diagnostics) {
61
+ return diagnostics.map((diagnostic) => remapDiagnosticFilePaths(diagnostic, toSourceFileName));
62
+ }
63
+ function hasRelatedInformation(diagnostic) {
64
+ return 'relatedInformation' in diagnostic;
65
+ }
66
+ function remapPreparedDiagnosticRange(diagnostic, preparedFile, diagnosticPreparedFiles) {
67
+ const remappedFilePath = diagnostic.filePath
68
+ ? toSourceFileName(diagnostic.filePath)
69
+ : diagnostic.filePath;
70
+ if (!preparedFile ||
71
+ !diagnostic.filePath ||
72
+ diagnostic.line === undefined ||
73
+ diagnostic.column === undefined) {
74
+ const remappedDiagnostic = {
75
+ ...diagnostic,
76
+ filePath: remappedFilePath,
77
+ };
78
+ if (hasRelatedInformation(diagnostic)) {
79
+ remappedDiagnostic.relatedInformation = diagnostic.relatedInformation?.map((relatedInformation) => remapPreparedDiagnosticRange(relatedInformation, relatedInformation.filePath
80
+ ? diagnosticPreparedFiles.get(toSourceFileName(relatedInformation.filePath))
81
+ : undefined, diagnosticPreparedFiles));
82
+ }
83
+ return remappedDiagnostic;
84
+ }
85
+ const programStart = getPositionOfLineAndCharacter(preparedFile.rewrittenText, diagnostic.line - 1, diagnostic.column - 1);
86
+ const programEnd = diagnostic.endLine !== undefined && diagnostic.endColumn !== undefined
87
+ ? getPositionOfLineAndCharacter(preparedFile.rewrittenText, diagnostic.endLine - 1, diagnostic.endColumn - 1)
88
+ : programStart;
89
+ const mappedRange = mapProgramEnclosingRangeToSource(preparedFile, programStart, programEnd);
90
+ const mappedStart = getLineAndCharacterOfPosition(preparedFile.originalText, mappedRange.start);
91
+ const mappedEnd = getLineAndCharacterOfPosition(preparedFile.originalText, mappedRange.end);
92
+ const remappedDiagnostic = {
93
+ ...diagnostic,
94
+ filePath: remappedFilePath,
95
+ line: mappedStart.line + 1,
96
+ column: mappedStart.character + 1,
97
+ endLine: mappedEnd.line + 1,
98
+ endColumn: mappedEnd.character + 1,
99
+ };
100
+ if (hasRelatedInformation(diagnostic)) {
101
+ remappedDiagnostic.relatedInformation = diagnostic.relatedInformation?.map((relatedInformation) => {
102
+ const relatedPreparedFile = relatedInformation.filePath
103
+ ? diagnosticPreparedFiles.get(toSourceFileName(relatedInformation.filePath))
104
+ : undefined;
105
+ return remapPreparedDiagnosticRange(relatedInformation, relatedPreparedFile, diagnosticPreparedFiles);
106
+ });
107
+ }
108
+ return remappedDiagnostic;
109
+ }
110
+ function remapSoundDiagnostics(diagnostics, diagnosticPreparedFiles) {
111
+ return diagnostics.map((diagnostic) => {
112
+ const preparedFile = diagnostic.filePath
113
+ ? diagnosticPreparedFiles.get(toSourceFileName(diagnostic.filePath))
114
+ : undefined;
115
+ return remapPreparedDiagnosticRange(diagnostic, preparedFile, diagnosticPreparedFiles);
116
+ });
117
+ }
118
+ function remapCompilerDiagnostics(diagnostics, diagnosticPreparedFiles) {
119
+ return diagnostics.map((diagnostic) => {
120
+ const preparedFile = diagnostic.filePath
121
+ ? diagnosticPreparedFiles.get(toSourceFileName(diagnostic.filePath))
122
+ : undefined;
123
+ return remapPreparedDiagnosticRange(diagnostic, preparedFile, diagnosticPreparedFiles);
124
+ });
125
+ }
60
126
  function createProgram(options) {
61
127
  const loadedConfig = loadConfig(options.projectPath, { target: options.target });
62
128
  const soundscriptRootNames = collectSoundscriptRootNames(options.projectPath, loadedConfig);
@@ -78,7 +144,7 @@ function createProgram(options) {
78
144
  analysisPreparedProgram: expandedProgram.analysisPreparedProgram,
79
145
  diagnosticPreparedFiles: expandedProgram.diagnosticPreparedFiles,
80
146
  dispose: () => expandedProgram.dispose(),
81
- frontendDiagnostics: expandedProgram.frontendDiagnostics(),
147
+ frontendDiagnostics: remapDiagnostics(expandedProgram.frontendDiagnostics()),
82
148
  program: expandedProgram.program,
83
149
  runtime: loadedConfig.runtime,
84
150
  tsDiagnosticPrograms: expandedProgram.tsDiagnosticPrograms,
@@ -193,7 +259,7 @@ function collectDiagnostics(analysisPreparedProgram, diagnosticPreparedFiles, pr
193
259
  workingDirectory,
194
260
  includeSourceFile: (sourceFile) => !sourceFile.isDeclarationFile,
195
261
  });
196
- const universalDiagnostics = runUniversalPolicyAnalysis(analysisContext);
262
+ const universalDiagnostics = remapSoundDiagnostics(runUniversalPolicyAnalysis(analysisContext), diagnosticPreparedFiles);
197
263
  if (hasErrorDiagnostics(tsDiagnostics)) {
198
264
  return [...frontendDiagnostics, ...tsDiagnostics, ...universalDiagnostics];
199
265
  }
@@ -201,7 +267,7 @@ function collectDiagnostics(analysisPreparedProgram, diagnosticPreparedFiles, pr
201
267
  ...frontendDiagnostics,
202
268
  ...tsDiagnostics,
203
269
  ...universalDiagnostics,
204
- ...runSoundAnalysis(analysisContext),
270
+ ...remapSoundDiagnostics(runSoundAnalysis(analysisContext), diagnosticPreparedFiles),
205
271
  ];
206
272
  }
207
273
  function findUnsupportedValueClass(program) {
@@ -242,13 +308,13 @@ export function compileProject(options) {
242
308
  }
243
309
  const unsupportedValueClass = findUnsupportedValueClass(program);
244
310
  if (unsupportedValueClass) {
245
- const compilerDiagnostics = [
311
+ const compilerDiagnostics = remapCompilerDiagnostics([
246
312
  createCompilerDiagnosticForNode(unsupportedValueClass, {
247
313
  code: COMPILER_DIAGNOSTIC_CODES.valueClassesRequireJsEmit,
248
314
  message: COMPILER_DIAGNOSTIC_MESSAGES.valueClassesRequireJsEmit,
249
315
  hint: 'Use `soundscript build`, `soundscript node`, or another JS emit path for `#[value]`, or remove the annotation before compiling to Wasm.',
250
316
  }),
251
- ];
317
+ ], diagnosticPreparedFiles);
252
318
  return {
253
319
  diagnostics: compilerDiagnostics,
254
320
  output: formatDiagnostics(compilerDiagnostics, options.workingDirectory),
@@ -286,11 +352,11 @@ export function compileProject(options) {
286
352
  hint: error.diagnosticHint,
287
353
  notes: error.diagnosticNotes,
288
354
  };
289
- const compilerDiagnostics = [
355
+ const compilerDiagnostics = remapCompilerDiagnostics([
290
356
  error.node
291
357
  ? createCompilerDiagnosticForNode(error.node, diagnosticOverrides)
292
358
  : createCompilerDiagnostic(options.projectPath, diagnosticOverrides),
293
- ];
359
+ ], diagnosticPreparedFiles);
294
360
  return {
295
361
  diagnostics: compilerDiagnostics,
296
362
  output: formatDiagnostics(compilerDiagnostics, options.workingDirectory),
@@ -10,6 +10,7 @@ import {
10
10
  getNodeDiagnosticRange,
11
11
  hasErrorDiagnostics,
12
12
  type MergedDiagnostic,
13
+ remapDiagnosticFilePaths,
13
14
  toMergedDiagnostic,
14
15
  } from '../checker/diagnostics.ts';
15
16
  import {
@@ -29,6 +30,7 @@ import {
29
30
  import { createBuiltinExpandedProgram } from '../frontend/builtin_macro_support.ts';
30
31
  import {
31
32
  getLineAndCharacterOfPosition,
33
+ getPositionOfLineAndCharacter,
32
34
  mapProgramEnclosingRangeToSource,
33
35
  type PreparedSourceFile,
34
36
  toSourceFileName,
@@ -118,6 +120,115 @@ function createCompilerDiagnosticForNode(
118
120
  };
119
121
  }
120
122
 
123
+ function remapDiagnostics<T extends MergedDiagnostic>(diagnostics: readonly T[]): T[] {
124
+ return diagnostics.map((diagnostic) => remapDiagnosticFilePaths(diagnostic, toSourceFileName));
125
+ }
126
+
127
+ function hasRelatedInformation(
128
+ diagnostic: MergedDiagnostic | DiagnosticRelatedInformation,
129
+ ): diagnostic is MergedDiagnostic {
130
+ return 'relatedInformation' in diagnostic;
131
+ }
132
+
133
+ function remapPreparedDiagnosticRange<T extends MergedDiagnostic | DiagnosticRelatedInformation>(
134
+ diagnostic: T,
135
+ preparedFile: PreparedSourceFile | undefined,
136
+ diagnosticPreparedFiles: ReadonlyMap<string, PreparedSourceFile>,
137
+ ): T {
138
+ const remappedFilePath = diagnostic.filePath
139
+ ? toSourceFileName(diagnostic.filePath)
140
+ : diagnostic.filePath;
141
+
142
+ if (
143
+ !preparedFile ||
144
+ !diagnostic.filePath ||
145
+ diagnostic.line === undefined ||
146
+ diagnostic.column === undefined
147
+ ) {
148
+ const remappedDiagnostic = {
149
+ ...diagnostic,
150
+ filePath: remappedFilePath,
151
+ } as T;
152
+ if (hasRelatedInformation(diagnostic)) {
153
+ (remappedDiagnostic as MergedDiagnostic).relatedInformation = diagnostic.relatedInformation?.map(
154
+ (relatedInformation) =>
155
+ remapPreparedDiagnosticRange(
156
+ relatedInformation,
157
+ relatedInformation.filePath
158
+ ? diagnosticPreparedFiles.get(toSourceFileName(relatedInformation.filePath))
159
+ : undefined,
160
+ diagnosticPreparedFiles,
161
+ ),
162
+ );
163
+ }
164
+ return remappedDiagnostic;
165
+ }
166
+
167
+ const programStart = getPositionOfLineAndCharacter(
168
+ preparedFile.rewrittenText,
169
+ diagnostic.line - 1,
170
+ diagnostic.column - 1,
171
+ );
172
+ const programEnd = diagnostic.endLine !== undefined && diagnostic.endColumn !== undefined
173
+ ? getPositionOfLineAndCharacter(
174
+ preparedFile.rewrittenText,
175
+ diagnostic.endLine - 1,
176
+ diagnostic.endColumn - 1,
177
+ )
178
+ : programStart;
179
+ const mappedRange = mapProgramEnclosingRangeToSource(preparedFile, programStart, programEnd);
180
+ const mappedStart = getLineAndCharacterOfPosition(preparedFile.originalText, mappedRange.start);
181
+ const mappedEnd = getLineAndCharacterOfPosition(preparedFile.originalText, mappedRange.end);
182
+
183
+ const remappedDiagnostic = {
184
+ ...diagnostic,
185
+ filePath: remappedFilePath,
186
+ line: mappedStart.line + 1,
187
+ column: mappedStart.character + 1,
188
+ endLine: mappedEnd.line + 1,
189
+ endColumn: mappedEnd.character + 1,
190
+ } as T;
191
+ if (hasRelatedInformation(diagnostic)) {
192
+ (remappedDiagnostic as MergedDiagnostic).relatedInformation = diagnostic.relatedInformation?.map(
193
+ (relatedInformation) => {
194
+ const relatedPreparedFile = relatedInformation.filePath
195
+ ? diagnosticPreparedFiles.get(toSourceFileName(relatedInformation.filePath))
196
+ : undefined;
197
+ return remapPreparedDiagnosticRange(
198
+ relatedInformation,
199
+ relatedPreparedFile,
200
+ diagnosticPreparedFiles,
201
+ );
202
+ },
203
+ );
204
+ }
205
+ return remappedDiagnostic;
206
+ }
207
+
208
+ function remapSoundDiagnostics<T extends MergedDiagnostic>(
209
+ diagnostics: readonly T[],
210
+ diagnosticPreparedFiles: ReadonlyMap<string, PreparedSourceFile>,
211
+ ): T[] {
212
+ return diagnostics.map((diagnostic) => {
213
+ const preparedFile = diagnostic.filePath
214
+ ? diagnosticPreparedFiles.get(toSourceFileName(diagnostic.filePath))
215
+ : undefined;
216
+ return remapPreparedDiagnosticRange(diagnostic, preparedFile, diagnosticPreparedFiles);
217
+ });
218
+ }
219
+
220
+ function remapCompilerDiagnostics<T extends MergedDiagnostic>(
221
+ diagnostics: readonly T[],
222
+ diagnosticPreparedFiles: ReadonlyMap<string, PreparedSourceFile>,
223
+ ): T[] {
224
+ return diagnostics.map((diagnostic) => {
225
+ const preparedFile = diagnostic.filePath
226
+ ? diagnosticPreparedFiles.get(toSourceFileName(diagnostic.filePath))
227
+ : undefined;
228
+ return remapPreparedDiagnosticRange(diagnostic, preparedFile, diagnosticPreparedFiles);
229
+ });
230
+ }
231
+
121
232
  function createProgram(options: CompileProjectOptions): {
122
233
  analysisPreparedProgram: {
123
234
  toProgramFileName(fileName: string): string;
@@ -159,7 +270,7 @@ function createProgram(options: CompileProjectOptions): {
159
270
  analysisPreparedProgram: expandedProgram.analysisPreparedProgram,
160
271
  diagnosticPreparedFiles: expandedProgram.diagnosticPreparedFiles,
161
272
  dispose: () => expandedProgram.dispose(),
162
- frontendDiagnostics: expandedProgram.frontendDiagnostics(),
273
+ frontendDiagnostics: remapDiagnostics(expandedProgram.frontendDiagnostics()),
163
274
  program: expandedProgram.program,
164
275
  runtime: loadedConfig.runtime,
165
276
  tsDiagnosticPrograms: expandedProgram.tsDiagnosticPrograms,
@@ -356,7 +467,10 @@ function collectDiagnostics(
356
467
  workingDirectory,
357
468
  includeSourceFile: (sourceFile) => !sourceFile.isDeclarationFile,
358
469
  });
359
- const universalDiagnostics = runUniversalPolicyAnalysis(analysisContext);
470
+ const universalDiagnostics = remapSoundDiagnostics(
471
+ runUniversalPolicyAnalysis(analysisContext),
472
+ diagnosticPreparedFiles,
473
+ );
360
474
  if (hasErrorDiagnostics(tsDiagnostics)) {
361
475
  return [...frontendDiagnostics, ...tsDiagnostics, ...universalDiagnostics];
362
476
  }
@@ -365,7 +479,7 @@ function collectDiagnostics(
365
479
  ...frontendDiagnostics,
366
480
  ...tsDiagnostics,
367
481
  ...universalDiagnostics,
368
- ...runSoundAnalysis(analysisContext),
482
+ ...remapSoundDiagnostics(runSoundAnalysis(analysisContext), diagnosticPreparedFiles),
369
483
  ];
370
484
  }
371
485
 
@@ -430,14 +544,14 @@ export function compileProject(options: CompileProjectOptions): CompileProjectRe
430
544
 
431
545
  const unsupportedValueClass = findUnsupportedValueClass(program);
432
546
  if (unsupportedValueClass) {
433
- const compilerDiagnostics = [
547
+ const compilerDiagnostics = remapCompilerDiagnostics([
434
548
  createCompilerDiagnosticForNode(unsupportedValueClass, {
435
549
  code: COMPILER_DIAGNOSTIC_CODES.valueClassesRequireJsEmit,
436
550
  message: COMPILER_DIAGNOSTIC_MESSAGES.valueClassesRequireJsEmit,
437
551
  hint:
438
552
  'Use `soundscript build`, `soundscript node`, or another JS emit path for `#[value]`, or remove the annotation before compiling to Wasm.',
439
553
  }),
440
- ];
554
+ ], diagnosticPreparedFiles);
441
555
  return {
442
556
  diagnostics: compilerDiagnostics,
443
557
  output: formatDiagnostics(compilerDiagnostics, options.workingDirectory),
@@ -475,11 +589,11 @@ export function compileProject(options: CompileProjectOptions): CompileProjectRe
475
589
  hint: error.diagnosticHint,
476
590
  notes: error.diagnosticNotes,
477
591
  };
478
- const compilerDiagnostics = [
592
+ const compilerDiagnostics = remapCompilerDiagnostics([
479
593
  error.node
480
594
  ? createCompilerDiagnosticForNode(error.node, diagnosticOverrides)
481
595
  : createCompilerDiagnostic(options.projectPath, diagnosticOverrides),
482
- ];
596
+ ], diagnosticPreparedFiles);
483
597
  return {
484
598
  diagnostics: compilerDiagnostics,
485
599
  output: formatDiagnostics(compilerDiagnostics, options.workingDirectory),
@@ -1337,6 +1337,15 @@ export interface CompilerWhileStatementIR {
1337
1337
  body: CompilerStatementIR[];
1338
1338
  }
1339
1339
 
1340
+ export interface CompilerTrapStatementIR {
1341
+ kind: 'trap';
1342
+ }
1343
+
1344
+ export interface CompilerThrowTaggedStatementIR {
1345
+ kind: 'throw_tagged';
1346
+ value: CompilerExpressionIR;
1347
+ }
1348
+
1340
1349
  export type CompilerStatementIR =
1341
1350
  | CompilerLocalSetStatementIR
1342
1351
  | CompilerReturnStatementIR
@@ -1350,7 +1359,9 @@ export type CompilerStatementIR =
1350
1359
  | CompilerBoxSetStatementIR
1351
1360
  | CompilerDynamicObjectPropertySetStatementIR
1352
1361
  | CompilerIfStatementIR
1353
- | CompilerWhileStatementIR;
1362
+ | CompilerWhileStatementIR
1363
+ | CompilerTrapStatementIR
1364
+ | CompilerThrowTaggedStatementIR;
1354
1365
 
1355
1366
  export interface CompilerTaggedPrimitiveBoundaryKindsIR {
1356
1367
  includesBoolean?: boolean;
@@ -1442,6 +1453,7 @@ export interface CompilerFunctionIR {
1442
1453
  hostImport?: {
1443
1454
  module: string;
1444
1455
  name: string;
1456
+ construct?: boolean;
1445
1457
  promiseResult?: boolean;
1446
1458
  };
1447
1459
  hostClassConstructorParams?: readonly CompilerFunctionHostClassConstructorParamIR[];
@@ -1455,6 +1467,9 @@ export interface CompilerFunctionIR {
1455
1467
  hostDynamicCollectionParams?: readonly CompilerFunctionHostDynamicCollectionParamIR[];
1456
1468
  hostPromiseParams?: readonly string[];
1457
1469
  hostPromiseResult?: boolean;
1470
+ hostGeneratorResult?: boolean;
1471
+ hostAsyncGeneratorResult?: boolean;
1472
+ usesAsyncGeneratorHostStepBridge?: boolean;
1458
1473
  hostFallbackClosureProperties?: readonly CompilerFunctionHostFallbackClosurePropertyIR[];
1459
1474
  hostFallbackClassConstructorProperties?:
1460
1475
  readonly CompilerFunctionHostFallbackClassConstructorPropertyIR[];
@@ -1494,6 +1509,7 @@ export interface CompilerFunctionHostDynamicCollectionParamIR {
1494
1509
 
1495
1510
  export interface CompilerModuleIR {
1496
1511
  closureSignatures?: readonly CompilerClosureSignatureIR[];
1512
+ syncTryCatchClosureSignatureId?: number;
1497
1513
  functions: CompilerFunctionIR[];
1498
1514
  jsHostImports?: readonly CompilerJsHostImportIR[];
1499
1515
  stringLiterals?: readonly string[];
@@ -1503,10 +1519,12 @@ export interface CompilerModuleIR {
1503
1519
 
1504
1520
  export interface CompilerJsHostImportIR {
1505
1521
  hostImportName: string;
1522
+ bindingKind: 'function' | 'constructor' | 'static_method' | 'property';
1506
1523
  importKind: 'default' | 'named';
1507
1524
  importerModulePath: string;
1508
1525
  moduleSpecifier: string;
1509
1526
  exportName?: string;
1527
+ memberName?: string;
1510
1528
  }
1511
1529
 
1512
1530
  export interface CompilerClosureSignatureIR {