94 lines
2.8 KiB
JavaScript
94 lines
2.8 KiB
JavaScript
// This module ensures that we never accidentally create a Symbol for the same type twice.
|
||
// Maybe we shouldn't use Symbols for types, but we also cannot use primitive values for types because they may accidentally overlap with 'real' values (that are not types)
|
||
// We also cannot use objects for types because similar to Symbols, objects are only equal to themselves if we use them as Map keys.
|
||
|
||
import { Function } from "./metacircular.js";
|
||
import { DefaultMap } from "./util.js";
|
||
|
||
// Global store of function types:
|
||
const fnTypes = new DefaultMap(() => new Map());
|
||
export const fnType = ({in: inType, out: outType}) => {
|
||
const m2 = fnTypes.getdefault(inType, true);
|
||
if (m2.has(outType)) {
|
||
return m2.get(outType);
|
||
}
|
||
else {
|
||
const fnType = {in: inType, out: outType};
|
||
m2.set(outType, fnType);
|
||
return fnType;
|
||
}
|
||
};
|
||
|
||
export const typedFnType = (instance, callback) => {
|
||
const fnTs = [];
|
||
const wrappedFnType = ({in: inType, out: outType}) => {
|
||
const fnT = fnType({in: inType, out: outType});
|
||
fnTs.push(fnT);
|
||
return fnT;
|
||
}
|
||
return [
|
||
{i: instance, t: callback(wrappedFnType)},
|
||
...fnTs.map(fnT => ({i: fnT, t: Function})),
|
||
];
|
||
}
|
||
|
||
// Global store of list types:
|
||
const listTypes = new Map();
|
||
export const lsType = (elementType) => {
|
||
if (listTypes.has(elementType)) {
|
||
// only generate each list type once
|
||
// this would not be necessary if we could define our own equality and hash functions on objects in JavaScript.
|
||
return listTypes.get(elementType);
|
||
}
|
||
else {
|
||
const type = {
|
||
listOf: elementType,
|
||
};
|
||
listTypes.set(elementType, type);
|
||
return type;
|
||
}
|
||
}
|
||
|
||
// Global store of product types:
|
||
const productTypes = new DefaultMap(() => new Map());
|
||
export const prodType = (leftType, rightType) => {
|
||
const m2 = productTypes.getdefault(leftType, true);
|
||
if (m2.has(rightType)) {
|
||
return m2.get(rightType);
|
||
}
|
||
else {
|
||
const pt = Symbol(`${leftType.toString()} × ${rightType.toString()}`);
|
||
m2.set(rightType, pt);
|
||
return pt;
|
||
}
|
||
}
|
||
|
||
// Global store of sum types:
|
||
const sumTypes = new DefaultMap(() => new Map());
|
||
export const sumType = (leftType, rightType) => {
|
||
const m2 = sumTypes.getdefault(leftType, true);
|
||
if (m2.has(rightType)) {
|
||
return m2.get(rightType);
|
||
}
|
||
else {
|
||
const st = Symbol(`${leftType.toString()} + ${rightType.toString()}`);
|
||
m2.set(rightType, st);
|
||
return st;
|
||
}
|
||
}
|
||
|
||
// const genericTypes = new Map();
|
||
// export const genericType = (underlyingType) => {
|
||
// if (genericTypes.has(underlyingType)) {
|
||
// // only generate each list type once
|
||
// // this would not be necessary if we could define our own equality and hash functions on objects in JavaScript.
|
||
// return genericTypes.get(underlyingType);
|
||
// }
|
||
// else {
|
||
// const type = {
|
||
// generic: underlyingType,
|
||
// };
|
||
// genericTypes.set(underlyingType, type);
|
||
// return type;
|
||
// }
|
||
// }
|