esolang/engines/execution-controller.ts
Nilay Majorwar 01ba292b9f Implement basic execution system and UI
This is a rather large commit that includes all of the following:
- React UI with code editor, runtime renderer and input-output panes
- Language providers for a sample language and Brainfuck
- Implementation of code execution in a web worker
- All-at-once unabortable execution of program fully functional
2021-12-14 22:30:41 +05:30

61 lines
1.6 KiB
TypeScript

import { LanguageEngine, StepExecutionResult } from "./types";
type ExecuteAllArgs<RS> = {
/** Interval between two execution steps, in milliseconds */
interval?: number;
/**
* Pass to run in streaming-response mode.
* Callback is called with exeuction result on every execution step.
*/
onResult?: (result: StepExecutionResult<RS>) => void;
};
class ExecutionController<RS> {
private _engine: LanguageEngine<RS>;
private _result: StepExecutionResult<RS> | null;
/**
* Create a new ExecutionController.
* @param engine Language engine to use for execution
*/
constructor(engine: LanguageEngine<RS>) {
this._engine = engine;
this._engine.resetState();
this._result = null;
}
/**
* Reset execution state in controller and engine.
* Clears out state from the current execution cycle.
*/
resetState() {
this._engine.resetState();
this._result = null;
}
/**
* Load code and user input into the engine to prepare for execution.
* @param code Code content, lines separated by `\n`
* @param input User input, lines separated by '\n'
*/
prepare(code: string, input: string) {
this._engine.prepare(code, input);
}
async executeAll({ interval, onResult }: ExecuteAllArgs<RS>) {
while (true) {
this._result = this._engine.executeStep();
onResult && onResult(this._result);
if (!this._result.nextStepLocation) break;
if (interval) await this.sleep(interval);
}
return this._result;
}
private async sleep(millis: number) {
return new Promise<void>((resolve) => setTimeout(resolve, millis));
}
}
export default ExecutionController;