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.
- package/README.md +111 -2
- package/dist/clang/app.d.ts +4 -0
- package/dist/clang/app.js +330 -15
- package/dist/clang/index.d.ts +10 -0
- package/dist/clang/index.js +284 -25
- package/dist/debug/controller.svelte.d.ts +43 -0
- package/dist/debug/controller.svelte.js +268 -0
- package/dist/debug/editor/index.d.ts +2 -1
- package/dist/debug/editor/index.js +1 -1
- package/dist/debug/editor/monaco.d.ts +8 -0
- package/dist/debug/editor/monaco.js +23 -0
- package/dist/debug/expression.d.ts +24 -0
- package/dist/debug/expression.js +307 -138
- package/dist/debug/index.d.ts +4 -1
- package/dist/debug/index.js +2 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.js +3 -3
- package/dist/playground/assetBridge.d.ts +20 -0
- package/dist/playground/assetBridge.js +192 -0
- package/dist/playground/assets.d.ts +37 -0
- package/dist/playground/assets.js +105 -0
- package/dist/playground/clang.d.ts +11 -1
- package/dist/playground/clang.js +58 -4
- package/dist/playground/index.d.ts +5 -5
- package/dist/playground/index.js +48 -6
- package/dist/playground/java.d.ts +7 -2
- package/dist/playground/java.js +31 -5
- package/dist/playground/javaStdin.js +235 -2
- package/dist/playground/options.d.ts +18 -0
- package/dist/playground/options.js +15 -1
- package/dist/playground/python.d.ts +7 -1
- package/dist/playground/python.js +50 -5
- package/dist/playground/rust.d.ts +32 -0
- package/dist/playground/rust.js +175 -0
- package/dist/playground/sandbox.d.ts +19 -4
- package/dist/playground/wasmRustVersion.d.ts +1 -0
- package/dist/playground/wasmRustVersion.js +1 -0
- package/dist/playground/worker/assets.d.ts +12 -0
- package/dist/playground/worker/assets.js +257 -0
- package/dist/playground/worker/clang.js +22 -6
- package/dist/playground/worker/java.js +15 -35
- package/dist/playground/worker/python.js +13 -33
- package/dist/playground/worker/rust.d.ts +1 -0
- package/dist/playground/worker/rust.js +159 -0
- package/dist/terminal/Terminal.svelte +121 -18
- package/dist/terminal/Terminal.svelte.d.ts +4 -0
- package/dist/terminal/theme.js +2 -2
- package/dist/terminal/types.d.ts +4 -0
- package/package.json +19 -13
package/dist/clang/index.js
CHANGED
|
@@ -20,7 +20,94 @@ const clangCommonArgs = [
|
|
|
20
20
|
'80',
|
|
21
21
|
'-fcolor-diagnostics'
|
|
22
22
|
];
|
|
23
|
-
const
|
|
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' :
|
|
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) +
|
|
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 === ',' &&
|
|
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:
|
|
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:
|
|
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) ||
|
|
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 &&
|
|
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)
|
|
652
|
-
? '
|
|
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
|
-
|
|
957
|
+
standardArg,
|
|
725
958
|
'-x',
|
|
726
|
-
|
|
959
|
+
languageArg,
|
|
727
960
|
input,
|
|
728
|
-
...
|
|
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
|
-
|
|
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({
|
|
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
|
-
|
|
1060
|
+
language,
|
|
1061
|
+
compileArgs,
|
|
807
1062
|
debug,
|
|
808
1063
|
breakpoints,
|
|
809
1064
|
pauseOnEntry,
|
|
1065
|
+
cppVersion,
|
|
1066
|
+
cVersion,
|
|
810
1067
|
debugBuffer,
|
|
811
|
-
interruptBuffer
|
|
812
|
-
|
|
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>;
|