Refactor schema schema
This commit is contained in:
parent
94f6959ac8
commit
121bcc7a53
|
@ -12,7 +12,7 @@ export function converterForDefinition(
|
|||
dest: string): Item[]
|
||||
{
|
||||
if (p._variant === 'or') {
|
||||
const alts = p.patterns;
|
||||
const alts = [p.pattern, ... p.patterns];
|
||||
function loop(i: number): Item[] {
|
||||
ctx.variantName = alts[i].variantLabel;
|
||||
return [... converterForAlternative(ctx, alts[i].alternative, src, dest),
|
||||
|
@ -20,7 +20,7 @@ export function converterForDefinition(
|
|||
? [seq(`if (${dest} === void 0) `, ctx.block(() => loop(i + 1)))]
|
||||
: [])];
|
||||
}
|
||||
return alts.length === 0 ? [] : loop(0);
|
||||
return loop(0);
|
||||
} else {
|
||||
ctx.variantName = void 0;
|
||||
return converterForAlternative(ctx, p.value, src, dest);
|
||||
|
@ -34,13 +34,13 @@ function converterForAlternative(
|
|||
dest: string): Item[]
|
||||
{
|
||||
if (p._variant === 'and') {
|
||||
const alts = p.patterns;
|
||||
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 alts.length === 0 ? [seq(`${dest} = ${src}`)] : loop(0);
|
||||
return loop(0);
|
||||
} else {
|
||||
return converterFor(ctx, M.NamedPattern.anonymous(p.value), src, simpleValue => {
|
||||
if (simpleValue === void 0) {
|
||||
|
|
|
@ -6,7 +6,8 @@ import { ANY_TYPE, AtomicType, CollectionType, FieldMap, SimpleType, Type } from
|
|||
export function typeForDefinition(mod: ModuleContext, d: M.Definition): Type {
|
||||
if (d._variant === 'or') {
|
||||
return Type.union(
|
||||
new Map(d.patterns.map(a => [a.variantLabel, typeForAlternative(mod, a.alternative)])));
|
||||
new Map([d.pattern, ... d.patterns].map(a =>
|
||||
[a.variantLabel, typeForAlternative(mod, a.alternative)])));
|
||||
} else {
|
||||
return typeForAlternative(mod, d.value);
|
||||
}
|
||||
|
@ -15,6 +16,7 @@ export function typeForDefinition(mod: ModuleContext, d: M.Definition): Type {
|
|||
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 {
|
||||
|
|
|
@ -13,7 +13,7 @@ export function unconverterForDefinition(
|
|||
{
|
||||
if (def._variant === 'or') {
|
||||
return [seq(`switch (${src}._variant) `, block(
|
||||
... def.patterns.map(p =>
|
||||
... [def.pattern, ... def.patterns].map(p =>
|
||||
seq(`case `, JSON.stringify(p.variantLabel), `: `, ctx.block(() => {
|
||||
const hasValueField =
|
||||
p.alternative._variant === 'Pattern' &&
|
||||
|
@ -37,7 +37,7 @@ function unconverterForAlternative(
|
|||
const t = typeForAlternative(ctx.mod, a);
|
||||
if (a._variant === 'and') {
|
||||
const errs: [string, InsufficientInformationError][] = [];
|
||||
const cs = a.patterns.flatMap(p => {
|
||||
const cs = [a.pattern, ... a.patterns].flatMap(p => {
|
||||
if (p._variant === 'anonymous' && p.value._variant === 'SimplePattern') {
|
||||
return [];
|
||||
} else {
|
||||
|
|
|
@ -40,14 +40,18 @@ export type PointerName = ({"_variant": "Ref", "value": Ref} | {"_variant": "fal
|
|||
export type Definitions = _.KeyedDictionary<symbol, Definition, _ptr>;
|
||||
|
||||
export type Definition = (
|
||||
{"_variant": "or", "patterns": Array<NamedAlternative>} |
|
||||
{
|
||||
"_variant": "or",
|
||||
"pattern": NamedAlternative,
|
||||
"patterns": Array<NamedAlternative>
|
||||
} |
|
||||
{"_variant": "Alternative", "value": Alternative}
|
||||
);
|
||||
|
||||
export type NamedAlternative = {"variantLabel": string, "alternative": Alternative};
|
||||
|
||||
export type Alternative = (
|
||||
{"_variant": "and", "patterns": Array<NamedPattern>} |
|
||||
{"_variant": "and", "pattern": NamedPattern, "patterns": Array<NamedPattern>} |
|
||||
{"_variant": "Pattern", "value": Pattern}
|
||||
);
|
||||
|
||||
|
@ -122,14 +126,16 @@ export namespace PointerName {
|
|||
export function Definitions(value: _.KeyedDictionary<symbol, Definition, _ptr>): Definitions {return value;}
|
||||
|
||||
export namespace Definition {
|
||||
export function or(patterns: Array<NamedAlternative>): Definition {return {"_variant": "or", "patterns": patterns};};
|
||||
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(patterns: Array<NamedPattern>): Alternative {return {"_variant": "and", "patterns": patterns};};
|
||||
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};};
|
||||
}
|
||||
|
||||
|
@ -319,35 +325,49 @@ export function toDefinition(v: _val): undefined | Definition {
|
|||
let _tmp0: (null) | undefined;
|
||||
_tmp0 = _.is(v.label, $or) ? null : void 0;
|
||||
if (_tmp0 !== void 0) {
|
||||
if (_.Array.isArray(v[0])) {
|
||||
let _tmp1: (Array<_val>) | undefined;
|
||||
let _tmp2: (Array<NamedAlternative>) | undefined;
|
||||
_tmp1 = v[0];
|
||||
{
|
||||
_tmp2 = [];
|
||||
for (const _tmp3 of _tmp1) {
|
||||
let _tmp4: (NamedAlternative) | undefined;
|
||||
_tmp4 = toNamedAlternative(_tmp3);
|
||||
if (_tmp4 !== void 0) {_tmp2.push(_tmp4); continue;};
|
||||
_tmp2 = void 0;
|
||||
break;
|
||||
if (_.Array.isArray(v[0]) && v[0].length >= 1) {
|
||||
let _tmp1: (NamedAlternative) | undefined;
|
||||
_tmp1 = toNamedAlternative(v[0][0]);
|
||||
if (_tmp1 !== void 0) {
|
||||
let _tmp2: (Array<_val>) | undefined;
|
||||
let _tmp3: (Array<NamedAlternative>) | undefined;
|
||||
_tmp2 = v[0].slice(1);
|
||||
{
|
||||
_tmp3 = [];
|
||||
for (const _tmp4 of _tmp2) {
|
||||
let _tmp5: (NamedAlternative) | undefined;
|
||||
_tmp5 = toNamedAlternative(_tmp4);
|
||||
if (_tmp5 !== void 0) {_tmp3.push(_tmp5); continue;};
|
||||
_tmp3 = void 0;
|
||||
break;
|
||||
};
|
||||
if (_tmp3 !== void 0) {result = {"_variant": "or", "pattern": _tmp1, "patterns": _tmp3};};
|
||||
};
|
||||
if (_tmp2 !== void 0) {result = {"_variant": "or", "patterns": _tmp2};};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (result === void 0) {
|
||||
let _tmp5: (Alternative) | undefined;
|
||||
_tmp5 = toAlternative(v);
|
||||
if (_tmp5 !== void 0) {result = {"_variant": "Alternative", "value": _tmp5};};
|
||||
let _tmp6: (Alternative) | undefined;
|
||||
_tmp6 = toAlternative(v);
|
||||
if (_tmp6 !== void 0) {result = {"_variant": "Alternative", "value": _tmp6};};
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
export function fromDefinition(_v: Definition): _val {
|
||||
switch (_v._variant) {
|
||||
case "or": {return _.Record($or, [_v["patterns"].map(v => fromNamedAlternative(v))]);};
|
||||
case "or": {
|
||||
return _.Record(
|
||||
$or,
|
||||
[
|
||||
[
|
||||
fromNamedAlternative(_v["pattern"]),
|
||||
... _v["patterns"].map(v => fromNamedAlternative(v))
|
||||
]
|
||||
]
|
||||
);
|
||||
};
|
||||
case "Alternative": {return fromAlternative(_v.value);};
|
||||
};
|
||||
}
|
||||
|
@ -386,35 +406,49 @@ export function toAlternative(v: _val): undefined | Alternative {
|
|||
let _tmp0: (null) | undefined;
|
||||
_tmp0 = _.is(v.label, $and) ? null : void 0;
|
||||
if (_tmp0 !== void 0) {
|
||||
if (_.Array.isArray(v[0])) {
|
||||
let _tmp1: (Array<_val>) | undefined;
|
||||
let _tmp2: (Array<NamedPattern>) | undefined;
|
||||
_tmp1 = v[0];
|
||||
{
|
||||
_tmp2 = [];
|
||||
for (const _tmp3 of _tmp1) {
|
||||
let _tmp4: (NamedPattern) | undefined;
|
||||
_tmp4 = toNamedPattern(_tmp3);
|
||||
if (_tmp4 !== void 0) {_tmp2.push(_tmp4); continue;};
|
||||
_tmp2 = void 0;
|
||||
break;
|
||||
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 (_tmp2 !== void 0) {result = {"_variant": "and", "patterns": _tmp2};};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if (result === void 0) {
|
||||
let _tmp5: (Pattern) | undefined;
|
||||
_tmp5 = toPattern(v);
|
||||
if (_tmp5 !== void 0) {result = {"_variant": "Pattern", "value": _tmp5};};
|
||||
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, [_v["patterns"].map(v => fromNamedPattern(v))]);};
|
||||
case "and": {
|
||||
return _.Record(
|
||||
$and,
|
||||
[
|
||||
[
|
||||
fromNamedPattern(_v["pattern"]),
|
||||
... _v["patterns"].map(v => fromNamedPattern(v))
|
||||
]
|
||||
]
|
||||
);
|
||||
};
|
||||
case "Pattern": {return fromPattern(_v.value);};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ export function parseSchema(toplevelTokens: Array<Input>,
|
|||
if (definitions.has(name)) {
|
||||
throw new SchemaSyntaxError(preserves`Duplicate definition: ${clause}`, pos);
|
||||
}
|
||||
definitions.set(name, parseDefinition(name, clause.slice(2)));
|
||||
definitions.set(name, parseDefinition(name, pos, clause.slice(2)));
|
||||
} else if (clause.length === 2 && is(clause[0], M.$version)) {
|
||||
version = M.asVersion(peel(clause[1]));
|
||||
} else if (clause.length === 2 && is(clause[0], M.$pointer)) {
|
||||
|
@ -125,7 +125,7 @@ function namedMustBeSimple(p: Position | null): never {
|
|||
throw new SchemaSyntaxError('Named patterns must be Simple patterns', p);
|
||||
}
|
||||
|
||||
function parseDefinition(name: symbol, body: Array<Input>): Definition {
|
||||
function parseDefinition(name: symbol, pos: Position | null, body: Array<Input>): Definition {
|
||||
let nextAnonymousAlternativeNumber = 0;
|
||||
function alternativeName([input, p]: readonly [Array<Input>, Alternative])
|
||||
: M.NamedAlternative
|
||||
|
@ -183,14 +183,22 @@ function parseDefinition(name: symbol, body: Array<Input>): Definition {
|
|||
// 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(body,
|
||||
return parseOp(pos,
|
||||
body,
|
||||
M.ORSYM,
|
||||
p => [p, parseOp(p,
|
||||
p => [p, parseOp(pos,
|
||||
p,
|
||||
M.ANDSYM,
|
||||
p => [p, parsePattern(name, p)] as const,
|
||||
ps => M.Alternative.and(ps.map(patternName)),
|
||||
(p0, ps) => M.Alternative.and({
|
||||
pattern: patternName(p0),
|
||||
patterns: ps.map(patternName)
|
||||
}),
|
||||
p => M.Alternative.Pattern(p[1]))] as const,
|
||||
ps => M.Definition.or(ps.map(alternativeName)),
|
||||
(p0, ps) => M.Definition.or({
|
||||
pattern: alternativeName(p0),
|
||||
patterns: ps.map(alternativeName)
|
||||
}),
|
||||
p => M.Definition.Alternative(p[1]));
|
||||
}
|
||||
|
||||
|
@ -340,14 +348,19 @@ function parsePattern(name: symbol, body0: Array<Input>): Pattern {
|
|||
() => M.Pattern.CompoundPattern(parseCompound(body[0])));
|
||||
}
|
||||
|
||||
function parseOp<Each, Combined>(body: Array<Input>,
|
||||
function parseOp<Each, Combined>(pos: Position | null,
|
||||
body: Array<Input>,
|
||||
op: Input,
|
||||
each: (p: Array<Input>) => Each,
|
||||
combineN: (ps: Array<Each>) => Combined,
|
||||
combineN: (p0: Each, ps: Array<Each>) => Combined,
|
||||
finish1: (p: Each) => Combined): Combined
|
||||
{
|
||||
const pieces = splitBy(body, op).map(each);
|
||||
return (pieces.length === 1) ? finish1(pieces[0]) : combineN(pieces);
|
||||
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 {
|
||||
|
|
|
@ -17,18 +17,13 @@ Definitions = { symbol: Definition ...:... }.
|
|||
|
||||
; Pattern / Pattern / ...
|
||||
; and the empty pattern is <or []>
|
||||
;
|
||||
; TODO: refactor to be
|
||||
; <or [@pattern NamedAlternative @patterns NamedAlternative ...]> / Alternative .
|
||||
; Similarly for <and...>
|
||||
;
|
||||
Definition = <or [@patterns NamedAlternative ...]> / Alternative .
|
||||
Definition = <or [@pattern NamedAlternative @patterns NamedAlternative ...]> / Alternative .
|
||||
|
||||
NamedAlternative = [@variantLabel string @alternative Alternative].
|
||||
|
||||
; Pattern & Pattern & ...
|
||||
; and the universal pattern, "any", is <and []>
|
||||
Alternative = <and [@patterns NamedPattern ...]> / Pattern .
|
||||
Alternative = <and [@pattern NamedPattern @patterns NamedPattern ...]> / Pattern .
|
||||
|
||||
Pattern = SimplePattern / CompoundPattern .
|
||||
|
||||
|
|
Loading…
Reference in New Issue