84 lines
3.0 KiB
TypeScript
84 lines
3.0 KiB
TypeScript
import { compare } from '@preserves/core';
|
|
|
|
import * as M from './meta';
|
|
import * as H from './gen/host';
|
|
|
|
export * from './gen/host';
|
|
|
|
export function definitionType<V>(p: M.Definition<V>): H.Definition {
|
|
switch (p._variant) {
|
|
case 'or': return H.Definition.union([p.pattern0, p.pattern1, ... p.patternN].map(p =>
|
|
H.Variant({ label: Symbol.for(p.variantLabel), type: patternType(p.pattern) })));
|
|
case 'and':
|
|
return H.Definition.Simple(productType([p.pattern0, p.pattern1, ... p.patternN]));
|
|
case 'Pattern':
|
|
return H.Definition.Simple(patternType(p.value));
|
|
}
|
|
}
|
|
|
|
export function patternType<V>(p: M.Pattern<V>): H.Simple {
|
|
switch (p._variant) {
|
|
case 'SimplePattern':
|
|
return H.Simple.Field(fieldType(p.value));
|
|
case 'CompoundPattern':
|
|
return productType([M.NamedPattern.anonymous(p)]);
|
|
}
|
|
}
|
|
|
|
export function fieldType<V>(p: M.SimplePattern<V>): H.Field {
|
|
switch (p._variant) {
|
|
case 'any': return H.Field.any();
|
|
case 'atom': return H.Field.AtomKind(p.atomKind);
|
|
case 'embedded': return H.Field.embedded();
|
|
case 'lit': return H.Field.unit();
|
|
case 'seqof': return H.Field.array(fieldType(p.pattern));
|
|
case 'setof': return H.Field.set(fieldType(p.pattern));
|
|
case 'dictof': return H.Field.map({ key: fieldType(p.key), value: fieldType(p.value) });
|
|
case 'Ref': return H.Field.ref(p.value);
|
|
}
|
|
}
|
|
|
|
export function productType<V>(ps: M.NamedPattern<V>[]): H.Simple {
|
|
const gathered: H.NamedField[] = [];
|
|
ps.forEach(p => gather(p, gathered));
|
|
if (gathered.length === 0) return H.Simple.Field(H.Field.unit());
|
|
return H.Simple.Record(H.Record(gathered));
|
|
}
|
|
|
|
function promote<V>(p: M.NamedSimplePattern<V>): M.NamedPattern<V> {
|
|
if (p._variant === 'named') return p;
|
|
return M.NamedPattern.anonymous(M.Pattern.SimplePattern(p.value));
|
|
}
|
|
|
|
function gather<V>(p: M.NamedPattern<V>, into: H.NamedField[]) {
|
|
switch (p._variant) {
|
|
case 'named': {
|
|
const t = fieldType(p.value.pattern);
|
|
if (t._variant !== 'unit') into.push(H.NamedField({ name: p.value.name, type: t }));
|
|
break;
|
|
}
|
|
case 'anonymous': {
|
|
if (p.value._variant === 'SimplePattern') return;
|
|
const q = p.value.value;
|
|
switch (q._variant) {
|
|
case 'rec':
|
|
gather(q.label, into);
|
|
gather(q.fields, into);
|
|
break;
|
|
case 'tuple':
|
|
q.patterns.forEach(p => gather(p, into));
|
|
break;
|
|
case 'tuplePrefix':
|
|
q.fixed.forEach(p => gather(p, into));
|
|
gather(promote(q.variable), into);
|
|
break;
|
|
case 'dict': {
|
|
const items = Array.from(q.entries.entries()).sort((a, b) => compare(a[0], b[0]));
|
|
items.forEach(([_key, p]) => gather(promote(p), into));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|