preserves/implementations/javascript/packages/schema/src/compiler/genunconverter.ts

144 lines
6.5 KiB
TypeScript

import { refPosition } from '../reader';
import * as M from '../meta';
import { block, brackets, Item, parens, seq } from './block';
import { FunctionContext } from "./context";
export function unconverterForDefinition(
ctx: FunctionContext,
def: M.Definition,
src: string): Item[]
{
switch (def._variant) {
case 'or':
return [seq(`switch (${src}._variant) `, block(
... [def.pattern0, def.pattern1, ... def.patternN].map(p =>
seq(`case `, JSON.stringify(p.variantLabel), `: `, ctx.block(() => {
const hasValueField = p.pattern._variant === 'SimplePattern';
return [seq(`return `, unconverterFor(
ctx, p.pattern, hasValueField ? `${src}.value` : src))];
})))))];
case 'and': {
const ps = [def.pattern0, def.pattern1, ... def.patternN];
const cs = ps.flatMap(p => {
if (p._variant === 'anonymous' && p.value._variant === 'SimplePattern') {
return [];
} else {
return [unconverterForNamed(ctx, p, src)];
}
});
return [seq(`return `, (cs.length === 1)
? cs[0]
: seq(`_.merge`, parens(`(a, b) => (a === b) ? a : void 0`, ... cs)))];
}
case 'Pattern':
return [seq(`return `, unconverterFor(ctx, def.value, `${src}`))];
}
}
function unconverterFor(ctx: FunctionContext, p: M.Pattern, src: string): Item {
switch (p._variant) {
case 'SimplePattern':
return ((p: M.SimplePattern) => {
switch (p._variant) {
case 'any':
return `${src}`;
case 'atom':
switch (p.atomKind._variant) {
case 'Float': return `_.Single(${src})`;
case 'Double': return `_.Double(${src})`;
default: return `${src}`;
}
case 'lit':
return ctx.mod.literal(p.value);
case 'embedded':
return `_.embed(${src})`;
case 'Ref':
return M.lookup(
refPosition(p.value), p.value, ctx.mod.env,
(_p) => `from${p.value.name.description!}(${src})`,
(modId, modPath, _p) => {
ctx.mod.imports.add([modId, modPath]);
return `${modId}.from${p.value.name.description!}(${src})`;
});
}
})(p.value);
case 'CompoundPattern':
return ((p: M.CompoundPattern) => {
switch (p._variant) {
case 'rec':
return seq(`_.Record`, parens(
unconverterForNamed(ctx, p.label, src),
unconverterForNamed(ctx, p.fields, src)));
case 'tuple':
return brackets(... p.patterns.map(pp =>
unconverterForNamed(ctx, pp, src)));
case 'tuple*': {
let varexp: Item;
if (p.variable._variant === 'named') {
const steppedSrc = stepSource(src, p.variable.value.name.description!);
varexp = seq(steppedSrc, `.map`, parens(
seq(`v => `, unconverterFor(
ctx,
M.Pattern.SimplePattern(p.variable.value.pattern),
`v`))));
} else {
varexp = seq(src, `.map`, parens(
seq(`v => `, unconverterFor(
ctx,
M.Pattern.SimplePattern(p.variable.value),
`v`))));
}
if (p.fixed.length === 0) {
return varexp;
} else {
return brackets(
... p.fixed.map(pp => unconverterForNamed(ctx, pp, src)),
seq(`... `, varexp));
}
}
case 'setof':
return seq(`new _.Set<_embedded>`, parens(
`_.Array.from(${src}.values()).map(v => `,
unconverterFor(ctx, M.Pattern.SimplePattern(p.pattern), 'v'),
`)`));
case 'dictof':
return seq(`new _.Dictionary<_embedded>`, parens(seq(
`_.Array.from(${src}.entries()).map(([k, v]) => `,
brackets(
unconverterFor(ctx, M.Pattern.SimplePattern(p.key), 'k'),
unconverterFor(ctx, M.Pattern.SimplePattern(p.value), 'v')),
`)`)));
case 'dict':
return seq(`new _.Dictionary<_embedded>`, parens(
brackets(... Array.from(p.entries.entries()).map(([k, n]) =>
brackets(
ctx.mod.literal(k),
unconverterForNamedSimple(ctx, M.addNameIfAbsent(n, k), src))))));
}
})(p.value);
}
}
function stepSource(src: string, key: string): string
{
return `${src}[${JSON.stringify(key)}]`;
}
function unconverterForNamed(ctx: FunctionContext, p: M.NamedPattern, src: string): Item {
if (p._variant === 'named') {
const steppedSrc = stepSource(src, p.value.name.description!);
return unconverterFor(ctx, M.Pattern.SimplePattern(p.value.pattern), steppedSrc);
} else {
return unconverterFor(ctx, p.value, src);
}
}
function unconverterForNamedSimple(ctx: FunctionContext, p: M.NamedSimplePattern, src: string): Item {
if (p._variant === 'named') {
const steppedSrc = stepSource(src, p.value.name.description!);
return unconverterFor(ctx, M.Pattern.SimplePattern(p.value.pattern), steppedSrc);
} else {
return unconverterFor(ctx, M.Pattern.SimplePattern(p.value), src);
}
}