132 lines
4.8 KiB
TypeScript
132 lines
4.8 KiB
TypeScript
import { refPosition } from "../reader";
|
|
import * as M from "../meta";
|
|
import { anglebrackets, braces, Item, keyvalue, opseq, seq } from "./block";
|
|
import { ModuleContext, variantFor, variantInitFor } from "./context";
|
|
|
|
export function typeFor(mod: ModuleContext, p: M.Pattern, variantName?: string): Item {
|
|
let typeItem: Item;
|
|
|
|
if (M.isSimplePattern(p)) {
|
|
typeItem = typeForSimple(mod, p);
|
|
} else {
|
|
switch (p.label) {
|
|
case M.$setof:
|
|
typeItem = seq(`_.KeyedSet`, anglebrackets(typeForSimple(mod, p[0]), '_ptr'));
|
|
break;
|
|
case M.$dictof:
|
|
typeItem = seq(`_.KeyedDictionary`, anglebrackets(typeForSimple(mod, p[0]),
|
|
typeForSimple(mod, p[1]),
|
|
'_ptr'));
|
|
break;
|
|
default: {
|
|
const arrayType = M.simpleArray(p);
|
|
if (arrayType === void 0) {
|
|
return braces(... variantInitFor(variantName),
|
|
... typeForCompound(mod, p));
|
|
} else {
|
|
typeItem = seq('Array<', typeForSimple(mod, arrayType), '>');
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (variantName === void 0) {
|
|
return typeItem;
|
|
} else {
|
|
return braces(variantFor(variantName), keyvalue('value', typeItem));
|
|
}
|
|
}
|
|
|
|
function typeForSimple(mod: ModuleContext, p: M.SimplePattern): Item {
|
|
switch (p.label) {
|
|
case M.$atom:
|
|
switch (p[0]) {
|
|
case M.$Boolean: return `boolean`;
|
|
case M.$Float: return `_.SingleFloat`;
|
|
case M.$Double: return `_.DoubleFloat`;
|
|
case M.$SignedInteger: return `number`;
|
|
case M.$String: return `string`;
|
|
case M.$ByteString: return `_.Bytes`;
|
|
case M.$Symbol: return `symbol`;
|
|
}
|
|
case M.$pointer:
|
|
return `_ptr`;
|
|
case M.$lit:
|
|
return `(typeof ${mod.literal(p[0])})`;
|
|
case M.$ref:
|
|
return M.lookup(refPosition(p), p, mod.env,
|
|
(_p) => p[1].description!,
|
|
(p) => typeForAlternative(mod, p, void 0),
|
|
(modId, modPath,_p) => {
|
|
mod.imports.add([modId, modPath]);
|
|
return `${modId}.${p[1].description!}`;
|
|
});
|
|
default:
|
|
((_p: never) => {})(p);
|
|
throw new Error("Unreachable");
|
|
}
|
|
}
|
|
|
|
function typeField(mod: ModuleContext, n: M.NamedPattern): Item[] {
|
|
return (n.label === M.$named)
|
|
? [keyvalue(n[0].description!, typeForSimple(mod, n[1]))]
|
|
: (M.isCompoundPattern(n)
|
|
? typeForCompound(mod, n)
|
|
: []);
|
|
}
|
|
|
|
function typeForCompound(mod: ModuleContext, p: M.CompoundPattern): Item[] {
|
|
switch (p.label) {
|
|
case M.$rec:
|
|
return [... typeField(mod, p[0]), ... typeField(mod, p[1])];
|
|
case M.$tuple:
|
|
return p[0].flatMap(pp => typeField(mod, pp));
|
|
case M.$tuple_STAR_: {
|
|
const n = p[1];
|
|
return [... p[0].flatMap(pp => typeField(mod, pp)),
|
|
... ((n.label === M.$named)
|
|
? [keyvalue(n[0].description!,
|
|
seq('Array<', typeForSimple(mod, n[1]), '>'))]
|
|
: [])];
|
|
}
|
|
case M.$setof:
|
|
case M.$dictof:
|
|
return [];
|
|
case M.$dict:
|
|
return Array.from(p[0]).flatMap(([k, n]) => {
|
|
if (n.label === M.$named) {
|
|
return typeField(mod, n);
|
|
} else {
|
|
const s = M.namelike(k);
|
|
if (s !== void 0) {
|
|
return [keyvalue(s, typeForSimple(mod, n))];
|
|
} else {
|
|
return [];
|
|
}
|
|
}
|
|
});
|
|
default:
|
|
((_p: never) => {})(p);
|
|
throw new Error("Unreachable");
|
|
}
|
|
}
|
|
|
|
export function typeForDefinition(mod: ModuleContext, d: M.Definition): Item {
|
|
if (d.label === M.$or) {
|
|
return opseq('never', ' | ', ... d[0].map(a => typeForAlternative(mod, a[1], a[0])));
|
|
} else {
|
|
return typeForAlternative(mod, d, void 0);
|
|
}
|
|
}
|
|
|
|
function typeForAlternative(mod: ModuleContext, a: M.Alternative, variantName: string | undefined): Item {
|
|
if (a.label === M.$and) {
|
|
return opseq('_val', ' & ',
|
|
... variantName === void 0 ? [] : [braces(variantFor(variantName))],
|
|
...a[0].map(p => typeFor(mod, M.unname(p))));
|
|
} else {
|
|
return typeFor(mod, a, variantName);
|
|
}
|
|
}
|