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