Simplify unconverter generation even further

This commit is contained in:
Tony Garnock-Jones 2021-05-21 15:56:01 +02:00
parent 20b676df27
commit b5b4effeac
1 changed files with 29 additions and 58 deletions

View File

@ -1,10 +1,7 @@
import { refPosition } from '../reader'; import { refPosition } from '../reader';
import * as M from '../meta'; import * as M from '../meta';
import { block, brackets, formatItems, Item, parens, seq } from './block'; import { block, brackets, Item, parens, seq } from './block';
import { FunctionContext } from "./context"; import { FunctionContext } from "./context";
import { FieldType, SimpleType } from '../type';
import { typeFor, typeForIntersection } from '../gentype';
import { renderType } from "./rendertype";
export function unconverterForDefinition( export function unconverterForDefinition(
ctx: FunctionContext, ctx: FunctionContext,
@ -17,17 +14,16 @@ export function unconverterForDefinition(
... [def.pattern0, def.pattern1, ... def.patternN].map(p => ... [def.pattern0, def.pattern1, ... def.patternN].map(p =>
seq(`case `, JSON.stringify(p.variantLabel), `: `, ctx.block(() => { seq(`case `, JSON.stringify(p.variantLabel), `: `, ctx.block(() => {
const hasValueField = p.pattern._variant === 'SimplePattern'; const hasValueField = p.pattern._variant === 'SimplePattern';
return [seq(`return `, unconverterForPattern( return [seq(`return `, unconverterFor(
ctx, p.pattern, hasValueField ? `${src}.value` : src))]; ctx, p.pattern, hasValueField ? `${src}.value` : src))];
})))))]; })))))];
case 'and': { case 'and': {
const ps = [def.pattern0, def.pattern1, ... def.patternN]; const ps = [def.pattern0, def.pattern1, ... def.patternN];
const t = typeForIntersection(ctx.mod.resolver(), ps);
const cs = ps.flatMap(p => { const cs = ps.flatMap(p => {
if (p._variant === 'anonymous' && p.value._variant === 'SimplePattern') { if (p._variant === 'anonymous' && p.value._variant === 'SimplePattern') {
return []; return [];
} else { } else {
return [unconverterForNamed(ctx, p, src, t)]; return [unconverterForNamed(ctx, p, src)];
} }
}); });
return [seq(`return `, (cs.length === 1) return [seq(`return `, (cs.length === 1)
@ -35,31 +31,11 @@ export function unconverterForDefinition(
: seq(`_.merge`, parens(`(a, b) => (a === b) ? a : void 0`, ... cs)))]; : seq(`_.merge`, parens(`(a, b) => (a === b) ? a : void 0`, ... cs)))];
} }
case 'Pattern': case 'Pattern':
return [seq(`return `, unconverterForPattern(ctx, def.value, `${src}`))]; return [seq(`return `, unconverterFor(ctx, def.value, `${src}`))];
} }
} }
function unconverterForPattern(ctx: FunctionContext, a: M.Pattern, src: string): Item function unconverterFor(ctx: FunctionContext, p: M.Pattern, src: string): Item {
{
return unconverterFor(ctx, a, src, typeFor(ctx.mod.resolver(), a));
}
function stepSource(
src: string,
t: SimpleType,
key: string): { steppedSrc: string, steppedType: FieldType }
{
if (t.kind !== 'record' || !t.fields.has(key)) {
throw new Error(
`Internal error: attempt to step type ${JSON.stringify(t)} with key ${key}`);
}
return {
steppedSrc: `${src}[${JSON.stringify(key)}]`,
steppedType: t.fields.get(key)!
};
}
function unconverterFor(ctx: FunctionContext, p: M.Pattern, src: string, t: SimpleType): Item {
switch (p._variant) { switch (p._variant) {
case 'SimplePattern': case 'SimplePattern':
return ((p: M.SimplePattern) => { return ((p: M.SimplePattern) => {
@ -91,82 +67,77 @@ function unconverterFor(ctx: FunctionContext, p: M.Pattern, src: string, t: Simp
switch (p._variant) { switch (p._variant) {
case 'rec': case 'rec':
return seq(`_.Record`, parens( return seq(`_.Record`, parens(
unconverterForNamed(ctx, p.label, src, t), unconverterForNamed(ctx, p.label, src),
unconverterForNamed(ctx, p.fields, src, t))); unconverterForNamed(ctx, p.fields, src)));
case 'tuple': case 'tuple':
return brackets(... p.patterns.map(pp => return brackets(... p.patterns.map(pp =>
unconverterForNamed(ctx, pp, src, t))); unconverterForNamed(ctx, pp, src)));
case 'tuple*': { case 'tuple*': {
let varexp: Item; let varexp: Item;
if (p.variable._variant === 'named') { if (p.variable._variant === 'named') {
const { steppedSrc, steppedType } = const steppedSrc = stepSource(src, p.variable.value.name.description!);
stepSource(src, t, p.variable.value.name.description!);
if (steppedType.kind !== 'array') {
throw new Error(
`Internal error: attempt to visit element type of ` +
`${formatItems([renderType(steppedType)])} after ` +
`stepping by key ${p.variable.value.name.description!}`);
}
varexp = seq(steppedSrc, `.map`, parens( varexp = seq(steppedSrc, `.map`, parens(
seq(`v => `, unconverterFor( seq(`v => `, unconverterFor(
ctx, ctx,
M.Pattern.SimplePattern(p.variable.value.pattern), M.Pattern.SimplePattern(p.variable.value.pattern),
`v`, `v`))));
steppedType.type))));
} else { } else {
if (t.kind !== 'array') throw new Error("Internal error");
varexp = seq(src, `.map`, parens( varexp = seq(src, `.map`, parens(
seq(`v => `, unconverterFor( seq(`v => `, unconverterFor(
ctx, ctx,
M.Pattern.SimplePattern(p.variable.value), M.Pattern.SimplePattern(p.variable.value),
`v`, `v`))));
t.type))));
} }
if (p.fixed.length === 0) { if (p.fixed.length === 0) {
return varexp; return varexp;
} else { } else {
return brackets( return brackets(
... p.fixed.map(pp => unconverterForNamed(ctx, pp, src, t)), ... p.fixed.map(pp => unconverterForNamed(ctx, pp, src)),
seq(`... `, varexp)); seq(`... `, varexp));
} }
} }
case 'setof': case 'setof':
return seq(`new _.Set<_embedded>`, parens( return seq(`new _.Set<_embedded>`, parens(
`_.Array.from(${src}.values()).map(v => `, `_.Array.from(${src}.values()).map(v => `,
unconverterFor(ctx, M.Pattern.SimplePattern(p.pattern), 'v', t), unconverterFor(ctx, M.Pattern.SimplePattern(p.pattern), 'v'),
`)`)); `)`));
case 'dictof': case 'dictof':
return seq(`new _.Dictionary<_embedded>`, parens(seq( return seq(`new _.Dictionary<_embedded>`, parens(seq(
`_.Array.from(${src}.entries()).map(([k, v]) => `, `_.Array.from(${src}.entries()).map(([k, v]) => `,
brackets( brackets(
unconverterFor(ctx, M.Pattern.SimplePattern(p.key), 'k', t), unconverterFor(ctx, M.Pattern.SimplePattern(p.key), 'k'),
unconverterFor(ctx, M.Pattern.SimplePattern(p.value), 'v', t)), unconverterFor(ctx, M.Pattern.SimplePattern(p.value), 'v')),
`)`))); `)`)));
case 'dict': case 'dict':
return seq(`new _.Dictionary<_embedded>`, parens( return seq(`new _.Dictionary<_embedded>`, parens(
brackets(... Array.from(p.entries.entries()).map(([k, n]) => brackets(... Array.from(p.entries.entries()).map(([k, n]) =>
brackets( brackets(
ctx.mod.literal(k), ctx.mod.literal(k),
unconverterForNamedSimple(ctx, M.addNameIfAbsent(n, k), src, t)))))); unconverterForNamedSimple(ctx, M.addNameIfAbsent(n, k), src))))));
} }
})(p.value); })(p.value);
} }
} }
function unconverterForNamed(ctx: FunctionContext, p: M.NamedPattern, src: string, t: SimpleType): Item { 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') { if (p._variant === 'named') {
const { steppedSrc, steppedType } = stepSource(src, t, p.value.name.description!); const steppedSrc = stepSource(src, p.value.name.description!);
return unconverterFor(ctx, M.Pattern.SimplePattern(p.value.pattern), steppedSrc, steppedType); return unconverterFor(ctx, M.Pattern.SimplePattern(p.value.pattern), steppedSrc);
} else { } else {
return unconverterFor(ctx, p.value, src, t); return unconverterFor(ctx, p.value, src);
} }
} }
function unconverterForNamedSimple(ctx: FunctionContext, p: M.NamedSimplePattern, src: string, t: SimpleType): Item { function unconverterForNamedSimple(ctx: FunctionContext, p: M.NamedSimplePattern, src: string): Item {
if (p._variant === 'named') { if (p._variant === 'named') {
const { steppedSrc, steppedType } = stepSource(src, t, p.value.name.description!); const steppedSrc = stepSource(src, p.value.name.description!);
return unconverterFor(ctx, M.Pattern.SimplePattern(p.value.pattern), steppedSrc, steppedType); return unconverterFor(ctx, M.Pattern.SimplePattern(p.value.pattern), steppedSrc);
} else { } else {
return unconverterFor(ctx, M.Pattern.SimplePattern(p.value), src, t); return unconverterFor(ctx, M.Pattern.SimplePattern(p.value), src);
} }
} }