import { compare } from '@preserves/core'; import * as M from './meta'; import * as H from './gen/host'; export * from './gen/host'; export function definitionType(p: M.Definition): 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(p: M.Pattern): 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(p: M.SimplePattern): 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(ps: M.NamedPattern[]): 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(p: M.NamedSimplePattern): M.NamedPattern { if (p._variant === 'named') return p; return M.NamedPattern.anonymous(M.Pattern.SimplePattern(p.value)); } function gather(p: M.NamedPattern, 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; } } } } }