import { compareStrings } from "../compare/primitives.js"; import { unit } from "../primitives/unit.js"; import { capitalizeFirstLetter } from "../util/util.js"; const eatParameters = (numParams, result) => { if (numParams === 0) { return result; } else return () => eatParameters(numParams-1, result); } export const makeMatchFn = variantNames => { if (variantNames.length === 0) { return _ => { throw new Error("Bottom!"); }; } return enumm => { return matchFn(enumm, variantNames); } }; const matchFn = (enumm, variantNames) => { const [variantName, ...remaining] = variantNames; return handler => { if (enumm.variant === variantName) { return eatParameters( remaining.length, handler(enumm.value)); } else { return matchFn(enumm, remaining); } }; }; export const symbolElse = Symbol('else'); export const makeNiceMatchFn = (variantNames) => handlers => enumm => { const incomplete = variantNames.filter(({l: variant}) => !handlers.hasOwnProperty(variant)).length > 0; if (incomplete && !handlers.hasOwnProperty(symbolElse)) { throw new Error("if not every variant is handled, must have 'else' handler"); } if (!incomplete && handlers.hasOwnProperty(symbolElse)) { console.warn("'else' handler will never be invoked because every variant is already handled"); } for (const [variant, handler] of Object.entries(handlers)) { if (enumm.variant === variant) { return handler(enumm.value); } } return handlers[symbolElse](unit); } export const makeConstructors = variantNames => { if (new Set(variantNames).size !== variantNames.length) { throw new Error("precondition failed: non-unique variant names"); } return variantNames.map(variantName => { const ctorName = `new${capitalizeFirstLetter(variantName)}`; const ctor = { [ctorName]: value => ({variant: variantName, value}) }[ctorName]; return ctor; }) }; export const makeEnumCompareFn = variantCompares => { return enumA => enumB => { const cmp = compareStrings(enumA.variant)(enumB.variant); if (cmp !== 0) { return cmp; } const getCompareFn = variantCompares.find(({l: variantName}) => variantName === enumA.variant).r; return getCompareFn()(enumA.value)(enumB.value); } };