Simplify schemas by allowing at most one of "&" or "/" in a definition

This commit is contained in:
Tony Garnock-Jones 2021-05-20 22:34:20 +02:00
parent 436b14e2fe
commit 10380e451a
10 changed files with 224 additions and 275 deletions

View File

@ -16,7 +16,7 @@ export function compile(env: M.Environment, schema: M.Schema, options: CompilerO
mod.defineType(seq(`export type _embedded = `,
renderType(embeddedName._variant === 'false'
? 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>;`);

View File

@ -46,13 +46,12 @@ export class ModuleContext {
if (refCount > RECURSION_LIMIT) {
throw new Error('Recursion limit exceeded');
}
if (p._variant === 'Alternative' &&
p.value._variant === 'Pattern' &&
p.value.value._variant === 'SimplePattern' &&
p.value.value.value._variant === 'Ref')
if (p._variant === 'Pattern' &&
p.value._variant === 'SimplePattern' &&
p.value.value._variant === 'Ref')
{
return M.lookup(refPosition(p.value.value.value.value),
p.value.value.value.value,
return M.lookup(refPosition(p.value.value.value),
p.value.value.value,
this.env,
(p) => this.derefPattern(p, refCount + 1),
(_modId, _modPath, pp) => this.derefPattern(pp ?? p, refCount + 1));

View File

@ -11,53 +11,54 @@ export function converterForDefinition(
src: string,
dest: string): Item[]
{
if (p._variant === 'or') {
const alts = [p.pattern, ... p.patterns];
function loop(i: number): Item[] {
ctx.variantName = alts[i].variantLabel;
return [... converterForAlternative(ctx, alts[i].alternative, src, dest),
... ((i < alts.length - 1)
? [seq(`if (${dest} === void 0) `, ctx.block(() => loop(i + 1)))]
: [])];
switch (p._variant) {
case 'or': {
const alts = [p.pattern, ... p.patterns];
function loop(i: number): Item[] {
ctx.variantName = alts[i].variantLabel;
return [... converterForPattern(ctx, alts[i].pattern, src, dest),
... ((i < alts.length - 1)
? [seq(`if (${dest} === void 0) `, ctx.block(() => loop(i + 1)))]
: [])];
}
return loop(0);
}
return loop(0);
} else {
ctx.variantName = void 0;
return converterForAlternative(ctx, p.value, src, dest);
case 'and': {
const pcs = [p.pattern, ... p.patterns];
function loop(i: number): Item[] {
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,
p: M.Alternative,
p: M.Pattern,
src: string,
dest: string): Item[]
{
if (p._variant === 'and') {
const alts = [p.pattern, ... p.patterns];
function loop(i: number): Item[] {
return (i < alts.length)
? converterFor(ctx, alts[i], src, () => loop(i + 1))
: [ctx.buildCapturedCompound(dest)];
}
return loop(0);
} else {
return converterFor(ctx, M.NamedPattern.anonymous(p.value), src, simpleValue => {
if (simpleValue === void 0) {
return converterFor(ctx, M.NamedPattern.anonymous(p), src, simpleValue => {
if (simpleValue === void 0) {
return [ctx.buildCapturedCompound(dest)];
} else if (ctx.variantName !== void 0) {
if (typeFor(ctx.mod, p).kind === 'unit') {
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 {
return [`${dest} = ${simpleValue}`];
return [ctx.withCapture('value',
simpleValue,
() => ctx.buildCapturedCompound(dest))];
}
});
}
} else {
return [`${dest} = ${simpleValue}`];
}
});
}
function converterForTuple(ctx: FunctionContext,

View File

@ -4,24 +4,22 @@ import { ModuleContext } from "./context";
import { ANY_TYPE, AtomicType, CollectionType, FieldMap, SimpleType, Type } from "./type";
export function typeForDefinition(mod: ModuleContext, d: M.Definition): Type {
if (d._variant === 'or') {
return Type.union(
new Map([d.pattern, ... d.patterns].map(a =>
[a.variantLabel, typeForAlternative(mod, a.alternative)])));
} else {
return typeForAlternative(mod, d.value);
switch (d._variant) {
case 'or':
return Type.union(
new Map([d.pattern, ... d.patterns].map(a =>
[a.variantLabel, typeFor(mod, a.pattern)])));
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 {
if (a._variant === 'and') {
const fs = new Map();
gatherFields(fs, mod, a.pattern);
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 typeForIntersection(mod: ModuleContext, ps: M.NamedPattern[]): SimpleType {
const fs = new Map();
ps.forEach(p => gatherFields(fs, mod, p));
return fs.size > 0 ? Type.record(fs) : Type.unit();
}
export function setType(mod: ModuleContext, p: M.SimplePattern): CollectionType {

View File

@ -2,8 +2,8 @@ import { refPosition } from '../reader';
import * as M from '../meta';
import { block, brackets, formatItems, Item, parens, seq } from './block';
import { FunctionContext } from "./context";
import { typeForAlternative } from './gentype';
import { FieldType, renderType, SimpleType } from './type';
import { typeFor, typeForIntersection } from './gentype';
export function unconverterForDefinition(
ctx: FunctionContext,
@ -11,61 +11,59 @@ export function unconverterForDefinition(
def: M.Definition,
src: string): Item[]
{
if (def._variant === 'or') {
return [seq(`switch (${src}._variant) `, block(
... [def.pattern, ... def.patterns].map(p =>
seq(`case `, JSON.stringify(p.variantLabel), `: `, ctx.block(() => {
const hasValueField =
p.alternative._variant === 'Pattern' &&
p.alternative.value._variant === 'SimplePattern';
return [seq(`return `, unconverterForAlternative(
ctx, name, p.alternative, hasValueField ? `${src}.value` : src))];
})))))];
} else {
return [seq(`return `, unconverterForAlternative(ctx, name, def.value, `${src}`))];
switch (def._variant) {
case 'or':
return [seq(`switch (${src}._variant) `, block(
... [def.pattern, ... def.patterns].map(p =>
seq(`case `, JSON.stringify(p.variantLabel), `: `, ctx.block(() => {
const hasValueField = p.pattern._variant === 'SimplePattern';
return [seq(`return `, unconverterForPattern(
ctx, name, p.pattern, hasValueField ? `${src}.value` : src))];
})))))];
case 'and': {
const ps = [def.pattern , ... def.patterns];
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 {}
function unconverterForAlternative(
ctx: FunctionContext,
name: string,
a: M.Alternative,
src: string): Item
function unconverterForPattern(ctx: FunctionContext, name: string, a: M.Pattern, src: string): Item
{
const t = typeForAlternative(ctx.mod, a);
if (a._variant === 'and') {
const errs: [string, InsufficientInformationError][] = [];
const cs = [a.pattern, ... a.patterns].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 (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;
const t = typeFor(ctx.mod, a);
try {
return unconverterFor(ctx, a, src, t);
} catch (e) {
if (e instanceof InsufficientInformationError) {
throw new Error(`Cannot produce unconverter for ${name}: ${e.message}`);
}
throw e;
}
}

View File

@ -55,12 +55,6 @@ export type Definition = (
"pattern": 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": "Pattern", "value": Pattern}
);
@ -103,6 +97,8 @@ export type AtomKind = (
{"_variant": "Symbol"}
);
export type NamedAlternative = {"variantLabel": string, "pattern": Pattern};
export type NamedSimplePattern = (
{"_variant": "named", "value": NamedSimplePattern_} |
{"_variant": "anonymous", "value": SimplePattern}
@ -143,14 +139,8 @@ export namespace Definition {
export function or(
{pattern, patterns}: {pattern: NamedAlternative, patterns: Array<NamedAlternative>}
): Definition {return {"_variant": "or", "pattern": pattern, "patterns": patterns};};
export function Alternative(value: Alternative): Definition {return {"_variant": "Alternative", "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 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 namespace Pattern {
@ -187,6 +177,8 @@ export namespace AtomKind {
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 function named(value: NamedSimplePattern_): NamedSimplePattern {return {"_variant": "named", "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) {
let _tmp6: (Alternative) | undefined;
_tmp6 = toAlternative(v);
if (_tmp6 !== void 0) {result = {"_variant": "Alternative", "value": _tmp6};};
if (_.Record.isRecord<_val, _.Tuple<_val>, _embedded>(v)) {
let _tmp6: (null) | undefined;
_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;
}
@ -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": {
return _.Record(
$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 {
let result = toNamedSimplePattern(v);
if (result === void 0) throw new TypeError(`Invalid NamedSimplePattern: ${_.stringify(v)}`);

View File

@ -1,13 +1,10 @@
import { is, Position } from '@preserves/core';
import * as M from './gen/schema';
import { SchemaSyntaxError } from './error';
import type { AtomicType } from './compiler/type';
import { isJsKeyword } from './compiler/jskw';
export * from './gen/schema';
export type Builtin = { type: AtomicType, pattern: M.Alternative };
export type Input = M._val;
export function isValidToken(s: string): boolean {

View File

@ -1,5 +1,5 @@
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 { SchemaSyntaxError } from './error';
@ -71,9 +71,7 @@ export function parseSchema(toplevelTokens: Array<Input>,
function process(toplevelTokens: Array<Input>): void {
const toplevelClauses = splitBy(peel(toplevelTokens) as Array<Input>, M.DOT);
for (const clause of toplevelClauses) {
if (!Array.isArray(clause)) {
invalidClause(clause);
} else if (clause.length >= 2 && is(clause[1], M.EQUALS)) {
if (clause.length >= 2 && is(clause[1], M.EQUALS)) {
const pos = position(clause[0]);
const name = peel(clause[0]);
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 {
let nextAnonymousAlternativeNumber = 0;
function alternativeName([input, p]: readonly [Array<Input>, Alternative])
: M.NamedAlternative
function alternativeName(input: Array<Input>): M.NamedAlternative
{
const n = findName(input) || findName(input[0]);
const p = parsePattern(name, input);
if (n !== false) {
return M.NamedAlternative({ variantLabel: n.description!, alternative: p });
return M.NamedAlternative({ variantLabel: n.description!, pattern: p });
}
if (p._variant === 'Pattern' &&
p.value._variant === 'CompoundPattern' &&
p.value.value._variant === 'rec' &&
p.value.value.label._variant === 'anonymous' &&
p.value.value.label.value._variant === 'SimplePattern' &&
p.value.value.label.value.value._variant === 'lit' &&
typeof p.value.value.label.value.value.value === 'symbol')
if (p._variant === 'CompoundPattern' &&
p.value._variant === 'rec' &&
p.value.label._variant === 'anonymous' &&
p.value.label.value._variant === 'SimplePattern' &&
p.value.label.value.value._variant === 'lit' &&
typeof p.value.label.value.value.value === 'symbol')
{
return M.NamedAlternative({
variantLabel: p.value.value.label.value.value.value.description!,
alternative: p
variantLabel: p.value.label.value.value.value.description!,
pattern: p
});
}
if (p._variant === 'Pattern' &&
p.value._variant === 'SimplePattern' &&
p.value.value._variant === 'Ref')
if (p._variant === 'SimplePattern' &&
p.value._variant === 'Ref')
{
return M.NamedAlternative({
variantLabel: p.value.value.value.name.description!,
alternative: p
variantLabel: p.value.value.name.description!,
pattern: p
});
}
if (p._variant === 'Pattern' &&
p.value._variant === 'SimplePattern' &&
p.value.value._variant === 'lit')
if (p._variant === 'SimplePattern' &&
p.value._variant === 'lit')
{
const s = M.namelike(p.value.value.value);
if (s !== void 0) return M.NamedAlternative({ variantLabel: s, alternative: p });
const s = M.namelike(p.value.value);
if (s !== void 0) return M.NamedAlternative({ variantLabel: s, pattern: p });
}
return M.NamedAlternative({
variantLabel: '_anonymous' + nextAnonymousAlternativeNumber++,
alternative: p
});
throw new SchemaSyntaxError(preserves`Name missing for alternative: ${input}`, pos);
}
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 p = parsePattern(name, input);
if (n !== false) {
if (p._variant !== 'SimplePattern') namedMustBeSimple(position(input[0]));
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);
}
// TODO: deal with situation where there's an or of ands, where
// the branches of the and are named. The parsing is ambiguous, and
// with the current code I think (?) you end up with the same name
// attached to the or-branch as to the leftmost and-branch.
const andPieces = splitBy(body, M.ANDSYM);
const orPieces = splitBy(body, M.ORSYM);
return parseOp(pos,
body,
M.ORSYM,
p => [p, parseOp(pos,
p,
M.ANDSYM,
p => [p, parsePattern(name, p)] as const,
(p0, ps) => M.Alternative.and({
pattern: patternName(p0),
patterns: ps.map(patternName)
}),
p => M.Alternative.Pattern(p[1]))] as const,
(p0, ps) => M.Definition.or({
pattern: alternativeName(p0),
patterns: ps.map(alternativeName)
}),
p => M.Definition.Alternative(p[1]));
if (andPieces.length === 0 || orPieces.length === 0) {
throw new SchemaSyntaxError(preserves`Invalid Schema clause: ${body}`, pos);
}
if (andPieces.length > 1 && orPieces.length > 1) {
throw new SchemaSyntaxError(preserves`Mixed "or" and "and" clause: ${body}`, pos);
}
if (andPieces.length > 1) {
return M.Definition.and({
pattern: patternName(andPieces[0]),
patterns: andPieces.slice(1).map(patternName),
});
}
if (orPieces.length > 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 {
@ -348,21 +344,6 @@ function parsePattern(name: symbol, body0: Array<Input>): Pattern {
() => 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 {
if (!Annotated.isAnnotated<never>(x)) return false;
for (const a0 of x.annotations) {

View File

@ -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„„µ±
ByteString´³lit³
ByteString„„µ±Symbol´³lit³Symbol„„„„³
Definition´³orµµ±or´³rec´³lit³or„´³tupleµ´³tuple*µ´³named³pattern´³refµ„³NamedAlternative„„„´³named³patterns´³refµ„³NamedAlternative„„„„„„„µ± Alternative´³refµ„³ Alternative„„„„³
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µ„³
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´³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„„³ 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³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€„„

View File

@ -21,15 +21,16 @@ EmbeddedTypeName = Ref / #f.
Definitions = { symbol: Definition ...:... }.
; Pattern / Pattern / ...
; and the empty pattern is <or []>
Definition = <or [@pattern NamedAlternative @patterns NamedAlternative ...]> / Alternative .
Definition =
; Pattern / Pattern / ...
/ <or [@pattern NamedAlternative @patterns NamedAlternative ...]>
NamedAlternative = [@variantLabel string @alternative Alternative].
; Pattern & Pattern & ...
/ <and [@pattern NamedPattern @patterns NamedPattern ...]>
; Pattern & Pattern & ...
; and the universal pattern, "any", is <and []>
Alternative = <and [@pattern NamedPattern @patterns NamedPattern ...]> / Pattern .
; Pattern
/ Pattern
.
Pattern = SimplePattern / CompoundPattern .
@ -76,6 +77,8 @@ DictionaryEntries = { any: NamedSimplePattern ...:... }.
AtomKind = =Boolean / =Float / =Double / =SignedInteger / =String / =ByteString / =Symbol .
NamedAlternative = [@variantLabel string @pattern Pattern].
NamedSimplePattern = @named NamedSimplePattern_ / @anonymous SimplePattern .
NamedPattern = @named NamedSimplePattern_ / @anonymous Pattern .