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': return [seq(`return _.merge`, parens( `(a, b) => (a === b) ? a : void 0`, ... [def.pattern0, def.pattern1, ... def.patternN].flatMap(p => { if (p._variant === 'anonymous' && p.value._variant === 'SimplePattern') { return []; } else { return [unconverterForNamed(ctx, p, src)]; } })))]; 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 'Double': return `_.Double(${src})`; default: return `${src}`; } case 'lit': return ctx.mod.literal(p.value); case 'embedded': return `_.embed(${src})`; case 'seqof': return seq(`${src}.map(v => `, unconverterFor(ctx, M.Pattern.SimplePattern(p.pattern), 'v'), `)`); case 'setof': return seq(`new _.Set<_embedded>`, parens(seq( `_.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 'Ref': return ctx.mod.lookup( p.value, (_p, _t) => `from${p.value.name.description!}${ctx.mod.genericArgs()}(${src})`, (modPath, modId, modFile, modExpr, _p, _t) => { ctx.mod.imports.add([modPath, modId, modFile, modExpr]); return `${modId}${modExpr}.from${p.value.name.description!}${ctx.mod.genericArgs()}(${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 'tuplePrefix': { const varExp = unconverterForNamed(ctx, M.promoteNamedSimplePattern(p.variable), src); if (p.fixed.length === 0) { return varExp; } else { return brackets( ... p.fixed.map(pp => unconverterForNamed(ctx, pp, src)), seq(`... `, varExp)); } } case 'dict': return seq(`new _.Dictionary<_embedded>`, parens( brackets(... Array.from(p.entries.entries()).map(([k, n]) => brackets( ctx.mod.literal(k), unconverterForNamedSimple(ctx, n, 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); } }