import { inspect } from "node:util"; // a -> Value export const newLiteral = val => ({ kind: "literal", out: val, [inspect.custom]: (depth, options, inspect) => `newLiteral(${inspect(val)})`, }); // Slot -> Value export const read = slot => ({ kind: "read", slot, out: slot.value.out, [inspect.custom]: (depth, options, inspect) => `read(${inspect(slot)})`, }); // Value -> Value b> -> Value export const transform = input => fn => { const output = fn.out(input.out); // const _inspect = (depth, options, inspect) => `transform(${inspect(input)}, ${inspect(fn)})`; if (input.kind === "literal") { // optimization: sandwich everything together return { kind: "literal", out: output, // [inspect.custom]: _inspect, }; } else { return { kind: "transform", in: input, fn, out: output, // [inspect.custom]: _inspect, }; } }; // Value -> Set> export const getReadDependencies = value => { if (value.kind === "literal") { return new Set(); } else if (value.kind === "read") { return new Set([value.slot]); } else if (value.kind === "transform") { return new Set([ ...getReadDependencies(value.in), ...getReadDependencies(value.fn), ]); } }; // for debugging export const verifyValue = (value, indent = 0) => { let success = true; const printIndent = (...args) => { console.log(" ".repeat(indent * 2), ...args); }; const compare = (a, b, kind) => { if (typeof a === 'function' && typeof b === 'function') { printIndent("note: cannot compare functions", `(${kind})`); } else if (deepEqual(a, b)) { printIndent(`ok (${kind})`); } else { printIndent(`bad (${kind})`); success = false; } }; if (value.kind === "literal") { compare(1, 1, "literal"); } else if (value.kind === "read") { compare(value.out, value.slot.value.out, "read"); } else if (value.kind === "transform") { compare(value.fn.out(value.in.out), value.out, "transform"); success &= verifyValue(value.in, indent + 1); success &= verifyValue(value.fn, indent + 1); } return success; };