val 0.7.0

An arbitrary precision calculator language
Documentation
import { failedExecution } from '@/lib/execution';
import type { ExecutionRequest, ExecutionState } from '@/lib/types';
import { useCallback, useEffect, useRef, useState } from 'react';
import type { Execution } from 'val-wasm';

export function useValExecution() {
  const worker = useRef<Worker>();

  const [state, setState] = useState<ExecutionState>({ status: 'idle' });

  const terminate = useCallback(() => {
    worker.current?.terminate();
    worker.current = undefined;
  }, []);

  useEffect(() => terminate, [terminate]);

  const run = useCallback(
    (code: string, input: string) => {
      terminate();
      setState({ status: 'running', code });

      try {
        const current = new Worker(
          new URL('../workers/execute.ts', import.meta.url),
          { type: 'module' }
        );

        worker.current = current;

        const complete = (result: Execution) => {
          if (worker.current !== current) {
            return;
          }

          terminate();
          setState({ status: 'complete', code, result });
        };

        current.onmessage = ({ data }: MessageEvent<Execution>) => {
          complete(data);
        };

        current.onerror = (event) => {
          event.preventDefault();
          complete(
            failedExecution(event.message || 'Program execution failed')
          );
        };

        current.onmessageerror = () => {
          complete(failedExecution('Failed to receive program output'));
        };

        current.postMessage({ code, input } satisfies ExecutionRequest);
      } catch (error) {
        terminate();
        setState({ status: 'complete', code, result: failedExecution(error) });
      }
    },
    [terminate]
  );

  const stop = useCallback(() => {
    terminate();
    setState((previous) =>
      previous.status === 'running'
        ? { status: 'stopped', code: previous.code }
        : previous
    );
  }, [terminate]);

  return { run, state, stop };
}