126 lines
4.2 KiB
TypeScript
126 lines
4.2 KiB
TypeScript
|
import { refPosition } from "../reader";
|
||
|
import * as M from "../meta";
|
||
|
import { ModuleContext } from "./context";
|
||
|
import { ANY_TYPE, AtomicType, CollectionType, FieldMap, SimpleType, Type } from "./type";
|
||
|
|
||
|
export function typeForDefinition(mod: ModuleContext, d: M.Definition): Type {
|
||
|
if (d.label === M.$or) {
|
||
|
return Type.union(
|
||
|
new Map(d[0].map(a => [a[0], typeForAlternative(mod, a[1])])));
|
||
|
} else {
|
||
|
return typeForAlternative(mod, d);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function typeForAlternative(mod: ModuleContext, a: M.Alternative): SimpleType {
|
||
|
if (a.label === M.$and) {
|
||
|
const fs = new Map();
|
||
|
a[0].forEach(n => gatherFields(fs, mod, n));
|
||
|
return Type.record(fs);
|
||
|
} else {
|
||
|
return typeFor(mod, a);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export function setType(mod: ModuleContext, p: M.SimplePattern): CollectionType {
|
||
|
return Type.set(simpleType(mod, p));
|
||
|
}
|
||
|
|
||
|
export function dictionaryType(mod: ModuleContext,
|
||
|
kp: M.SimplePattern,
|
||
|
vp: M.SimplePattern): CollectionType
|
||
|
{
|
||
|
return Type.dictionary(simpleType(mod, kp), simpleType(mod, vp));
|
||
|
}
|
||
|
|
||
|
export function typeFor(mod: ModuleContext, p: M.Pattern): SimpleType {
|
||
|
if (M.isSimplePattern(p)) {
|
||
|
return simpleType(mod, p);
|
||
|
} else {
|
||
|
switch (p.label) {
|
||
|
case M.$setof:
|
||
|
return setType(mod, p[0]);
|
||
|
case M.$dictof:
|
||
|
return dictionaryType(mod, p[0], p[1]);
|
||
|
default: {
|
||
|
const arrayType = M.simpleArray(p);
|
||
|
if (arrayType === void 0) {
|
||
|
const fs = new Map();
|
||
|
compoundFields(fs, mod, p);
|
||
|
return Type.record(fs);
|
||
|
} else {
|
||
|
return Type.array(simpleType(mod, arrayType));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export function simpleType(mod: ModuleContext, p: M.SimplePattern): AtomicType {
|
||
|
switch (p.label) {
|
||
|
case M.$any:
|
||
|
return ANY_TYPE;
|
||
|
case M.$atom:
|
||
|
switch (p[0]) {
|
||
|
case M.$Boolean: return Type.ref(`boolean`);
|
||
|
case M.$Float: return Type.ref(`_.SingleFloat`);
|
||
|
case M.$Double: return Type.ref(`_.DoubleFloat`);
|
||
|
case M.$SignedInteger: return Type.ref(`number`);
|
||
|
case M.$String: return Type.ref(`string`);
|
||
|
case M.$ByteString: return Type.ref(`_.Bytes`);
|
||
|
case M.$Symbol: return Type.ref(`symbol`);
|
||
|
}
|
||
|
case M.$pointer:
|
||
|
return Type.ref(`_ptr`);
|
||
|
case M.$lit:
|
||
|
return Type.unit();
|
||
|
case M.$ref:
|
||
|
return M.lookup(refPosition(p), p, mod.env,
|
||
|
(_p) => Type.ref(p[1].description!),
|
||
|
(modId, modPath,_p) => {
|
||
|
mod.imports.add([modId, modPath]);
|
||
|
return Type.ref(`${modId}.${p[1].description!}`);
|
||
|
});
|
||
|
default:
|
||
|
((_p: never) => {})(p);
|
||
|
throw new Error("Unreachable");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function compoundFields(fs: FieldMap, mod: ModuleContext, p: M.CompoundPattern): void {
|
||
|
switch (p.label) {
|
||
|
case M.$rec:
|
||
|
gatherFields(fs, mod, p[0]);
|
||
|
gatherFields(fs, mod, p[1]);
|
||
|
break;
|
||
|
case M.$tuple:
|
||
|
p[0].forEach(pp => gatherFields(fs, mod, pp));
|
||
|
break;
|
||
|
case M.$tuple_STAR_: {
|
||
|
p[0].forEach(pp => gatherFields(fs, mod, pp));
|
||
|
const n = p[1];
|
||
|
if (n.label === M.$named) {
|
||
|
fs.set(n[0].description!, Type.array(simpleType(mod, n[1])));
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case M.$setof:
|
||
|
case M.$dictof:
|
||
|
break;
|
||
|
case M.$dict:
|
||
|
p[0].forEach((n, k) => gatherFields(fs, mod, M.addNameIfAbsent(n, k)));
|
||
|
break;
|
||
|
default:
|
||
|
((_p: never) => {})(p);
|
||
|
throw new Error("Unreachable");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function gatherFields(fs: FieldMap, mod: ModuleContext, n: M.NamedPattern): void {
|
||
|
if (n.label === M.$named) {
|
||
|
fs.set(n[0].description!, simpleType(mod, n[1]));
|
||
|
} else if (M.isCompoundPattern(n)) {
|
||
|
compoundFields(fs, mod, n);
|
||
|
}
|
||
|
}
|