preserves/implementations/javascript/packages/schema/src/gentype.ts

122 lines
4.3 KiB
TypeScript
Raw Normal View History

import * as M from "./meta";
2021-03-19 22:42:43 +00:00
import { ANY_TYPE, AtomicType, CollectionType, FieldMap, SimpleType, Type } from "./type";
export type RefResolver = (ref: M.Ref) => AtomicType;
export function typeForDefinition(resolver: RefResolver, d: M.Definition): Type {
switch (d._variant) {
case 'or':
return Type.union(
new Map([d.pattern0, d.pattern1, ... d.patternN].map(a =>
[a.variantLabel, typeFor(resolver, a.pattern)])));
case 'and':
return typeForIntersection(resolver, [d.pattern0, d.pattern1, ... d.patternN]);
case 'Pattern':
return typeFor(resolver, d.value);
2021-03-19 22:42:43 +00:00
}
}
export function typeForIntersection(resolver: RefResolver, ps: M.NamedPattern[]): SimpleType {
const fs = new Map();
ps.forEach(p => gatherFields(fs, resolver, p));
return fs.size > 0 ? Type.record(fs) : Type.unit();
2021-03-19 22:42:43 +00:00
}
export function setType(resolver: RefResolver, p: M.SimplePattern): CollectionType {
return Type.set(simpleType(resolver, p));
2021-03-19 22:42:43 +00:00
}
export function dictionaryType(resolver: RefResolver,
2021-03-19 22:42:43 +00:00
kp: M.SimplePattern,
vp: M.SimplePattern): CollectionType
{
return Type.dictionary(simpleType(resolver, kp), simpleType(resolver, vp));
2021-03-19 22:42:43 +00:00
}
export function typeFor(resolver: RefResolver, p: M.Pattern): SimpleType {
2021-03-22 11:13:34 +00:00
if (p._variant === 'SimplePattern') {
return simpleType(resolver, p.value);
2021-03-19 22:42:43 +00:00
} else {
2021-03-22 11:13:34 +00:00
switch (p.value._variant) {
case 'setof':
return setType(resolver, p.value.pattern);
2021-03-22 11:13:34 +00:00
case 'dictof':
return dictionaryType(resolver, p.value.key, p.value.value);
2021-03-19 22:42:43 +00:00
default: {
2021-03-22 11:13:34 +00:00
const arrayType = M.simpleArray(p.value);
2021-03-19 22:42:43 +00:00
if (arrayType === void 0) {
const fs = new Map();
compoundFields(fs, resolver, p.value);
2021-03-23 10:36:55 +00:00
return fs.size > 0 ? Type.record(fs) : Type.unit();
2021-03-19 22:42:43 +00:00
} else {
return Type.array(simpleType(resolver, arrayType));
2021-03-19 22:42:43 +00:00
}
}
}
}
}
export function simpleType(resolver: RefResolver, p: M.SimplePattern): AtomicType {
2021-03-22 11:13:34 +00:00
switch (p._variant) {
case 'any':
2021-03-19 22:42:43 +00:00
return ANY_TYPE;
2021-03-22 11:13:34 +00:00
case 'atom':
switch (p.atomKind._variant) {
case 'Boolean': return Type.ref(`boolean`);
2021-03-23 10:36:55 +00:00
case 'Float': return Type.ref(`number`);
case 'Double': return Type.ref(`number`);
2021-03-22 11:13:34 +00:00
case 'SignedInteger': return Type.ref(`number`);
case 'String': return Type.ref(`string`);
case 'ByteString': return Type.ref(`_.Bytes`);
case 'Symbol': return Type.ref(`symbol`);
2021-03-19 22:42:43 +00:00
}
case 'embedded':
return Type.ref(`_embedded`);
2021-03-22 11:13:34 +00:00
case 'lit':
2021-03-19 22:42:43 +00:00
return Type.unit();
2021-03-22 11:13:34 +00:00
case 'Ref':
return resolver(p.value);
2021-03-19 22:42:43 +00:00
default:
((_p: never) => {})(p);
throw new Error("Unreachable");
}
}
function compoundFields(fs: FieldMap, resolver: RefResolver, p: M.CompoundPattern): void {
2021-03-22 11:13:34 +00:00
switch (p._variant) {
case 'rec':
gatherFields(fs, resolver, p.label);
gatherFields(fs, resolver, p.fields);
2021-03-19 22:42:43 +00:00
break;
2021-03-22 11:13:34 +00:00
case 'tuple':
p.patterns.forEach(pp => gatherFields(fs, resolver, pp));
2021-03-19 22:42:43 +00:00
break;
2021-03-22 11:13:34 +00:00
case 'tuple*': {
p.fixed.forEach(pp => gatherFields(fs, resolver, pp));
2021-03-22 11:13:34 +00:00
const n = p.variable;
if (n._variant === 'named') {
fs.set(n.value.name.description!, Type.array(simpleType(resolver, n.value.pattern)));
2021-03-19 22:42:43 +00:00
}
break;
}
2021-03-22 11:13:34 +00:00
case 'setof':
case 'dictof':
2021-03-19 22:42:43 +00:00
break;
2021-03-22 11:13:34 +00:00
case 'dict':
p.entries.forEach((n, k) =>
gatherFields(fs, resolver, M.promoteNamedSimplePattern(M.addNameIfAbsent(n, k))));
2021-03-19 22:42:43 +00:00
break;
default:
((_p: never) => {})(p);
throw new Error("Unreachable");
}
}
function gatherFields(fs: FieldMap, resolver: RefResolver, n: M.NamedPattern): void {
2021-03-22 11:13:34 +00:00
if (n._variant === 'named') {
fs.set(n.value.name.description!, simpleType(resolver, n.value.pattern));
2021-03-22 11:13:34 +00:00
} else if (n.value._variant === 'CompoundPattern') {
compoundFields(fs, resolver, n.value.value);
2021-03-19 22:42:43 +00:00
}
}