wasm-idle 0.4.1 → 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 +94 -3
- package/dist/clang/app.d.ts +4 -0
- package/dist/clang/app.js +315 -12
- package/dist/clang/index.d.ts +4 -0
- package/dist/clang/index.js +151 -8
- 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 +5 -3
- package/dist/index.js +3 -3
- package/dist/playground/assets.d.ts +5 -0
- package/dist/playground/assets.js +8 -0
- package/dist/playground/clang.d.ts +5 -0
- package/dist/playground/clang.js +45 -2
- package/dist/playground/index.d.ts +5 -5
- package/dist/playground/index.js +45 -5
- package/dist/playground/options.d.ts +9 -0
- package/dist/playground/python.d.ts +1 -0
- package/dist/playground/python.js +12 -0
- package/dist/playground/rust.d.ts +32 -0
- package/dist/playground/rust.js +175 -0
- package/dist/playground/sandbox.d.ts +18 -4
- package/dist/playground/wasmRustVersion.d.ts +1 -0
- package/dist/playground/wasmRustVersion.js +1 -0
- package/dist/playground/worker/clang.js +12 -4
- package/dist/playground/worker/rust.d.ts +1 -0
- package/dist/playground/worker/rust.js +159 -0
- package/dist/terminal/Terminal.svelte +78 -25
- package/dist/terminal/Terminal.svelte.d.ts +2 -0
- package/dist/terminal/theme.js +2 -2
- package/dist/terminal/types.d.ts +3 -0
- package/package.json +15 -9
package/dist/playground/clang.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { resolveSandboxExecutionArgs } from './options';
|
|
2
|
-
import { flushBufferedEof, flushQueuedStdin, resetBufferedStdin } from './stdinBuffer';
|
|
2
|
+
import { bufferedSequence, flushBufferedEof, flushQueuedStdin, resetBufferedStdin, waitForBufferedSequenceChange } from './stdinBuffer';
|
|
3
|
+
const debugBreakpointBufferInts = 1028;
|
|
3
4
|
class Clang {
|
|
4
5
|
language;
|
|
5
6
|
ts = Date.now();
|
|
@@ -7,7 +8,9 @@ class Clang {
|
|
|
7
8
|
ondebug;
|
|
8
9
|
worker = null;
|
|
9
10
|
buffer = new SharedArrayBuffer(1024);
|
|
10
|
-
debugBuffer = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT *
|
|
11
|
+
debugBuffer = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * debugBreakpointBufferInts);
|
|
12
|
+
watchBuffer = new SharedArrayBuffer(1024);
|
|
13
|
+
watchResultBuffer = new SharedArrayBuffer(1024);
|
|
11
14
|
interruptBuffer = new SharedArrayBuffer(1);
|
|
12
15
|
pendingInput = [];
|
|
13
16
|
begin = 0;
|
|
@@ -17,6 +20,7 @@ class Clang {
|
|
|
17
20
|
waitingForInput = false;
|
|
18
21
|
pendingEof = false;
|
|
19
22
|
exit = true;
|
|
23
|
+
activeReject = null;
|
|
20
24
|
constructor(language) {
|
|
21
25
|
this.language = language;
|
|
22
26
|
}
|
|
@@ -65,7 +69,9 @@ class Clang {
|
|
|
65
69
|
return new Promise(async (resolve, reject) => {
|
|
66
70
|
if (!this.worker)
|
|
67
71
|
return reject('Worker not loaded');
|
|
72
|
+
this.activeReject = reject;
|
|
68
73
|
const { compileArgs, programArgs } = resolveSandboxExecutionArgs(this.language, args, options);
|
|
74
|
+
this.setBreakpoints(options.debug ? [...(options.breakpoints || [])] : []);
|
|
69
75
|
const interrupt = new Uint8Array(this.interruptBuffer), _uid = ++this.uid;
|
|
70
76
|
const handler = (event) => {
|
|
71
77
|
if (!this.worker)
|
|
@@ -86,6 +92,7 @@ class Clang {
|
|
|
86
92
|
this.exit = true;
|
|
87
93
|
this.waitingForInput = false;
|
|
88
94
|
this.pendingEof = false;
|
|
95
|
+
this.activeReject = null;
|
|
89
96
|
this.ondebug?.({ type: 'stop' });
|
|
90
97
|
resolve(results);
|
|
91
98
|
}
|
|
@@ -95,6 +102,7 @@ class Clang {
|
|
|
95
102
|
this.elapse = Date.now() - this.begin;
|
|
96
103
|
this.waitingForInput = false;
|
|
97
104
|
this.pendingEof = false;
|
|
105
|
+
this.activeReject = null;
|
|
98
106
|
this.exit = true;
|
|
99
107
|
this.ondebug?.({ type: 'stop' });
|
|
100
108
|
reject(error);
|
|
@@ -110,6 +118,8 @@ class Clang {
|
|
|
110
118
|
prepare,
|
|
111
119
|
buffer: this.buffer,
|
|
112
120
|
debugBuffer: this.debugBuffer,
|
|
121
|
+
watchBuffer: this.watchBuffer,
|
|
122
|
+
watchResultBuffer: this.watchResultBuffer,
|
|
113
123
|
interrupt: this.interruptBuffer,
|
|
114
124
|
context: {},
|
|
115
125
|
log,
|
|
@@ -131,15 +141,46 @@ class Clang {
|
|
|
131
141
|
Atomics.notify(control, 0);
|
|
132
142
|
this.ondebug?.({ type: 'resume', command });
|
|
133
143
|
}
|
|
144
|
+
setBreakpoints(lines) {
|
|
145
|
+
const control = new Int32Array(this.debugBuffer);
|
|
146
|
+
const next = [...new Set(lines.filter((line) => Number.isInteger(line) && line > 0))]
|
|
147
|
+
.sort((left, right) => left - right)
|
|
148
|
+
.slice(0, Math.max(0, control.length - 4));
|
|
149
|
+
for (let index = 4; index < control.length; index += 1) {
|
|
150
|
+
Atomics.store(control, index, next[index - 4] || 0);
|
|
151
|
+
}
|
|
152
|
+
Atomics.store(control, 3, next.length);
|
|
153
|
+
Atomics.add(control, 2, 1);
|
|
154
|
+
}
|
|
155
|
+
async debugEvaluate(expression) {
|
|
156
|
+
if (!this.worker)
|
|
157
|
+
throw new Error('Worker not loaded');
|
|
158
|
+
resetBufferedStdin(this.watchResultBuffer);
|
|
159
|
+
const previousSequence = bufferedSequence(this.watchResultBuffer);
|
|
160
|
+
flushQueuedStdin([expression], this.watchBuffer);
|
|
161
|
+
const control = new Int32Array(this.debugBuffer);
|
|
162
|
+
Atomics.store(control, 1, 5);
|
|
163
|
+
Atomics.add(control, 0, 1);
|
|
164
|
+
Atomics.notify(control, 0);
|
|
165
|
+
return ((await waitForBufferedSequenceChange(this.watchResultBuffer, previousSequence, 5000)) ??
|
|
166
|
+
'?');
|
|
167
|
+
}
|
|
134
168
|
kill() {
|
|
135
169
|
this.terminate();
|
|
136
170
|
}
|
|
137
171
|
terminate() {
|
|
172
|
+
this.activeReject?.('Process terminated');
|
|
173
|
+
this.activeReject = null;
|
|
174
|
+
this.waitingForInput = false;
|
|
138
175
|
this.pendingEof = false;
|
|
176
|
+
this.uid += 1;
|
|
139
177
|
new Uint8Array(this.interruptBuffer)[0] = 2;
|
|
140
178
|
const control = new Int32Array(this.debugBuffer);
|
|
141
179
|
Atomics.add(control, 0, 1);
|
|
142
180
|
Atomics.notify(control, 0);
|
|
181
|
+
this.worker?.terminate?.();
|
|
182
|
+
delete this.worker;
|
|
183
|
+
this.exit = true;
|
|
143
184
|
}
|
|
144
185
|
async clear() {
|
|
145
186
|
this.terminate();
|
|
@@ -149,6 +190,8 @@ class Clang {
|
|
|
149
190
|
if (this.worker)
|
|
150
191
|
this.worker.onmessage = null;
|
|
151
192
|
resetBufferedStdin(this.buffer);
|
|
193
|
+
resetBufferedStdin(this.watchBuffer);
|
|
194
|
+
resetBufferedStdin(this.watchResultBuffer);
|
|
152
195
|
const debugBuffer = new Int32Array(this.debugBuffer);
|
|
153
196
|
debugBuffer.fill(0);
|
|
154
197
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import Java from './java';
|
|
3
|
-
import Python from './python';
|
|
4
|
-
import type { Sandbox } from './sandbox';
|
|
1
|
+
import type { BoundSandbox, PlaygroundBinding, Sandbox, SandboxRuntimeAssets } from './sandbox';
|
|
5
2
|
export declare const supportedLanguages: string[];
|
|
6
|
-
export
|
|
3
|
+
export declare function createPlaygroundBinding(runtimeAssets: SandboxRuntimeAssets): PlaygroundBinding;
|
|
4
|
+
declare function playground(language: string): Promise<Sandbox>;
|
|
5
|
+
declare function playground(language: string, runtimeAssets: SandboxRuntimeAssets): Promise<BoundSandbox>;
|
|
6
|
+
export default playground;
|
package/dist/playground/index.js
CHANGED
|
@@ -1,11 +1,45 @@
|
|
|
1
1
|
import Clang from './clang';
|
|
2
2
|
import Java from './java';
|
|
3
3
|
import Python from './python';
|
|
4
|
+
import Rust from './rust';
|
|
4
5
|
const sandboxCache = {};
|
|
5
|
-
export const supportedLanguages = ['PYTHON3', 'PYPY3', 'C', 'CPP', 'JAVA'];
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
export const supportedLanguages = ['PYTHON3', 'PYPY3', 'C', 'CPP', 'JAVA', 'RUST'];
|
|
7
|
+
function bindRuntimeAssets(sandbox, runtimeAssets) {
|
|
8
|
+
return new Proxy(sandbox, {
|
|
9
|
+
get(target, prop, receiver) {
|
|
10
|
+
if (prop === 'runtimeAssets')
|
|
11
|
+
return runtimeAssets;
|
|
12
|
+
if (prop === 'load') {
|
|
13
|
+
return (code = '', log = true, args = [], options = {}, progress) => target.load(runtimeAssets, code, log, args, options, progress);
|
|
14
|
+
}
|
|
15
|
+
const value = Reflect.get(target, prop, receiver);
|
|
16
|
+
return typeof value === 'function' ? value.bind(target) : value;
|
|
17
|
+
},
|
|
18
|
+
set(target, prop, value, receiver) {
|
|
19
|
+
return Reflect.set(target, prop, value, receiver);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
export function createPlaygroundBinding(runtimeAssets) {
|
|
24
|
+
const binding = {
|
|
25
|
+
runtimeAssets,
|
|
26
|
+
terminalProps: {},
|
|
27
|
+
async load(language) {
|
|
28
|
+
return bindRuntimeAssets(await playground(language), runtimeAssets);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
binding.terminalProps = {
|
|
32
|
+
playground: binding,
|
|
33
|
+
runtimeAssets
|
|
34
|
+
};
|
|
35
|
+
return binding;
|
|
36
|
+
}
|
|
37
|
+
async function playground(language, runtimeAssets) {
|
|
38
|
+
if (sandboxCache[language]) {
|
|
39
|
+
return runtimeAssets
|
|
40
|
+
? bindRuntimeAssets(sandboxCache[language], runtimeAssets)
|
|
41
|
+
: sandboxCache[language];
|
|
42
|
+
}
|
|
9
43
|
let sandbox;
|
|
10
44
|
switch (language) {
|
|
11
45
|
case 'PYTHON3':
|
|
@@ -22,6 +56,9 @@ export default async function load(language) {
|
|
|
22
56
|
case 'JAVA':
|
|
23
57
|
sandbox = new Java();
|
|
24
58
|
break;
|
|
59
|
+
case 'RUST':
|
|
60
|
+
sandbox = new Rust();
|
|
61
|
+
break;
|
|
25
62
|
default:
|
|
26
63
|
throw new Error(`Unsupported language: ${language}`);
|
|
27
64
|
}
|
|
@@ -39,6 +76,9 @@ export default async function load(language) {
|
|
|
39
76
|
sandboxCache['CPP'] = sandbox;
|
|
40
77
|
if (language === 'JAVA')
|
|
41
78
|
sandboxCache['JAVA'] = sandbox;
|
|
79
|
+
if (language === 'RUST')
|
|
80
|
+
sandboxCache['RUST'] = sandbox;
|
|
42
81
|
}
|
|
43
|
-
return sandbox;
|
|
82
|
+
return runtimeAssets ? bindRuntimeAssets(sandbox, runtimeAssets) : sandbox;
|
|
44
83
|
}
|
|
84
|
+
export default playground;
|
|
@@ -13,8 +13,14 @@ export interface CompilerDiagnostic {
|
|
|
13
13
|
severity: CompilerDiagnosticSeverity;
|
|
14
14
|
message: string;
|
|
15
15
|
}
|
|
16
|
+
export type RustTargetTriple = 'wasm32-wasip1' | 'wasm32-wasip2' | 'wasm32-wasip3';
|
|
16
17
|
export type DebugVariableKind = 'number' | 'bool' | 'array' | 'text';
|
|
17
18
|
export type DebugArrayElementKind = 'int' | 'float' | 'double' | 'bool' | 'char';
|
|
19
|
+
export interface DebugStructFieldMetadata {
|
|
20
|
+
name: string;
|
|
21
|
+
kind: DebugArrayElementKind;
|
|
22
|
+
offset: number;
|
|
23
|
+
}
|
|
18
24
|
export interface DebugVariableMetadata {
|
|
19
25
|
slot: number;
|
|
20
26
|
name: string;
|
|
@@ -24,6 +30,8 @@ export interface DebugVariableMetadata {
|
|
|
24
30
|
elementKind?: DebugArrayElementKind;
|
|
25
31
|
length?: number;
|
|
26
32
|
dimensions?: number[];
|
|
33
|
+
structFields?: DebugStructFieldMetadata[];
|
|
34
|
+
structSize?: number;
|
|
27
35
|
}
|
|
28
36
|
export interface DebugFrame {
|
|
29
37
|
functionName: string;
|
|
@@ -50,6 +58,7 @@ export interface SandboxExecutionOptions {
|
|
|
50
58
|
programArgs?: string[];
|
|
51
59
|
cppVersion?: string;
|
|
52
60
|
cVersion?: string;
|
|
61
|
+
rustTargetTriple?: RustTargetTriple;
|
|
53
62
|
}
|
|
54
63
|
export interface ResolvedSandboxExecutionArgs {
|
|
55
64
|
compileArgs: string[];
|
|
@@ -25,6 +25,7 @@ declare class Python implements Sandbox {
|
|
|
25
25
|
pendingEof: boolean;
|
|
26
26
|
exit: boolean;
|
|
27
27
|
assetBridge: WorkerAssetBridge | null;
|
|
28
|
+
activeReject: ((reason?: string) => void) | null;
|
|
28
29
|
load(runtimeAssets?: string | PlaygroundRuntimeAssets, code?: string, log?: boolean, _args?: string[], _options?: SandboxExecutionOptions, progress?: {
|
|
29
30
|
set?: (value: number) => void;
|
|
30
31
|
} | import('svelte/store').Writable<number>): Promise<void>;
|
|
@@ -20,6 +20,7 @@ class Python {
|
|
|
20
20
|
pendingEof = false;
|
|
21
21
|
exit = true;
|
|
22
22
|
assetBridge = null;
|
|
23
|
+
activeReject = null;
|
|
23
24
|
load(runtimeAssets = '', code = '', log = true, _args = [], _options = {}, progress) {
|
|
24
25
|
return new Promise(async (resolve, reject) => {
|
|
25
26
|
this.pendingInput = [];
|
|
@@ -89,6 +90,7 @@ class Python {
|
|
|
89
90
|
return new Promise(async (resolve, reject) => {
|
|
90
91
|
if (!this.worker)
|
|
91
92
|
return reject('Worker not loaded');
|
|
93
|
+
this.activeReject = reject;
|
|
92
94
|
const interrupt = new Uint8Array(this.interruptBuffer), _uid = ++this.uid;
|
|
93
95
|
const handler = (event) => {
|
|
94
96
|
if (this.assetBridge?.handleMessage(event))
|
|
@@ -113,6 +115,7 @@ class Python {
|
|
|
113
115
|
this.exit = true;
|
|
114
116
|
this.waitingForInput = false;
|
|
115
117
|
this.pendingEof = false;
|
|
118
|
+
this.activeReject = null;
|
|
116
119
|
this.ondebug?.({ type: 'stop' });
|
|
117
120
|
resolve(results);
|
|
118
121
|
}
|
|
@@ -123,6 +126,7 @@ class Python {
|
|
|
123
126
|
this.exit = true;
|
|
124
127
|
this.waitingForInput = false;
|
|
125
128
|
this.pendingEof = false;
|
|
129
|
+
this.activeReject = null;
|
|
126
130
|
this.ondebug?.({ type: 'stop' });
|
|
127
131
|
reject(error);
|
|
128
132
|
}
|
|
@@ -169,11 +173,19 @@ class Python {
|
|
|
169
173
|
this.terminate();
|
|
170
174
|
}
|
|
171
175
|
terminate() {
|
|
176
|
+
this.activeReject?.('Process terminated');
|
|
177
|
+
this.activeReject = null;
|
|
178
|
+
this.waitingForInput = false;
|
|
172
179
|
this.pendingEof = false;
|
|
180
|
+
this.uid += 1;
|
|
173
181
|
new Uint8Array(this.interruptBuffer)[0] = 2;
|
|
174
182
|
const control = new Int32Array(this.debugBuffer);
|
|
175
183
|
Atomics.add(control, 0, 1);
|
|
176
184
|
Atomics.notify(control, 0);
|
|
185
|
+
this.worker?.terminate?.();
|
|
186
|
+
delete this.worker;
|
|
187
|
+
this.assetBridge = null;
|
|
188
|
+
this.exit = true;
|
|
177
189
|
}
|
|
178
190
|
async clear() {
|
|
179
191
|
this.terminate();
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type PlaygroundRuntimeAssets } from './assets';
|
|
2
|
+
import { type CompilerDiagnostic, type SandboxExecutionOptions } from './options';
|
|
3
|
+
import type { Sandbox } from './sandbox';
|
|
4
|
+
declare class Rust implements Sandbox {
|
|
5
|
+
output: any;
|
|
6
|
+
worker?: Worker;
|
|
7
|
+
buffer: SharedArrayBuffer;
|
|
8
|
+
pendingInput: string[];
|
|
9
|
+
begin: number;
|
|
10
|
+
elapse: number;
|
|
11
|
+
uid: number;
|
|
12
|
+
exit: boolean;
|
|
13
|
+
compilerUrl: string;
|
|
14
|
+
assetPath: string;
|
|
15
|
+
activeReject: ((reason: string) => void) | null;
|
|
16
|
+
oncompilerdiagnostic?: (diagnostic: CompilerDiagnostic) => void;
|
|
17
|
+
waitingForInput: boolean;
|
|
18
|
+
pendingEof: boolean;
|
|
19
|
+
load(runtimeAssets?: string | PlaygroundRuntimeAssets, _code?: string, _log?: boolean, _args?: string[], _options?: SandboxExecutionOptions, progress?: {
|
|
20
|
+
set?: (value: number) => void;
|
|
21
|
+
} | import('svelte/store').Writable<number>): Promise<void>;
|
|
22
|
+
write(input: string): void;
|
|
23
|
+
eof(): void;
|
|
24
|
+
private flushPendingInput;
|
|
25
|
+
run(code: string, prepare: boolean, _log?: boolean, _prog?: {
|
|
26
|
+
set?: (value: number) => void;
|
|
27
|
+
} | import('svelte/store').Writable<number>, args?: string[], options?: SandboxExecutionOptions): Promise<boolean | string>;
|
|
28
|
+
kill(): void;
|
|
29
|
+
terminate(): void;
|
|
30
|
+
clear(): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
export default Rust;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { resolveRustCompilerUrl } from './assets';
|
|
2
|
+
import { resolveSandboxExecutionArgs } from './options';
|
|
3
|
+
import { flushBufferedEof, flushQueuedStdin, resetBufferedStdin } from './stdinBuffer';
|
|
4
|
+
class Rust {
|
|
5
|
+
output = null;
|
|
6
|
+
worker = null;
|
|
7
|
+
buffer = new SharedArrayBuffer(1024);
|
|
8
|
+
pendingInput = [];
|
|
9
|
+
begin = 0;
|
|
10
|
+
elapse = 0;
|
|
11
|
+
uid = 0;
|
|
12
|
+
exit = true;
|
|
13
|
+
compilerUrl = '';
|
|
14
|
+
assetPath = '';
|
|
15
|
+
activeReject = null;
|
|
16
|
+
oncompilerdiagnostic;
|
|
17
|
+
waitingForInput = false;
|
|
18
|
+
pendingEof = false;
|
|
19
|
+
load(runtimeAssets = '', _code = '', _log = true, _args = [], _options = {}, progress) {
|
|
20
|
+
return new Promise(async (resolve, reject) => {
|
|
21
|
+
this.pendingInput = [];
|
|
22
|
+
this.waitingForInput = false;
|
|
23
|
+
this.pendingEof = false;
|
|
24
|
+
const currentUrl = typeof window !== 'undefined' ? window.location.href : '';
|
|
25
|
+
const nextCompilerUrl = resolveRustCompilerUrl(runtimeAssets, currentUrl);
|
|
26
|
+
const nextAssetPath = typeof runtimeAssets === 'string'
|
|
27
|
+
? runtimeAssets
|
|
28
|
+
: runtimeAssets?.rootUrl ||
|
|
29
|
+
(typeof window !== 'undefined'
|
|
30
|
+
? window.location.pathname.replace(/\/$/, '')
|
|
31
|
+
: '');
|
|
32
|
+
if (!nextCompilerUrl) {
|
|
33
|
+
return reject('Rust runtime is not configured. Set PUBLIC_WASM_RUST_COMPILER_URL or runtimeAssets.rust.compilerUrl.');
|
|
34
|
+
}
|
|
35
|
+
const needsWorkerReset = !this.worker || this.compilerUrl !== nextCompilerUrl || this.assetPath !== nextAssetPath;
|
|
36
|
+
this.compilerUrl = nextCompilerUrl;
|
|
37
|
+
this.assetPath = nextAssetPath;
|
|
38
|
+
if (needsWorkerReset && this.worker) {
|
|
39
|
+
this.worker.terminate();
|
|
40
|
+
delete this.worker;
|
|
41
|
+
}
|
|
42
|
+
if (!this.worker) {
|
|
43
|
+
this.worker = new (await import('./worker/rust?worker')).default();
|
|
44
|
+
this.worker.onerror = (event) => {
|
|
45
|
+
const location = event.filename && event.lineno
|
|
46
|
+
? ` (${event.filename}:${event.lineno}:${event.colno})`
|
|
47
|
+
: '';
|
|
48
|
+
reject(`Rust worker script error: ${event.message || 'unknown error'}${location}`);
|
|
49
|
+
};
|
|
50
|
+
this.worker.onmessageerror = () => {
|
|
51
|
+
reject('Rust worker message deserialization failed');
|
|
52
|
+
};
|
|
53
|
+
this.worker.onmessage = (event) => {
|
|
54
|
+
if (event.data?.load) {
|
|
55
|
+
progress?.set?.(1);
|
|
56
|
+
resolve();
|
|
57
|
+
}
|
|
58
|
+
if (event.data?.error)
|
|
59
|
+
reject(event.data.error);
|
|
60
|
+
};
|
|
61
|
+
this.worker.postMessage({
|
|
62
|
+
load: true,
|
|
63
|
+
compilerUrl: this.compilerUrl,
|
|
64
|
+
path: this.assetPath
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
progress?.set?.(1);
|
|
69
|
+
resolve();
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
write(input) {
|
|
74
|
+
this.pendingInput.push(input);
|
|
75
|
+
this.pendingEof = false;
|
|
76
|
+
this.flushPendingInput();
|
|
77
|
+
}
|
|
78
|
+
eof() {
|
|
79
|
+
this.pendingEof = true;
|
|
80
|
+
this.flushPendingInput();
|
|
81
|
+
}
|
|
82
|
+
flushPendingInput() {
|
|
83
|
+
if (!this.waitingForInput)
|
|
84
|
+
return;
|
|
85
|
+
if (flushQueuedStdin(this.pendingInput, this.buffer)) {
|
|
86
|
+
this.waitingForInput = false;
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (this.pendingEof) {
|
|
90
|
+
flushBufferedEof(this.buffer);
|
|
91
|
+
this.pendingEof = false;
|
|
92
|
+
this.waitingForInput = false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
run(code, prepare, _log = true, _prog, args = [], options = {}) {
|
|
96
|
+
this.exit = false;
|
|
97
|
+
return new Promise((resolve, reject) => {
|
|
98
|
+
if (!this.worker)
|
|
99
|
+
return reject('Worker not loaded');
|
|
100
|
+
const { programArgs } = resolveSandboxExecutionArgs('RUST', args, options);
|
|
101
|
+
const targetTriple = options.rustTargetTriple || 'wasm32-wasip1';
|
|
102
|
+
const _uid = ++this.uid;
|
|
103
|
+
this.activeReject = reject;
|
|
104
|
+
const handler = (event) => {
|
|
105
|
+
if (!this.worker)
|
|
106
|
+
return reject('Worker not loaded');
|
|
107
|
+
if (_uid !== this.uid)
|
|
108
|
+
return (this.worker.onmessage = null);
|
|
109
|
+
const { output, results, error, buffer, diagnostic, progress } = event.data;
|
|
110
|
+
if (buffer) {
|
|
111
|
+
this.waitingForInput = true;
|
|
112
|
+
this.flushPendingInput();
|
|
113
|
+
}
|
|
114
|
+
if (progress && typeof progress.percent === 'number') {
|
|
115
|
+
_prog?.set?.(Math.max(0, Math.min(progress.percent / 100, 1)));
|
|
116
|
+
}
|
|
117
|
+
if (output)
|
|
118
|
+
this.output(output);
|
|
119
|
+
if (diagnostic)
|
|
120
|
+
this.oncompilerdiagnostic?.(diagnostic);
|
|
121
|
+
if (results) {
|
|
122
|
+
this.elapse = Date.now() - this.begin;
|
|
123
|
+
this.exit = true;
|
|
124
|
+
this.waitingForInput = false;
|
|
125
|
+
this.pendingEof = false;
|
|
126
|
+
this.activeReject = null;
|
|
127
|
+
resolve(results);
|
|
128
|
+
}
|
|
129
|
+
if (error) {
|
|
130
|
+
this.elapse = Date.now() - this.begin;
|
|
131
|
+
this.exit = true;
|
|
132
|
+
this.waitingForInput = false;
|
|
133
|
+
this.pendingEof = false;
|
|
134
|
+
this.activeReject = null;
|
|
135
|
+
reject(error);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
this.worker.onmessage = handler;
|
|
139
|
+
this.begin = Date.now();
|
|
140
|
+
this.worker.postMessage({
|
|
141
|
+
code,
|
|
142
|
+
prepare,
|
|
143
|
+
buffer: this.buffer,
|
|
144
|
+
args: programArgs,
|
|
145
|
+
targetTriple,
|
|
146
|
+
log: _log
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
kill() {
|
|
151
|
+
this.terminate();
|
|
152
|
+
}
|
|
153
|
+
terminate() {
|
|
154
|
+
this.activeReject?.('Process terminated');
|
|
155
|
+
this.activeReject = null;
|
|
156
|
+
this.waitingForInput = false;
|
|
157
|
+
this.pendingEof = false;
|
|
158
|
+
this.uid += 1;
|
|
159
|
+
this.worker?.terminate?.();
|
|
160
|
+
delete this.worker;
|
|
161
|
+
this.exit = true;
|
|
162
|
+
}
|
|
163
|
+
async clear() {
|
|
164
|
+
this.pendingInput = [];
|
|
165
|
+
this.waitingForInput = false;
|
|
166
|
+
this.pendingEof = false;
|
|
167
|
+
if (this.worker)
|
|
168
|
+
this.worker.onmessage = null;
|
|
169
|
+
resetBufferedStdin(this.buffer);
|
|
170
|
+
if (!this.exit) {
|
|
171
|
+
this.terminate();
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
export default Rust;
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type { CompilerDiagnostic, DebugCommand, DebugSessionEvent, SandboxExecutionOptions } from './options';
|
|
2
2
|
import type { PlaygroundRuntimeAssets } from './assets';
|
|
3
3
|
import type { Writable } from 'svelte/store';
|
|
4
|
-
type
|
|
4
|
+
export type SandboxRuntimeAssets = string | PlaygroundRuntimeAssets;
|
|
5
|
+
export type SandboxProgress = Writable<number> | {
|
|
5
6
|
set?: (value: number) => void;
|
|
6
7
|
};
|
|
7
8
|
export interface Sandbox {
|
|
8
9
|
constructor: any;
|
|
9
10
|
eof: () => void;
|
|
10
|
-
load: (runtimeAssets?:
|
|
11
|
-
run: (code: string, prepare: boolean, log?: boolean, prog?:
|
|
11
|
+
load: (runtimeAssets?: SandboxRuntimeAssets, code?: string, log?: boolean, args?: string[], options?: SandboxExecutionOptions, progress?: SandboxProgress) => Promise<void>;
|
|
12
|
+
run: (code: string, prepare: boolean, log?: boolean, prog?: SandboxProgress, args?: string[], options?: SandboxExecutionOptions) => Promise<boolean | string>;
|
|
12
13
|
terminate: () => void;
|
|
13
14
|
clear: () => Promise<void>;
|
|
14
15
|
kill?: () => void;
|
|
@@ -17,6 +18,7 @@ export interface Sandbox {
|
|
|
17
18
|
ondebug?: (event: DebugSessionEvent) => void;
|
|
18
19
|
oncompilerdiagnostic?: (diagnostic: CompilerDiagnostic) => void;
|
|
19
20
|
debugCommand?: (command: DebugCommand) => void;
|
|
21
|
+
setBreakpoints?: (lines: number[]) => void;
|
|
20
22
|
debugEvaluate?: (expression: string) => Promise<string>;
|
|
21
23
|
image?: (data: {
|
|
22
24
|
mime: string;
|
|
@@ -25,4 +27,16 @@ export interface Sandbox {
|
|
|
25
27
|
}) => void;
|
|
26
28
|
elapse?: number;
|
|
27
29
|
}
|
|
28
|
-
export {
|
|
30
|
+
export interface BoundSandbox extends Omit<Sandbox, 'load'> {
|
|
31
|
+
load: (code?: string, log?: boolean, args?: string[], options?: SandboxExecutionOptions, progress?: SandboxProgress) => Promise<void>;
|
|
32
|
+
runtimeAssets: SandboxRuntimeAssets;
|
|
33
|
+
}
|
|
34
|
+
export interface PlaygroundTerminalProps {
|
|
35
|
+
playground: PlaygroundBinding;
|
|
36
|
+
runtimeAssets: SandboxRuntimeAssets;
|
|
37
|
+
}
|
|
38
|
+
export interface PlaygroundBinding {
|
|
39
|
+
runtimeAssets: SandboxRuntimeAssets;
|
|
40
|
+
terminalProps: PlaygroundTerminalProps;
|
|
41
|
+
load: (language: string) => Promise<BoundSandbox>;
|
|
42
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const WASM_RUST_ASSET_VERSION = "2d36c8a3cd2cbbfd";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const WASM_RUST_ASSET_VERSION = "2d36c8a3cd2cbbfd";
|
|
@@ -4,7 +4,7 @@ self.document = {
|
|
|
4
4
|
return [];
|
|
5
5
|
}
|
|
6
6
|
};
|
|
7
|
-
let stdinBufferClang, debugBufferClang, interruptBufferClang, clang;
|
|
7
|
+
let stdinBufferClang, debugBufferClang, watchBufferClang, watchResultBufferClang, interruptBufferClang, clang;
|
|
8
8
|
async function loadClang(path, log) {
|
|
9
9
|
const { default: Clang } = await import('../../clang');
|
|
10
10
|
clang = new Clang({
|
|
@@ -17,7 +17,7 @@ async function loadClang(path, log) {
|
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
19
|
self.onmessage = async (event) => {
|
|
20
|
-
const { code, buffer, debugBuffer, load, interrupt, log, path, prepare, language, compileArgs, programArgs, cppVersion, cVersion, debug, breakpoints, pauseOnEntry } = event.data;
|
|
20
|
+
const { code, buffer, debugBuffer, watchBuffer, watchResultBuffer, load, interrupt, log, path, prepare, language, compileArgs, programArgs, cppVersion, cVersion, debug, breakpoints, pauseOnEntry } = event.data;
|
|
21
21
|
if (load) {
|
|
22
22
|
await loadClang(path, log);
|
|
23
23
|
postMessage({ load: true });
|
|
@@ -25,6 +25,8 @@ self.onmessage = async (event) => {
|
|
|
25
25
|
else if (prepare) {
|
|
26
26
|
stdinBufferClang = new Int32Array(buffer);
|
|
27
27
|
debugBufferClang = new Int32Array(debugBuffer);
|
|
28
|
+
watchBufferClang = new Int32Array(watchBuffer);
|
|
29
|
+
watchResultBufferClang = new Int32Array(watchResultBuffer);
|
|
28
30
|
interruptBufferClang = new Uint8Array(interrupt);
|
|
29
31
|
try {
|
|
30
32
|
await clang.compileLink(code, {
|
|
@@ -37,7 +39,9 @@ self.onmessage = async (event) => {
|
|
|
37
39
|
breakpoints,
|
|
38
40
|
pauseOnEntry,
|
|
39
41
|
debugBuffer: debugBufferClang,
|
|
40
|
-
interruptBuffer: interruptBufferClang
|
|
42
|
+
interruptBuffer: interruptBufferClang,
|
|
43
|
+
watchBuffer: watchBufferClang,
|
|
44
|
+
watchResultBuffer: watchResultBufferClang
|
|
41
45
|
});
|
|
42
46
|
self.postMessage({ results: true });
|
|
43
47
|
}
|
|
@@ -49,6 +53,8 @@ self.onmessage = async (event) => {
|
|
|
49
53
|
clang.log = log;
|
|
50
54
|
stdinBufferClang = new Int32Array(buffer);
|
|
51
55
|
debugBufferClang = new Int32Array(debugBuffer);
|
|
56
|
+
watchBufferClang = new Int32Array(watchBuffer);
|
|
57
|
+
watchResultBufferClang = new Int32Array(watchResultBuffer);
|
|
52
58
|
interruptBufferClang = new Uint8Array(interrupt);
|
|
53
59
|
try {
|
|
54
60
|
await clang.compileLinkRun(code, {
|
|
@@ -61,7 +67,9 @@ self.onmessage = async (event) => {
|
|
|
61
67
|
breakpoints,
|
|
62
68
|
pauseOnEntry,
|
|
63
69
|
debugBuffer: debugBufferClang,
|
|
64
|
-
interruptBuffer: interruptBufferClang
|
|
70
|
+
interruptBuffer: interruptBufferClang,
|
|
71
|
+
watchBuffer: watchBufferClang,
|
|
72
|
+
watchResultBuffer: watchResultBufferClang
|
|
65
73
|
});
|
|
66
74
|
self.postMessage({ results: true });
|
|
67
75
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|