Skip to content

Commit fe1b57d

Browse files
Make brainfuck interpreter updates asynchronous (#108)
- allow the interpreter loop to yield to the browser for live UI updates - clear status messages and outputs before each run so the UI refreshes cleanly ------ [Codex Task](https://chatgpt.com/codex/tasks/task_e_69599edb57988325a00c3af13f44fbc1)
1 parent 43184f5 commit fe1b57d

1 file changed

Lines changed: 26 additions & 5 deletions

File tree

brainfuck-interpreter.html

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,17 @@ <h2 style="margin: 0;">Fail-safe settings</h2>
417417
return settings;
418418
}
419419

420-
function runProgram(program, inputs, failsafeSettings, onOutput) {
420+
function waitForNextFrame() {
421+
return new Promise((resolve) => {
422+
if (typeof requestAnimationFrame === 'function') {
423+
requestAnimationFrame(() => resolve());
424+
} else {
425+
setTimeout(resolve, 0);
426+
}
427+
});
428+
}
429+
430+
async function runProgram(program, inputs, failsafeSettings, onOutput) {
421431
const commands = program.replace(/[^\>\<\+\-\.\,\[\]]/g, '');
422432
const jumpMap = buildJumpMap(commands);
423433

@@ -428,6 +438,8 @@ <h2 style="margin: 0;">Fail-safe settings</h2>
428438
const output = [];
429439
const timeoutMs = failsafeSettings.timeoutSeconds * 1000;
430440
const startTime = performance.now();
441+
const yieldInterval = 2000;
442+
let stepsUntilYield = yieldInterval;
431443

432444
function enforceFailSafe(message) {
433445
const debugInfo = [
@@ -463,7 +475,7 @@ <h2 style="margin: 0;">Fail-safe settings</h2>
463475
case '.':
464476
output.push(tape[pointer]);
465477
if (onOutput) {
466-
onOutput(tape[pointer], output);
478+
await onOutput(tape[pointer], output);
467479
}
468480
break;
469481
case ',':
@@ -487,6 +499,12 @@ <h2 style="margin: 0;">Fail-safe settings</h2>
487499
enforceFailSafe(`Execution stopped because the tape exceeded ${failsafeSettings.tapeLengthLimit} cell${failsafeSettings.tapeLengthLimit === 1 ? '' : 's'}.`);
488500
}
489501
ip += 1;
502+
503+
stepsUntilYield -= 1;
504+
if (stepsUntilYield <= 0) {
505+
stepsUntilYield = yieldInterval;
506+
await waitForNextFrame();
507+
}
490508
}
491509

492510
return output;
@@ -513,20 +531,23 @@ <h2 style="margin: 0;">Fail-safe settings</h2>
513531
}
514532
}
515533

516-
runButton.addEventListener('click', () => {
534+
runButton.addEventListener('click', async () => {
517535
try {
518536
const mode = asciiModeRadio.checked ? 'ascii' : 'numbers';
519537
const inputs = parseInputs(bfInput.value, mode);
520538
const program = editor.getValue();
539+
updateStatus('');
521540
clearOutputs();
541+
await waitForNextFrame();
522542

523543
const liveOutput = [];
524-
const onOutput = (byte) => {
544+
const onOutput = async (byte) => {
525545
liveOutput.push(clampByte(byte));
526546
renderOutput(liveOutput);
547+
await waitForNextFrame();
527548
};
528549

529-
const output = runProgram(program, inputs, collectFailsafeSettingsFromInputs(), onOutput);
550+
const output = await runProgram(program, inputs, collectFailsafeSettingsFromInputs(), onOutput);
530551
renderOutput(output);
531552
updateStatus(`Program ran successfully. Output length: ${output.length} byte${output.length === 1 ? '' : 's'}.`);
532553
} catch (error) {

0 commit comments

Comments
 (0)