2021-03-18 10:15:10 +00:00
|
|
|
import { Annotated, Bytes, Dictionary, Fold, fold, Record, stringify, Tuple, Value } from "@preserves/core";
|
|
|
|
import * as M from "./meta";
|
|
|
|
import { CompilerOptions, ModuleContext } from "./compiler/context";
|
2021-03-21 21:02:34 +00:00
|
|
|
import { block, brackets, Formatter, Item, parens, seq } from "./compiler/block";
|
2021-03-19 22:42:43 +00:00
|
|
|
import { typeForDefinition } from "./compiler/gentype";
|
2021-03-18 21:33:37 +00:00
|
|
|
// import { decoderFor } from "./compiler/decoder";
|
2021-03-19 22:42:43 +00:00
|
|
|
import { converterForDefinition } from "./compiler/genconverter";
|
|
|
|
import { EMPTY_TYPE, renderType } from "./compiler/type";
|
2021-03-21 21:02:34 +00:00
|
|
|
import { genConstructor } from "./compiler/genctor";
|
2021-03-18 10:15:10 +00:00
|
|
|
|
|
|
|
export function compile(env: M.Environment, schema: M.Schema, options: CompilerOptions = {}): string {
|
2021-03-17 14:59:46 +00:00
|
|
|
const mod = new ModuleContext(env, schema, options);
|
2021-03-09 14:59:40 +00:00
|
|
|
|
2021-03-22 11:13:34 +00:00
|
|
|
const pointerName = schema.pointer;
|
2021-03-17 15:25:29 +00:00
|
|
|
mod.defineType(seq(`export type _ptr = `,
|
2021-03-22 11:13:34 +00:00
|
|
|
renderType(pointerName._variant === 'false'
|
2021-03-19 22:42:43 +00:00
|
|
|
? EMPTY_TYPE
|
2021-03-22 11:13:34 +00:00
|
|
|
: typeForDefinition(mod, M.Definition.Alternative(M.Alternative.Pattern(M.Pattern.SimplePattern(M.SimplePattern.Ref(pointerName.value)))))),
|
2021-03-17 15:25:29 +00:00
|
|
|
`;`));
|
|
|
|
mod.defineType(`export type _val = _.Value<_ptr>;`);
|
|
|
|
|
|
|
|
mod.defineFunction(ctx =>
|
|
|
|
seq(`export const _decodePtr = `,
|
2021-03-22 11:13:34 +00:00
|
|
|
(pointerName._variant === 'false'
|
2021-03-17 15:25:29 +00:00
|
|
|
? '() => { throw new _.DecodeError("Pointers forbidden"); }'
|
|
|
|
: seq(`(d: _.TypedDecoder<_ptr>) => `, ctx.block(() => [
|
|
|
|
seq(`let result`),
|
2021-03-18 21:33:37 +00:00
|
|
|
seq(`/* TODO */`),
|
|
|
|
// ... decoderFor(ctx, pointerName, 'result'),
|
2021-03-17 15:25:29 +00:00
|
|
|
seq(`return result`)]))),
|
|
|
|
`;`));
|
|
|
|
|
2021-03-22 11:13:34 +00:00
|
|
|
for (const [name, def] of schema.definitions) {
|
2021-03-21 21:02:34 +00:00
|
|
|
const t = typeForDefinition(mod, def);
|
|
|
|
const nameStr = stringify(name);
|
|
|
|
|
|
|
|
mod.defineType(seq(`export type ${nameStr} = `, renderType(t), `;`));
|
|
|
|
|
|
|
|
if (t.kind === 'union') {
|
|
|
|
mod.defineFunction(_ctx =>
|
|
|
|
seq(`export namespace ${nameStr} `, block(
|
|
|
|
... Array.from(t.variants).map(([vn, vt]) =>
|
|
|
|
genConstructor(vn, vn, vt, nameStr))
|
|
|
|
)));
|
|
|
|
} else {
|
|
|
|
mod.defineFunction(_ctx =>
|
|
|
|
genConstructor(nameStr, void 0, t, nameStr));
|
|
|
|
}
|
2021-03-17 15:25:29 +00:00
|
|
|
}
|
|
|
|
|
2021-03-22 11:13:34 +00:00
|
|
|
for (const [name0, def] of schema.definitions) {
|
2021-03-17 15:25:29 +00:00
|
|
|
const name = name0 as symbol;
|
2021-03-17 14:59:46 +00:00
|
|
|
|
|
|
|
mod.defineFunction(ctx =>
|
2021-03-12 19:41:35 +00:00
|
|
|
seq(`export function as${name.description!}`,
|
2021-03-18 21:33:37 +00:00
|
|
|
'(v: _val): ', name.description!, ' ',
|
2021-03-17 14:59:46 +00:00
|
|
|
ctx.block(() => [
|
2021-03-18 10:15:10 +00:00
|
|
|
seq(`let result = to${name.description!}(v)`),
|
|
|
|
seq(`if (result === void 0) `,
|
|
|
|
`throw new TypeError(\`Invalid ${name.description!}: \${_.stringify(v)}\`)`),
|
|
|
|
seq(`return result`)])));
|
|
|
|
|
|
|
|
mod.defineFunction(ctx =>
|
|
|
|
seq(`export function to${name.description!}`,
|
2021-03-18 21:33:37 +00:00
|
|
|
'(v: _val): undefined | ', name.description!, ' ',
|
|
|
|
ctx.block(() => [seq(`let result: undefined | `, name.description!),
|
2021-03-18 10:15:10 +00:00
|
|
|
... converterForDefinition(ctx, def, 'v', 'result'),
|
|
|
|
seq(`return result`)])));
|
2021-03-12 19:41:35 +00:00
|
|
|
|
2021-03-18 21:33:37 +00:00
|
|
|
// mod.defineFunction(ctx =>
|
|
|
|
// seq(`export function decode${name.description!}`,
|
|
|
|
// `(d: _.TypedDecoder<_ptr>): undefined | `, name.description!,
|
|
|
|
// ctx.block(() => [seq(`let result: undefined | `, name.description!),
|
|
|
|
// seq(`/* TODO */`),
|
|
|
|
// // ... decoderFor(ctx, def, 'result'),
|
|
|
|
// seq(`return result`)])));
|
2021-03-09 14:59:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const f = new Formatter();
|
2021-03-11 16:59:40 +00:00
|
|
|
f.write(`import * as _ from ${JSON.stringify(options.preservesModule ?? '@preserves/core')};\n`);
|
2021-03-17 14:59:46 +00:00
|
|
|
mod.imports.forEach(([identifier, path]) => {
|
2021-03-11 13:43:06 +00:00
|
|
|
f.write(`import * as ${identifier} from ${JSON.stringify(path)};\n`);
|
|
|
|
});
|
2021-03-09 14:59:40 +00:00
|
|
|
f.newline();
|
|
|
|
|
2021-03-17 14:59:46 +00:00
|
|
|
const sortedLiterals = Array.from(mod.literals);
|
2021-03-09 15:45:57 +00:00
|
|
|
sortedLiterals.sort((a, b) => a[1] < b[1] ? -1 : a[1] === b[1] ? 0 : 1);
|
|
|
|
for (const [lit, varname] of sortedLiterals) {
|
|
|
|
f.write(seq(`export const ${varname} = `, sourceCodeFor(lit), `;\n`));
|
2021-03-09 14:59:40 +00:00
|
|
|
}
|
|
|
|
f.newline();
|
|
|
|
|
2021-03-17 14:59:46 +00:00
|
|
|
mod.typedefs.forEach(t => {
|
2021-03-09 14:59:40 +00:00
|
|
|
f.write(t);
|
|
|
|
f.newline();
|
2021-03-09 15:45:57 +00:00
|
|
|
f.newline();
|
2021-03-09 14:59:40 +00:00
|
|
|
});
|
|
|
|
f.newline();
|
|
|
|
|
2021-03-17 14:59:46 +00:00
|
|
|
mod.functiondefs.forEach(p => {
|
2021-03-09 14:59:40 +00:00
|
|
|
f.write(p);
|
|
|
|
f.newline();
|
|
|
|
f.newline();
|
|
|
|
});
|
|
|
|
|
|
|
|
return f.toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
export function sourceCodeFor(v: Value<any>): Item {
|
|
|
|
return fold(v, {
|
|
|
|
boolean(b: boolean): Item { return b.toString(); },
|
|
|
|
single(f: number): Item { return f.toString(); },
|
|
|
|
double(f: number): Item { return f.toString(); },
|
|
|
|
integer(i: number): Item { return i.toString(); },
|
2021-03-18 10:15:10 +00:00
|
|
|
string(s: string): Item { return JSON.stringify(s); },
|
2021-03-09 14:59:40 +00:00
|
|
|
bytes(b: Bytes): Item {
|
|
|
|
return seq(`Uint8Array.from(`, brackets(... Array.from(b).map(b => b.toString())), `)`);
|
|
|
|
},
|
2021-03-18 10:15:10 +00:00
|
|
|
symbol(s: symbol): Item { return `Symbol.for(${JSON.stringify(s.description!)})`; },
|
2021-03-09 14:59:40 +00:00
|
|
|
|
|
|
|
record(r: Record<Value<any>, Tuple<Value<any>>, any>, k: Fold<any, Item>): Item {
|
2021-03-11 16:59:40 +00:00
|
|
|
return seq(`_.Record<_val, _.Tuple<_val>, _ptr>`, parens(k(r.label), brackets(... r.map(k))));
|
2021-03-09 14:59:40 +00:00
|
|
|
},
|
|
|
|
array(a: Array<Value<any>>, k: Fold<any, Item>): Item {
|
|
|
|
return brackets(... a.map(k));
|
|
|
|
},
|
|
|
|
set(s: Set<any>, k: Fold<any, Item>): Item {
|
2021-03-11 16:59:40 +00:00
|
|
|
return seq('new _.Set<_val>', parens(brackets(... Array.from(s).map(k))));
|
2021-03-09 14:59:40 +00:00
|
|
|
},
|
2021-03-17 11:20:50 +00:00
|
|
|
dictionary(d: Dictionary<any>, k: Fold<any, Item>): Item {
|
|
|
|
return seq('new _.Dictionary<_ptr>', parens(brackets(... Array.from(d).map(([kk,vv]) =>
|
2021-03-09 14:59:40 +00:00
|
|
|
brackets(k(kk), k(vv))))));
|
|
|
|
},
|
|
|
|
|
|
|
|
annotated(a: Annotated<any>, k: Fold<any, Item>): Item {
|
2021-03-11 16:59:40 +00:00
|
|
|
return seq('_.annotate<_ptr>', parens(k(a.item), ... a.annotations.map(k)));
|
2021-03-09 14:59:40 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
pointer(t: any, _k: Fold<any, Item>): Item {
|
2021-03-18 10:15:10 +00:00
|
|
|
throw new Error(`Cannot emit source code for construction of pointer ${stringify(t)}`);
|
2021-03-09 14:59:40 +00:00
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|