wasm-idle 1.0.11 → 1.1.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 (56) hide show
  1. package/README.md +92 -64
  2. package/dist/playground/aheui.d.ts +18 -0
  3. package/dist/playground/aheui.js +21 -0
  4. package/dist/playground/apecode.d.ts +18 -0
  5. package/dist/playground/apecode.js +21 -0
  6. package/dist/playground/applicationAssets.js +2 -0
  7. package/dist/playground/assets.d.ts +18 -0
  8. package/dist/playground/assets.js +28 -0
  9. package/dist/playground/commonlisp.d.ts +8 -0
  10. package/dist/playground/commonlisp.js +33 -0
  11. package/dist/playground/commonlispAssets.d.ts +30 -0
  12. package/dist/playground/commonlispAssets.js +184 -0
  13. package/dist/playground/golfscript.d.ts +6 -0
  14. package/dist/playground/golfscript.js +8 -0
  15. package/dist/playground/index.d.ts +1 -1
  16. package/dist/playground/index.js +95 -0
  17. package/dist/playground/javaRuntimeStdin.d.ts +9 -0
  18. package/dist/playground/javaRuntimeStdin.js +145 -0
  19. package/dist/playground/lean4.d.ts +13 -0
  20. package/dist/playground/lean4.js +50 -0
  21. package/dist/playground/lean4Assets.d.ts +25 -0
  22. package/dist/playground/lean4Assets.js +123 -0
  23. package/dist/playground/loadingProgress.js +4 -1
  24. package/dist/playground/python.d.ts +6 -2
  25. package/dist/playground/python.js +81 -15
  26. package/dist/playground/ruby.d.ts +6 -0
  27. package/dist/playground/ruby.js +108 -56
  28. package/dist/playground/wasiInterpreters.d.ts +15 -0
  29. package/dist/playground/wasiInterpreters.js +67 -0
  30. package/dist/playground/wasm.d.ts +3 -0
  31. package/dist/playground/wasm.js +44 -3
  32. package/dist/playground/wasmAheuiVersion.d.ts +7 -0
  33. package/dist/playground/wasmAheuiVersion.js +10 -0
  34. package/dist/playground/wasmApecodeVersion.d.ts +7 -0
  35. package/dist/playground/wasmApecodeVersion.js +9 -0
  36. package/dist/playground/wasmCommonLispVersion.d.ts +32 -0
  37. package/dist/playground/wasmCommonLispVersion.js +33 -0
  38. package/dist/playground/wasmGolfscriptVersion.d.ts +10 -0
  39. package/dist/playground/wasmGolfscriptVersion.js +10 -0
  40. package/dist/playground/wasmLean4Version.d.ts +110 -0
  41. package/dist/playground/wasmLean4Version.js +111 -0
  42. package/dist/playground/worker/golfscriptMount.d.ts +45 -0
  43. package/dist/playground/worker/golfscriptMount.js +79 -0
  44. package/dist/playground/worker/java.js +17 -29
  45. package/dist/playground/worker/python.js +311 -155
  46. package/dist/playground/worker/python.runtime.cases.d.ts +1 -0
  47. package/dist/playground/worker/python.runtime.cases.js +374 -0
  48. package/dist/playground/worker/pythonDebugPreview.d.ts +2 -0
  49. package/dist/playground/worker/pythonDebugPreview.js +55 -0
  50. package/dist/playground/worker/pythonExecution.d.ts +8 -0
  51. package/dist/playground/worker/pythonExecution.js +167 -0
  52. package/dist/playground/worker/pythonStdio.d.ts +32 -0
  53. package/dist/playground/worker/pythonStdio.js +253 -0
  54. package/dist/playground/worker/ruby.js +151 -15
  55. package/dist/playground/worker/wasm.js +106 -7
  56. package/package.json +32 -10
@@ -0,0 +1,184 @@
1
+ import { AssetIntegrityError, defineRuntimeRegistryManifest, UnsupportedBrowserFeatureError, preflightRuntimeAssets, ResourceLimitError, RuntimeConfigurationError, verifyRuntimeAssetIntegrity } from '@wasm-idle/core';
2
+ import { WASM_COMMONLISP_PROFILE as profile } from './wasmCommonLispVersion';
3
+ export const COMMONLISP_INITIAL_MEMORY_BYTES = 64 * 1024 * 1024;
4
+ /** ecl.wasm is delivered as the producer's pinned gzip bytes; `.bin` keeps hosts from adding
5
+ * Content-Encoding, so the browser never transparently decodes it before verification. */
6
+ export const COMMONLISP_WASM_STORAGE_PATH = 'ecl.wasm.gz.bin';
7
+ const identityAsset = (name, mediaType) => ({
8
+ key: name,
9
+ path: name,
10
+ compressedSha256: profile.assets[name].sha256,
11
+ uncompressedSha256: profile.assets[name].sha256,
12
+ compressedBytes: profile.assets[name].bytes,
13
+ uncompressedBytes: profile.assets[name].bytes,
14
+ encoding: 'identity',
15
+ mediaType
16
+ });
17
+ const deliveryAssets = [
18
+ identityAsset('producer-receipt.json', 'application/json'),
19
+ identityAsset('ecl.mjs', 'text/javascript'),
20
+ {
21
+ key: 'ecl.wasm',
22
+ path: COMMONLISP_WASM_STORAGE_PATH,
23
+ compressedSha256: profile.assets['ecl.wasm.gz'].sha256,
24
+ uncompressedSha256: profile.runtime['ecl.wasm'].sha256,
25
+ compressedBytes: profile.assets['ecl.wasm.gz'].bytes,
26
+ uncompressedBytes: profile.runtime['ecl.wasm'].bytes,
27
+ encoding: 'gzip',
28
+ mediaType: 'application/wasm'
29
+ }
30
+ ];
31
+ export const COMMONLISP_RUNTIME_MANIFEST = defineRuntimeRegistryManifest({
32
+ schemaVersion: 2,
33
+ manifestId: 'wasm-idle/commonlisp',
34
+ revision: profile.assets['producer-receipt.json'].sha256,
35
+ runtimes: [
36
+ {
37
+ runtimeId: 'COMMONLISP',
38
+ identity: {
39
+ languageId: 'COMMONLISP',
40
+ implementationId: 'ecl-emscripten',
41
+ implementationVersion: profile.version,
42
+ profile: {
43
+ profileId: profile.profileId,
44
+ manifestSchemaVersion: 1,
45
+ manifestSha256: profile.assets['producer-receipt.json'].sha256,
46
+ protocolVersion: 1,
47
+ trustProfileId: profile.profileId,
48
+ trustProfileSchemaVersion: 1
49
+ }
50
+ },
51
+ capabilities: {
52
+ stdin: 'streaming',
53
+ workspace: true,
54
+ abort: true,
55
+ artifacts: false,
56
+ streamingOutput: true
57
+ },
58
+ workerLifetime: { mode: 'per-run' },
59
+ requiredBrowserFeatures: ['wasm', 'wasm-exceptions', 'decompression-stream'],
60
+ assetRoot: '.',
61
+ assets: deliveryAssets,
62
+ contracts: {
63
+ routeId: 'COMMONLISP',
64
+ runtimeAssetKey: 'commonlisp',
65
+ documentationId: 'commonlisp',
66
+ syncTarget: 'wasm-commonlisp',
67
+ browserTestId: 'COMMONLISP'
68
+ }
69
+ }
70
+ ]
71
+ });
72
+ export function resolveCommonLispRuntimeAssetConfig(assets, currentUrl) {
73
+ const root = typeof assets === 'string' ? assets : assets.rootUrl || '';
74
+ const override = typeof assets === 'string' ? undefined : assets.commonlisp?.baseUrl;
75
+ const baseUrl = new URL(override ?? `${root.replace(/\/+$/, '')}/wasm-commonlisp/`, currentUrl);
76
+ if (!['http:', 'https:'].includes(baseUrl.protocol) ||
77
+ baseUrl.username ||
78
+ baseUrl.password ||
79
+ baseUrl.search ||
80
+ baseUrl.hash) {
81
+ throw new RuntimeConfigurationError('Common Lisp requires a credential-free HTTP(S) asset directory.', { runtimeId: 'COMMONLISP' });
82
+ }
83
+ if (!baseUrl.pathname.endsWith('/'))
84
+ baseUrl.pathname += '/';
85
+ const workerUrl = new URL('runner-worker.js', baseUrl);
86
+ workerUrl.searchParams.set('v', profile.workerReceipt.sha256);
87
+ return {
88
+ baseUrl: baseUrl.href,
89
+ workerUrl: workerUrl.href,
90
+ manifestFingerprint: profile.assets['producer-receipt.json'].sha256,
91
+ workerReceipt: profile.workerReceipt
92
+ };
93
+ }
94
+ export async function preflightCommonLispRuntimeAssets(baseUrl, options) {
95
+ if (options.limits.maxWasmMemoryBytes < COMMONLISP_INITIAL_MEMORY_BYTES) {
96
+ throw new ResourceLimitError('Common Lisp needs at least 64 MiB of Wasm memory.', {
97
+ runtimeId: 'COMMONLISP',
98
+ phase: 'asset',
99
+ resource: 'wasm-memory',
100
+ actual: COMMONLISP_INITIAL_MEMORY_BYTES,
101
+ limit: options.limits.maxWasmMemoryBytes
102
+ });
103
+ }
104
+ const loaded = new Map();
105
+ const total = deliveryAssets.reduce((sum, asset) => sum + asset.compressedBytes, 0);
106
+ const result = await preflightRuntimeAssets({
107
+ manifest: COMMONLISP_RUNTIME_MANIFEST,
108
+ runtimeId: 'COMMONLISP',
109
+ rootUrl: baseUrl,
110
+ assetUrls: Object.fromEntries(deliveryAssets.map((asset) => [
111
+ asset.key,
112
+ new URL(`${asset.path}?v=${asset.compressedSha256}`, baseUrl)
113
+ ])),
114
+ limits: options.limits,
115
+ persistentCache: options.persistentCache,
116
+ signal: options.signal,
117
+ fetch: options.fetch,
118
+ redirect: 'error',
119
+ requireExactResponseUrl: true,
120
+ maxConcurrentDownloads: 2,
121
+ maxTotalDeliveryBytes: total,
122
+ reportProgress(progress) {
123
+ loaded.set(progress.assetKey, progress.loadedBytes);
124
+ options.reportProgress?.(0.04 + (0.13 * [...loaded.values()].reduce((a, b) => a + b, 0)) / total, `Verifying ECL ${progress.assetKey}`);
125
+ }
126
+ });
127
+ const wasm = await decompressCommonLispWasm(result.assets['ecl.wasm'].bytes, options.signal);
128
+ return Object.freeze({
129
+ fingerprint: profile.assets['producer-receipt.json'].sha256,
130
+ 'producer-receipt.json': result.assets['producer-receipt.json'].bytes,
131
+ 'ecl.mjs': result.assets['ecl.mjs'].bytes,
132
+ 'ecl.wasm': wasm
133
+ });
134
+ }
135
+ /** Decode the verified gzip delivery into an exactly sized buffer and verify the logical receipt. */
136
+ export async function decompressCommonLispWasm(compressed, signal) {
137
+ const context = { runtimeId: 'COMMONLISP', profileId: profile.profileId };
138
+ if (typeof DecompressionStream !== 'function')
139
+ throw new UnsupportedBrowserFeatureError('DecompressionStream(gzip)', {
140
+ ...context,
141
+ phase: 'asset'
142
+ });
143
+ const expected = profile.runtime['ecl.wasm'];
144
+ const body = new Response(Uint8Array.from(compressed)).body;
145
+ const reader = body.pipeThrough(new DecompressionStream('gzip')).getReader();
146
+ const wasm = new Uint8Array(expected.bytes);
147
+ let offset = 0;
148
+ try {
149
+ for (;;) {
150
+ signal?.throwIfAborted();
151
+ const { done, value } = await reader.read();
152
+ if (done)
153
+ break;
154
+ if (offset + value.byteLength > wasm.byteLength)
155
+ throw new AssetIntegrityError('ECL ecl.wasm gzip output exceeds its receipt', context);
156
+ wasm.set(value, offset);
157
+ offset += value.byteLength;
158
+ }
159
+ }
160
+ catch (error) {
161
+ void reader.cancel().catch(() => undefined);
162
+ if (error instanceof AssetIntegrityError || signal?.aborted)
163
+ throw error;
164
+ throw new AssetIntegrityError('ECL ecl.wasm gzip decompression failed', {
165
+ ...context,
166
+ cause: error
167
+ });
168
+ }
169
+ if (offset !== wasm.byteLength)
170
+ throw new AssetIntegrityError('ECL ecl.wasm gzip output is truncated', context);
171
+ await verifyRuntimeAssetIntegrity({
172
+ asset: 'ecl.wasm',
173
+ bytes: wasm,
174
+ expected: {
175
+ ...expected,
176
+ uncompressedSha256: expected.sha256,
177
+ uncompressedBytes: expected.bytes
178
+ },
179
+ stage: 'uncompressed',
180
+ mimeType: 'application/wasm',
181
+ ...context
182
+ });
183
+ return wasm;
184
+ }
@@ -0,0 +1,6 @@
1
+ import Ruby from './ruby';
2
+ /** Runs the unchanged upstream GolfScript interpreter on the real bundled Ruby VM. */
3
+ declare class Golfscript extends Ruby {
4
+ constructor();
5
+ }
6
+ export default Golfscript;
@@ -0,0 +1,8 @@
1
+ import Ruby from './ruby';
2
+ /** Runs the unchanged upstream GolfScript interpreter on the real bundled Ruby VM. */
3
+ class Golfscript extends Ruby {
4
+ constructor() {
5
+ super('golfscript');
6
+ }
7
+ }
8
+ export default Golfscript;
@@ -1,6 +1,6 @@
1
1
  import type { BoundSandbox, PlaygroundBinding, Sandbox, SandboxRuntimeAssets } from './sandbox';
2
2
  import { type PlaygroundBindingOptions } from '@wasm-idle/core';
3
- export declare const supportedLanguages: ("C" | "CPP" | "OBJC" | "OBJECTIVECXX" | "D" | "TINYGO" | "RUBY" | "PERL" | "TCL" | "AWK" | "PASCAL" | "JANET" | "JULIA" | "NIM" | "BASH" | "BQN" | "CLOJURESCRIPT" | "FORTH" | "J" | "PROLOG" | "RESCRIPT" | "C3" | "PYTHON3" | "JAVA" | "RUST" | "GO" | "CSHARP" | "FSHARP" | "VBNET" | "ELIXIR" | "ERLANG" | "GLEAM" | "GRAIN" | "HY" | "FORTRAN" | "LFORTRAN" | "COBOL" | "V" | "OCAML" | "JAVASCRIPT" | "TYPESCRIPT" | "ASSEMBLYSCRIPT" | "WAT" | "WASM" | "LUA" | "FENNEL" | "ZIG" | "LISP" | "HASKELL" | "R" | "OCTAVE" | "DUCKDB" | "SQLITE" | "POSTGRESQL" | "PHP")[];
3
+ export declare const supportedLanguages: ("C" | "CPP" | "OBJC" | "OBJECTIVECXX" | "D" | "TINYGO" | "RUBY" | "PERL" | "TCL" | "AWK" | "PASCAL" | "JANET" | "JULIA" | "NIM" | "BASH" | "GOLFSCRIPT" | "APECODE" | "AHEUI" | "PYTHON3" | "BRAINFUCK" | "BEFUNGE93" | "WHITESPACE" | "MALBOLGE" | "UHMLANG" | "LOLCODE" | "WASM" | "BQN" | "CLOJURESCRIPT" | "FORTH" | "J" | "PROLOG" | "RESCRIPT" | "C3" | "JAVA" | "RUST" | "GO" | "CSHARP" | "FSHARP" | "VBNET" | "ELIXIR" | "ERLANG" | "GLEAM" | "GRAIN" | "HY" | "FORTRAN" | "LFORTRAN" | "LEAN4" | "COBOL" | "V" | "OCAML" | "JAVASCRIPT" | "TYPESCRIPT" | "ASSEMBLYSCRIPT" | "WAT" | "LUA" | "FENNEL" | "ZIG" | "LISP" | "COMMONLISP" | "HASKELL" | "R" | "OCTAVE" | "DUCKDB" | "SQLITE" | "POSTGRESQL" | "PHP")[];
4
4
  export declare function createPlaygroundBinding(runtimeAssets: SandboxRuntimeAssets, options?: PlaygroundBindingOptions): PlaygroundBinding;
5
5
  declare function playground(language: string): Promise<Sandbox>;
6
6
  declare function playground(language: string, runtimeAssets: SandboxRuntimeAssets, options?: PlaygroundBindingOptions): Promise<BoundSandbox>;
@@ -1,5 +1,86 @@
1
1
  import { createPlaygroundBinding as createCorePlaygroundBinding, isSupportedLanguageId, normalizeLanguageId, supportedLanguageIds } from '@wasm-idle/core';
2
2
  const sandboxRoutes = [
3
+ {
4
+ languageId: 'GOLFSCRIPT',
5
+ load: async () => {
6
+ const { default: Golfscript } = await import('./golfscript');
7
+ return new Golfscript();
8
+ }
9
+ },
10
+ {
11
+ languageId: 'APECODE',
12
+ load: async () => {
13
+ const { default: Apecode } = await import('./apecode');
14
+ return new Apecode();
15
+ }
16
+ },
17
+ {
18
+ languageId: 'LOLCODE',
19
+ load: async () => {
20
+ const [{ default: Wasm }, { WASI_INTERPRETERS }] = await Promise.all([
21
+ import('./wasm'),
22
+ import('./wasiInterpreters')
23
+ ]);
24
+ return new Wasm(WASI_INTERPRETERS.LOLCODE);
25
+ }
26
+ },
27
+ {
28
+ languageId: 'UHMLANG',
29
+ load: async () => {
30
+ const [{ default: Wasm }, { WASI_INTERPRETERS }] = await Promise.all([
31
+ import('./wasm'),
32
+ import('./wasiInterpreters')
33
+ ]);
34
+ return new Wasm(WASI_INTERPRETERS.UHMLANG);
35
+ }
36
+ },
37
+ {
38
+ languageId: 'AHEUI',
39
+ load: async () => {
40
+ const { default: Aheui } = await import('./aheui');
41
+ return new Aheui();
42
+ }
43
+ },
44
+ {
45
+ languageId: 'MALBOLGE',
46
+ load: async () => {
47
+ const [{ default: Wasm }, { WASI_INTERPRETERS }] = await Promise.all([
48
+ import('./wasm'),
49
+ import('./wasiInterpreters')
50
+ ]);
51
+ return new Wasm(WASI_INTERPRETERS.MALBOLGE);
52
+ }
53
+ },
54
+ {
55
+ languageId: 'WHITESPACE',
56
+ load: async () => {
57
+ const [{ default: Wasm }, { WASI_INTERPRETERS }] = await Promise.all([
58
+ import('./wasm'),
59
+ import('./wasiInterpreters')
60
+ ]);
61
+ return new Wasm(WASI_INTERPRETERS.WHITESPACE);
62
+ }
63
+ },
64
+ {
65
+ languageId: 'BEFUNGE93',
66
+ load: async () => {
67
+ const [{ default: Wasm }, { WASI_INTERPRETERS }] = await Promise.all([
68
+ import('./wasm'),
69
+ import('./wasiInterpreters')
70
+ ]);
71
+ return new Wasm(WASI_INTERPRETERS.BEFUNGE93);
72
+ }
73
+ },
74
+ {
75
+ languageId: 'BRAINFUCK',
76
+ load: async () => {
77
+ const [{ default: Wasm }, { WASI_INTERPRETERS }] = await Promise.all([
78
+ import('./wasm'),
79
+ import('./wasiInterpreters')
80
+ ]);
81
+ return new Wasm(WASI_INTERPRETERS.BRAINFUCK);
82
+ }
83
+ },
3
84
  {
4
85
  languageId: 'C3',
5
86
  load: async () => {
@@ -231,6 +312,13 @@ const sandboxRoutes = [
231
312
  return new LFortran();
232
313
  }
233
314
  },
315
+ {
316
+ languageId: 'LEAN4',
317
+ load: async () => {
318
+ const { default: Lean4 } = await import('./lean4');
319
+ return new Lean4();
320
+ }
321
+ },
234
322
  {
235
323
  languageId: 'FORTRAN',
236
324
  load: async () => {
@@ -329,6 +417,13 @@ const sandboxRoutes = [
329
417
  return new Lisp();
330
418
  }
331
419
  },
420
+ {
421
+ languageId: 'COMMONLISP',
422
+ load: async () => {
423
+ const { default: CommonLisp } = await import('./commonlisp');
424
+ return new CommonLisp();
425
+ }
426
+ },
332
427
  {
333
428
  languageId: 'RUBY',
334
429
  load: async () => {
@@ -0,0 +1,9 @@
1
+ import { type PreparedJavaStdinInjection } from './javaStdin';
2
+ /** Browser execution input is runtime data. Retain the snapshot API for standalone callers. */
3
+ export declare function prepareJavaRuntimeStdinInjection(code: string): PreparedJavaStdinInjection;
4
+ /** Single cursor shared by compatibility byte reads and bounded block reads. */
5
+ export declare function createJavaStdinBridge(initialInput: string, explicit: boolean, readInput: () => string | null, maxChunkBytes?: number): {
6
+ readByte(): number;
7
+ readChunk(): Int8Array | null;
8
+ dispose(): void;
9
+ };
@@ -0,0 +1,145 @@
1
+ import { prepareJavaStdinInjection } from './javaStdin';
2
+ /** Browser execution input is runtime data. Retain the snapshot API for standalone callers. */
3
+ export function prepareJavaRuntimeStdinInjection(code) {
4
+ const injection = prepareJavaStdinInjection(code, '', false);
5
+ if (!injection.usesStdin || !injection.helperSourcePath)
6
+ return injection;
7
+ const parts = injection.helperSourcePath.split('/');
8
+ const className = parts.pop().replace(/\.java$/, '');
9
+ const packageName = parts.join('.');
10
+ return {
11
+ ...injection,
12
+ stdinCacheKey: 'host-chunks-v2-jso',
13
+ helperSource: `${packageName ? `package ${packageName};\n\n` : ''}import java.io.InputStream;
14
+ import org.teavm.jso.JSObject;
15
+ import org.teavm.jso.browser.Window;
16
+ import org.teavm.jso.core.JSFunction;
17
+ import org.teavm.jso.core.JSMapLike;
18
+ import org.teavm.jso.core.JSObjects;
19
+ import org.teavm.jso.typedarrays.Int8Array;
20
+
21
+ final class ${className} extends InputStream {
22
+ private static final ${className} INSTANCE = new ${className}();
23
+ private byte[] chunk = new byte[0];
24
+ private int position = 0;
25
+ private boolean ended = false;
26
+
27
+ private ${className}() {}
28
+
29
+ static InputStream open() {
30
+ return INSTANCE;
31
+ }
32
+
33
+ // Use classlib overlay methods: the pinned source compiler cannot compile @JSBody.
34
+ // A host call obtains a block; copying its bytes keeps Java array ownership explicit.
35
+ private static byte[] readFromHost() {
36
+ Window current = Window.current();
37
+ if (current == null) return null;
38
+ JSMapLike<JSObject> globals = current.cast();
39
+ JSObject stdin = globals.get("wasmIdleJavaStdin");
40
+ if (stdin == null) return null;
41
+ JSMapLike<JSObject> input = stdin.cast();
42
+ if (JSObjects.hasProperty(stdin, "readChunk")) {
43
+ JSFunction readChunk = input.get("readChunk").cast();
44
+ JSObject result = (JSObject) readChunk.call(stdin);
45
+ if (result == null) return null;
46
+ Int8Array array = result.cast();
47
+ byte[] next = new byte[array.getLength()];
48
+ for (int i = 0; i < next.length; i++) next[i] = array.get(i);
49
+ return next;
50
+ }
51
+ JSFunction readByte = input.get("readByte").cast();
52
+ Object value = readByte.call(stdin);
53
+ int next = value != null ? Integer.parseInt(value.toString()) : -1;
54
+ return next < 0 ? null : new byte[] { (byte) next };
55
+ }
56
+
57
+ private boolean ensureChunk() {
58
+ while (position == chunk.length && !ended) {
59
+ byte[] next = readFromHost();
60
+ position = 0;
61
+ if (next == null) {
62
+ chunk = new byte[0];
63
+ ended = true;
64
+ } else {
65
+ chunk = next;
66
+ }
67
+ }
68
+ return position < chunk.length;
69
+ }
70
+
71
+ @Override
72
+ public int read() {
73
+ return ensureChunk() ? chunk[position++] & 0xff : -1;
74
+ }
75
+
76
+ @Override
77
+ public int read(byte[] bytes, int offset, int length) {
78
+ if (bytes == null) throw new NullPointerException();
79
+ if (offset < 0 || length < 0 || length > bytes.length - offset) {
80
+ throw new IndexOutOfBoundsException();
81
+ }
82
+ if (length == 0) return 0;
83
+ if (!ensureChunk()) return -1;
84
+ int count = Math.min(length, chunk.length - position);
85
+ System.arraycopy(chunk, position, bytes, offset, count);
86
+ position += count;
87
+ return count;
88
+ }
89
+
90
+ @Override
91
+ public int available() {
92
+ return chunk.length - position;
93
+ }
94
+ }
95
+ `
96
+ };
97
+ }
98
+ /** Single cursor shared by compatibility byte reads and bounded block reads. */
99
+ export function createJavaStdinBridge(initialInput, explicit, readInput, maxChunkBytes = 4096) {
100
+ if (!Number.isSafeInteger(maxChunkBytes) || maxChunkBytes < 1) {
101
+ throw new RangeError('Java stdin chunk size must be a positive safe integer');
102
+ }
103
+ const encoder = new TextEncoder();
104
+ let bytes = encoder.encode(initialInput);
105
+ let offset = 0;
106
+ let ended = false;
107
+ function ensureBytes() {
108
+ while (offset === bytes.length && !ended) {
109
+ const input = explicit ? null : readInput();
110
+ bytes = input === null ? new Uint8Array(0) : encoder.encode(input);
111
+ offset = 0;
112
+ ended = input === null;
113
+ }
114
+ return offset < bytes.length;
115
+ }
116
+ function releaseConsumed() {
117
+ if (offset === bytes.length) {
118
+ bytes = new Uint8Array(0);
119
+ offset = 0;
120
+ }
121
+ }
122
+ return {
123
+ readByte() {
124
+ if (!ensureBytes())
125
+ return -1;
126
+ const value = bytes[offset++];
127
+ releaseConsumed();
128
+ return value;
129
+ },
130
+ readChunk() {
131
+ if (!ensureBytes())
132
+ return null;
133
+ const count = Math.min(maxChunkBytes, bytes.length - offset);
134
+ const chunk = new Int8Array(bytes.buffer, bytes.byteOffset + offset, count);
135
+ offset += count;
136
+ releaseConsumed();
137
+ return chunk;
138
+ },
139
+ dispose() {
140
+ bytes = new Uint8Array(0);
141
+ offset = 0;
142
+ ended = true;
143
+ }
144
+ };
145
+ }
@@ -0,0 +1,13 @@
1
+ import { StaticWorkerRuntimeSandbox } from './staticWorkerRuntime';
2
+ /** Upstream Lean 4 frontend and IR interpreter (`lean --run`) compiled to wasm32 Emscripten. */
3
+ export default class Lean4 extends StaticWorkerRuntimeSandbox {
4
+ readonly defaultExecutionLimits: Readonly<{
5
+ maxWasmMemoryBytes: number;
6
+ }>;
7
+ readonly evidence: {
8
+ current: unknown;
9
+ };
10
+ constructor();
11
+ load(...args: Parameters<StaticWorkerRuntimeSandbox['load']>): Promise<void>;
12
+ run(...args: Parameters<StaticWorkerRuntimeSandbox['run']>): Promise<string | boolean>;
13
+ }
@@ -0,0 +1,50 @@
1
+ import { StaticWorkerRuntimeSandbox } from './staticWorkerRuntime';
2
+ import { LEAN4_DEFAULT_WASM_MEMORY_BYTES, preflightLean4RuntimeAssets, resolveLean4RuntimeAssetConfig } from './lean4Assets';
3
+ function lean4ExecutionOptions(options = {}) {
4
+ return {
5
+ ...options,
6
+ limits: {
7
+ ...options.limits,
8
+ maxWasmMemoryBytes: options.limits?.maxWasmMemoryBytes ?? LEAN4_DEFAULT_WASM_MEMORY_BYTES
9
+ }
10
+ };
11
+ }
12
+ /** Upstream Lean 4 frontend and IR interpreter (`lean --run`) compiled to wasm32 Emscripten. */
13
+ export default class Lean4 extends StaticWorkerRuntimeSandbox {
14
+ defaultExecutionLimits = Object.freeze({
15
+ maxWasmMemoryBytes: LEAN4_DEFAULT_WASM_MEMORY_BYTES
16
+ });
17
+ evidence;
18
+ constructor() {
19
+ const evidence = { current: undefined };
20
+ super({
21
+ displayName: 'Lean 4',
22
+ languageId: 'LEAN4',
23
+ defaultActivePath: 'Main.lean',
24
+ workerLifetime: { mode: 'per-run' },
25
+ runtimePreflightDelivery: 'transfer-owned',
26
+ inlineVerifiedWorker: true,
27
+ requireExactWorkerResponseUrl: true,
28
+ moduleWorker: true,
29
+ includeExecutionLimits: true,
30
+ onEvidence(value) {
31
+ evidence.current = value;
32
+ },
33
+ stdin: { mode: 'streaming', sourceHintPattern: /\b(?:getStdin|getLine|readToEnd)\b/u },
34
+ resolveRuntimeAssets: resolveLean4RuntimeAssetConfig,
35
+ async preflightRuntimeAssets(urls, context) {
36
+ evidence.current = undefined;
37
+ return context.createOwnedDelivery(await preflightLean4RuntimeAssets(urls.baseUrl, context));
38
+ }
39
+ });
40
+ this.evidence = evidence;
41
+ }
42
+ async load(...args) {
43
+ args[4] = lean4ExecutionOptions(args[4]);
44
+ return super.load(...args);
45
+ }
46
+ async run(...args) {
47
+ args[5] = lean4ExecutionOptions(args[5]);
48
+ return super.run(...args);
49
+ }
50
+ }
@@ -0,0 +1,25 @@
1
+ import { type ExecutionLimits, type RuntimeAssetCacheOptions } from '@wasm-idle/core';
2
+ import type { PlaygroundRuntimeAssets } from './assets';
3
+ /** Linear memory needed to start Lean, import Init, and interpret a small program. */
4
+ export declare const LEAN4_INITIAL_MEMORY_BYTES: number;
5
+ /** Default limit: importing the 277 MB Init library grows the heap to about 370 MiB. */
6
+ export declare const LEAN4_DEFAULT_WASM_MEMORY_BYTES: number;
7
+ export declare const LEAN4_RUNTIME_MANIFEST: import("@wasm-idle/core").RuntimeRegistryManifest;
8
+ export declare function resolveLean4RuntimeAssetConfig(runtimeAssets: string | PlaygroundRuntimeAssets, currentUrl: string): {
9
+ baseUrl: string;
10
+ workerUrl: string;
11
+ manifestFingerprint: "e60eb3fdcc108fa7c6127c5a8925ffb622706facb17bc4f84e9ed27f82495fa1";
12
+ workerReceipt: {
13
+ readonly bytes: 15759;
14
+ readonly sha256: "469ef5ec7accf4c221d06134ccd4989f14e9229c61dd35c386617a015aec6f03";
15
+ };
16
+ };
17
+ export declare function preflightLean4RuntimeAssets(baseUrl: string, options: {
18
+ limits: ExecutionLimits;
19
+ persistentCache?: RuntimeAssetCacheOptions;
20
+ signal?: AbortSignal;
21
+ reportProgress?: (value: number, stage: string) => void;
22
+ fetch?: typeof globalThis.fetch;
23
+ }): Promise<Readonly<{
24
+ fingerprint: "e60eb3fdcc108fa7c6127c5a8925ffb622706facb17bc4f84e9ed27f82495fa1";
25
+ }>>;