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 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); } } 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 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: throw new Error('Internal error: setof and dictof are handled in typeFor()'); case M.$dict: return Array.from(p[0]).flatMap(([k, n]) => typeField(mod, M.addNameIfAbsent(n, k))); 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) : []); }