Prepare for alternative compiler output
This commit is contained in:
parent
b9019d03f1
commit
e6f99ae2e1
|
@ -4,7 +4,7 @@ import * as M from './gen/schema';
|
|||
export const BASE: M.Schema = M.asSchema(Record(M.$schema, [new Dictionary<never>([
|
||||
[M.$version, 1],
|
||||
[M.$pointer, false],
|
||||
[M.$definitions, new Dictionary<never>([
|
||||
[M.$definitions, new Dictionary<never, M.Alternative>([
|
||||
[Symbol.for('any'), Record(M.$and, [[] as M.Pattern[]])],
|
||||
[Symbol.for('bool'), Record(M.$atom, [M.$Boolean])],
|
||||
[Symbol.for('float'), Record(M.$atom, [M.$Float])],
|
||||
|
|
|
@ -88,7 +88,8 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
|
|||
}
|
||||
}
|
||||
|
||||
function decoderForTuple(ps: Pattern[],
|
||||
function decoderForTuple(tuplePattern: Pattern,
|
||||
ps: Pattern[],
|
||||
dest: string,
|
||||
recordFields: boolean,
|
||||
variablePattern: Pattern | undefined): void {
|
||||
|
@ -103,8 +104,8 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
|
|||
emit(seq(`if (d.closeCompound()) ${dest} = `, brackets(... temps)));
|
||||
} else {
|
||||
emit(block(
|
||||
seq(`let vN: Array<`, typeFor(variablePattern),
|
||||
`> | undefined = `, brackets(... temps)),
|
||||
seq(`let vN: `, typeFor(tuplePattern),
|
||||
` | undefined = `, brackets(... temps)),
|
||||
accumulateCompound(variablePattern,
|
||||
() => [`vN = void 0`],
|
||||
(t) => [`vN.push(${t})`]),
|
||||
|
@ -245,11 +246,11 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
|
|||
break;
|
||||
case M.$tuple:
|
||||
// assume dest is already void 0
|
||||
decoderForTuple(p[0].map(unname), dest, recordFields, void 0);
|
||||
decoderForTuple(p, p[0].map(unname), dest, recordFields, void 0);
|
||||
break;
|
||||
case M.$tuple_STAR_:
|
||||
// assume dest is already void 0
|
||||
decoderForTuple(p[0].map(unname), dest, recordFields, unname(p[1]));
|
||||
decoderForTuple(p, p[0].map(unname), dest, recordFields, unname(p[1]));
|
||||
break;
|
||||
case M.$setof:
|
||||
// assume dest is already void 0
|
||||
|
@ -288,7 +289,7 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
|
|||
}
|
||||
}
|
||||
|
||||
function typeFor(p: Definition): Item {
|
||||
function typeFor(p: Pattern): Item {
|
||||
switch (p.label) {
|
||||
case M.$atom:
|
||||
switch (p[0]) {
|
||||
|
@ -305,15 +306,11 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
|
|||
case M.$ref:
|
||||
return lookup(refPosition(p), p, env,
|
||||
(_p) => p[1].description!,
|
||||
(p) => typeFor(p),
|
||||
(p) => typeForAlternative(p),
|
||||
(mod, modPath,_p) => {
|
||||
imports.add([mod, modPath]);
|
||||
return `${mod}.${p[1].description!}`;
|
||||
});
|
||||
case M.$or:
|
||||
return opseq('never', ' | ', ... p[0].map(pp => typeFor(pp[1])));
|
||||
case M.$and:
|
||||
return opseq('_val', ' & ', ... p[0].map(pp => typeFor(pp)));
|
||||
case M.$pointer:
|
||||
return `_ptr`;
|
||||
case M.$rec:
|
||||
|
@ -345,6 +342,22 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
|
|||
}
|
||||
}
|
||||
|
||||
function typeForDefinition(name: symbol, d: Definition): Item {
|
||||
if (d.label === M.$or) {
|
||||
return opseq('never', ' | ', ... d[0].map(a => typeForAlternative(a[1])));
|
||||
} else {
|
||||
return typeForAlternative(d);
|
||||
}
|
||||
}
|
||||
|
||||
function typeForAlternative(a: Alternative): Item {
|
||||
if (a.label === M.$and) {
|
||||
return opseq('_val', ' & ', ... a[0].map(p => typeFor(p)));
|
||||
} else {
|
||||
return typeFor(a);
|
||||
}
|
||||
}
|
||||
|
||||
function predicateFor(v: string, p: Definition, recordOkAsTuple = false): Item {
|
||||
switch (p.label) {
|
||||
case M.$atom:
|
||||
|
@ -450,22 +463,22 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
|
|||
return seq(JSON.stringify(fieldName(np, index)), ': ', typeFor(unname(np)));
|
||||
}
|
||||
|
||||
for (const [name0, pattern] of Schema._.details(schema).get(M.$definitions)) {
|
||||
for (const [name0, def] of Schema._.details(schema).get(M.$definitions)) {
|
||||
const name = name0 as symbol;
|
||||
temps = [];
|
||||
const recognizer = predicateFor('v', pattern);
|
||||
if (pattern.label === M.$rec &&
|
||||
pattern[0].label === M.$lit &&
|
||||
pattern[1].label === M.$tuple)
|
||||
const recognizer = predicateFor('v', def);
|
||||
if (def.label === M.$rec &&
|
||||
def[0].label === M.$lit &&
|
||||
def[1].label === M.$tuple)
|
||||
{
|
||||
types.push(
|
||||
seq(`export const ${name.description!} = _.Record.makeConstructor<`,
|
||||
braces(... pattern[1][0].map(fieldEntry)),
|
||||
`, _ptr>()(${literal(pattern[0][0])}, `,
|
||||
JSON.stringify(pattern[1][0].map(fieldName)), `);`));
|
||||
braces(... def[1][0].map(fieldEntry)),
|
||||
`, _ptr>()(${literal(def[0][0])}, `,
|
||||
JSON.stringify(def[1][0].map(fieldName)), `);`));
|
||||
}
|
||||
types.push(
|
||||
seq(`export type ${name.description!} = `, typeFor(pattern), `;`));
|
||||
seq(`export type ${name.description!} = `, typeForDefinition(name, def), `;`));
|
||||
functions.push(
|
||||
seq(`export function is${name.description!}`,
|
||||
'(v: any): v is ', name.description!, ' ',
|
||||
|
@ -486,7 +499,7 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
|
|||
`(d: _.TypedDecoder<_ptr>): ${name.description!} | undefined `,
|
||||
collectBody(() => {
|
||||
emit(seq(`let result`));
|
||||
decoderFor(pattern, 'result');
|
||||
decoderFor(def, 'result');
|
||||
emit(seq(`return result`));
|
||||
})));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Value, is, Position } from '@preserves/core';
|
||||
import { ModulePath, Ref, Schema, $definitions, Definition } from './gen/schema';
|
||||
import { ModulePath, Ref, Schema, $definitions, Definition, Alternative } from './gen/schema';
|
||||
import { BASE } from './base';
|
||||
import { SchemaSyntaxError } from './error';
|
||||
|
||||
|
@ -42,7 +42,7 @@ export function lookup<R>(namePos: Position | null,
|
|||
name: Ref,
|
||||
env: Environment,
|
||||
kLocal: (p: Definition) => R,
|
||||
kBase: (p: Definition) => R,
|
||||
kBase: (p: Alternative) => R,
|
||||
kOther: (mod: string, modPath: string, p: Definition | null) => R): R
|
||||
{
|
||||
for (const e of env) {
|
||||
|
@ -67,7 +67,7 @@ export function lookup<R>(namePos: Position | null,
|
|||
|
||||
if (Ref._.module(name).length === 0) {
|
||||
const p = Schema._.details(BASE).get($definitions).get(Ref._.name(name));
|
||||
if (p !== void 0) return kBase(p);
|
||||
if (p !== void 0) return kBase(p as Alternative);
|
||||
}
|
||||
|
||||
throw new SchemaSyntaxError(`Undefined reference: ${formatRef(name)}`, namePos);
|
||||
|
|
Loading…
Reference in New Issue