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