wasm-idle 0.4.0 → 0.5.0

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 (49) hide show
  1. package/README.md +111 -2
  2. package/dist/clang/app.d.ts +4 -0
  3. package/dist/clang/app.js +330 -15
  4. package/dist/clang/index.d.ts +10 -0
  5. package/dist/clang/index.js +284 -25
  6. package/dist/debug/controller.svelte.d.ts +43 -0
  7. package/dist/debug/controller.svelte.js +268 -0
  8. package/dist/debug/editor/index.d.ts +2 -1
  9. package/dist/debug/editor/index.js +1 -1
  10. package/dist/debug/editor/monaco.d.ts +8 -0
  11. package/dist/debug/editor/monaco.js +23 -0
  12. package/dist/debug/expression.d.ts +24 -0
  13. package/dist/debug/expression.js +307 -138
  14. package/dist/debug/index.d.ts +4 -1
  15. package/dist/debug/index.js +2 -1
  16. package/dist/index.d.ts +6 -3
  17. package/dist/index.js +3 -3
  18. package/dist/playground/assetBridge.d.ts +20 -0
  19. package/dist/playground/assetBridge.js +192 -0
  20. package/dist/playground/assets.d.ts +37 -0
  21. package/dist/playground/assets.js +105 -0
  22. package/dist/playground/clang.d.ts +11 -1
  23. package/dist/playground/clang.js +58 -4
  24. package/dist/playground/index.d.ts +5 -5
  25. package/dist/playground/index.js +48 -6
  26. package/dist/playground/java.d.ts +7 -2
  27. package/dist/playground/java.js +31 -5
  28. package/dist/playground/javaStdin.js +235 -2
  29. package/dist/playground/options.d.ts +18 -0
  30. package/dist/playground/options.js +15 -1
  31. package/dist/playground/python.d.ts +7 -1
  32. package/dist/playground/python.js +50 -5
  33. package/dist/playground/rust.d.ts +32 -0
  34. package/dist/playground/rust.js +175 -0
  35. package/dist/playground/sandbox.d.ts +19 -4
  36. package/dist/playground/wasmRustVersion.d.ts +1 -0
  37. package/dist/playground/wasmRustVersion.js +1 -0
  38. package/dist/playground/worker/assets.d.ts +12 -0
  39. package/dist/playground/worker/assets.js +257 -0
  40. package/dist/playground/worker/clang.js +22 -6
  41. package/dist/playground/worker/java.js +15 -35
  42. package/dist/playground/worker/python.js +13 -33
  43. package/dist/playground/worker/rust.d.ts +1 -0
  44. package/dist/playground/worker/rust.js +159 -0
  45. package/dist/terminal/Terminal.svelte +121 -18
  46. package/dist/terminal/Terminal.svelte.d.ts +4 -0
  47. package/dist/terminal/theme.js +2 -2
  48. package/dist/terminal/types.d.ts +4 -0
  49. package/package.json +19 -13
@@ -20,7 +20,94 @@ const clangCommonArgs = [
20
20
  '80',
21
21
  '-fcolor-diagnostics'
22
22
  ];
23
- const clangLanguageStandardArg = '-std=gnu++2a';
23
+ const defaultCppStandardArg = '-std=gnu++2a';
24
+ const defaultCStandardArg = '-std=gnu11';
25
+ function normalizeStandardCode(value) {
26
+ return (value || '').trim().toUpperCase().replaceAll(/\s+/g, '');
27
+ }
28
+ function resolveCppStandardArg(version) {
29
+ switch (normalizeStandardCode(version)) {
30
+ case '03':
31
+ case 'CPP03':
32
+ case 'C++03':
33
+ case 'GNU++03':
34
+ case 'GNUC++03':
35
+ return '-std=gnu++03';
36
+ case '11':
37
+ case 'CPP11':
38
+ case 'C++11':
39
+ case 'GNU++11':
40
+ case 'GNUC++11':
41
+ return '-std=gnu++11';
42
+ case '14':
43
+ case 'CPP14':
44
+ case 'C++14':
45
+ case 'GNU++14':
46
+ case 'GNUC++14':
47
+ return '-std=gnu++14';
48
+ case '17':
49
+ case 'CPP17':
50
+ case 'C++17':
51
+ case 'GNU++17':
52
+ case 'GNUC++17':
53
+ return '-std=gnu++17';
54
+ case '20':
55
+ case '23':
56
+ case '26':
57
+ case 'CPP20':
58
+ case 'CPP23':
59
+ case 'CPP26':
60
+ case 'C++20':
61
+ case 'C++23':
62
+ case 'C++26':
63
+ case 'GNU++20':
64
+ case 'GNU++23':
65
+ case 'GNU++26':
66
+ case 'GNUC++20':
67
+ case 'GNUC++23':
68
+ case 'GNUC++26':
69
+ return defaultCppStandardArg;
70
+ default:
71
+ return defaultCppStandardArg;
72
+ }
73
+ }
74
+ function resolveCStandardArg(version) {
75
+ switch (normalizeStandardCode(version)) {
76
+ case '99':
77
+ case 'C99':
78
+ case 'GNU99':
79
+ case 'GNUC99':
80
+ return '-std=gnu99';
81
+ case '11':
82
+ case 'C11':
83
+ case 'GNU11':
84
+ case 'GNUC11':
85
+ return '-std=gnu11';
86
+ case '17':
87
+ case '18':
88
+ case 'C17':
89
+ case 'C18':
90
+ case 'GNU17':
91
+ case 'GNU18':
92
+ case 'GNUC17':
93
+ case 'GNUC18':
94
+ return '-std=gnu17';
95
+ default:
96
+ return defaultCStandardArg;
97
+ }
98
+ }
99
+ function resolveClangLanguageArgs(language, options) {
100
+ if (language === 'C') {
101
+ return {
102
+ languageArg: 'c',
103
+ standardArg: resolveCStandardArg(options.cVersion)
104
+ };
105
+ }
106
+ return {
107
+ languageArg: 'c++',
108
+ standardArg: resolveCppStandardArg(options.cppVersion)
109
+ };
110
+ }
24
111
  const toUtf8 = (text) => {
25
112
  const surrogate = encodeURIComponent(text);
26
113
  let result = '';
@@ -50,6 +137,8 @@ export default class Clang {
50
137
  debugPauseOnEntry = false;
51
138
  debugBuffer;
52
139
  debugInterruptBuffer;
140
+ debugWatchBuffer;
141
+ debugWatchResultBuffer;
53
142
  onDebugEvent;
54
143
  debugVariableMetadata = {};
55
144
  debugGlobalMetadata = [];
@@ -98,7 +187,7 @@ export default class Clang {
98
187
  this.traceStartedAt = Date.now();
99
188
  }
100
189
  trace(message) {
101
- if (!this.debug)
190
+ if (!this.debug || !this.log)
102
191
  return;
103
192
  const elapsed = Date.now() - this.traceStartedAt;
104
193
  this.stdout(`\x1b[2m[debug +${elapsed}ms] ${message}\x1b[0m\n`);
@@ -127,8 +216,11 @@ export default class Clang {
127
216
  const input = options.input;
128
217
  let source = options.code;
129
218
  const obj = options.obj;
219
+ const language = options.language === 'C' ? 'C' : 'CPP';
220
+ const compileArgs = options.compileArgs ?? options.args ?? [];
221
+ const { languageArg, standardArg } = resolveClangLanguageArgs(language, options);
130
222
  const debug = !!options.debug;
131
- const opt = debug ? '0' : (options.opt || '2');
223
+ const opt = debug ? '0' : options.opt || '2';
132
224
  if (debug) {
133
225
  const lines = source.split('\n');
134
226
  let braceDepth = 0;
@@ -141,11 +233,98 @@ export default class Clang {
141
233
  let currentFunctionContainers = new Map();
142
234
  let inBlockComment = false;
143
235
  let pendingFunctionHeader;
236
+ const debugStructTypes = new Map();
237
+ let structName = '';
238
+ let structFields = [];
239
+ let structInBlockComment = false;
240
+ for (const rawLine of lines) {
241
+ let structLine = rawLine;
242
+ if (structInBlockComment) {
243
+ const commentEnd = structLine.indexOf('*/');
244
+ if (commentEnd === -1)
245
+ continue;
246
+ structLine = structLine.slice(commentEnd + 2);
247
+ structInBlockComment = false;
248
+ }
249
+ const commentStart = structLine.indexOf('/*');
250
+ if (commentStart !== -1) {
251
+ const commentEnd = structLine.indexOf('*/', commentStart + 2);
252
+ if (commentEnd === -1) {
253
+ structInBlockComment = true;
254
+ structLine = structLine.slice(0, commentStart);
255
+ }
256
+ else {
257
+ structLine =
258
+ structLine.slice(0, commentStart) + structLine.slice(commentEnd + 2);
259
+ }
260
+ }
261
+ const lineComment = structLine.indexOf('//');
262
+ if (lineComment !== -1)
263
+ structLine = structLine.slice(0, lineComment);
264
+ const normalizedStructLine = structLine.trim();
265
+ if (!structName) {
266
+ const structMatch = normalizedStructLine.match(/^struct\s+([A-Za-z_]\w*)\s*\{$/);
267
+ if (structMatch?.[1]) {
268
+ structName = structMatch[1];
269
+ structFields = [];
270
+ }
271
+ continue;
272
+ }
273
+ if (normalizedStructLine === '};') {
274
+ let structOffset = 0;
275
+ let structAlignment = 1;
276
+ const resolvedFields = [];
277
+ for (const field of structFields) {
278
+ const fieldSize = field.kind === 'double'
279
+ ? 8
280
+ : field.kind === 'bool' || field.kind === 'char'
281
+ ? 1
282
+ : 4;
283
+ if (structOffset % fieldSize !== 0) {
284
+ structOffset += fieldSize - (structOffset % fieldSize);
285
+ }
286
+ resolvedFields.push({
287
+ name: field.name,
288
+ kind: field.kind,
289
+ offset: structOffset
290
+ });
291
+ structOffset += fieldSize;
292
+ structAlignment = Math.max(structAlignment, fieldSize);
293
+ }
294
+ if (structOffset % structAlignment !== 0) {
295
+ structOffset += structAlignment - (structOffset % structAlignment);
296
+ }
297
+ debugStructTypes.set(structName, {
298
+ fields: resolvedFields,
299
+ size: Math.max(structOffset, 1)
300
+ });
301
+ structName = '';
302
+ structFields = [];
303
+ continue;
304
+ }
305
+ const structFieldMatch = normalizedStructLine.match(/^(?:const\s+)?(?:(?:unsigned|signed)\s+)?(?:(?:short|long long|long)\s+)?(int|float|double|bool|char)\s+(.+);$/);
306
+ if (!structFieldMatch)
307
+ continue;
308
+ for (const declaration of structFieldMatch[2].split(',')) {
309
+ const declarator = declaration.split('=')[0]?.trim() || '';
310
+ if (!declarator || /[*&\[]/.test(declarator))
311
+ continue;
312
+ const name = declarator.match(/([A-Za-z_]\w*)\s*$/)?.[1];
313
+ if (!name)
314
+ continue;
315
+ structFields.push({
316
+ name,
317
+ kind: structFieldMatch[1]
318
+ });
319
+ }
320
+ }
144
321
  this.debugVariableMetadata = {};
145
322
  this.debugGlobalMetadata = [];
146
323
  this.debugFunctionMetadata = {};
147
324
  const globalInitialization = [];
148
325
  const instrumented = [
326
+ '#include <cstdio>',
327
+ '#include <iostream>',
149
328
  '#include <map>',
150
329
  '#include <set>',
151
330
  '#include <string>',
@@ -231,7 +410,8 @@ export default class Clang {
231
410
  }
232
411
  else {
233
412
  analysisLine =
234
- analysisLine.slice(0, commentStart) + analysisLine.slice(commentEnd + 2);
413
+ analysisLine.slice(0, commentStart) +
414
+ analysisLine.slice(commentEnd + 2);
235
415
  }
236
416
  }
237
417
  const lineComment = analysisLine.indexOf('//');
@@ -297,6 +477,29 @@ export default class Clang {
297
477
  globalInitialization.push(`${kind === 'bool' ? '__wasm_idle_debug_value_bool' : '__wasm_idle_debug_value_num'}(0, ${slot}, ${name});`);
298
478
  }
299
479
  }
480
+ const globalStructArrayMatch = isTopLevelDeclarationContext &&
481
+ normalized.match(/^(?:const\s+)?([A-Za-z_]\w*)\s+([A-Za-z_]\w*)\s*\[(\d+)\]\s*(?:=.*)?;$/);
482
+ if (globalStructArrayMatch) {
483
+ const structType = debugStructTypes.get(globalStructArrayMatch[1]);
484
+ if (structType) {
485
+ const slot = nextVariableSlot++;
486
+ this.debugGlobalMetadata = [
487
+ ...this.debugGlobalMetadata,
488
+ {
489
+ slot,
490
+ name: globalStructArrayMatch[2],
491
+ kind: 'array',
492
+ length: Number(globalStructArrayMatch[3]),
493
+ dimensions: [Number(globalStructArrayMatch[3])],
494
+ structFields: structType.fields,
495
+ structSize: structType.size,
496
+ fromLine: index + 1,
497
+ toLine: Number.MAX_SAFE_INTEGER
498
+ }
499
+ ];
500
+ globalInitialization.push(`__wasm_idle_debug_value_addr(0, ${slot}, (int)((unsigned long long)(${globalStructArrayMatch[2]})));`);
501
+ }
502
+ }
300
503
  if (inFunctionBody &&
301
504
  normalized &&
302
505
  !normalized.startsWith('#') &&
@@ -343,7 +546,9 @@ export default class Clang {
343
546
  let declarationParenDepth = 0;
344
547
  let declarationBraceDepth = 0;
345
548
  for (const character of declarationMatch[2]) {
346
- if (character === ',' && declarationParenDepth === 0 && declarationBraceDepth === 0) {
549
+ if (character === ',' &&
550
+ declarationParenDepth === 0 &&
551
+ declarationBraceDepth === 0) {
347
552
  if (declarationBuffer.trim())
348
553
  declarations.push(declarationBuffer.trim());
349
554
  declarationBuffer = '';
@@ -429,7 +634,7 @@ export default class Clang {
429
634
  slot,
430
635
  kind,
431
636
  fromLine: index + 1,
432
- toLine: index + 1
637
+ toLine: Number.MAX_SAFE_INTEGER
433
638
  });
434
639
  this.debugVariableMetadata[currentFunctionId] = [
435
640
  ...(this.debugVariableMetadata[currentFunctionId] || []),
@@ -438,7 +643,7 @@ export default class Clang {
438
643
  name,
439
644
  kind,
440
645
  fromLine: index + 1,
441
- toLine: index + 1
646
+ toLine: Number.MAX_SAFE_INTEGER
442
647
  }
443
648
  ];
444
649
  }
@@ -458,10 +663,23 @@ export default class Clang {
458
663
  continue;
459
664
  if (new RegExp(`(?:^|[^\\w])(?:\\+\\+|--)\\s*${escapedName}\\b`).test(normalized) ||
460
665
  new RegExp(`\\b${escapedName}\\s*(?:[+\\-*/%]?=|\\+\\+|--)`).test(normalized) ||
461
- new RegExp(`&\\s*${escapedName}\\b`).test(normalized)) {
666
+ new RegExp(`&\\s*${escapedName}\\b`).test(normalized) ||
667
+ new RegExp(`\\b(?:cin|std::cin)\\b[^;]*>>\\s*${escapedName}\\b`).test(normalized)) {
462
668
  trailingInstrumentation.push(`${indent}${variable.kind === 'bool' ? '__wasm_idle_debug_value_bool' : '__wasm_idle_debug_value_num'}(${currentFunctionId}, ${variable.slot}, ${name});`);
463
669
  }
464
670
  }
671
+ for (const [name, variable] of globalVariables) {
672
+ if (currentFunctionVariables.has(name) ||
673
+ currentFunctionContainers.has(name))
674
+ continue;
675
+ const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
676
+ if (new RegExp(`(?:^|[^\\w])(?:\\+\\+|--)\\s*${escapedName}\\b`).test(normalized) ||
677
+ new RegExp(`\\b${escapedName}\\s*(?:[+\\-*/%]?=|\\+\\+|--)`).test(normalized) ||
678
+ new RegExp(`&\\s*${escapedName}\\b`).test(normalized) ||
679
+ new RegExp(`\\b(?:cin|std::cin)\\b[^;]*>>\\s*${escapedName}\\b`).test(normalized)) {
680
+ trailingInstrumentation.push(`${indent}${variable.kind === 'bool' ? '__wasm_idle_debug_value_bool' : '__wasm_idle_debug_value_num'}(0, ${variable.slot}, ${name});`);
681
+ }
682
+ }
465
683
  }
466
684
  if (/^return\b/.test(normalized))
467
685
  leadingInstrumentation.push(`${indent}__wasm_idle_debug_leave(${currentFunctionId});`);
@@ -491,7 +709,8 @@ export default class Clang {
491
709
  }
492
710
  }
493
711
  for (const [name, variable] of globalVariables) {
494
- if (currentFunctionVariables.has(name) || currentFunctionContainers.has(name))
712
+ if (currentFunctionVariables.has(name) ||
713
+ currentFunctionContainers.has(name))
495
714
  continue;
496
715
  const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
497
716
  if (new RegExp(`(?:^|[^\\w])(?:\\+\\+|--)\\s*${escapedName}\\b`).test(normalized) ||
@@ -524,14 +743,20 @@ export default class Clang {
524
743
  const initSource = segments[0].trim();
525
744
  const updateSource = segments[2].trim();
526
745
  const initHooks = [];
746
+ const conditionHooks = [];
527
747
  const updateHooks = [];
528
748
  const initLooksLikeDeclaration = /^(?:const\s+)?(?:(?:unsigned|signed)\s+)?(?:(?:short|long long|long)\s+)?(?:int|float|double|bool|char)\b/.test(initSource);
529
749
  for (const [name, variable] of currentFunctionVariables) {
530
750
  const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
531
751
  const mutationPattern = new RegExp(`(?:^|[^\\w])(?:\\+\\+|--)\\s*${escapedName}\\b|\\b${escapedName}\\s*(?:[+\\-*/%]?=|\\+\\+|--)`);
532
- if (!initLooksLikeDeclaration && mutationPattern.test(initSource)) {
752
+ if (!initLooksLikeDeclaration &&
753
+ mutationPattern.test(initSource)) {
533
754
  initHooks.push(`${variable.kind === 'bool' ? '__wasm_idle_debug_value_bool' : '__wasm_idle_debug_value_num'}(${currentFunctionId}, ${variable.slot}, ${name})`);
534
755
  }
756
+ if (initLooksLikeDeclaration &&
757
+ mutationPattern.test(initSource)) {
758
+ conditionHooks.push(`${variable.kind === 'bool' ? '__wasm_idle_debug_value_bool' : '__wasm_idle_debug_value_num'}(${currentFunctionId}, ${variable.slot}, ${name})`);
759
+ }
535
760
  if (mutationPattern.test(updateSource)) {
536
761
  updateHooks.push(`${variable.kind === 'bool' ? '__wasm_idle_debug_value_bool' : '__wasm_idle_debug_value_num'}(${currentFunctionId}, ${variable.slot}, ${name})`);
537
762
  }
@@ -544,7 +769,7 @@ export default class Clang {
544
769
  : segments[2];
545
770
  rewrittenLine =
546
771
  line.slice(0, openIndex + 1) +
547
- `${instrumentedInit}; (__wasm_idle_debug_line(${currentFunctionId}, ${index + 1}), (${segments[1].trim()})); ${instrumentedUpdate}` +
772
+ `${instrumentedInit}; (${conditionHooks.length ? `${conditionHooks.join(', ')}, ` : ''}__wasm_idle_debug_line(${currentFunctionId}, ${index + 1}), (${segments[1].trim()})); ${instrumentedUpdate}` +
548
773
  line.slice(closeIndex);
549
774
  }
550
775
  }
@@ -585,6 +810,12 @@ export default class Clang {
585
810
  currentFunctionVariables = new Map();
586
811
  currentFunctionContainers = new Map();
587
812
  instrumented.push(`${indent} __wasm_idle_debug_enter(${currentFunctionId}, ${index + 1});`);
813
+ if (functionName === 'main') {
814
+ instrumented.push(`${indent} std::cout.setf(std::ios::unitbuf);`);
815
+ instrumented.push(`${indent} std::cerr.setf(std::ios::unitbuf);`);
816
+ instrumented.push(`${indent} setvbuf(stdout, nullptr, _IONBF, 0);`);
817
+ instrumented.push(`${indent} setvbuf(stderr, nullptr, _IONBF, 0);`);
818
+ }
588
819
  const parameterSource = startsInlineFunctionBody
589
820
  ? normalized.slice(normalized.indexOf('(') + 1, normalized.lastIndexOf(')'))
590
821
  : pendingFunctionHeader?.parameters || '';
@@ -648,9 +879,11 @@ export default class Clang {
648
879
  if (!nameMatch)
649
880
  continue;
650
881
  const name = nameMatch[1];
651
- const kind = /\bbool\b/.test(cleaned) ? 'bool' : /\b(?:int|float|double|char|short|long)\b/.test(cleaned)
652
- ? 'number'
653
- : '';
882
+ const kind = /\bbool\b/.test(cleaned)
883
+ ? 'bool'
884
+ : /\b(?:int|float|double|char|short|long)\b/.test(cleaned)
885
+ ? 'number'
886
+ : '';
654
887
  if (!kind)
655
888
  continue;
656
889
  const slot = nextVariableSlot++;
@@ -721,11 +954,11 @@ export default class Clang {
721
954
  '-O' + opt,
722
955
  '-o',
723
956
  obj,
724
- clangLanguageStandardArg,
957
+ standardArg,
725
958
  '-x',
726
- 'c++',
959
+ languageArg,
727
960
  input,
728
- ...(options.args || [])
961
+ ...compileArgs
729
962
  ];
730
963
  this.trace(`compile ${input} -> ${obj}`);
731
964
  return await this.run(clang, true, 'clang', ...compilerArgs);
@@ -750,7 +983,10 @@ export default class Clang {
750
983
  app.debugSession = {
751
984
  buffer: this.debugBuffer,
752
985
  interruptBuffer: this.debugInterruptBuffer,
986
+ watchBuffer: this.debugWatchBuffer,
987
+ watchResultBuffer: this.debugWatchResultBuffer,
753
988
  breakpoints: new Set(this.debugBreakpoints),
989
+ breakpointVersion: 0,
754
990
  pauseOnEntry: this.debugPauseOnEntry,
755
991
  stepArmed: this.debugPauseOnEntry,
756
992
  nextLineArmed: false,
@@ -781,34 +1017,57 @@ export default class Clang {
781
1017
  return stillRunning ? app : null;
782
1018
  }
783
1019
  async compileLink(code, options = {}) {
784
- const { args = [], debug = false, breakpoints = [], pauseOnEntry = false, debugBuffer, interruptBuffer } = options;
785
- const input = `test.cc`, obj = `test.o`, wasm = `test.wasm`;
1020
+ const { language = 'CPP', args = [], compileArgs = args, debug = false, breakpoints = [], pauseOnEntry = false, cppVersion, cVersion, debugBuffer, interruptBuffer, watchBuffer, watchResultBuffer } = options;
1021
+ const input = language === 'C' ? `test.c` : `test.cc`, obj = `test.o`, wasm = `test.wasm`;
786
1022
  this.beginTrace(debug);
787
1023
  this.debugBreakpoints = new Set(debug ? breakpoints : []);
788
1024
  this.debugPauseOnEntry = debug && pauseOnEntry;
789
1025
  this.debugBuffer = debugBuffer;
790
1026
  this.debugInterruptBuffer = interruptBuffer;
791
- const buildKey = JSON.stringify({ code, args, debug });
1027
+ this.debugWatchBuffer = watchBuffer;
1028
+ this.debugWatchResultBuffer = watchResultBuffer;
1029
+ const buildKey = JSON.stringify({
1030
+ code,
1031
+ language,
1032
+ compileArgs,
1033
+ cppVersion,
1034
+ cVersion,
1035
+ debug
1036
+ });
792
1037
  if (this.lastBuildKey === buildKey) {
793
1038
  this.trace(`reuse ${wasm}`);
794
1039
  return this.wasm;
795
1040
  }
796
- await this.compile({ input, code, obj, args, debug });
1041
+ await this.compile({
1042
+ input,
1043
+ code,
1044
+ obj,
1045
+ language,
1046
+ compileArgs,
1047
+ cppVersion,
1048
+ cVersion,
1049
+ debug
1050
+ });
797
1051
  await this.link(obj, wasm, debug);
798
1052
  this.lastBuildKey = buildKey;
799
1053
  const wasmBytes = Uint8Array.from(this.memfs.getFileContents(wasm));
800
1054
  return (this.wasm = await this.hostLogAsync(`Compiling ${wasm}`, WebAssembly.compile(wasmBytes)));
801
1055
  }
802
1056
  async compileLinkRun(code, options = {}) {
803
- const { args = [], debug = false, breakpoints = [], pauseOnEntry = false, debugBuffer, interruptBuffer } = options;
1057
+ const { language = 'CPP', args = [], compileArgs = args, programArgs = [], debug = false, breakpoints = [], pauseOnEntry = false, cppVersion, cVersion, debugBuffer, interruptBuffer, watchBuffer, watchResultBuffer } = options;
804
1058
  this.debug = debug;
805
1059
  return await this.run(await this.compileLink(code, {
806
- args,
1060
+ language,
1061
+ compileArgs,
807
1062
  debug,
808
1063
  breakpoints,
809
1064
  pauseOnEntry,
1065
+ cppVersion,
1066
+ cVersion,
810
1067
  debugBuffer,
811
- interruptBuffer
812
- }), true, `test.wasm`);
1068
+ interruptBuffer,
1069
+ watchBuffer,
1070
+ watchResultBuffer
1071
+ }), true, `test.wasm`, ...programArgs);
813
1072
  }
814
1073
  }
@@ -0,0 +1,43 @@
1
+ import type { DebugLanguageAdapter } from './language';
2
+ import type { DebugCommand, DebugFrame, DebugSessionEvent, DebugVariable } from '../playground/options';
3
+ import type { TerminalControl } from '../terminal';
4
+ export type DebugWatchValue = {
5
+ expression: string;
6
+ value: string;
7
+ };
8
+ export type DebugSessionControllerOptions = {
9
+ terminal?: TerminalControl;
10
+ adapter?: DebugLanguageAdapter | null;
11
+ breakpoints?: number[];
12
+ cursorLine?: number | null;
13
+ syncBreakpointsWhile?: boolean | (() => boolean);
14
+ };
15
+ export declare function createDebugSessionController(options?: DebugSessionControllerOptions): {
16
+ readonly active: boolean;
17
+ readonly paused: boolean;
18
+ readonly pausedLine: number | null;
19
+ readonly locals: DebugVariable[];
20
+ readonly callStack: DebugFrame[];
21
+ readonly runToCursorLine: number | null;
22
+ readonly breakpoints: number[];
23
+ readonly effectiveBreakpoints: number[];
24
+ readonly cursorLine: number | null;
25
+ readonly canRunToCursor: boolean;
26
+ watchInput: string;
27
+ readonly watchExpressions: string[];
28
+ readonly watchValues: DebugWatchValue[];
29
+ begin: () => void;
30
+ reset: () => void;
31
+ handleEvent: (event: DebugSessionEvent) => void;
32
+ setTerminal: (terminal?: TerminalControl) => void;
33
+ setAdapter: (adapter: DebugLanguageAdapter | null) => void;
34
+ setBreakpoints: (lines: number[]) => void;
35
+ setCursorLine: (line: number | null) => void;
36
+ sendCommand: (command: DebugCommand) => Promise<boolean>;
37
+ runToCursor: (targetLine?: number | null) => Promise<boolean>;
38
+ stop: () => Promise<boolean>;
39
+ addWatchExpression: (expression?: string) => boolean;
40
+ removeWatchExpression: (expression: string) => void;
41
+ clearWatches: () => void;
42
+ };
43
+ export type DebugSessionController = ReturnType<typeof createDebugSessionController>;