wasm-idle 0.3.2 → 0.4.1
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 +22 -2
- package/dist/clang/app.d.ts +2 -1
- package/dist/clang/app.js +166 -137
- package/dist/clang/index.d.ts +6 -0
- package/dist/clang/index.js +137 -21
- package/dist/debug/expression.js +135 -19
- package/dist/debug/index.d.ts +1 -1
- package/dist/debug/index.js +1 -1
- package/dist/debug/language/index.d.ts +1 -0
- package/dist/debug/language/index.js +1 -0
- package/dist/debug/language/python.d.ts +2 -0
- package/dist/debug/language/python.js +14 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -1
- package/dist/playground/assetBridge.d.ts +20 -0
- package/dist/playground/assetBridge.js +192 -0
- package/dist/playground/assets.d.ts +32 -0
- package/dist/playground/assets.js +97 -0
- package/dist/playground/clang.d.ts +11 -3
- package/dist/playground/clang.js +57 -20
- package/dist/playground/index.d.ts +2 -1
- package/dist/playground/index.js +10 -2
- package/dist/playground/java.d.ts +33 -0
- package/dist/playground/java.js +161 -0
- package/dist/playground/javaStdin.d.ts +8 -0
- package/dist/playground/javaStdin.js +323 -0
- package/dist/playground/options.d.ts +19 -0
- package/dist/playground/options.js +15 -1
- package/dist/playground/python.d.ts +21 -6
- package/dist/playground/python.js +135 -25
- package/dist/playground/sandbox.d.ts +5 -2
- package/dist/playground/stdinBuffer.d.ts +7 -0
- package/dist/playground/stdinBuffer.js +100 -0
- package/dist/playground/teavmConfig.d.ts +3 -0
- package/dist/playground/teavmConfig.js +14 -0
- package/dist/playground/worker/assets.d.ts +12 -0
- package/dist/playground/worker/assets.js +257 -0
- package/dist/playground/worker/clang.js +13 -23
- package/dist/playground/worker/java.d.ts +1 -0
- package/dist/playground/worker/java.js +228 -0
- package/dist/playground/worker/python.js +264 -58
- package/dist/terminal/Terminal.svelte +98 -18
- package/dist/terminal/Terminal.svelte.d.ts +4 -1
- package/dist/terminal/theme.js +2 -2
- package/dist/terminal/types.d.ts +4 -2
- package/package.json +11 -11
package/README.md
CHANGED
|
@@ -2,8 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
Executes C++, Python
|
|
5
|
+
Executes C++, Python, and Java code with working stdio.
|
|
6
6
|
|
|
7
7
|
Refer to src/lib/clang.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Java uses TeaVM's browser compiler/runtime. TeaVM compiler/runtime/classlib assets are bundled under `static/teavm/` by default, and the asset base URL can be overridden with `PUBLIC_TEAVM_BASE_URL`.
|
|
10
|
+
|
|
11
|
+
`Terminal` and `playground(...).load(...)` support either the legacy shared `path`/`rootUrl` or per-runtime asset config:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import type { PlaygroundRuntimeAssets } from 'wasm-idle';
|
|
15
|
+
|
|
16
|
+
const runtimeAssets: PlaygroundRuntimeAssets = {
|
|
17
|
+
rootUrl: 'https://cdn.example.com/repl',
|
|
18
|
+
python: {
|
|
19
|
+
loader: async ({ asset }) => ({ url: `https://cdn.example.com/repl/pyodide/${asset}` })
|
|
20
|
+
},
|
|
21
|
+
java: {
|
|
22
|
+
baseUrl: 'https://cdn.example.com/repl/teavm/'
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Python custom loaders receive file names under the Pyodide asset root and can serve both core assets and package files. TeaVM custom loaders receive file names under the TeaVM asset root. Compressed TeaVM runtime assets are no longer unpacked inside the library; provide the final file URL or handle decompression in your own loader.
|
|
28
|
+
|
|
29
|
+
Powered by [wasm-clang](https://github.com/binji/wasm-clang), Pyodide, and TeaVM.
|
package/dist/clang/app.d.ts
CHANGED
|
@@ -52,7 +52,8 @@ export default class App {
|
|
|
52
52
|
constructor(module: WebAssembly.Module, memfs: MemFS, name: string, ...args: string[]);
|
|
53
53
|
run(): Promise<boolean | undefined>;
|
|
54
54
|
proc_exit(code: number): void;
|
|
55
|
-
|
|
55
|
+
private pauseDebugSession;
|
|
56
|
+
__wasm_idle_debug_enter(functionId: number, line: number): number;
|
|
56
57
|
__wasm_idle_debug_leave(functionId: number): number;
|
|
57
58
|
__wasm_idle_debug_value_num(functionId: number, slot: number, value: number): number;
|
|
58
59
|
__wasm_idle_debug_value_bool(functionId: number, slot: number, value: number): number;
|
package/dist/clang/app.js
CHANGED
|
@@ -68,139 +68,15 @@ export default class App {
|
|
|
68
68
|
proc_exit(code) {
|
|
69
69
|
throw new ProcExit(code);
|
|
70
70
|
}
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
if (!
|
|
74
|
-
return ESUCCESS;
|
|
75
|
-
session.callDepth += 1;
|
|
76
|
-
session.currentFunctionId = functionId;
|
|
77
|
-
session.frames.push({
|
|
78
|
-
functionId,
|
|
79
|
-
functionName: session.functionMetadata[functionId] || `fn_${functionId}`,
|
|
80
|
-
line: 0,
|
|
81
|
-
values: new Map()
|
|
82
|
-
});
|
|
83
|
-
this.trace(`enter(function=${functionId}, depth=${session.callDepth})`);
|
|
84
|
-
return ESUCCESS;
|
|
85
|
-
}
|
|
86
|
-
__wasm_idle_debug_leave(functionId) {
|
|
87
|
-
const session = this.debugSession;
|
|
88
|
-
if (!session?.buffer)
|
|
89
|
-
return ESUCCESS;
|
|
90
|
-
this.trace(`leave(function=${functionId}, depth=${session.callDepth})`);
|
|
91
|
-
session.callDepth = Math.max(0, session.callDepth - 1);
|
|
92
|
-
if (session.currentFunctionId === functionId)
|
|
93
|
-
session.currentFunctionId = 0;
|
|
94
|
-
for (let index = session.frames.length - 1; index >= 0; index -= 1) {
|
|
95
|
-
if (session.frames[index]?.functionId === functionId) {
|
|
96
|
-
session.frames.splice(index, 1);
|
|
97
|
-
break;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return ESUCCESS;
|
|
101
|
-
}
|
|
102
|
-
__wasm_idle_debug_value_num(functionId, slot, value) {
|
|
103
|
-
const session = this.debugSession;
|
|
104
|
-
if (!session?.buffer)
|
|
105
|
-
return ESUCCESS;
|
|
106
|
-
if (functionId === 0) {
|
|
107
|
-
session.globalValues.set(slot, Number.isInteger(value) ? String(value) : `${value}`);
|
|
108
|
-
return ESUCCESS;
|
|
109
|
-
}
|
|
110
|
-
for (let index = session.frames.length - 1; index >= 0; index -= 1) {
|
|
111
|
-
const frame = session.frames[index];
|
|
112
|
-
if (frame?.functionId !== functionId)
|
|
113
|
-
continue;
|
|
114
|
-
frame.values.set(slot, Number.isInteger(value) ? String(value) : `${value}`);
|
|
115
|
-
break;
|
|
116
|
-
}
|
|
117
|
-
return ESUCCESS;
|
|
118
|
-
}
|
|
119
|
-
__wasm_idle_debug_value_bool(functionId, slot, value) {
|
|
120
|
-
const session = this.debugSession;
|
|
121
|
-
if (!session?.buffer)
|
|
122
|
-
return ESUCCESS;
|
|
123
|
-
if (functionId === 0) {
|
|
124
|
-
session.globalValues.set(slot, value ? 'true' : 'false');
|
|
125
|
-
return ESUCCESS;
|
|
126
|
-
}
|
|
127
|
-
for (let index = session.frames.length - 1; index >= 0; index -= 1) {
|
|
128
|
-
const frame = session.frames[index];
|
|
129
|
-
if (frame?.functionId !== functionId)
|
|
130
|
-
continue;
|
|
131
|
-
frame.values.set(slot, value ? 'true' : 'false');
|
|
132
|
-
break;
|
|
133
|
-
}
|
|
134
|
-
return ESUCCESS;
|
|
135
|
-
}
|
|
136
|
-
__wasm_idle_debug_value_addr(functionId, slot, value) {
|
|
137
|
-
const session = this.debugSession;
|
|
138
|
-
if (!session?.buffer)
|
|
139
|
-
return ESUCCESS;
|
|
140
|
-
if (functionId === 0) {
|
|
141
|
-
session.globalValues.set(slot, String(value >>> 0));
|
|
142
|
-
return ESUCCESS;
|
|
143
|
-
}
|
|
144
|
-
for (let index = session.frames.length - 1; index >= 0; index -= 1) {
|
|
145
|
-
const frame = session.frames[index];
|
|
146
|
-
if (frame?.functionId !== functionId)
|
|
147
|
-
continue;
|
|
148
|
-
frame.values.set(slot, String(value >>> 0));
|
|
149
|
-
break;
|
|
150
|
-
}
|
|
151
|
-
return ESUCCESS;
|
|
152
|
-
}
|
|
153
|
-
__wasm_idle_debug_value_text(functionId, slot, ptr, len) {
|
|
154
|
-
const session = this.debugSession;
|
|
155
|
-
if (!session?.buffer)
|
|
156
|
-
return ESUCCESS;
|
|
157
|
-
this.mem?.check?.();
|
|
158
|
-
const text = this.mem?.readStr ? this.mem.readStr(ptr, len) : '?';
|
|
159
|
-
if (functionId === 0) {
|
|
160
|
-
session.globalValues.set(slot, text);
|
|
161
|
-
return ESUCCESS;
|
|
162
|
-
}
|
|
163
|
-
for (let index = session.frames.length - 1; index >= 0; index -= 1) {
|
|
164
|
-
const frame = session.frames[index];
|
|
165
|
-
if (frame?.functionId !== functionId)
|
|
166
|
-
continue;
|
|
167
|
-
frame.values.set(slot, text);
|
|
168
|
-
break;
|
|
169
|
-
}
|
|
170
|
-
return ESUCCESS;
|
|
171
|
-
}
|
|
172
|
-
__wasm_idle_debug_line(functionId, line) {
|
|
173
|
-
const session = this.debugSession;
|
|
174
|
-
if (!session?.buffer)
|
|
175
|
-
return ESUCCESS;
|
|
176
|
-
if (session.resumeSkipActive) {
|
|
177
|
-
if (functionId === session.resumeSkipFunctionId && line === session.resumeSkipLine) {
|
|
178
|
-
return ESUCCESS;
|
|
179
|
-
}
|
|
180
|
-
session.resumeSkipActive = false;
|
|
181
|
-
session.resumeSkipFunctionId = 0;
|
|
182
|
-
session.resumeSkipLine = 0;
|
|
183
|
-
}
|
|
184
|
-
let reason = '';
|
|
185
|
-
if (session.pauseOnEntry)
|
|
186
|
-
reason = 'entry';
|
|
187
|
-
else if (session.breakpoints.has(line))
|
|
188
|
-
reason = 'breakpoint';
|
|
189
|
-
else if (session.stepArmed)
|
|
190
|
-
reason = 'step';
|
|
191
|
-
else if (session.nextLineArmed &&
|
|
192
|
-
functionId === session.nextLineFunctionId &&
|
|
193
|
-
line !== session.nextLineLine) {
|
|
194
|
-
reason = 'nextLine';
|
|
195
|
-
}
|
|
196
|
-
else if (session.stepOutArmed && session.callDepth <= session.stepOutDepth) {
|
|
197
|
-
reason = 'stepOut';
|
|
198
|
-
}
|
|
199
|
-
if (!reason)
|
|
71
|
+
pauseDebugSession(session, functionId, line, reason) {
|
|
72
|
+
const buffer = session.buffer;
|
|
73
|
+
if (!buffer)
|
|
200
74
|
return ESUCCESS;
|
|
201
75
|
session.currentFunctionId = functionId;
|
|
202
76
|
session.currentLine = line;
|
|
203
|
-
const frame = [...session.frames]
|
|
77
|
+
const frame = [...session.frames]
|
|
78
|
+
.reverse()
|
|
79
|
+
.find((candidate) => candidate.functionId === functionId);
|
|
204
80
|
if (frame)
|
|
205
81
|
frame.line = line;
|
|
206
82
|
session.pauseOnEntry = false;
|
|
@@ -219,7 +95,10 @@ export default class App {
|
|
|
219
95
|
: variable.length
|
|
220
96
|
? [variable.length]
|
|
221
97
|
: [];
|
|
222
|
-
if (!Number.isFinite(address) ||
|
|
98
|
+
if (!Number.isFinite(address) ||
|
|
99
|
+
address <= 0 ||
|
|
100
|
+
!dimensions.length ||
|
|
101
|
+
!variable.elementKind) {
|
|
223
102
|
return [{ name: variable.name, value: '?' }];
|
|
224
103
|
}
|
|
225
104
|
const elementStride = variable.elementKind === 'double'
|
|
@@ -241,7 +120,9 @@ export default class App {
|
|
|
241
120
|
}
|
|
242
121
|
if (variable.elementKind === 'char') {
|
|
243
122
|
const charCode = this.mem.read8(offset);
|
|
244
|
-
values.push(charCode >= 0x20 && charCode <= 0x7e
|
|
123
|
+
values.push(charCode >= 0x20 && charCode <= 0x7e
|
|
124
|
+
? `'${String.fromCharCode(charCode)}'`
|
|
125
|
+
: `${charCode}`);
|
|
245
126
|
continue;
|
|
246
127
|
}
|
|
247
128
|
if (variable.elementKind === 'float') {
|
|
@@ -273,7 +154,9 @@ export default class App {
|
|
|
273
154
|
}
|
|
274
155
|
if (variable.elementKind === 'char') {
|
|
275
156
|
const charCode = this.mem.read8(offset);
|
|
276
|
-
values.push(charCode >= 0x20 && charCode <= 0x7e
|
|
157
|
+
values.push(charCode >= 0x20 && charCode <= 0x7e
|
|
158
|
+
? `'${String.fromCharCode(charCode)}'`
|
|
159
|
+
: `${charCode}`);
|
|
277
160
|
continue;
|
|
278
161
|
}
|
|
279
162
|
if (variable.elementKind === 'float') {
|
|
@@ -312,16 +195,19 @@ export default class App {
|
|
|
312
195
|
locals: [...locals, ...globals],
|
|
313
196
|
callStack: [...session.frames]
|
|
314
197
|
.reverse()
|
|
315
|
-
.map((stackFrame) => ({
|
|
198
|
+
.map((stackFrame) => ({
|
|
199
|
+
functionName: stackFrame.functionName,
|
|
200
|
+
line: stackFrame.line
|
|
201
|
+
}))
|
|
316
202
|
});
|
|
317
|
-
const sequence = Atomics.load(
|
|
203
|
+
const sequence = Atomics.load(buffer, 0);
|
|
318
204
|
while (true) {
|
|
319
205
|
if (session.interruptBuffer?.[0] === 2)
|
|
320
206
|
throw new AbortError();
|
|
321
|
-
Atomics.wait(
|
|
207
|
+
Atomics.wait(buffer, 0, sequence, 100);
|
|
322
208
|
if (session.interruptBuffer?.[0] === 2)
|
|
323
209
|
throw new AbortError();
|
|
324
|
-
const command = Atomics.exchange(
|
|
210
|
+
const command = Atomics.exchange(buffer, 1, 0);
|
|
325
211
|
if (command === 1) {
|
|
326
212
|
session.resumeSkipActive = true;
|
|
327
213
|
session.resumeSkipFunctionId = session.currentFunctionId;
|
|
@@ -354,6 +240,149 @@ export default class App {
|
|
|
354
240
|
}
|
|
355
241
|
}
|
|
356
242
|
}
|
|
243
|
+
__wasm_idle_debug_enter(functionId, line) {
|
|
244
|
+
const session = this.debugSession;
|
|
245
|
+
if (!session?.buffer)
|
|
246
|
+
return ESUCCESS;
|
|
247
|
+
session.callDepth += 1;
|
|
248
|
+
session.currentFunctionId = functionId;
|
|
249
|
+
session.currentLine = line;
|
|
250
|
+
session.frames.push({
|
|
251
|
+
functionId,
|
|
252
|
+
functionName: session.functionMetadata[functionId] || `fn_${functionId}`,
|
|
253
|
+
line,
|
|
254
|
+
values: new Map()
|
|
255
|
+
});
|
|
256
|
+
this.trace(`enter(function=${functionId}, line=${line}, depth=${session.callDepth})`);
|
|
257
|
+
if (session.pauseOnEntry) {
|
|
258
|
+
return this.pauseDebugSession(session, functionId, line, 'entry');
|
|
259
|
+
}
|
|
260
|
+
if (session.stepArmed) {
|
|
261
|
+
return this.pauseDebugSession(session, functionId, line, 'step');
|
|
262
|
+
}
|
|
263
|
+
return ESUCCESS;
|
|
264
|
+
}
|
|
265
|
+
__wasm_idle_debug_leave(functionId) {
|
|
266
|
+
const session = this.debugSession;
|
|
267
|
+
if (!session?.buffer)
|
|
268
|
+
return ESUCCESS;
|
|
269
|
+
this.trace(`leave(function=${functionId}, depth=${session.callDepth})`);
|
|
270
|
+
if (session.nextLineArmed && functionId === session.nextLineFunctionId) {
|
|
271
|
+
session.nextLineArmed = false;
|
|
272
|
+
session.stepArmed = true;
|
|
273
|
+
}
|
|
274
|
+
session.callDepth = Math.max(0, session.callDepth - 1);
|
|
275
|
+
if (session.currentFunctionId === functionId)
|
|
276
|
+
session.currentFunctionId = 0;
|
|
277
|
+
for (let index = session.frames.length - 1; index >= 0; index -= 1) {
|
|
278
|
+
if (session.frames[index]?.functionId === functionId) {
|
|
279
|
+
session.frames.splice(index, 1);
|
|
280
|
+
break;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return ESUCCESS;
|
|
284
|
+
}
|
|
285
|
+
__wasm_idle_debug_value_num(functionId, slot, value) {
|
|
286
|
+
const session = this.debugSession;
|
|
287
|
+
if (!session?.buffer)
|
|
288
|
+
return ESUCCESS;
|
|
289
|
+
if (functionId === 0) {
|
|
290
|
+
session.globalValues.set(slot, Number.isInteger(value) ? String(value) : `${value}`);
|
|
291
|
+
return ESUCCESS;
|
|
292
|
+
}
|
|
293
|
+
for (let index = session.frames.length - 1; index >= 0; index -= 1) {
|
|
294
|
+
const frame = session.frames[index];
|
|
295
|
+
if (frame?.functionId !== functionId)
|
|
296
|
+
continue;
|
|
297
|
+
frame.values.set(slot, Number.isInteger(value) ? String(value) : `${value}`);
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
return ESUCCESS;
|
|
301
|
+
}
|
|
302
|
+
__wasm_idle_debug_value_bool(functionId, slot, value) {
|
|
303
|
+
const session = this.debugSession;
|
|
304
|
+
if (!session?.buffer)
|
|
305
|
+
return ESUCCESS;
|
|
306
|
+
if (functionId === 0) {
|
|
307
|
+
session.globalValues.set(slot, value ? 'true' : 'false');
|
|
308
|
+
return ESUCCESS;
|
|
309
|
+
}
|
|
310
|
+
for (let index = session.frames.length - 1; index >= 0; index -= 1) {
|
|
311
|
+
const frame = session.frames[index];
|
|
312
|
+
if (frame?.functionId !== functionId)
|
|
313
|
+
continue;
|
|
314
|
+
frame.values.set(slot, value ? 'true' : 'false');
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
return ESUCCESS;
|
|
318
|
+
}
|
|
319
|
+
__wasm_idle_debug_value_addr(functionId, slot, value) {
|
|
320
|
+
const session = this.debugSession;
|
|
321
|
+
if (!session?.buffer)
|
|
322
|
+
return ESUCCESS;
|
|
323
|
+
if (functionId === 0) {
|
|
324
|
+
session.globalValues.set(slot, String(value >>> 0));
|
|
325
|
+
return ESUCCESS;
|
|
326
|
+
}
|
|
327
|
+
for (let index = session.frames.length - 1; index >= 0; index -= 1) {
|
|
328
|
+
const frame = session.frames[index];
|
|
329
|
+
if (frame?.functionId !== functionId)
|
|
330
|
+
continue;
|
|
331
|
+
frame.values.set(slot, String(value >>> 0));
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
return ESUCCESS;
|
|
335
|
+
}
|
|
336
|
+
__wasm_idle_debug_value_text(functionId, slot, ptr, len) {
|
|
337
|
+
const session = this.debugSession;
|
|
338
|
+
if (!session?.buffer)
|
|
339
|
+
return ESUCCESS;
|
|
340
|
+
this.mem?.check?.();
|
|
341
|
+
const text = this.mem?.readStr ? this.mem.readStr(ptr, len) : '?';
|
|
342
|
+
if (functionId === 0) {
|
|
343
|
+
session.globalValues.set(slot, text);
|
|
344
|
+
return ESUCCESS;
|
|
345
|
+
}
|
|
346
|
+
for (let index = session.frames.length - 1; index >= 0; index -= 1) {
|
|
347
|
+
const frame = session.frames[index];
|
|
348
|
+
if (frame?.functionId !== functionId)
|
|
349
|
+
continue;
|
|
350
|
+
frame.values.set(slot, text);
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
return ESUCCESS;
|
|
354
|
+
}
|
|
355
|
+
__wasm_idle_debug_line(functionId, line) {
|
|
356
|
+
const session = this.debugSession;
|
|
357
|
+
if (!session?.buffer)
|
|
358
|
+
return ESUCCESS;
|
|
359
|
+
if (session.resumeSkipActive) {
|
|
360
|
+
if (functionId === session.resumeSkipFunctionId && line === session.resumeSkipLine) {
|
|
361
|
+
return ESUCCESS;
|
|
362
|
+
}
|
|
363
|
+
session.resumeSkipActive = false;
|
|
364
|
+
session.resumeSkipFunctionId = 0;
|
|
365
|
+
session.resumeSkipLine = 0;
|
|
366
|
+
}
|
|
367
|
+
let reason = '';
|
|
368
|
+
if (session.pauseOnEntry)
|
|
369
|
+
reason = 'entry';
|
|
370
|
+
else if (session.breakpoints.has(line))
|
|
371
|
+
reason = 'breakpoint';
|
|
372
|
+
else if (session.stepArmed)
|
|
373
|
+
reason = 'step';
|
|
374
|
+
else if (session.nextLineArmed &&
|
|
375
|
+
functionId === session.nextLineFunctionId &&
|
|
376
|
+
line !== session.nextLineLine) {
|
|
377
|
+
reason = 'nextLine';
|
|
378
|
+
}
|
|
379
|
+
else if (session.stepOutArmed && session.callDepth <= session.stepOutDepth) {
|
|
380
|
+
reason = 'stepOut';
|
|
381
|
+
}
|
|
382
|
+
if (!reason)
|
|
383
|
+
return ESUCCESS;
|
|
384
|
+
return this.pauseDebugSession(session, functionId, line, reason);
|
|
385
|
+
}
|
|
357
386
|
environ_sizes_get(environ_count_out, environ_buf_size_out) {
|
|
358
387
|
this.mem.check();
|
|
359
388
|
let size = 0;
|
package/dist/clang/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { DebugVariable, DebugVariableMetadata } from '../playground/options
|
|
|
2
2
|
import App from './app';
|
|
3
3
|
import { MemFS } from './memory';
|
|
4
4
|
import { type Writable } from 'svelte/store';
|
|
5
|
+
type ClangSourceLanguage = 'C' | 'CPP';
|
|
5
6
|
interface APIOption {
|
|
6
7
|
stdin: () => string;
|
|
7
8
|
stdout: (str: string) => void;
|
|
@@ -17,7 +18,12 @@ interface APIOption {
|
|
|
17
18
|
path: string;
|
|
18
19
|
}
|
|
19
20
|
interface DebugRunOptions {
|
|
21
|
+
language?: ClangSourceLanguage;
|
|
20
22
|
args?: string[];
|
|
23
|
+
compileArgs?: string[];
|
|
24
|
+
programArgs?: string[];
|
|
25
|
+
cppVersion?: string;
|
|
26
|
+
cVersion?: string;
|
|
21
27
|
debug?: boolean;
|
|
22
28
|
breakpoints?: number[];
|
|
23
29
|
pauseOnEntry?: boolean;
|
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 = '';
|
|
@@ -127,8 +214,11 @@ export default class Clang {
|
|
|
127
214
|
const input = options.input;
|
|
128
215
|
let source = options.code;
|
|
129
216
|
const obj = options.obj;
|
|
217
|
+
const language = options.language === 'C' ? 'C' : 'CPP';
|
|
218
|
+
const compileArgs = options.compileArgs ?? options.args ?? [];
|
|
219
|
+
const { languageArg, standardArg } = resolveClangLanguageArgs(language, options);
|
|
130
220
|
const debug = !!options.debug;
|
|
131
|
-
const opt = debug ? '0' :
|
|
221
|
+
const opt = debug ? '0' : options.opt || '2';
|
|
132
222
|
if (debug) {
|
|
133
223
|
const lines = source.split('\n');
|
|
134
224
|
let braceDepth = 0;
|
|
@@ -151,7 +241,7 @@ export default class Clang {
|
|
|
151
241
|
'#include <string>',
|
|
152
242
|
'#include <type_traits>',
|
|
153
243
|
'#include <vector>',
|
|
154
|
-
'extern "C" __attribute__((import_module("env"), import_name("__wasm_idle_debug_enter"))) void __wasm_idle_debug_enter(int functionId);',
|
|
244
|
+
'extern "C" __attribute__((import_module("env"), import_name("__wasm_idle_debug_enter"))) void __wasm_idle_debug_enter(int functionId, int line);',
|
|
155
245
|
'extern "C" __attribute__((import_module("env"), import_name("__wasm_idle_debug_leave"))) void __wasm_idle_debug_leave(int functionId);',
|
|
156
246
|
'extern "C" __attribute__((import_module("env"), import_name("__wasm_idle_debug_value_num"))) void __wasm_idle_debug_value_num(int functionId, int slot, double value);',
|
|
157
247
|
'extern "C" __attribute__((import_module("env"), import_name("__wasm_idle_debug_value_bool"))) void __wasm_idle_debug_value_bool(int functionId, int slot, int value);',
|
|
@@ -231,7 +321,8 @@ export default class Clang {
|
|
|
231
321
|
}
|
|
232
322
|
else {
|
|
233
323
|
analysisLine =
|
|
234
|
-
analysisLine.slice(0, commentStart) +
|
|
324
|
+
analysisLine.slice(0, commentStart) +
|
|
325
|
+
analysisLine.slice(commentEnd + 2);
|
|
235
326
|
}
|
|
236
327
|
}
|
|
237
328
|
const lineComment = analysisLine.indexOf('//');
|
|
@@ -343,7 +434,9 @@ export default class Clang {
|
|
|
343
434
|
let declarationParenDepth = 0;
|
|
344
435
|
let declarationBraceDepth = 0;
|
|
345
436
|
for (const character of declarationMatch[2]) {
|
|
346
|
-
if (character === ',' &&
|
|
437
|
+
if (character === ',' &&
|
|
438
|
+
declarationParenDepth === 0 &&
|
|
439
|
+
declarationBraceDepth === 0) {
|
|
347
440
|
if (declarationBuffer.trim())
|
|
348
441
|
declarations.push(declarationBuffer.trim());
|
|
349
442
|
declarationBuffer = '';
|
|
@@ -491,7 +584,8 @@ export default class Clang {
|
|
|
491
584
|
}
|
|
492
585
|
}
|
|
493
586
|
for (const [name, variable] of globalVariables) {
|
|
494
|
-
if (currentFunctionVariables.has(name) ||
|
|
587
|
+
if (currentFunctionVariables.has(name) ||
|
|
588
|
+
currentFunctionContainers.has(name))
|
|
495
589
|
continue;
|
|
496
590
|
const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
497
591
|
if (new RegExp(`(?:^|[^\\w])(?:\\+\\+|--)\\s*${escapedName}\\b`).test(normalized) ||
|
|
@@ -529,7 +623,8 @@ export default class Clang {
|
|
|
529
623
|
for (const [name, variable] of currentFunctionVariables) {
|
|
530
624
|
const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
531
625
|
const mutationPattern = new RegExp(`(?:^|[^\\w])(?:\\+\\+|--)\\s*${escapedName}\\b|\\b${escapedName}\\s*(?:[+\\-*/%]?=|\\+\\+|--)`);
|
|
532
|
-
if (!initLooksLikeDeclaration &&
|
|
626
|
+
if (!initLooksLikeDeclaration &&
|
|
627
|
+
mutationPattern.test(initSource)) {
|
|
533
628
|
initHooks.push(`${variable.kind === 'bool' ? '__wasm_idle_debug_value_bool' : '__wasm_idle_debug_value_num'}(${currentFunctionId}, ${variable.slot}, ${name})`);
|
|
534
629
|
}
|
|
535
630
|
if (mutationPattern.test(updateSource)) {
|
|
@@ -584,7 +679,7 @@ export default class Clang {
|
|
|
584
679
|
nextVariableSlot = 1;
|
|
585
680
|
currentFunctionVariables = new Map();
|
|
586
681
|
currentFunctionContainers = new Map();
|
|
587
|
-
instrumented.push(`${indent} __wasm_idle_debug_enter(${currentFunctionId});`);
|
|
682
|
+
instrumented.push(`${indent} __wasm_idle_debug_enter(${currentFunctionId}, ${index + 1});`);
|
|
588
683
|
const parameterSource = startsInlineFunctionBody
|
|
589
684
|
? normalized.slice(normalized.indexOf('(') + 1, normalized.lastIndexOf(')'))
|
|
590
685
|
: pendingFunctionHeader?.parameters || '';
|
|
@@ -648,9 +743,11 @@ export default class Clang {
|
|
|
648
743
|
if (!nameMatch)
|
|
649
744
|
continue;
|
|
650
745
|
const name = nameMatch[1];
|
|
651
|
-
const kind = /\bbool\b/.test(cleaned)
|
|
652
|
-
? '
|
|
653
|
-
:
|
|
746
|
+
const kind = /\bbool\b/.test(cleaned)
|
|
747
|
+
? 'bool'
|
|
748
|
+
: /\b(?:int|float|double|char|short|long)\b/.test(cleaned)
|
|
749
|
+
? 'number'
|
|
750
|
+
: '';
|
|
654
751
|
if (!kind)
|
|
655
752
|
continue;
|
|
656
753
|
const slot = nextVariableSlot++;
|
|
@@ -721,11 +818,11 @@ export default class Clang {
|
|
|
721
818
|
'-O' + opt,
|
|
722
819
|
'-o',
|
|
723
820
|
obj,
|
|
724
|
-
|
|
821
|
+
standardArg,
|
|
725
822
|
'-x',
|
|
726
|
-
|
|
823
|
+
languageArg,
|
|
727
824
|
input,
|
|
728
|
-
...
|
|
825
|
+
...compileArgs
|
|
729
826
|
];
|
|
730
827
|
this.trace(`compile ${input} -> ${obj}`);
|
|
731
828
|
return await this.run(clang, true, 'clang', ...compilerArgs);
|
|
@@ -781,34 +878,53 @@ export default class Clang {
|
|
|
781
878
|
return stillRunning ? app : null;
|
|
782
879
|
}
|
|
783
880
|
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`;
|
|
881
|
+
const { language = 'CPP', args = [], compileArgs = args, debug = false, breakpoints = [], pauseOnEntry = false, cppVersion, cVersion, debugBuffer, interruptBuffer } = options;
|
|
882
|
+
const input = language === 'C' ? `test.c` : `test.cc`, obj = `test.o`, wasm = `test.wasm`;
|
|
786
883
|
this.beginTrace(debug);
|
|
787
884
|
this.debugBreakpoints = new Set(debug ? breakpoints : []);
|
|
788
885
|
this.debugPauseOnEntry = debug && pauseOnEntry;
|
|
789
886
|
this.debugBuffer = debugBuffer;
|
|
790
887
|
this.debugInterruptBuffer = interruptBuffer;
|
|
791
|
-
const buildKey = JSON.stringify({
|
|
888
|
+
const buildKey = JSON.stringify({
|
|
889
|
+
code,
|
|
890
|
+
language,
|
|
891
|
+
compileArgs,
|
|
892
|
+
cppVersion,
|
|
893
|
+
cVersion,
|
|
894
|
+
debug
|
|
895
|
+
});
|
|
792
896
|
if (this.lastBuildKey === buildKey) {
|
|
793
897
|
this.trace(`reuse ${wasm}`);
|
|
794
898
|
return this.wasm;
|
|
795
899
|
}
|
|
796
|
-
await this.compile({
|
|
900
|
+
await this.compile({
|
|
901
|
+
input,
|
|
902
|
+
code,
|
|
903
|
+
obj,
|
|
904
|
+
language,
|
|
905
|
+
compileArgs,
|
|
906
|
+
cppVersion,
|
|
907
|
+
cVersion,
|
|
908
|
+
debug
|
|
909
|
+
});
|
|
797
910
|
await this.link(obj, wasm, debug);
|
|
798
911
|
this.lastBuildKey = buildKey;
|
|
799
912
|
const wasmBytes = Uint8Array.from(this.memfs.getFileContents(wasm));
|
|
800
913
|
return (this.wasm = await this.hostLogAsync(`Compiling ${wasm}`, WebAssembly.compile(wasmBytes)));
|
|
801
914
|
}
|
|
802
915
|
async compileLinkRun(code, options = {}) {
|
|
803
|
-
const { args = [], debug = false, breakpoints = [], pauseOnEntry = false, debugBuffer, interruptBuffer } = options;
|
|
916
|
+
const { language = 'CPP', args = [], compileArgs = args, programArgs = [], debug = false, breakpoints = [], pauseOnEntry = false, cppVersion, cVersion, debugBuffer, interruptBuffer } = options;
|
|
804
917
|
this.debug = debug;
|
|
805
918
|
return await this.run(await this.compileLink(code, {
|
|
806
|
-
|
|
919
|
+
language,
|
|
920
|
+
compileArgs,
|
|
807
921
|
debug,
|
|
808
922
|
breakpoints,
|
|
809
923
|
pauseOnEntry,
|
|
924
|
+
cppVersion,
|
|
925
|
+
cVersion,
|
|
810
926
|
debugBuffer,
|
|
811
927
|
interruptBuffer
|
|
812
|
-
}), true, `test.wasm
|
|
928
|
+
}), true, `test.wasm`, ...programArgs);
|
|
813
929
|
}
|
|
814
930
|
}
|