// SOURCE: ARCHITECTURE/32-LANGUAGE-OFFICIAL-13-IMPLEMENTATION-11.md // AUTO-EXTRACTED - Do not edit directly. Edit the source document. import type { Runtime } from "../../../../src/core/eval/runtime"; import type { State } from "../../../../src/core/eval/machine"; import type { Val } from "../../../../src/core/eval/values"; import { stepOnce } from "../../../../src/core/eval/machineStep"; export type NondetMode = "first" | "all"; export type Frontier = "bfs" | "dfs"; export type NondetOptions = { mode: NondetMode; frontier: Frontier; quantumSteps: number; maxTotalSteps: number; maxJobs: number; }; export type NondetResult = | { tag: "None" } | { tag: "One"; value: Val } | { tag: "Many"; values: Val[] }; type Job = { state: State }; function isVectorVal(v: Val): v is { tag: "Vector"; items: Val[] } { return v.tag === "Vector"; } function enqueue(frontier: Frontier, q: Job[], j: Job): Job[] { if (frontier === "bfs") return q.concat([j]); // dfs return [j].concat(q); } export async function runNondet(runtime: Runtime, initial: State, opts: NondetOptions): Promise { let queue: Job[] = [{ state: initial }]; const solutions: Val[] = []; let totalSteps = 0; while (queue.length > 0) { if (queue.length > opts.maxJobs) throw new Error("runNondet: maxJobs exceeded"); const job = queue[0]; queue = queue.slice(1); let st = job.state; for (let q = 0; q < opts.quantumSteps; q++) { totalSteps++; if (totalSteps > opts.maxTotalSteps) throw new Error("runNondet: maxTotalSteps exceeded"); const out = stepOnce(st); if (out.tag === "State") { st = out.state; continue; } if (out.tag === "Done") { solutions.push(out.value); if (opts.mode === "first") return { tag: "One", value: out.value }; break; // finish this job } if (out.tag === "Op") { const op = out.opcall.op; if (op === "amb.op") { // Convention: amb.op args: // either a single Vector of choices, or a variadic list of choices. let choices: Val[] = []; if (out.opcall.args.length === 1 && isVectorVal(out.opcall.args[0])) { choices = out.opcall.args[0].items; } else { choices = out.opcall.args; } // Fork: each choice resumes the continuation with that choice as the op result. for (const ch of choices) { const child = out.opcall.resumption.invoke(ch); queue = enqueue(opts.frontier, queue, { state: child }); } break; // stop current job; replaced by children } const handled = await runtime.dispatch(out.state, out.opcall); if (handled === "Uncaught") throw new Error(`Uncaught op: ${out.opcall.op}`); st = handled; continue; } } // If quantum expired and we still have a running state, requeue it (fair scheduling). if (st.control.tag !== "Val" || st.kont.length > 0) { queue = enqueue(opts.frontier, queue, { state: st }); } } if (solutions.length === 0) return { tag: "None" }; return { tag: "Many", values: solutions }; }