wasm-idle 0.3.1 → 0.4.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 (38) hide show
  1. package/README.md +4 -2
  2. package/dist/clang/app.d.ts +4 -1
  3. package/dist/clang/app.js +159 -117
  4. package/dist/clang/index.d.ts +1 -0
  5. package/dist/clang/index.js +80 -2
  6. package/dist/debug/expression.js +135 -19
  7. package/dist/debug/index.d.ts +1 -1
  8. package/dist/debug/index.js +1 -1
  9. package/dist/debug/language/index.d.ts +1 -0
  10. package/dist/debug/language/index.js +1 -0
  11. package/dist/debug/language/python.d.ts +2 -0
  12. package/dist/debug/language/python.js +14 -0
  13. package/dist/index.d.ts +2 -1
  14. package/dist/index.js +1 -1
  15. package/dist/playground/clang.d.ts +5 -2
  16. package/dist/playground/clang.js +44 -18
  17. package/dist/playground/index.d.ts +2 -1
  18. package/dist/playground/index.js +7 -1
  19. package/dist/playground/java.d.ts +28 -0
  20. package/dist/playground/java.js +135 -0
  21. package/dist/playground/javaStdin.d.ts +8 -0
  22. package/dist/playground/javaStdin.js +90 -0
  23. package/dist/playground/options.d.ts +10 -0
  24. package/dist/playground/python.d.ts +15 -5
  25. package/dist/playground/python.js +98 -21
  26. package/dist/playground/sandbox.d.ts +3 -1
  27. package/dist/playground/stdinBuffer.d.ts +7 -0
  28. package/dist/playground/stdinBuffer.js +100 -0
  29. package/dist/playground/teavmConfig.d.ts +3 -0
  30. package/dist/playground/teavmConfig.js +14 -0
  31. package/dist/playground/worker/clang.js +2 -20
  32. package/dist/playground/worker/java.d.ts +1 -0
  33. package/dist/playground/worker/java.js +248 -0
  34. package/dist/playground/worker/python.js +253 -27
  35. package/dist/terminal/Terminal.svelte +41 -11
  36. package/dist/terminal/Terminal.svelte.d.ts +2 -1
  37. package/dist/terminal/types.d.ts +3 -2
  38. package/package.json +1 -1
@@ -8,6 +8,38 @@ export function evaluateDebugExpression(expression, variables) {
8
8
  values.set(variable.name, variable.value);
9
9
  const parsedValues = new Map();
10
10
  const tokens = [];
11
+ const parseQuotedValue = (text, start) => {
12
+ const quote = text[start];
13
+ if (quote !== "'" && quote !== '"')
14
+ throw new Error('expected quoted string');
15
+ let index = start + 1;
16
+ let value = '';
17
+ while (index < text.length) {
18
+ const character = text[index];
19
+ if (!character)
20
+ break;
21
+ if (character === '\\') {
22
+ const escaped = text[index + 1];
23
+ if (!escaped)
24
+ throw new Error('unterminated string literal');
25
+ if (escaped === 'n')
26
+ value += '\n';
27
+ else if (escaped === 'r')
28
+ value += '\r';
29
+ else if (escaped === 't')
30
+ value += '\t';
31
+ else
32
+ value += escaped;
33
+ index += 2;
34
+ continue;
35
+ }
36
+ if (character === quote)
37
+ return { value, next: index + 1 };
38
+ value += character;
39
+ index += 1;
40
+ }
41
+ throw new Error('unterminated string literal');
42
+ };
11
43
  for (let index = 0; index < source.length;) {
12
44
  const character = source[index];
13
45
  if (!character)
@@ -32,6 +64,12 @@ export function evaluateDebugExpression(expression, variables) {
32
64
  index += operator.length;
33
65
  continue;
34
66
  }
67
+ if (character === "'" || character === '"') {
68
+ const parsed = parseQuotedValue(source, index);
69
+ tokens.push({ type: 'string', value: parsed.value });
70
+ index = parsed.next;
71
+ continue;
72
+ }
35
73
  const number = source.slice(index).match(/^\d+(?:\.\d+)?/);
36
74
  if (number?.[0]) {
37
75
  tokens.push({ type: 'number', value: number[0] });
@@ -40,8 +78,26 @@ export function evaluateDebugExpression(expression, variables) {
40
78
  }
41
79
  const identifier = source.slice(index).match(/^[A-Za-z_]\w*/);
42
80
  if (identifier?.[0]) {
43
- if (identifier[0] === 'true' || identifier[0] === 'false') {
44
- tokens.push({ type: 'boolean', value: identifier[0] === 'true' });
81
+ if (identifier[0] === 'true' ||
82
+ identifier[0] === 'false' ||
83
+ identifier[0] === 'True' ||
84
+ identifier[0] === 'False') {
85
+ tokens.push({
86
+ type: 'boolean',
87
+ value: identifier[0] === 'true' || identifier[0] === 'True'
88
+ });
89
+ }
90
+ else if (identifier[0] === 'null' || identifier[0] === 'None') {
91
+ tokens.push({ type: 'null' });
92
+ }
93
+ else if (identifier[0] === 'and') {
94
+ tokens.push({ type: 'operator', value: '&&' });
95
+ }
96
+ else if (identifier[0] === 'or') {
97
+ tokens.push({ type: 'operator', value: '||' });
98
+ }
99
+ else if (identifier[0] === 'not') {
100
+ tokens.push({ type: 'operator', value: '!' });
45
101
  }
46
102
  else {
47
103
  tokens.push({ type: 'identifier', value: identifier[0] });
@@ -81,16 +137,44 @@ export function evaluateDebugExpression(expression, variables) {
81
137
  throw new Error('unsupported array preview');
82
138
  }
83
139
  }
84
- if (character === "'") {
85
- const end = text.indexOf("'", index + 1);
86
- if (end === -1)
87
- throw new Error('unsupported char preview');
88
- return { value: text.slice(index + 1, end), next: end + 1 };
140
+ if (character === '(') {
141
+ index += 1;
142
+ const items = [];
143
+ while (true) {
144
+ while (/\s/.test(text[index] || ''))
145
+ index += 1;
146
+ if (text[index] === ')')
147
+ return { value: items, next: index + 1 };
148
+ if (text.startsWith('...', index))
149
+ throw new Error('unavailable');
150
+ const item = parsePreviewValue(text, index);
151
+ items.push(item.value);
152
+ index = item.next;
153
+ while (/\s/.test(text[index] || ''))
154
+ index += 1;
155
+ if (text[index] === ',') {
156
+ index += 1;
157
+ continue;
158
+ }
159
+ if (text[index] === ')')
160
+ return { value: items, next: index + 1 };
161
+ throw new Error('unsupported tuple preview');
162
+ }
89
163
  }
164
+ if (character === "'" || character === '"')
165
+ return parseQuotedValue(text, index);
90
166
  if (text.startsWith('true', index))
91
167
  return { value: true, next: index + 4 };
92
168
  if (text.startsWith('false', index))
93
169
  return { value: false, next: index + 5 };
170
+ if (text.startsWith('True', index))
171
+ return { value: true, next: index + 4 };
172
+ if (text.startsWith('False', index))
173
+ return { value: false, next: index + 5 };
174
+ if (text.startsWith('null', index))
175
+ return { value: null, next: index + 4 };
176
+ if (text.startsWith('None', index))
177
+ return { value: null, next: index + 4 };
94
178
  const number = text.slice(index).match(/^-?\d+(?:\.\d+)?/);
95
179
  if (number?.[0])
96
180
  return { value: Number(number[0]), next: index + number[0].length };
@@ -102,17 +186,24 @@ export function evaluateDebugExpression(expression, variables) {
102
186
  const value = values.get(name);
103
187
  if (value == null || value === '?')
104
188
  throw new Error('unavailable');
105
- if (value === 'true' || value === 'false') {
106
- const parsed = value === 'true';
189
+ if (value === 'true' || value === 'false' || value === 'True' || value === 'False') {
190
+ const parsed = value === 'true' || value === 'True';
107
191
  parsedValues.set(name, parsed);
108
192
  return parsed;
109
193
  }
194
+ if (value === 'null' || value === 'None') {
195
+ parsedValues.set(name, null);
196
+ return null;
197
+ }
110
198
  const numeric = Number(value);
111
199
  if (!Number.isNaN(numeric)) {
112
200
  parsedValues.set(name, numeric);
113
201
  return numeric;
114
202
  }
115
- if (value.startsWith('[')) {
203
+ if (value.startsWith('[') ||
204
+ value.startsWith('(') ||
205
+ value.startsWith("'") ||
206
+ value.startsWith('"')) {
116
207
  const parsed = parsePreviewValue(value).value;
117
208
  parsedValues.set(name, parsed);
118
209
  return parsed;
@@ -131,10 +222,21 @@ export function evaluateDebugExpression(expression, variables) {
131
222
  cursor += 1;
132
223
  return token.value;
133
224
  }
225
+ if (token.type === 'null') {
226
+ cursor += 1;
227
+ return null;
228
+ }
229
+ if (token.type === 'string') {
230
+ cursor += 1;
231
+ return token.value;
232
+ }
134
233
  if (token.type === 'identifier') {
135
234
  cursor += 1;
136
235
  let resolved = resolveIdentifierValue(token.value);
137
- while (tokens[cursor]?.type === 'bracket' && tokens[cursor]?.value === '[') {
236
+ while (true) {
237
+ const bracket = tokens[cursor];
238
+ if (!bracket || bracket.type !== 'bracket' || bracket.value !== '[')
239
+ break;
138
240
  cursor += 1;
139
241
  const index = Number(parseOr());
140
242
  const closing = tokens[cursor];
@@ -201,8 +303,14 @@ export function evaluateDebugExpression(expression, variables) {
201
303
  return left;
202
304
  cursor += 1;
203
305
  const right = parseMul();
204
- if (operator.value === '+')
205
- left = Number(left) + Number(right);
306
+ if (operator.value === '+') {
307
+ if (typeof left === 'string' || typeof right === 'string') {
308
+ left = `${left ?? 'null'}${right ?? 'null'}`;
309
+ }
310
+ else {
311
+ left = Number(left) + Number(right);
312
+ }
313
+ }
206
314
  if (operator.value === '-')
207
315
  left = Number(left) - Number(right);
208
316
  }
@@ -215,14 +323,16 @@ export function evaluateDebugExpression(expression, variables) {
215
323
  return left;
216
324
  cursor += 1;
217
325
  const right = parseAdd();
326
+ const leftValue = typeof left === 'string' && typeof right === 'string' ? left : Number(left);
327
+ const rightValue = typeof left === 'string' && typeof right === 'string' ? right : Number(right);
218
328
  if (operator.value === '<')
219
- left = Number(left) < Number(right);
329
+ left = leftValue < rightValue;
220
330
  if (operator.value === '<=')
221
- left = Number(left) <= Number(right);
331
+ left = leftValue <= rightValue;
222
332
  if (operator.value === '>')
223
- left = Number(left) > Number(right);
333
+ left = leftValue > rightValue;
224
334
  if (operator.value === '>=')
225
- left = Number(left) >= Number(right);
335
+ left = leftValue >= rightValue;
226
336
  }
227
337
  };
228
338
  const parseEquality = () => {
@@ -241,7 +351,10 @@ export function evaluateDebugExpression(expression, variables) {
241
351
  };
242
352
  const parseAnd = () => {
243
353
  let left = parseEquality();
244
- while (tokens[cursor]?.type === 'operator' && tokens[cursor]?.value === '&&') {
354
+ while (true) {
355
+ const operator = tokens[cursor];
356
+ if (!operator || operator.type !== 'operator' || operator.value !== '&&')
357
+ break;
245
358
  cursor += 1;
246
359
  left = Boolean(left) && Boolean(parseEquality());
247
360
  }
@@ -249,7 +362,10 @@ export function evaluateDebugExpression(expression, variables) {
249
362
  };
250
363
  const parseOr = () => {
251
364
  let left = parseAnd();
252
- while (tokens[cursor]?.type === 'operator' && tokens[cursor]?.value === '||') {
365
+ while (true) {
366
+ const operator = tokens[cursor];
367
+ if (!operator || operator.type !== 'operator' || operator.value !== '||')
368
+ break;
253
369
  cursor += 1;
254
370
  left = Boolean(left) || Boolean(parseAnd());
255
371
  }
@@ -1,5 +1,5 @@
1
1
  export { evaluateDebugExpression } from './expression';
2
2
  export { selectInlineDebugLocals } from './locals';
3
- export { cppDebugLanguageAdapter } from './language';
3
+ export { cppDebugLanguageAdapter, pythonDebugLanguageAdapter } from './language';
4
4
  export { MonacoDebugView } from './editor';
5
5
  export type { DebugLanguageAdapter } from './language';
@@ -1,4 +1,4 @@
1
1
  export { evaluateDebugExpression } from './expression';
2
2
  export { selectInlineDebugLocals } from './locals';
3
- export { cppDebugLanguageAdapter } from './language';
3
+ export { cppDebugLanguageAdapter, pythonDebugLanguageAdapter } from './language';
4
4
  export { MonacoDebugView } from './editor';
@@ -1,2 +1,3 @@
1
1
  export { cppDebugLanguageAdapter } from './cpp';
2
+ export { pythonDebugLanguageAdapter } from './python';
2
3
  export type { DebugLanguageAdapter } from './types';
@@ -1 +1,2 @@
1
1
  export { cppDebugLanguageAdapter } from './cpp';
2
+ export { pythonDebugLanguageAdapter } from './python';
@@ -0,0 +1,2 @@
1
+ import type { DebugLanguageAdapter } from './types';
2
+ export declare const pythonDebugLanguageAdapter: DebugLanguageAdapter;
@@ -0,0 +1,14 @@
1
+ import { evaluateDebugExpression } from '../expression';
2
+ const selectInlinePythonLocals = (lineText, locals) => {
3
+ const sanitized = lineText
4
+ .replace(/#.*$/g, ' ')
5
+ .replace(/"(?:\\.|[^"\\])*"/g, ' ')
6
+ .replace(/'(?:\\.|[^'\\])*'/g, ' ');
7
+ const identifiers = new Set(sanitized.match(/[A-Za-z_]\w*/g) || []);
8
+ return locals.filter((variable) => identifiers.has(variable.name));
9
+ };
10
+ export const pythonDebugLanguageAdapter = {
11
+ id: 'python',
12
+ evaluateExpression: evaluateDebugExpression,
13
+ selectInlineLocals: selectInlinePythonLocals
14
+ };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import Terminal from './terminal';
2
- export { cppDebugLanguageAdapter, evaluateDebugExpression, MonacoDebugView, selectInlineDebugLocals } from './debug';
2
+ export { cppDebugLanguageAdapter, pythonDebugLanguageAdapter, evaluateDebugExpression, MonacoDebugView, selectInlineDebugLocals } from './debug';
3
3
  import playground from './playground';
4
4
  export default Terminal;
5
5
  export { playground };
6
6
  export type { DebugCommand, DebugFrame, DebugSessionEvent, DebugVariable, SandboxExecutionOptions, TerminalControl } from './terminal';
7
+ export type { CompilerDiagnostic } from './playground/options';
7
8
  export type { DebugLanguageAdapter } from './debug';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import Terminal from './terminal';
2
- export { cppDebugLanguageAdapter, evaluateDebugExpression, MonacoDebugView, selectInlineDebugLocals } from './debug';
2
+ export { cppDebugLanguageAdapter, pythonDebugLanguageAdapter, evaluateDebugExpression, MonacoDebugView, selectInlineDebugLocals } from './debug';
3
3
  import playground from './playground';
4
4
  export default Terminal;
5
5
  export { playground };
@@ -9,20 +9,23 @@ declare class Clang implements Sandbox {
9
9
  buffer: SharedArrayBuffer;
10
10
  debugBuffer: SharedArrayBuffer;
11
11
  interruptBuffer: SharedArrayBuffer;
12
- internalBuffer: string[];
12
+ pendingInput: string[];
13
13
  begin: number;
14
14
  elapse: number;
15
15
  uid: number;
16
16
  log: boolean;
17
+ waitingForInput: boolean;
18
+ pendingEof: boolean;
17
19
  exit: boolean;
18
20
  load(path: string, code?: string, log?: boolean, args?: string[], _options?: SandboxExecutionOptions): Promise<void>;
19
21
  write(input: string): void;
20
- _write(input: string): void;
21
22
  eof(): void;
23
+ private flushPendingInput;
22
24
  run(code: string, prepare: boolean, log?: boolean, prog?: Writable<number> | {
23
25
  set?: (value: number) => void;
24
26
  }, args?: string[], options?: SandboxExecutionOptions): Promise<boolean | string>;
25
27
  debugCommand(command: DebugCommand): void;
28
+ kill(): void;
26
29
  terminate(): void;
27
30
  clear(): Promise<void>;
28
31
  }
@@ -1,3 +1,4 @@
1
+ import { flushBufferedEof, flushQueuedStdin, resetBufferedStdin } from './stdinBuffer';
1
2
  class Clang {
2
3
  ts = Date.now();
3
4
  output = null;
@@ -6,16 +7,20 @@ class Clang {
6
7
  buffer = new SharedArrayBuffer(1024);
7
8
  debugBuffer = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4);
8
9
  interruptBuffer = new SharedArrayBuffer(1);
9
- internalBuffer = [];
10
+ pendingInput = [];
10
11
  begin = 0;
11
12
  elapse = 0;
12
13
  uid = 0;
13
14
  log = true;
15
+ waitingForInput = false;
16
+ pendingEof = false;
14
17
  exit = true;
15
18
  load(path, code = '', log = true, args = [], _options = {}) {
16
19
  return new Promise(async (resolve) => {
17
20
  this.log = log;
18
- this.internalBuffer = [];
21
+ this.pendingInput = [];
22
+ this.waitingForInput = false;
23
+ this.pendingEof = false;
19
24
  if (!this.worker) {
20
25
  this.worker = new (await import('./worker/clang?worker')).default();
21
26
  this.worker.onmessage = () => resolve();
@@ -28,19 +33,27 @@ class Clang {
28
33
  });
29
34
  }
30
35
  write(input) {
31
- this.internalBuffer.push(input);
36
+ this.pendingInput.push(input);
37
+ this.pendingEof = false;
38
+ this.flushPendingInput();
32
39
  }
33
- _write(input) {
34
- let strInfo = input, padding = 4 - (strInfo.length % 4);
35
- while (strInfo.length % 4 !== 3)
36
- strInfo += ' ';
37
- strInfo += padding;
38
- const buffer = new Int32Array(this.buffer);
39
- const enc = new TextEncoder();
40
- const data = enc.encode(strInfo);
41
- buffer.set(new Int32Array(data.buffer.slice(data.byteOffset), 0));
40
+ eof() {
41
+ this.pendingEof = true;
42
+ this.flushPendingInput();
43
+ }
44
+ flushPendingInput() {
45
+ if (!this.waitingForInput)
46
+ return;
47
+ if (flushQueuedStdin(this.pendingInput, this.buffer)) {
48
+ this.waitingForInput = false;
49
+ return;
50
+ }
51
+ if (this.pendingEof) {
52
+ flushBufferedEof(this.buffer);
53
+ this.pendingEof = false;
54
+ this.waitingForInput = false;
55
+ }
42
56
  }
43
- eof() { }
44
57
  run(code, prepare, log = this.log, prog, args = [], options = {}) {
45
58
  this.exit = false;
46
59
  return new Promise(async (resolve, reject) => {
@@ -53,8 +66,10 @@ class Clang {
53
66
  if (_uid !== this.uid)
54
67
  return (this.worker.onmessage = null);
55
68
  const { id, output, results, log, error, buffer, progress, debugEvent } = event.data;
56
- if (buffer && this.internalBuffer.length)
57
- this._write(this.internalBuffer.splice(0, 1)[0]);
69
+ if (buffer) {
70
+ this.waitingForInput = true;
71
+ this.flushPendingInput();
72
+ }
58
73
  if (output)
59
74
  this.output(output);
60
75
  if (debugEvent)
@@ -62,6 +77,8 @@ class Clang {
62
77
  if (results) {
63
78
  this.elapse = Date.now() - this.begin;
64
79
  this.exit = true;
80
+ this.waitingForInput = false;
81
+ this.pendingEof = false;
65
82
  this.ondebug?.({ type: 'stop' });
66
83
  resolve(results);
67
84
  }
@@ -69,6 +86,10 @@ class Clang {
69
86
  console.log(log);
70
87
  if (error) {
71
88
  this.elapse = Date.now() - this.begin;
89
+ this.waitingForInput = false;
90
+ this.pendingEof = false;
91
+ this.exit = true;
92
+ this.ondebug?.({ type: 'stop' });
72
93
  reject(error);
73
94
  }
74
95
  if (progress)
@@ -99,7 +120,11 @@ class Clang {
99
120
  Atomics.notify(control, 0);
100
121
  this.ondebug?.({ type: 'resume', command });
101
122
  }
123
+ kill() {
124
+ this.terminate();
125
+ }
102
126
  terminate() {
127
+ this.pendingEof = false;
103
128
  new Uint8Array(this.interruptBuffer)[0] = 2;
104
129
  const control = new Int32Array(this.debugBuffer);
105
130
  Atomics.add(control, 0, 1);
@@ -107,11 +132,12 @@ class Clang {
107
132
  }
108
133
  async clear() {
109
134
  this.terminate();
110
- this.internalBuffer = [];
135
+ this.pendingInput = [];
136
+ this.waitingForInput = false;
137
+ this.pendingEof = false;
111
138
  if (this.worker)
112
139
  this.worker.onmessage = null;
113
- const buffer = new Int32Array(this.buffer);
114
- buffer.fill(0);
140
+ resetBufferedStdin(this.buffer);
115
141
  const debugBuffer = new Int32Array(this.debugBuffer);
116
142
  debugBuffer.fill(0);
117
143
  await new Promise((resolve) => setTimeout(resolve, 200));
@@ -1,5 +1,6 @@
1
1
  import Clang from './clang';
2
+ import Java from './java';
2
3
  import Python from './python';
3
4
  import type { Sandbox } from './sandbox';
4
5
  export declare const supportedLanguages: string[];
5
- export default function load(language: string): Promise<Sandbox | Clang | Python>;
6
+ export default function load(language: string): Promise<Sandbox | Clang | Java | Python>;
@@ -1,7 +1,8 @@
1
1
  import Clang from './clang';
2
+ import Java from './java';
2
3
  import Python from './python';
3
4
  const sandboxCache = {};
4
- export const supportedLanguages = ['PYTHON3', 'PYPY3', 'C', 'CPP'];
5
+ export const supportedLanguages = ['PYTHON3', 'PYPY3', 'C', 'CPP', 'JAVA'];
5
6
  export default async function load(language) {
6
7
  if (sandboxCache[language])
7
8
  return sandboxCache[language];
@@ -16,6 +17,9 @@ export default async function load(language) {
16
17
  case 'CPP':
17
18
  sandbox = new Clang();
18
19
  break;
20
+ case 'JAVA':
21
+ sandbox = new Java();
22
+ break;
19
23
  default:
20
24
  throw new Error(`Unsupported language: ${language}`);
21
25
  }
@@ -31,6 +35,8 @@ export default async function load(language) {
31
35
  sandboxCache['C'] = sandbox;
32
36
  if (language === 'CPP')
33
37
  sandboxCache['CPP'] = sandbox;
38
+ if (language === 'JAVA')
39
+ sandboxCache['JAVA'] = sandbox;
34
40
  }
35
41
  return sandbox;
36
42
  }
@@ -0,0 +1,28 @@
1
+ import type { CompilerDiagnostic, SandboxExecutionOptions } from './options';
2
+ import type { Sandbox } from './sandbox';
3
+ declare class Java implements Sandbox {
4
+ output: any;
5
+ worker?: Worker;
6
+ buffer: SharedArrayBuffer;
7
+ pendingInput: string[];
8
+ begin: number;
9
+ elapse: number;
10
+ uid: number;
11
+ exit: boolean;
12
+ baseUrl: string;
13
+ activeReject: ((reason: string) => void) | null;
14
+ oncompilerdiagnostic?: (diagnostic: CompilerDiagnostic) => void;
15
+ waitingForInput: boolean;
16
+ pendingEof: boolean;
17
+ load(path: string, _code?: string, _log?: boolean, _args?: string[], _options?: SandboxExecutionOptions): Promise<void>;
18
+ write(input: string): void;
19
+ eof(): void;
20
+ private flushPendingInput;
21
+ run(code: string, prepare: boolean, _log?: boolean, _prog?: {
22
+ set?: (value: number) => void;
23
+ } | import('svelte/store').Writable<number>, args?: string[], options?: SandboxExecutionOptions): Promise<boolean | string>;
24
+ kill(): void;
25
+ terminate(): void;
26
+ clear(): Promise<void>;
27
+ }
28
+ export default Java;
@@ -0,0 +1,135 @@
1
+ import { flushBufferedEof, flushQueuedStdin, resetBufferedStdin } from './stdinBuffer';
2
+ import { resolveTeaVmBaseUrl } from './teavmConfig';
3
+ class Java {
4
+ output = null;
5
+ worker = null;
6
+ buffer = new SharedArrayBuffer(1024);
7
+ pendingInput = [];
8
+ begin = 0;
9
+ elapse = 0;
10
+ uid = 0;
11
+ exit = true;
12
+ baseUrl = '';
13
+ activeReject = null;
14
+ oncompilerdiagnostic;
15
+ waitingForInput = false;
16
+ pendingEof = false;
17
+ load(path, _code = '', _log = true, _args = [], _options = {}) {
18
+ return new Promise(async (resolve, reject) => {
19
+ this.pendingInput = [];
20
+ this.waitingForInput = false;
21
+ this.pendingEof = false;
22
+ this.baseUrl = resolveTeaVmBaseUrl(path, typeof window !== 'undefined' ? window.location.href : '');
23
+ if (!this.worker) {
24
+ this.worker = new (await import('./worker/java?worker')).default();
25
+ this.worker.onmessage = (event) => {
26
+ if (event.data?.load)
27
+ resolve();
28
+ if (event.data?.error)
29
+ reject(event.data.error);
30
+ };
31
+ this.worker.postMessage({ load: true, baseUrl: this.baseUrl });
32
+ }
33
+ else {
34
+ resolve();
35
+ }
36
+ });
37
+ }
38
+ write(input) {
39
+ this.pendingInput.push(input);
40
+ this.pendingEof = false;
41
+ this.flushPendingInput();
42
+ }
43
+ eof() {
44
+ this.pendingEof = true;
45
+ this.flushPendingInput();
46
+ }
47
+ flushPendingInput() {
48
+ if (!this.waitingForInput)
49
+ return;
50
+ if (flushQueuedStdin(this.pendingInput, this.buffer)) {
51
+ this.waitingForInput = false;
52
+ return;
53
+ }
54
+ if (this.pendingEof) {
55
+ flushBufferedEof(this.buffer);
56
+ this.pendingEof = false;
57
+ this.waitingForInput = false;
58
+ }
59
+ }
60
+ run(code, prepare, _log = true, _prog, args = [], options = {}) {
61
+ this.exit = false;
62
+ return new Promise((resolve, reject) => {
63
+ if (!this.worker)
64
+ return reject('Worker not loaded');
65
+ const _uid = ++this.uid;
66
+ this.activeReject = reject;
67
+ const handler = (event) => {
68
+ if (!this.worker)
69
+ return reject('Worker not loaded');
70
+ if (_uid !== this.uid)
71
+ return (this.worker.onmessage = null);
72
+ const { output, results, error, buffer, diagnostic } = event.data;
73
+ if (buffer) {
74
+ this.waitingForInput = true;
75
+ this.flushPendingInput();
76
+ }
77
+ if (output)
78
+ this.output(output);
79
+ if (diagnostic)
80
+ this.oncompilerdiagnostic?.(diagnostic);
81
+ if (results) {
82
+ this.elapse = Date.now() - this.begin;
83
+ this.exit = true;
84
+ this.waitingForInput = false;
85
+ this.pendingEof = false;
86
+ this.activeReject = null;
87
+ resolve(results);
88
+ }
89
+ if (error) {
90
+ this.elapse = Date.now() - this.begin;
91
+ this.exit = true;
92
+ this.waitingForInput = false;
93
+ this.pendingEof = false;
94
+ this.activeReject = null;
95
+ reject(error);
96
+ }
97
+ };
98
+ this.worker.onmessage = handler;
99
+ this.begin = Date.now();
100
+ this.worker.postMessage({
101
+ code,
102
+ prepare,
103
+ buffer: this.buffer,
104
+ args,
105
+ stdin: options.stdin || '',
106
+ baseUrl: this.baseUrl
107
+ });
108
+ });
109
+ }
110
+ kill() {
111
+ this.terminate();
112
+ }
113
+ terminate() {
114
+ this.activeReject?.('Process terminated');
115
+ this.activeReject = null;
116
+ this.waitingForInput = false;
117
+ this.pendingEof = false;
118
+ this.uid += 1;
119
+ this.worker?.terminate?.();
120
+ delete this.worker;
121
+ this.exit = true;
122
+ }
123
+ async clear() {
124
+ this.pendingInput = [];
125
+ this.waitingForInput = false;
126
+ this.pendingEof = false;
127
+ if (this.worker)
128
+ this.worker.onmessage = null;
129
+ resetBufferedStdin(this.buffer);
130
+ if (!this.exit) {
131
+ this.terminate();
132
+ }
133
+ }
134
+ }
135
+ export default Java;
@@ -0,0 +1,8 @@
1
+ export interface PreparedJavaStdinInjection {
2
+ usesStdin: boolean;
3
+ stdinCacheKey: string;
4
+ transformedCode: string;
5
+ helperSourcePath: string | null;
6
+ helperSource: string | null;
7
+ }
8
+ export declare const prepareJavaStdinInjection: (code: string, stdin: string) => PreparedJavaStdinInjection;