dope2/structures/enum.js
Joeri Exelmans 8eec5b9239 recursive types (and operations on them, like pretty-printing, comparison and unification) seem to be working.
big part of the code base still needs to be 'ported' to the updated type constructors.
2025-05-05 17:17:45 +02:00

57 lines
1.8 KiB
JavaScript

import { Bottom } from "../primitives/types.js";
import { capitalizeFirstLetter } from "../util/util.js";
import { newProduct as newProduct, getLeft, getRight } from "./product.js";
import { newLeft, newRight, match } from "./sum.js";
import { sumType } from "./types.js";
// 'variants' is an array of (name: string, type: Type) pairs.
// e.g., the list of variants:
// [ { l: "price" , r: Int },
// { l: "prices" , r: [Int] },
// { l: "not_found", r: Unit } ]
// results in the type:
// (Int | ([Int] | (Unit | ⊥)))
export const enumType = variants => {
if (variants.length === 0) {
return Bottom; // empty enum is equal to Bottom-type (cannot be instantiated)
}
const [variant, ...rest] = variants;
const variantType = getRight(variant);
return sumType(() => variantType)(() => enumType(rest));
};
const eatParameters = (numParams, result) => {
if (numParams === 0) {
return result;
}
else return () => eatParameters(numParams-1, result);
}
export const makeMatchFn = variants => {
if (variants.length === 0) {
return undefined;
}
const [_, ...remainingVariants] = variants;
return sum => handler => {
return (
match(sum)(newProduct
(leftValue => eatParameters(remainingVariants.length, handler(leftValue)))
(rightValue => makeMatchFn(remainingVariants)(rightValue))
));
};
};
export const makeConstructors = variants => {
if (variants.length === 0) {
return [];
}
const [variant, ...remainingVariants] = variants;
const name = getLeft(variant);
const ctorName = `new${capitalizeFirstLetter(name)}`;
const constructor = { [ctorName]: val => newLeft(val) }[ctorName];
return [
constructor,
...makeConstructors(remainingVariants).map(ctor =>
({[ctor.name]: val => newRight(ctor(val))}[ctor.name])),
];
}