Simplify schemas by allowing at most one of "&" or "/" in a definition
This commit is contained in:
parent
436b14e2fe
commit
10380e451a
|
@ -16,7 +16,7 @@ export function compile(env: M.Environment, schema: M.Schema, options: CompilerO
|
||||||
mod.defineType(seq(`export type _embedded = `,
|
mod.defineType(seq(`export type _embedded = `,
|
||||||
renderType(embeddedName._variant === 'false'
|
renderType(embeddedName._variant === 'false'
|
||||||
? Type.ref('any')
|
? Type.ref('any')
|
||||||
: typeForDefinition(mod, M.Definition.Alternative(M.Alternative.Pattern(M.Pattern.SimplePattern(M.SimplePattern.Ref(embeddedName.value)))))),
|
: typeForDefinition(mod, M.Definition.Pattern(M.Pattern.SimplePattern(M.SimplePattern.Ref(embeddedName.value))))),
|
||||||
`;`));
|
`;`));
|
||||||
mod.defineType(`export type _val = _.Value<_embedded>;`);
|
mod.defineType(`export type _val = _.Value<_embedded>;`);
|
||||||
|
|
||||||
|
|
|
@ -46,13 +46,12 @@ export class ModuleContext {
|
||||||
if (refCount > RECURSION_LIMIT) {
|
if (refCount > RECURSION_LIMIT) {
|
||||||
throw new Error('Recursion limit exceeded');
|
throw new Error('Recursion limit exceeded');
|
||||||
}
|
}
|
||||||
if (p._variant === 'Alternative' &&
|
if (p._variant === 'Pattern' &&
|
||||||
p.value._variant === 'Pattern' &&
|
p.value._variant === 'SimplePattern' &&
|
||||||
p.value.value._variant === 'SimplePattern' &&
|
p.value.value._variant === 'Ref')
|
||||||
p.value.value.value._variant === 'Ref')
|
|
||||||
{
|
{
|
||||||
return M.lookup(refPosition(p.value.value.value.value),
|
return M.lookup(refPosition(p.value.value.value),
|
||||||
p.value.value.value.value,
|
p.value.value.value,
|
||||||
this.env,
|
this.env,
|
||||||
(p) => this.derefPattern(p, refCount + 1),
|
(p) => this.derefPattern(p, refCount + 1),
|
||||||
(_modId, _modPath, pp) => this.derefPattern(pp ?? p, refCount + 1));
|
(_modId, _modPath, pp) => this.derefPattern(pp ?? p, refCount + 1));
|
||||||
|
|
|
@ -11,53 +11,54 @@ export function converterForDefinition(
|
||||||
src: string,
|
src: string,
|
||||||
dest: string): Item[]
|
dest: string): Item[]
|
||||||
{
|
{
|
||||||
if (p._variant === 'or') {
|
switch (p._variant) {
|
||||||
const alts = [p.pattern, ... p.patterns];
|
case 'or': {
|
||||||
function loop(i: number): Item[] {
|
const alts = [p.pattern, ... p.patterns];
|
||||||
ctx.variantName = alts[i].variantLabel;
|
function loop(i: number): Item[] {
|
||||||
return [... converterForAlternative(ctx, alts[i].alternative, src, dest),
|
ctx.variantName = alts[i].variantLabel;
|
||||||
... ((i < alts.length - 1)
|
return [... converterForPattern(ctx, alts[i].pattern, src, dest),
|
||||||
? [seq(`if (${dest} === void 0) `, ctx.block(() => loop(i + 1)))]
|
... ((i < alts.length - 1)
|
||||||
: [])];
|
? [seq(`if (${dest} === void 0) `, ctx.block(() => loop(i + 1)))]
|
||||||
|
: [])];
|
||||||
|
}
|
||||||
|
return loop(0);
|
||||||
}
|
}
|
||||||
return loop(0);
|
case 'and': {
|
||||||
} else {
|
const pcs = [p.pattern, ... p.patterns];
|
||||||
ctx.variantName = void 0;
|
function loop(i: number): Item[] {
|
||||||
return converterForAlternative(ctx, p.value, src, dest);
|
return (i < pcs.length)
|
||||||
|
? converterFor(ctx, pcs[i], src, () => loop(i + 1))
|
||||||
|
: [ctx.buildCapturedCompound(dest)];
|
||||||
|
}
|
||||||
|
return loop(0);
|
||||||
|
}
|
||||||
|
case 'Pattern':
|
||||||
|
ctx.variantName = void 0;
|
||||||
|
return converterForPattern(ctx, p.value, src, dest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function converterForAlternative(
|
function converterForPattern(
|
||||||
ctx: FunctionContext,
|
ctx: FunctionContext,
|
||||||
p: M.Alternative,
|
p: M.Pattern,
|
||||||
src: string,
|
src: string,
|
||||||
dest: string): Item[]
|
dest: string): Item[]
|
||||||
{
|
{
|
||||||
if (p._variant === 'and') {
|
return converterFor(ctx, M.NamedPattern.anonymous(p), src, simpleValue => {
|
||||||
const alts = [p.pattern, ... p.patterns];
|
if (simpleValue === void 0) {
|
||||||
function loop(i: number): Item[] {
|
return [ctx.buildCapturedCompound(dest)];
|
||||||
return (i < alts.length)
|
} else if (ctx.variantName !== void 0) {
|
||||||
? converterFor(ctx, alts[i], src, () => loop(i + 1))
|
if (typeFor(ctx.mod, p).kind === 'unit') {
|
||||||
: [ctx.buildCapturedCompound(dest)];
|
|
||||||
}
|
|
||||||
return loop(0);
|
|
||||||
} else {
|
|
||||||
return converterFor(ctx, M.NamedPattern.anonymous(p.value), src, simpleValue => {
|
|
||||||
if (simpleValue === void 0) {
|
|
||||||
return [ctx.buildCapturedCompound(dest)];
|
return [ctx.buildCapturedCompound(dest)];
|
||||||
} else if (ctx.variantName !== void 0) {
|
|
||||||
if (typeFor(ctx.mod, p.value).kind === 'unit') {
|
|
||||||
return [ctx.buildCapturedCompound(dest)];
|
|
||||||
} else {
|
|
||||||
return [ctx.withCapture('value',
|
|
||||||
simpleValue,
|
|
||||||
() => ctx.buildCapturedCompound(dest))];
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return [`${dest} = ${simpleValue}`];
|
return [ctx.withCapture('value',
|
||||||
|
simpleValue,
|
||||||
|
() => ctx.buildCapturedCompound(dest))];
|
||||||
}
|
}
|
||||||
});
|
} else {
|
||||||
}
|
return [`${dest} = ${simpleValue}`];
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function converterForTuple(ctx: FunctionContext,
|
function converterForTuple(ctx: FunctionContext,
|
||||||
|
|
|
@ -4,24 +4,22 @@ import { ModuleContext } from "./context";
|
||||||
import { ANY_TYPE, AtomicType, CollectionType, FieldMap, SimpleType, Type } from "./type";
|
import { ANY_TYPE, AtomicType, CollectionType, FieldMap, SimpleType, Type } from "./type";
|
||||||
|
|
||||||
export function typeForDefinition(mod: ModuleContext, d: M.Definition): Type {
|
export function typeForDefinition(mod: ModuleContext, d: M.Definition): Type {
|
||||||
if (d._variant === 'or') {
|
switch (d._variant) {
|
||||||
return Type.union(
|
case 'or':
|
||||||
new Map([d.pattern, ... d.patterns].map(a =>
|
return Type.union(
|
||||||
[a.variantLabel, typeForAlternative(mod, a.alternative)])));
|
new Map([d.pattern, ... d.patterns].map(a =>
|
||||||
} else {
|
[a.variantLabel, typeFor(mod, a.pattern)])));
|
||||||
return typeForAlternative(mod, d.value);
|
case 'and':
|
||||||
|
return typeForIntersection(mod, [d.pattern, ... d.patterns]);
|
||||||
|
case 'Pattern':
|
||||||
|
return typeFor(mod, d.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function typeForAlternative(mod: ModuleContext, a: M.Alternative): SimpleType {
|
export function typeForIntersection(mod: ModuleContext, ps: M.NamedPattern[]): SimpleType {
|
||||||
if (a._variant === 'and') {
|
const fs = new Map();
|
||||||
const fs = new Map();
|
ps.forEach(p => gatherFields(fs, mod, p));
|
||||||
gatherFields(fs, mod, a.pattern);
|
return fs.size > 0 ? Type.record(fs) : Type.unit();
|
||||||
a.patterns.forEach(n => gatherFields(fs, mod, n));
|
|
||||||
return fs.size > 0 ? Type.record(fs) : Type.unit();
|
|
||||||
} else {
|
|
||||||
return typeFor(mod, a.value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setType(mod: ModuleContext, p: M.SimplePattern): CollectionType {
|
export function setType(mod: ModuleContext, p: M.SimplePattern): CollectionType {
|
||||||
|
|
|
@ -2,8 +2,8 @@ import { refPosition } from '../reader';
|
||||||
import * as M from '../meta';
|
import * as M from '../meta';
|
||||||
import { block, brackets, formatItems, Item, parens, seq } from './block';
|
import { block, brackets, formatItems, Item, parens, seq } from './block';
|
||||||
import { FunctionContext } from "./context";
|
import { FunctionContext } from "./context";
|
||||||
import { typeForAlternative } from './gentype';
|
|
||||||
import { FieldType, renderType, SimpleType } from './type';
|
import { FieldType, renderType, SimpleType } from './type';
|
||||||
|
import { typeFor, typeForIntersection } from './gentype';
|
||||||
|
|
||||||
export function unconverterForDefinition(
|
export function unconverterForDefinition(
|
||||||
ctx: FunctionContext,
|
ctx: FunctionContext,
|
||||||
|
@ -11,61 +11,59 @@ export function unconverterForDefinition(
|
||||||
def: M.Definition,
|
def: M.Definition,
|
||||||
src: string): Item[]
|
src: string): Item[]
|
||||||
{
|
{
|
||||||
if (def._variant === 'or') {
|
switch (def._variant) {
|
||||||
return [seq(`switch (${src}._variant) `, block(
|
case 'or':
|
||||||
... [def.pattern, ... def.patterns].map(p =>
|
return [seq(`switch (${src}._variant) `, block(
|
||||||
seq(`case `, JSON.stringify(p.variantLabel), `: `, ctx.block(() => {
|
... [def.pattern, ... def.patterns].map(p =>
|
||||||
const hasValueField =
|
seq(`case `, JSON.stringify(p.variantLabel), `: `, ctx.block(() => {
|
||||||
p.alternative._variant === 'Pattern' &&
|
const hasValueField = p.pattern._variant === 'SimplePattern';
|
||||||
p.alternative.value._variant === 'SimplePattern';
|
return [seq(`return `, unconverterForPattern(
|
||||||
return [seq(`return `, unconverterForAlternative(
|
ctx, name, p.pattern, hasValueField ? `${src}.value` : src))];
|
||||||
ctx, name, p.alternative, hasValueField ? `${src}.value` : src))];
|
})))))];
|
||||||
})))))];
|
case 'and': {
|
||||||
} else {
|
const ps = [def.pattern , ... def.patterns];
|
||||||
return [seq(`return `, unconverterForAlternative(ctx, name, def.value, `${src}`))];
|
const t = typeForIntersection(ctx.mod, ps);
|
||||||
|
const errs: [string, InsufficientInformationError][] = [];
|
||||||
|
const cs = ps.flatMap(p => {
|
||||||
|
if (p._variant === 'anonymous' && p.value._variant === 'SimplePattern') {
|
||||||
|
return [];
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
return [unconverterForNamed(ctx, p, src, t)];
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof InsufficientInformationError) {
|
||||||
|
errs.push([name + '/' + (M.nameFor(p) ?? '<anonymous>'), e]);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (cs.length === 0 || errs.length > 0) {
|
||||||
|
throw new Error(`Cannot produce unconverter for ${name}: ` +
|
||||||
|
errs.map(e => `${e[0]}: ${e[1].message}`).join(', '));
|
||||||
|
}
|
||||||
|
return [seq(`return `, (cs.length === 1)
|
||||||
|
? cs[0]
|
||||||
|
: seq(`_.merge`, parens(`(a, b) => (a === b) ? a : void 0`, ... cs)))];
|
||||||
|
}
|
||||||
|
case 'Pattern':
|
||||||
|
return [seq(`return `, unconverterForPattern(ctx, name, def.value, `${src}`))];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class InsufficientInformationError extends Error {}
|
export class InsufficientInformationError extends Error {}
|
||||||
|
|
||||||
function unconverterForAlternative(
|
function unconverterForPattern(ctx: FunctionContext, name: string, a: M.Pattern, src: string): Item
|
||||||
ctx: FunctionContext,
|
|
||||||
name: string,
|
|
||||||
a: M.Alternative,
|
|
||||||
src: string): Item
|
|
||||||
{
|
{
|
||||||
const t = typeForAlternative(ctx.mod, a);
|
const t = typeFor(ctx.mod, a);
|
||||||
if (a._variant === 'and') {
|
try {
|
||||||
const errs: [string, InsufficientInformationError][] = [];
|
return unconverterFor(ctx, a, src, t);
|
||||||
const cs = [a.pattern, ... a.patterns].flatMap(p => {
|
} catch (e) {
|
||||||
if (p._variant === 'anonymous' && p.value._variant === 'SimplePattern') {
|
if (e instanceof InsufficientInformationError) {
|
||||||
return [];
|
throw new Error(`Cannot produce unconverter for ${name}: ${e.message}`);
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
return [unconverterForNamed(ctx, p, src, t)];
|
|
||||||
} catch (e) {
|
|
||||||
if (e instanceof InsufficientInformationError) {
|
|
||||||
errs.push([name + '/' + (M.nameFor(p) ?? '<anonymous>'), e]);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (cs.length === 0 || errs.length > 0) {
|
|
||||||
throw new Error(`Cannot produce unconverter for ${name}: ` +
|
|
||||||
errs.map(e => `${e[0]}: ${e[1].message}`).join(', '));
|
|
||||||
}
|
|
||||||
return (cs.length === 1) ? cs[0] : seq(`_.merge`, parens(`(a, b) => (a === b) ? a : void 0`, ... cs));
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
return unconverterFor(ctx, a.value, src, t);
|
|
||||||
} catch (e) {
|
|
||||||
if (e instanceof InsufficientInformationError) {
|
|
||||||
throw new Error(`Cannot produce unconverter for ${name}: ${e.message}`);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,12 +55,6 @@ export type Definition = (
|
||||||
"pattern": NamedAlternative,
|
"pattern": NamedAlternative,
|
||||||
"patterns": Array<NamedAlternative>
|
"patterns": Array<NamedAlternative>
|
||||||
} |
|
} |
|
||||||
{"_variant": "Alternative", "value": Alternative}
|
|
||||||
);
|
|
||||||
|
|
||||||
export type NamedAlternative = {"variantLabel": string, "alternative": Alternative};
|
|
||||||
|
|
||||||
export type Alternative = (
|
|
||||||
{"_variant": "and", "pattern": NamedPattern, "patterns": Array<NamedPattern>} |
|
{"_variant": "and", "pattern": NamedPattern, "patterns": Array<NamedPattern>} |
|
||||||
{"_variant": "Pattern", "value": Pattern}
|
{"_variant": "Pattern", "value": Pattern}
|
||||||
);
|
);
|
||||||
|
@ -103,6 +97,8 @@ export type AtomKind = (
|
||||||
{"_variant": "Symbol"}
|
{"_variant": "Symbol"}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export type NamedAlternative = {"variantLabel": string, "pattern": Pattern};
|
||||||
|
|
||||||
export type NamedSimplePattern = (
|
export type NamedSimplePattern = (
|
||||||
{"_variant": "named", "value": NamedSimplePattern_} |
|
{"_variant": "named", "value": NamedSimplePattern_} |
|
||||||
{"_variant": "anonymous", "value": SimplePattern}
|
{"_variant": "anonymous", "value": SimplePattern}
|
||||||
|
@ -143,14 +139,8 @@ export namespace Definition {
|
||||||
export function or(
|
export function or(
|
||||||
{pattern, patterns}: {pattern: NamedAlternative, patterns: Array<NamedAlternative>}
|
{pattern, patterns}: {pattern: NamedAlternative, patterns: Array<NamedAlternative>}
|
||||||
): Definition {return {"_variant": "or", "pattern": pattern, "patterns": patterns};};
|
): Definition {return {"_variant": "or", "pattern": pattern, "patterns": patterns};};
|
||||||
export function Alternative(value: Alternative): Definition {return {"_variant": "Alternative", "value": value};};
|
export function and({pattern, patterns}: {pattern: NamedPattern, patterns: Array<NamedPattern>}): Definition {return {"_variant": "and", "pattern": pattern, "patterns": patterns};};
|
||||||
}
|
export function Pattern(value: Pattern): Definition {return {"_variant": "Pattern", "value": value};};
|
||||||
|
|
||||||
export function NamedAlternative({variantLabel, alternative}: {variantLabel: string, alternative: Alternative}): NamedAlternative {return {"variantLabel": variantLabel, "alternative": alternative};}
|
|
||||||
|
|
||||||
export namespace Alternative {
|
|
||||||
export function and({pattern, patterns}: {pattern: NamedPattern, patterns: Array<NamedPattern>}): Alternative {return {"_variant": "and", "pattern": pattern, "patterns": patterns};};
|
|
||||||
export function Pattern(value: Pattern): Alternative {return {"_variant": "Pattern", "value": value};};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace Pattern {
|
export namespace Pattern {
|
||||||
|
@ -187,6 +177,8 @@ export namespace AtomKind {
|
||||||
export function Symbol(): AtomKind {return {"_variant": "Symbol"};};
|
export function Symbol(): AtomKind {return {"_variant": "Symbol"};};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function NamedAlternative({variantLabel, pattern}: {variantLabel: string, pattern: Pattern}): NamedAlternative {return {"variantLabel": variantLabel, "pattern": pattern};}
|
||||||
|
|
||||||
export namespace NamedSimplePattern {
|
export namespace NamedSimplePattern {
|
||||||
export function named(value: NamedSimplePattern_): NamedSimplePattern {return {"_variant": "named", "value": value};};
|
export function named(value: NamedSimplePattern_): NamedSimplePattern {return {"_variant": "named", "value": value};};
|
||||||
export function anonymous(value: SimplePattern): NamedSimplePattern {return {"_variant": "anonymous", "value": value};};
|
export function anonymous(value: SimplePattern): NamedSimplePattern {return {"_variant": "anonymous", "value": value};};
|
||||||
|
@ -415,9 +407,37 @@ export function toDefinition(v: _val): undefined | Definition {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (result === void 0) {
|
if (result === void 0) {
|
||||||
let _tmp6: (Alternative) | undefined;
|
if (_.Record.isRecord<_val, _.Tuple<_val>, _embedded>(v)) {
|
||||||
_tmp6 = toAlternative(v);
|
let _tmp6: (null) | undefined;
|
||||||
if (_tmp6 !== void 0) {result = {"_variant": "Alternative", "value": _tmp6};};
|
_tmp6 = _.is(v.label, $and) ? null : void 0;
|
||||||
|
if (_tmp6 !== void 0) {
|
||||||
|
if (_.Array.isArray(v[0]) && v[0].length >= 1) {
|
||||||
|
let _tmp7: (NamedPattern) | undefined;
|
||||||
|
_tmp7 = toNamedPattern(v[0][0]);
|
||||||
|
if (_tmp7 !== void 0) {
|
||||||
|
let _tmp8: (Array<_val>) | undefined;
|
||||||
|
let _tmp9: (Array<NamedPattern>) | undefined;
|
||||||
|
_tmp8 = v[0].slice(1);
|
||||||
|
{
|
||||||
|
_tmp9 = [];
|
||||||
|
for (const _tmp10 of _tmp8) {
|
||||||
|
let _tmp11: (NamedPattern) | undefined;
|
||||||
|
_tmp11 = toNamedPattern(_tmp10);
|
||||||
|
if (_tmp11 !== void 0) {_tmp9.push(_tmp11); continue;};
|
||||||
|
_tmp9 = void 0;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
if (_tmp9 !== void 0) {result = {"_variant": "and", "pattern": _tmp7, "patterns": _tmp9};};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (result === void 0) {
|
||||||
|
let _tmp12: (Pattern) | undefined;
|
||||||
|
_tmp12 = toPattern(v);
|
||||||
|
if (_tmp12 !== void 0) {result = {"_variant": "Pattern", "value": _tmp12};};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -435,76 +455,6 @@ export function fromDefinition(_v: Definition): _val {
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
case "Alternative": {return fromAlternative(_v.value);};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function asNamedAlternative(v: _val): NamedAlternative {
|
|
||||||
let result = toNamedAlternative(v);
|
|
||||||
if (result === void 0) throw new TypeError(`Invalid NamedAlternative: ${_.stringify(v)}`);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toNamedAlternative(v: _val): undefined | NamedAlternative {
|
|
||||||
let result: undefined | NamedAlternative;
|
|
||||||
if (_.Array.isArray(v) && v.length === 2) {
|
|
||||||
let _tmp0: (string) | undefined;
|
|
||||||
_tmp0 = typeof v[0] === 'string' ? v[0] : void 0;
|
|
||||||
if (_tmp0 !== void 0) {
|
|
||||||
let _tmp1: (Alternative) | undefined;
|
|
||||||
_tmp1 = toAlternative(v[1]);
|
|
||||||
if (_tmp1 !== void 0) {result = {"variantLabel": _tmp0, "alternative": _tmp1};};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fromNamedAlternative(_v: NamedAlternative): _val {return [_v["variantLabel"], fromAlternative(_v["alternative"])];}
|
|
||||||
|
|
||||||
export function asAlternative(v: _val): Alternative {
|
|
||||||
let result = toAlternative(v);
|
|
||||||
if (result === void 0) throw new TypeError(`Invalid Alternative: ${_.stringify(v)}`);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toAlternative(v: _val): undefined | Alternative {
|
|
||||||
let result: undefined | Alternative;
|
|
||||||
if (_.Record.isRecord<_val, _.Tuple<_val>, _embedded>(v)) {
|
|
||||||
let _tmp0: (null) | undefined;
|
|
||||||
_tmp0 = _.is(v.label, $and) ? null : void 0;
|
|
||||||
if (_tmp0 !== void 0) {
|
|
||||||
if (_.Array.isArray(v[0]) && v[0].length >= 1) {
|
|
||||||
let _tmp1: (NamedPattern) | undefined;
|
|
||||||
_tmp1 = toNamedPattern(v[0][0]);
|
|
||||||
if (_tmp1 !== void 0) {
|
|
||||||
let _tmp2: (Array<_val>) | undefined;
|
|
||||||
let _tmp3: (Array<NamedPattern>) | undefined;
|
|
||||||
_tmp2 = v[0].slice(1);
|
|
||||||
{
|
|
||||||
_tmp3 = [];
|
|
||||||
for (const _tmp4 of _tmp2) {
|
|
||||||
let _tmp5: (NamedPattern) | undefined;
|
|
||||||
_tmp5 = toNamedPattern(_tmp4);
|
|
||||||
if (_tmp5 !== void 0) {_tmp3.push(_tmp5); continue;};
|
|
||||||
_tmp3 = void 0;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
if (_tmp3 !== void 0) {result = {"_variant": "and", "pattern": _tmp1, "patterns": _tmp3};};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
if (result === void 0) {
|
|
||||||
let _tmp6: (Pattern) | undefined;
|
|
||||||
_tmp6 = toPattern(v);
|
|
||||||
if (_tmp6 !== void 0) {result = {"_variant": "Pattern", "value": _tmp6};};
|
|
||||||
};
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fromAlternative(_v: Alternative): _val {
|
|
||||||
switch (_v._variant) {
|
|
||||||
case "and": {
|
case "and": {
|
||||||
return _.Record(
|
return _.Record(
|
||||||
$and,
|
$and,
|
||||||
|
@ -827,6 +777,28 @@ export function fromAtomKind(_v: AtomKind): _val {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function asNamedAlternative(v: _val): NamedAlternative {
|
||||||
|
let result = toNamedAlternative(v);
|
||||||
|
if (result === void 0) throw new TypeError(`Invalid NamedAlternative: ${_.stringify(v)}`);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toNamedAlternative(v: _val): undefined | NamedAlternative {
|
||||||
|
let result: undefined | NamedAlternative;
|
||||||
|
if (_.Array.isArray(v) && v.length === 2) {
|
||||||
|
let _tmp0: (string) | undefined;
|
||||||
|
_tmp0 = typeof v[0] === 'string' ? v[0] : void 0;
|
||||||
|
if (_tmp0 !== void 0) {
|
||||||
|
let _tmp1: (Pattern) | undefined;
|
||||||
|
_tmp1 = toPattern(v[1]);
|
||||||
|
if (_tmp1 !== void 0) {result = {"variantLabel": _tmp0, "pattern": _tmp1};};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fromNamedAlternative(_v: NamedAlternative): _val {return [_v["variantLabel"], fromPattern(_v["pattern"])];}
|
||||||
|
|
||||||
export function asNamedSimplePattern(v: _val): NamedSimplePattern {
|
export function asNamedSimplePattern(v: _val): NamedSimplePattern {
|
||||||
let result = toNamedSimplePattern(v);
|
let result = toNamedSimplePattern(v);
|
||||||
if (result === void 0) throw new TypeError(`Invalid NamedSimplePattern: ${_.stringify(v)}`);
|
if (result === void 0) throw new TypeError(`Invalid NamedSimplePattern: ${_.stringify(v)}`);
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
import { is, Position } from '@preserves/core';
|
import { is, Position } from '@preserves/core';
|
||||||
import * as M from './gen/schema';
|
import * as M from './gen/schema';
|
||||||
import { SchemaSyntaxError } from './error';
|
import { SchemaSyntaxError } from './error';
|
||||||
import type { AtomicType } from './compiler/type';
|
|
||||||
import { isJsKeyword } from './compiler/jskw';
|
import { isJsKeyword } from './compiler/jskw';
|
||||||
|
|
||||||
export * from './gen/schema';
|
export * from './gen/schema';
|
||||||
|
|
||||||
export type Builtin = { type: AtomicType, pattern: M.Alternative };
|
|
||||||
|
|
||||||
export type Input = M._val;
|
export type Input = M._val;
|
||||||
|
|
||||||
export function isValidToken(s: string): boolean {
|
export function isValidToken(s: string): boolean {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Reader, Annotated, Dictionary, is, peel, preserves, Record, strip, Tuple, Position, position, ReaderOptions, stringify, isCompound, KeyedDictionary } from '@preserves/core';
|
import { Reader, Annotated, Dictionary, is, peel, preserves, Record, strip, Tuple, Position, position, ReaderOptions, stringify, isCompound, KeyedDictionary } from '@preserves/core';
|
||||||
import { Input, Pattern, Schema, Alternative, Definition, CompoundPattern, SimplePattern } from './meta';
|
import { Input, Pattern, Schema, Definition, CompoundPattern, SimplePattern } from './meta';
|
||||||
import * as M from './meta';
|
import * as M from './meta';
|
||||||
import { SchemaSyntaxError } from './error';
|
import { SchemaSyntaxError } from './error';
|
||||||
|
|
||||||
|
@ -71,9 +71,7 @@ export function parseSchema(toplevelTokens: Array<Input>,
|
||||||
function process(toplevelTokens: Array<Input>): void {
|
function process(toplevelTokens: Array<Input>): void {
|
||||||
const toplevelClauses = splitBy(peel(toplevelTokens) as Array<Input>, M.DOT);
|
const toplevelClauses = splitBy(peel(toplevelTokens) as Array<Input>, M.DOT);
|
||||||
for (const clause of toplevelClauses) {
|
for (const clause of toplevelClauses) {
|
||||||
if (!Array.isArray(clause)) {
|
if (clause.length >= 2 && is(clause[1], M.EQUALS)) {
|
||||||
invalidClause(clause);
|
|
||||||
} else if (clause.length >= 2 && is(clause[1], M.EQUALS)) {
|
|
||||||
const pos = position(clause[0]);
|
const pos = position(clause[0]);
|
||||||
const name = peel(clause[0]);
|
const name = peel(clause[0]);
|
||||||
if (typeof name !== 'symbol') invalidClause(clause);
|
if (typeof name !== 'symbol') invalidClause(clause);
|
||||||
|
@ -126,51 +124,45 @@ function namedMustBeSimple(p: Position | null): never {
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDefinition(name: symbol, pos: Position | null, body: Array<Input>): Definition {
|
function parseDefinition(name: symbol, pos: Position | null, body: Array<Input>): Definition {
|
||||||
let nextAnonymousAlternativeNumber = 0;
|
function alternativeName(input: Array<Input>): M.NamedAlternative
|
||||||
function alternativeName([input, p]: readonly [Array<Input>, Alternative])
|
|
||||||
: M.NamedAlternative
|
|
||||||
{
|
{
|
||||||
const n = findName(input) || findName(input[0]);
|
const n = findName(input) || findName(input[0]);
|
||||||
|
const p = parsePattern(name, input);
|
||||||
if (n !== false) {
|
if (n !== false) {
|
||||||
return M.NamedAlternative({ variantLabel: n.description!, alternative: p });
|
return M.NamedAlternative({ variantLabel: n.description!, pattern: p });
|
||||||
}
|
}
|
||||||
if (p._variant === 'Pattern' &&
|
if (p._variant === 'CompoundPattern' &&
|
||||||
p.value._variant === 'CompoundPattern' &&
|
p.value._variant === 'rec' &&
|
||||||
p.value.value._variant === 'rec' &&
|
p.value.label._variant === 'anonymous' &&
|
||||||
p.value.value.label._variant === 'anonymous' &&
|
p.value.label.value._variant === 'SimplePattern' &&
|
||||||
p.value.value.label.value._variant === 'SimplePattern' &&
|
p.value.label.value.value._variant === 'lit' &&
|
||||||
p.value.value.label.value.value._variant === 'lit' &&
|
typeof p.value.label.value.value.value === 'symbol')
|
||||||
typeof p.value.value.label.value.value.value === 'symbol')
|
|
||||||
{
|
{
|
||||||
return M.NamedAlternative({
|
return M.NamedAlternative({
|
||||||
variantLabel: p.value.value.label.value.value.value.description!,
|
variantLabel: p.value.label.value.value.value.description!,
|
||||||
alternative: p
|
pattern: p
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (p._variant === 'Pattern' &&
|
if (p._variant === 'SimplePattern' &&
|
||||||
p.value._variant === 'SimplePattern' &&
|
p.value._variant === 'Ref')
|
||||||
p.value.value._variant === 'Ref')
|
|
||||||
{
|
{
|
||||||
return M.NamedAlternative({
|
return M.NamedAlternative({
|
||||||
variantLabel: p.value.value.value.name.description!,
|
variantLabel: p.value.value.name.description!,
|
||||||
alternative: p
|
pattern: p
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (p._variant === 'Pattern' &&
|
if (p._variant === 'SimplePattern' &&
|
||||||
p.value._variant === 'SimplePattern' &&
|
p.value._variant === 'lit')
|
||||||
p.value.value._variant === 'lit')
|
|
||||||
{
|
{
|
||||||
const s = M.namelike(p.value.value.value);
|
const s = M.namelike(p.value.value);
|
||||||
if (s !== void 0) return M.NamedAlternative({ variantLabel: s, alternative: p });
|
if (s !== void 0) return M.NamedAlternative({ variantLabel: s, pattern: p });
|
||||||
}
|
}
|
||||||
return M.NamedAlternative({
|
throw new SchemaSyntaxError(preserves`Name missing for alternative: ${input}`, pos);
|
||||||
variantLabel: '_anonymous' + nextAnonymousAlternativeNumber++,
|
|
||||||
alternative: p
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function patternName([input, p]: readonly [Array<Input>, Pattern]) : M.NamedPattern {
|
function patternName(input: Array<Input>): M.NamedPattern {
|
||||||
const n = findName(input) || findName(input[0]);
|
const n = findName(input) || findName(input[0]);
|
||||||
|
const p = parsePattern(name, input);
|
||||||
if (n !== false) {
|
if (n !== false) {
|
||||||
if (p._variant !== 'SimplePattern') namedMustBeSimple(position(input[0]));
|
if (p._variant !== 'SimplePattern') namedMustBeSimple(position(input[0]));
|
||||||
return M.NamedPattern.named(M.NamedSimplePattern_({ name: n, pattern: p.value }));
|
return M.NamedPattern.named(M.NamedSimplePattern_({ name: n, pattern: p.value }));
|
||||||
|
@ -178,28 +170,32 @@ function parseDefinition(name: symbol, pos: Position | null, body: Array<Input>)
|
||||||
return M.NamedPattern.anonymous(p);
|
return M.NamedPattern.anonymous(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: deal with situation where there's an or of ands, where
|
const andPieces = splitBy(body, M.ANDSYM);
|
||||||
// the branches of the and are named. The parsing is ambiguous, and
|
const orPieces = splitBy(body, M.ORSYM);
|
||||||
// with the current code I think (?) you end up with the same name
|
|
||||||
// attached to the or-branch as to the leftmost and-branch.
|
|
||||||
|
|
||||||
return parseOp(pos,
|
if (andPieces.length === 0 || orPieces.length === 0) {
|
||||||
body,
|
throw new SchemaSyntaxError(preserves`Invalid Schema clause: ${body}`, pos);
|
||||||
M.ORSYM,
|
}
|
||||||
p => [p, parseOp(pos,
|
|
||||||
p,
|
if (andPieces.length > 1 && orPieces.length > 1) {
|
||||||
M.ANDSYM,
|
throw new SchemaSyntaxError(preserves`Mixed "or" and "and" clause: ${body}`, pos);
|
||||||
p => [p, parsePattern(name, p)] as const,
|
}
|
||||||
(p0, ps) => M.Alternative.and({
|
|
||||||
pattern: patternName(p0),
|
if (andPieces.length > 1) {
|
||||||
patterns: ps.map(patternName)
|
return M.Definition.and({
|
||||||
}),
|
pattern: patternName(andPieces[0]),
|
||||||
p => M.Alternative.Pattern(p[1]))] as const,
|
patterns: andPieces.slice(1).map(patternName),
|
||||||
(p0, ps) => M.Definition.or({
|
});
|
||||||
pattern: alternativeName(p0),
|
}
|
||||||
patterns: ps.map(alternativeName)
|
|
||||||
}),
|
if (orPieces.length > 1) {
|
||||||
p => M.Definition.Alternative(p[1]));
|
return M.Definition.or({
|
||||||
|
pattern: alternativeName(orPieces[0]),
|
||||||
|
patterns: orPieces.slice(1).map(alternativeName),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return M.Definition.Pattern(parsePattern(name, orPieces[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
function parsePattern(name: symbol, body0: Array<Input>): Pattern {
|
function parsePattern(name: symbol, body0: Array<Input>): Pattern {
|
||||||
|
@ -348,21 +344,6 @@ function parsePattern(name: symbol, body0: Array<Input>): Pattern {
|
||||||
() => M.Pattern.CompoundPattern(parseCompound(body[0])));
|
() => M.Pattern.CompoundPattern(parseCompound(body[0])));
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseOp<Each, Combined>(pos: Position | null,
|
|
||||||
body: Array<Input>,
|
|
||||||
op: Input,
|
|
||||||
each: (p: Array<Input>) => Each,
|
|
||||||
combineN: (p0: Each, ps: Array<Each>) => Combined,
|
|
||||||
finish1: (p: Each) => Combined): Combined
|
|
||||||
{
|
|
||||||
const pieces = splitBy(body, op).map(each);
|
|
||||||
if (pieces.length === 0) {
|
|
||||||
throw new SchemaSyntaxError(
|
|
||||||
preserves`Invalid Schema clause: cannot handle empty ${op}`, pos);
|
|
||||||
}
|
|
||||||
return (pieces.length === 1) ? finish1(pieces[0]) : combineN(pieces[0], pieces.slice(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
function findName(x: Input): symbol | false {
|
function findName(x: Input): symbol | false {
|
||||||
if (!Annotated.isAnnotated<never>(x)) return false;
|
if (!Annotated.isAnnotated<never>(x)) return false;
|
||||||
for (const a0 of x.annotations) {
|
for (const a0 of x.annotations) {
|
||||||
|
|
|
@ -3,6 +3,6 @@ ModulePath
|
||||||
ModulePath„´³refµ„³Schema„„³Pattern´³orµµ±
SimplePattern´³refµ„³
SimplePattern„„µ±CompoundPattern´³refµ„³CompoundPattern„„„„³Version´³lit‘„³AtomKind´³orµµ±Boolean´³lit³Boolean„„µ±Float´³lit³Float„„µ±Double´³lit³Double„„µ±
SignedInteger´³lit³
SignedInteger„„µ±String´³lit³String„„µ±
|
ModulePath„´³refµ„³Schema„„³Pattern´³orµµ±
SimplePattern´³refµ„³
SimplePattern„„µ±CompoundPattern´³refµ„³CompoundPattern„„„„³Version´³lit‘„³AtomKind´³orµµ±Boolean´³lit³Boolean„„µ±Float´³lit³Float„„µ±Double´³lit³Double„„µ±
SignedInteger´³lit³
SignedInteger„„µ±String´³lit³String„„µ±
|
||||||
ByteString´³lit³
|
ByteString´³lit³
|
||||||
ByteString„„µ±Symbol´³lit³Symbol„„„„³
|
ByteString„„µ±Symbol´³lit³Symbol„„„„³
|
||||||
Definition´³orµµ±or´³rec´³lit³or„´³tupleµ´³tuple*µ´³named³pattern´³refµ„³NamedAlternative„„„´³named³patterns´³refµ„³NamedAlternative„„„„„„„µ±Alternative´³refµ„³Alternative„„„„³
|
Definition´³orµµ±or´³rec´³lit³or„´³tupleµ´³tuple*µ´³named³pattern´³refµ„³NamedAlternative„„„´³named³patterns´³refµ„³NamedAlternative„„„„„„„µ±and´³rec´³lit³and„´³tupleµ´³tuple*µ´³named³pattern´³refµ„³NamedPattern„„„´³named³patterns´³refµ„³NamedPattern„„„„„„„µ±Pattern´³refµ„³Pattern„„„„³
|
||||||
ModulePath´³tuple*µ„´³atom³Symbol„„³Alternative´³orµµ±and´³rec´³lit³and„´³tupleµ´³tuple*µ´³named³pattern´³refµ„³NamedPattern„„„´³named³patterns´³refµ„³NamedPattern„„„„„„„µ±Pattern´³refµ„³Pattern„„„„³Definitions´³dictof´³atom³Symbol„´³refµ„³
|
ModulePath´³tuple*µ„´³atom³Symbol„„³Definitions´³dictof´³atom³Symbol„´³refµ„³
|
||||||
Definition„„³NamedPattern´³orµµ±named´³refµ„³NamedSimplePattern_„„µ± anonymous´³refµ„³Pattern„„„„³
SimplePattern´³orµµ±any´³lit³any„„µ±atom´³rec´³lit³atom„´³tupleµ´³named³atomKind´³refµ„³AtomKind„„„„„„µ±embedded´³rec´³lit³embedded„´³tupleµ„„„„µ±lit´³rec´³lit³lit„´³tupleµ´³named³value³any„„„„„µ±Ref´³refµ„³Ref„„„„³CompoundPattern´³orµµ±rec´³rec´³lit³rec„´³tupleµ´³named³label´³refµ„³NamedPattern„„´³named³fields´³refµ„³NamedPattern„„„„„„µ±tuple´³rec´³lit³tuple„´³tupleµ´³tuple*µ„´³named³patterns´³refµ„³NamedPattern„„„„„„„µ±tuple*´³rec´³lit³tuple*„´³tupleµ´³tuple*µ„´³named³fixed´³refµ„³NamedPattern„„„´³named³variable´³refµ„³NamedSimplePattern„„„„„„µ±setof´³rec´³lit³setof„´³tupleµ´³named³pattern´³refµ„³
SimplePattern„„„„„„µ±dictof´³rec´³lit³dictof„´³tupleµ´³named³key´³refµ„³
SimplePattern„„´³named³value´³refµ„³
SimplePattern„„„„„„µ±dict´³rec´³lit³dict„´³tupleµ´³named³entries´³refµ„³DictionaryEntries„„„„„„„„³EmbeddedTypeName´³orµµ±Ref´³refµ„³Ref„„µ±false´³lit€„„„„³NamedAlternative´³tupleµ´³named³variantLabel´³atom³String„„´³named³alternative´³refµ„³Alternative„„„„³DictionaryEntries´³dictof³any´³refµ„³NamedSimplePattern„„³NamedSimplePattern´³orµµ±named´³refµ„³NamedSimplePattern_„„µ± anonymous´³refµ„³
SimplePattern„„„„³NamedSimplePattern_´³rec´³lit³named„´³tupleµ´³named³name´³atom³Symbol„„´³named³pattern´³refµ„³
SimplePattern„„„„„„³embeddedType€„„
|
Definition„„³NamedPattern´³orµµ±named´³refµ„³NamedSimplePattern_„„µ± anonymous´³refµ„³Pattern„„„„³
SimplePattern´³orµµ±any´³lit³any„„µ±atom´³rec´³lit³atom„´³tupleµ´³named³atomKind´³refµ„³AtomKind„„„„„„µ±embedded´³rec´³lit³embedded„´³tupleµ„„„„µ±lit´³rec´³lit³lit„´³tupleµ´³named³value³any„„„„„µ±Ref´³refµ„³Ref„„„„³CompoundPattern´³orµµ±rec´³rec´³lit³rec„´³tupleµ´³named³label´³refµ„³NamedPattern„„´³named³fields´³refµ„³NamedPattern„„„„„„µ±tuple´³rec´³lit³tuple„´³tupleµ´³tuple*µ„´³named³patterns´³refµ„³NamedPattern„„„„„„„µ±tuple*´³rec´³lit³tuple*„´³tupleµ´³tuple*µ„´³named³fixed´³refµ„³NamedPattern„„„´³named³variable´³refµ„³NamedSimplePattern„„„„„„µ±setof´³rec´³lit³setof„´³tupleµ´³named³pattern´³refµ„³
SimplePattern„„„„„„µ±dictof´³rec´³lit³dictof„´³tupleµ´³named³key´³refµ„³
SimplePattern„„´³named³value´³refµ„³
SimplePattern„„„„„„µ±dict´³rec´³lit³dict„´³tupleµ´³named³entries´³refµ„³DictionaryEntries„„„„„„„„³EmbeddedTypeName´³orµµ±Ref´³refµ„³Ref„„µ±false´³lit€„„„„³NamedAlternative´³tupleµ´³named³variantLabel´³atom³String„„´³named³pattern´³refµ„³Pattern„„„„³DictionaryEntries´³dictof³any´³refµ„³NamedSimplePattern„„³NamedSimplePattern´³orµµ±named´³refµ„³NamedSimplePattern_„„µ± anonymous´³refµ„³
SimplePattern„„„„³NamedSimplePattern_´³rec´³lit³named„´³tupleµ´³named³name´³atom³Symbol„„´³named³pattern´³refµ„³
SimplePattern„„„„„„³embeddedType€„„
|
|
@ -21,15 +21,16 @@ EmbeddedTypeName = Ref / #f.
|
||||||
|
|
||||||
Definitions = { symbol: Definition ...:... }.
|
Definitions = { symbol: Definition ...:... }.
|
||||||
|
|
||||||
; Pattern / Pattern / ...
|
Definition =
|
||||||
; and the empty pattern is <or []>
|
; Pattern / Pattern / ...
|
||||||
Definition = <or [@pattern NamedAlternative @patterns NamedAlternative ...]> / Alternative .
|
/ <or [@pattern NamedAlternative @patterns NamedAlternative ...]>
|
||||||
|
|
||||||
NamedAlternative = [@variantLabel string @alternative Alternative].
|
; Pattern & Pattern & ...
|
||||||
|
/ <and [@pattern NamedPattern @patterns NamedPattern ...]>
|
||||||
|
|
||||||
; Pattern & Pattern & ...
|
; Pattern
|
||||||
; and the universal pattern, "any", is <and []>
|
/ Pattern
|
||||||
Alternative = <and [@pattern NamedPattern @patterns NamedPattern ...]> / Pattern .
|
.
|
||||||
|
|
||||||
Pattern = SimplePattern / CompoundPattern .
|
Pattern = SimplePattern / CompoundPattern .
|
||||||
|
|
||||||
|
@ -76,6 +77,8 @@ DictionaryEntries = { any: NamedSimplePattern ...:... }.
|
||||||
|
|
||||||
AtomKind = =Boolean / =Float / =Double / =SignedInteger / =String / =ByteString / =Symbol .
|
AtomKind = =Boolean / =Float / =Double / =SignedInteger / =String / =ByteString / =Symbol .
|
||||||
|
|
||||||
|
NamedAlternative = [@variantLabel string @pattern Pattern].
|
||||||
|
|
||||||
NamedSimplePattern = @named NamedSimplePattern_ / @anonymous SimplePattern .
|
NamedSimplePattern = @named NamedSimplePattern_ / @anonymous SimplePattern .
|
||||||
NamedPattern = @named NamedSimplePattern_ / @anonymous Pattern .
|
NamedPattern = @named NamedSimplePattern_ / @anonymous Pattern .
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue