2021-03-18 10:15:10 +00:00
|
|
|
import { FunctionContext } from "./context";
|
|
|
|
import * as M from '../meta';
|
2021-03-18 21:33:37 +00:00
|
|
|
import { block, Item, seq } from "./block";
|
2021-03-19 22:42:43 +00:00
|
|
|
import { simpleType, dictionaryType, setType, typeFor } from "./gentype";
|
2021-03-18 10:15:10 +00:00
|
|
|
import { refPosition } from "../reader";
|
2021-03-19 22:42:43 +00:00
|
|
|
import { ANY_TYPE, Type } from "./type";
|
2021-03-18 10:15:10 +00:00
|
|
|
|
|
|
|
export function converterForDefinition(
|
|
|
|
ctx: FunctionContext,
|
|
|
|
p: M.Definition,
|
|
|
|
src: string,
|
|
|
|
dest: string): Item[]
|
|
|
|
{
|
2021-03-22 11:13:34 +00:00
|
|
|
if (p._variant === 'or') {
|
|
|
|
const alts = p.patterns;
|
2021-03-18 21:33:37 +00:00
|
|
|
function loop(i: number): Item[] {
|
2021-03-22 11:13:34 +00:00
|
|
|
ctx.variantName = alts[i].variantLabel;
|
|
|
|
return [... converterForAlternative(ctx, alts[i].alternative, src, dest),
|
2021-03-18 21:33:37 +00:00
|
|
|
... ((i < alts.length - 1)
|
|
|
|
? [seq(`if (${dest} === void 0) `, ctx.block(() => loop(i + 1)))]
|
|
|
|
: [])];
|
2021-03-18 10:15:10 +00:00
|
|
|
}
|
2021-03-18 21:33:37 +00:00
|
|
|
return alts.length === 0 ? [] : loop(0);
|
2021-03-18 10:15:10 +00:00
|
|
|
} else {
|
2021-03-18 21:33:37 +00:00
|
|
|
ctx.variantName = void 0;
|
2021-03-22 11:13:34 +00:00
|
|
|
return converterForAlternative(ctx, p.value, src, dest);
|
2021-03-18 10:15:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-18 21:33:37 +00:00
|
|
|
function converterForAlternative(
|
|
|
|
ctx: FunctionContext,
|
|
|
|
p: M.Alternative,
|
|
|
|
src: string,
|
|
|
|
dest: string): Item[]
|
|
|
|
{
|
2021-03-22 11:13:34 +00:00
|
|
|
if (p._variant === 'and') {
|
|
|
|
const alts = p.patterns;
|
2021-03-18 21:33:37 +00:00
|
|
|
function loop(i: number): Item[] {
|
|
|
|
return (i < alts.length)
|
|
|
|
? converterFor(ctx, alts[i], src, () => loop(i + 1))
|
|
|
|
: [ctx.buildCapturedCompound(dest)];
|
|
|
|
}
|
|
|
|
return alts.length === 0 ? [seq(`${dest} = ${src}`)] : loop(0);
|
|
|
|
} else {
|
2021-03-22 11:13:34 +00:00
|
|
|
return converterFor(ctx, M.NamedPattern.anonymous(p.value), src, simpleValue => {
|
2021-03-18 21:33:37 +00:00
|
|
|
if (simpleValue === void 0) {
|
|
|
|
return [ctx.buildCapturedCompound(dest)];
|
|
|
|
} else if (ctx.variantName !== void 0) {
|
2021-03-22 11:13:34 +00:00
|
|
|
if (typeFor(ctx.mod, p.value).kind === 'unit') {
|
2021-03-19 22:42:43 +00:00
|
|
|
return [ctx.buildCapturedCompound(dest)];
|
|
|
|
} else {
|
|
|
|
return [ctx.withCapture('value',
|
|
|
|
simpleValue,
|
|
|
|
() => ctx.buildCapturedCompound(dest))];
|
|
|
|
}
|
2021-03-18 21:33:37 +00:00
|
|
|
} else {
|
|
|
|
return [`${dest} = ${simpleValue}`];
|
2021-03-18 10:15:10 +00:00
|
|
|
}
|
2021-03-18 21:33:37 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function converterForTuple(ctx: FunctionContext,
|
|
|
|
ps: M.NamedPattern[],
|
|
|
|
src: string,
|
|
|
|
recordFields: boolean,
|
|
|
|
variablePattern: M.NamedSimplePattern | undefined,
|
|
|
|
k: () => Item[]): Item[]
|
|
|
|
{
|
|
|
|
function loop(i: number): Item[] {
|
|
|
|
if (i < ps.length) {
|
|
|
|
return converterFor(ctx, ps[i], `${src}[${i}]`, () => loop(i + 1));
|
|
|
|
} else {
|
|
|
|
if (variablePattern === void 0) {
|
|
|
|
return k();
|
|
|
|
} else {
|
2021-03-19 22:42:43 +00:00
|
|
|
const vN = ctx.gentemp(Type.array(ANY_TYPE));
|
2021-03-18 21:33:37 +00:00
|
|
|
return [ps.length > 0 ? `${vN} = ${src}.slice(${ps.length})` : `${vN} = ${src}`,
|
|
|
|
converterForArray(ctx, variablePattern, vN, false, k)];
|
2021-03-18 10:15:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-03-18 21:33:37 +00:00
|
|
|
|
|
|
|
const lengthCheck = variablePattern === void 0
|
|
|
|
? seq(` && ${src}.length === ${ps.length}`)
|
|
|
|
: ((ps.length === 0) ? '' : seq(` && ${src}.length >= ${ps.length}`));
|
|
|
|
|
|
|
|
return recordFields
|
|
|
|
? loop(0)
|
|
|
|
: [seq(`if (_.Array.isArray(${src})`, lengthCheck, `) `, ctx.block(() => loop(0)))];
|
2021-03-18 10:15:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function converterForArray(ctx: FunctionContext,
|
2021-03-18 21:33:37 +00:00
|
|
|
arrayType: M.NamedSimplePattern,
|
2021-03-18 10:15:10 +00:00
|
|
|
src: string,
|
2021-03-18 21:33:37 +00:00
|
|
|
checkArray: boolean,
|
|
|
|
k: (dest: string) => Item[]): Item
|
2021-03-18 10:15:10 +00:00
|
|
|
{
|
2021-03-18 21:33:37 +00:00
|
|
|
const postCheck = () => {
|
2021-03-22 11:13:34 +00:00
|
|
|
const r = ctx.gentemp(Type.array(simpleType(ctx.mod, M.unnameSimplePattern(arrayType))));
|
2021-03-18 21:33:37 +00:00
|
|
|
const v = ctx.gentempname();
|
|
|
|
return [
|
|
|
|
seq(`${r} = []`),
|
|
|
|
seq(`for (const ${v} of ${src}) `, ctx.block(() => [
|
2021-03-22 11:13:34 +00:00
|
|
|
... converterFor(ctx, M.promoteNamedSimplePattern(arrayType), v, vv =>
|
|
|
|
[`${r}.push(${vv})`, `continue`]),
|
2021-03-18 21:33:37 +00:00
|
|
|
seq(`${r} = void 0`),
|
|
|
|
seq(`break`)])),
|
2021-03-18 21:41:27 +00:00
|
|
|
ctx.convertCapture(M.nameFor(arrayType), r, k)];
|
2021-03-18 21:33:37 +00:00
|
|
|
};
|
2021-03-18 10:15:10 +00:00
|
|
|
return (checkArray
|
|
|
|
? seq(`if (_.Array.isArray(${src})) `, ctx.block(postCheck))
|
|
|
|
: block(... postCheck()));
|
|
|
|
}
|
|
|
|
|
|
|
|
function converterFor(
|
|
|
|
ctx: FunctionContext,
|
2021-03-18 21:33:37 +00:00
|
|
|
np: M.NamedPattern,
|
2021-03-18 10:15:10 +00:00
|
|
|
src: string,
|
2021-03-18 21:33:37 +00:00
|
|
|
ks: (dest: string | undefined) => Item[],
|
2021-03-18 10:15:10 +00:00
|
|
|
recordFields = false): Item[]
|
|
|
|
{
|
2021-03-22 11:13:34 +00:00
|
|
|
let p = M.unnamePattern(np);
|
2021-03-18 21:33:37 +00:00
|
|
|
let maybeName = M.nameFor(np);
|
2021-03-18 10:15:10 +00:00
|
|
|
|
2021-03-22 11:13:34 +00:00
|
|
|
if (p._variant === 'SimplePattern') {
|
|
|
|
const dest = ctx.gentemp(simpleType(ctx.mod, p.value));
|
|
|
|
return [... converterForSimple(ctx, p.value, src, dest),
|
2021-03-18 21:41:27 +00:00
|
|
|
ctx.convertCapture(maybeName, dest, ks)];
|
2021-03-18 10:15:10 +00:00
|
|
|
} else {
|
2021-03-22 11:13:34 +00:00
|
|
|
switch (p.value._variant) {
|
|
|
|
case 'setof': {
|
|
|
|
const setPattern = p.value.pattern;
|
2021-03-19 22:42:43 +00:00
|
|
|
const r = ctx.gentemp(setType(ctx.mod, setPattern));
|
2021-03-18 21:33:37 +00:00
|
|
|
const v = ctx.gentempname();
|
|
|
|
return [
|
|
|
|
seq(`if (_.Set.isSet<_ptr>(${src})) `, ctx.block(() => [
|
|
|
|
seq(`${r} = new _.KeyedSet()`),
|
|
|
|
seq(`for (const ${v} of ${src}) `, ctx.block(() => [
|
2021-03-22 11:13:34 +00:00
|
|
|
... converterFor(ctx, M.anonymousSimplePattern(setPattern), v, vv =>
|
2021-03-18 21:33:37 +00:00
|
|
|
[`${r}.add(${vv})`, `continue`]),
|
|
|
|
seq(`${r} = void 0`),
|
|
|
|
seq(`break`)])),
|
2021-03-18 21:41:27 +00:00
|
|
|
ctx.convertCapture(maybeName, r, ks)]))];
|
2021-03-18 21:33:37 +00:00
|
|
|
}
|
2021-03-22 11:13:34 +00:00
|
|
|
case 'dictof': {
|
|
|
|
const keyPattern = p.value.key;
|
|
|
|
const valPattern = p.value.value;
|
2021-03-19 22:42:43 +00:00
|
|
|
const r = ctx.gentemp(dictionaryType(ctx.mod, keyPattern, valPattern));
|
2021-03-18 21:33:37 +00:00
|
|
|
const v = ctx.gentempname();
|
|
|
|
const k = ctx.gentempname();
|
|
|
|
return [
|
|
|
|
seq(`if (_.Dictionary.isDictionary<_ptr>(${src})) `, ctx.block(() => [
|
|
|
|
seq(`${r} = new _.KeyedDictionary()`),
|
|
|
|
seq(`for (const [${k}, ${v}] of ${src}) `, ctx.block(() => [
|
2021-03-22 11:13:34 +00:00
|
|
|
... converterFor(ctx, M.anonymousSimplePattern(keyPattern), k, kk =>
|
|
|
|
converterFor(ctx, M.anonymousSimplePattern(valPattern), v, vv =>
|
2021-03-18 21:33:37 +00:00
|
|
|
[`${r}.set(${kk}, ${vv})`, `continue`])),
|
|
|
|
seq(`${r} = void 0`),
|
|
|
|
seq(`break`)])),
|
2021-03-18 21:41:27 +00:00
|
|
|
ctx.convertCapture(maybeName, r, ks)]))];
|
2021-03-18 21:33:37 +00:00
|
|
|
}
|
2021-03-18 10:15:10 +00:00
|
|
|
default: {
|
2021-03-22 11:13:34 +00:00
|
|
|
const arrayType = M.simpleArray(p.value);
|
2021-03-18 10:15:10 +00:00
|
|
|
if (arrayType === void 0) {
|
2021-03-22 11:13:34 +00:00
|
|
|
return converterForCompound(ctx, p.value, src, recordFields, () => ks(void 0));
|
2021-03-18 10:15:10 +00:00
|
|
|
} else {
|
2021-03-22 11:13:34 +00:00
|
|
|
return [converterForArray(
|
|
|
|
ctx, M.NamedSimplePattern.anonymous(arrayType), src, !recordFields, ks)];
|
2021-03-18 10:15:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-22 13:43:40 +00:00
|
|
|
export function converterForSimple(
|
2021-03-18 10:15:10 +00:00
|
|
|
ctx: FunctionContext,
|
|
|
|
p: M.SimplePattern,
|
|
|
|
src: string,
|
|
|
|
dest: string): Item[]
|
|
|
|
{
|
2021-03-22 11:13:34 +00:00
|
|
|
switch (p._variant) {
|
|
|
|
case 'any':
|
2021-03-19 22:42:43 +00:00
|
|
|
return [`${dest} = ${src}`];
|
2021-03-22 11:13:34 +00:00
|
|
|
case 'atom': {
|
2021-03-18 10:15:10 +00:00
|
|
|
let test: Item;
|
2021-03-23 10:36:55 +00:00
|
|
|
let valexp: Item = `${src}`;
|
2021-03-22 11:13:34 +00:00
|
|
|
switch (p.atomKind._variant) {
|
|
|
|
case 'Boolean': test = `typeof ${src} === 'boolean'`; break;
|
2021-03-23 10:36:55 +00:00
|
|
|
case 'Float': test = `_.Float.isSingle(${src})`; valexp = `${src}.value`; break;
|
|
|
|
case 'Double': test =`_.Float.isDouble(${src})`; valexp = `${src}.value`; break;
|
2021-03-22 11:13:34 +00:00
|
|
|
case 'SignedInteger': test = `typeof ${src} === 'number'`; break;
|
|
|
|
case 'String': test = `typeof ${src} === 'string'`; break;
|
|
|
|
case 'ByteString': test = `_.Bytes.isBytes(${src})`; break;
|
|
|
|
case 'Symbol': test = `typeof ${src} === 'symbol'`; break;
|
2021-03-18 10:15:10 +00:00
|
|
|
}
|
2021-03-23 10:36:55 +00:00
|
|
|
return [seq(`${dest} = `, test, ` ? `, valexp, ` : void 0`)];
|
2021-03-18 10:15:10 +00:00
|
|
|
}
|
2021-03-22 11:13:34 +00:00
|
|
|
case 'lit':
|
|
|
|
return [`${dest} = _.is(${src}, ${ctx.mod.literal(p.value)}) ? null : void 0`];
|
|
|
|
case 'Ref':
|
|
|
|
return M.lookup(refPosition(p.value), p.value, ctx.mod.env,
|
|
|
|
(_p) => [`${dest} = to${p.value.name.description!}(${src})`],
|
2021-03-18 10:15:10 +00:00
|
|
|
(modId, modPath,_p) => {
|
|
|
|
ctx.mod.imports.add([modId, modPath]);
|
2021-03-22 13:43:40 +00:00
|
|
|
return [`${dest} = ${modId}.to${p.value.name.description!}(${src})`];
|
2021-03-18 10:15:10 +00:00
|
|
|
});
|
2021-03-22 11:13:34 +00:00
|
|
|
case 'pointer':
|
2021-03-18 10:15:10 +00:00
|
|
|
return [`${dest} = _toPtr(${src})`];
|
|
|
|
default:
|
|
|
|
((_p: never) => {})(p);
|
|
|
|
throw new Error("Unreachable");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function converterForCompound(
|
|
|
|
ctx: FunctionContext,
|
|
|
|
p: M.CompoundPattern,
|
|
|
|
src: string,
|
2021-03-18 21:33:37 +00:00
|
|
|
recordFields: boolean,
|
|
|
|
ks: () => Item[]): Item[]
|
2021-03-18 10:15:10 +00:00
|
|
|
{
|
2021-03-22 11:13:34 +00:00
|
|
|
switch (p._variant) {
|
|
|
|
case 'rec':
|
2021-03-18 21:33:37 +00:00
|
|
|
return [seq(`if (_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(${src})) `, ctx.block(() =>
|
2021-03-22 11:13:34 +00:00
|
|
|
converterFor(ctx, p.label, `${src}.label`, () =>
|
|
|
|
converterFor(ctx, p.fields, src, ks, true))))];
|
|
|
|
case 'tuple':
|
|
|
|
return converterForTuple(ctx, p.patterns, src, recordFields, void 0, ks);
|
|
|
|
case 'tuple*':
|
|
|
|
return converterForTuple(ctx, p.fixed, src, recordFields, p.variable, ks);
|
|
|
|
case 'setof':
|
|
|
|
case 'dictof':
|
2021-03-18 10:15:10 +00:00
|
|
|
throw new Error('Internal error: setof and dictof are handled in converterFor()');
|
2021-03-22 11:13:34 +00:00
|
|
|
case 'dict': {
|
|
|
|
const entries = Array.from(p.entries);
|
2021-03-18 10:15:10 +00:00
|
|
|
function loop(i: number): Item[] {
|
|
|
|
if (i < entries.length) {
|
|
|
|
const [k, n] = entries[i];
|
|
|
|
const tmpSrc = ctx.gentemp();
|
2021-03-18 21:33:37 +00:00
|
|
|
return [seq(`if ((${tmpSrc} = ${src}.get(${ctx.mod.literal(k)})) !== void 0) `,
|
|
|
|
ctx.block(() =>
|
2021-03-22 11:13:34 +00:00
|
|
|
converterFor(
|
|
|
|
ctx,
|
|
|
|
M.promoteNamedSimplePattern(M.addNameIfAbsent(n, k)),
|
|
|
|
tmpSrc,
|
|
|
|
() => loop(i + 1))))];
|
2021-03-18 10:15:10 +00:00
|
|
|
} else {
|
2021-03-18 21:33:37 +00:00
|
|
|
return ks();
|
2021-03-18 10:15:10 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-18 21:33:37 +00:00
|
|
|
return [seq(`if (_.Dictionary.isDictionary<_ptr>(${src})) `, ctx.block(() => loop(0)))];
|
2021-03-18 10:15:10 +00:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
((_p: never) => {})(p);
|
|
|
|
throw new Error("Unreachable");
|
|
|
|
}
|
|
|
|
}
|