Skip to content
Snippets Groups Projects
Select Git revision
  • 46ece88ca90ee35eccb971c08aaed7a66bb85b72
  • master default protected
2 results

control_inversion.js

Blame
  • control_inversion.js 1.38 KiB
    import './utility.js';
    
    const runningCoprograms = [];
    
    export class Coprogram {
      constructor(main) {
        this._main = main;
        this._running = false;
        this.state = main();
        this.inputQueue = [];
      }
    
      _continue(input) {
        runningCoprograms.push(this);
        this.state.next(input);
        while (this.inputQueue.length > 0) {
          this.state.next(this.inputQueue.shift());
        }
        runningCoprograms.pop();
      }
    
      run() {
        console.assert(!this._running, `Tried to run the coprogram ${this._main} when it is already running.`);
        this._running = true;
        this._continue();
      }
    
      unblock(input) {
        if (!this._running || runningCoprograms.includes(this)) {
          this.inputQueue.push(input);
        } else {
          console.assert(this.inputQueue.length === 0, `Found coprogram ${this} blocked waiting for input when there was already input in its queue.`);
          this._continue(input);
        }
      }
    }
    
    export function*block(arm, disarm) {
      const coprogram = runningCoprograms.top();
      arm((input) => coprogram.unblock(input));
      const result = yield;
      if (disarm !== undefined) {
        disarm();
      }
      return result;
    }
    
    export const UNPAUSE = Symbol('UNPAUSE');
    
    export function*pause(delay) {
      return yield* block((unblock) => {
        if (Number.isFinite(delay)) {
          window.setTimeout(() => {
            unblock(UNPAUSE);
          }, delay);
        }
      });
    }
    
    export const internals = {runningCoprograms};