Tighten schema definition to permit simpler codegen

This commit is contained in:
Tony Garnock-Jones 2021-03-17 12:20:50 +01:00
parent 178f528bf0
commit b9019d03f1
6 changed files with 423 additions and 349 deletions

View File

@ -1,10 +1,11 @@
import { Record, Dictionary, Value } from '@preserves/core';
import { Record, Dictionary } from '@preserves/core';
import * as M from './gen/schema';
export const BASE: M.Schema = Record(M.$schema, [new Dictionary<Value, never>([
export const BASE: M.Schema = M.asSchema(Record(M.$schema, [new Dictionary<never>([
[M.$version, 1],
[M.$definitions, new Dictionary<M.Pattern, never>([
[Symbol.for('any'), Record(M.$and, [[]])],
[M.$pointer, false],
[M.$definitions, new Dictionary<never>([
[Symbol.for('any'), Record(M.$and, [[] as M.Pattern[]])],
[Symbol.for('bool'), Record(M.$atom, [M.$Boolean])],
[Symbol.for('float'), Record(M.$atom, [M.$Float])],
[Symbol.for('double'), Record(M.$atom, [M.$Double])],
@ -14,4 +15,4 @@ export const BASE: M.Schema = Record(M.$schema, [new Dictionary<Value, never>([
[Symbol.for('symbol'), Record(M.$atom, [M.$Symbol])],
[Symbol.for('ref'), Record(M.$pointer, [])],
])],
])]);
])]));

View File

@ -3,6 +3,7 @@ import * as M from './meta';
import { Annotated, Bytes, Dictionary, Fold, fold, KeyedSet, Position, preserves, Record, Set, Tuple, Value } from "@preserves/core";
import { Formatter, parens, seq, Item, opseq, block, commas, brackets, anglebrackets, braces } from "./block";
import { refPosition } from "./reader";
import { Alternative, Definition } from "gen/schema";
export interface CompilerOptions {
preservesModule?: string;
@ -15,7 +16,7 @@ function fnblock(... items: Item[]): Item {
}
export function compile(env: Environment, schema: Schema, options: CompilerOptions = {}): string {
const literals = new Dictionary<string, never>();
const literals = new Dictionary<never, string>();
const types: Array<Item> = [];
const functions: Array<Item> = [];
const imports = new KeyedSet<[string, string]>();
@ -76,7 +77,7 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
}));
}
function derefPattern(p: Pattern): Pattern {
function derefPattern([_name, p]: [symbol, Alternative]): Definition {
if (p.label === M.$ref) {
return lookup(refPosition(p), p, env,
(p) => p,
@ -118,7 +119,7 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
}
}
function decoderFor(p: Pattern, dest: string, recordFields = false): void {
function decoderFor(p: Definition, dest: string, recordFields = false): void {
switch (p.label) {
case M.$atom:
switch (p[0]) {
@ -188,12 +189,12 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
} else {
switch (alts.length) {
case 0: break; // assume dest is already void 0
case 1: decoderFor(alts[0], dest); break;
case 1: decoderFor(alts[0][1], dest); break;
default: {
const mark = gentemp();
emit(`${mark} = d.mark()`);
function loop(i: number) {
decoderFor(alts[i], dest);
decoderFor(alts[i][1], dest);
if (i < alts.length - 1) {
emit(seq(`if (${dest} === void 0) `, collectBody(() => {
emit(`d.restoreMark(${mark})`);
@ -287,7 +288,7 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
}
}
function typeFor(p: Pattern): Item {
function typeFor(p: Definition): Item {
switch (p.label) {
case M.$atom:
switch (p[0]) {
@ -310,7 +311,7 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
return `${mod}.${p[1].description!}`;
});
case M.$or:
return opseq('never', ' | ', ... p[0].map(pp => typeFor(pp)));
return opseq('never', ' | ', ... p[0].map(pp => typeFor(pp[1])));
case M.$and:
return opseq('_val', ' & ', ... p[0].map(pp => typeFor(pp)));
case M.$pointer:
@ -337,14 +338,14 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
seq(`get(k: typeof ${literal(k)}): `, typeFor(vp))),
... Array.from(p[0]).map(([k, _vp]) =>
seq(`has(k: typeof ${literal(k)}): true`))),
' & _.Dictionary<_val, _ptr>'));
' & _.Dictionary<_ptr>'));
default:
((_p: never) => {})(p);
throw new Error("Unreachable");
}
}
function predicateFor(v: string, p: Pattern, recordOkAsTuple = false): Item {
function predicateFor(v: string, p: Definition, recordOkAsTuple = false): Item {
switch (p.label) {
case M.$atom:
switch (p[0]) {
@ -379,7 +380,7 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
' && ',
predicateFor(v, r[1], true)))))));
} else {
return opseq('false', ' || ', ... p[0].map(pp => predicateFor(v, pp)));
return opseq('false', ' || ', ... p[0].map(pp => predicateFor(v, pp[1])));
}
}
case M.$and:
@ -416,7 +417,7 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
seq('return true')));
case M.$dictof:
return opseq('true', ' && ',
`_.Dictionary.isDictionary<_val, _ptr>(${v})`,
`_.Dictionary.isDictionary<_ptr>(${v})`,
fnblock(
seq(`for (const e of ${v}) `, block(
seq('if (!(', predicateFor('e[0]', p[0]), ')) return false'),
@ -424,7 +425,7 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
seq('return true')));
case M.$dict:
return opseq('true', ' && ',
`_.Dictionary.isDictionary<_val, _ptr>(${v})`,
`_.Dictionary.isDictionary<_ptr>(${v})`,
... Array.from(p[0]).map(([k, vp]) => {
const tmp = gentemp();
return parens(seq(
@ -558,8 +559,8 @@ export function sourceCodeFor(v: Value<any>): Item {
set(s: Set<any>, k: Fold<any, Item>): Item {
return seq('new _.Set<_val>', parens(brackets(... Array.from(s).map(k))));
},
dictionary(d: Dictionary<Value<any>, any>, k: Fold<any, Item>): Item {
return seq('new _.Dictionary<_val, _ptr>', parens(brackets(... Array.from(d).map(([kk,vv]) =>
dictionary(d: Dictionary<any>, k: Fold<any, Item>): Item {
return seq('new _.Dictionary<_ptr>', parens(brackets(... Array.from(d).map(([kk,vv]) =>
brackets(k(kk), k(vv))))));
},

View File

@ -31,11 +31,11 @@ export const Schema = _.Record.makeConstructor<{
{
get(k: typeof $version): Version;
get(k: typeof $pointer): PointerName;
get(k: typeof $definitions): _.KeyedDictionary<symbol, Pattern, _ptr>;
get(k: typeof $definitions): _.KeyedDictionary<symbol, Definition, _ptr>;
has(k: typeof $version): true;
has(k: typeof $pointer): true;
has(k: typeof $definitions): true;
} & _.Dictionary<_val, _ptr>
} & _.Dictionary<_ptr>
)
}, _ptr>()($schema, ["details"]);
@ -46,11 +46,11 @@ export type Schema = _.Record<
{
get(k: typeof $version): Version;
get(k: typeof $pointer): PointerName;
get(k: typeof $definitions): _.KeyedDictionary<symbol, Pattern, _ptr>;
get(k: typeof $definitions): _.KeyedDictionary<symbol, Definition, _ptr>;
has(k: typeof $version): true;
has(k: typeof $pointer): true;
has(k: typeof $definitions): true;
} & _.Dictionary<_val, _ptr>
} & _.Dictionary<_ptr>
)
],
_ptr
@ -60,27 +60,15 @@ export type Version = (typeof $1);
export type PointerName = (Ref | (typeof __lit5));
export type Definition = (_.Record<(typeof $or), [Array<[symbol, Alternative]>], _ptr> | Alternative);
export type Alternative = (_.Record<(typeof $and), [Array<Pattern>], _ptr> | Pattern);
export type Pattern = (
_.Record<
(typeof $atom),
[
(
(typeof $Boolean) |
(typeof $Float) |
(typeof $Double) |
(typeof $SignedInteger) |
(typeof $String) |
(typeof $ByteString) |
(typeof $Symbol)
)
],
_ptr
> |
_.Record<(typeof $atom), [AtomKind], _ptr> |
_.Record<(typeof $pointer), [], _ptr> |
_.Record<(typeof $lit), [_val], _ptr> |
Ref |
_.Record<(typeof $or), [Array<Pattern>], _ptr> |
_.Record<(typeof $and), [Array<Pattern>], _ptr> |
_.Record<(typeof $rec), [Pattern, Pattern], _ptr> |
_.Record<(typeof $tuple), [Array<NamedPattern>], _ptr> |
_.Record<(typeof $tuple_STAR_), [Array<NamedPattern>, NamedPattern], _ptr> |
@ -89,6 +77,16 @@ export type Pattern = (
_.Record<(typeof $dict), [_.KeyedDictionary<_val, Pattern, _ptr>], _ptr>
);
export type AtomKind = (
(typeof $Boolean) |
(typeof $Float) |
(typeof $Double) |
(typeof $SignedInteger) |
(typeof $String) |
(typeof $ByteString) |
(typeof $Symbol)
);
export type NamedPattern = (_.Record<(typeof $named), [symbol, Pattern], _ptr> | Pattern);
export const Ref = _.Record.makeConstructor<{"module": ModulePath, "name": symbol}, _ptr>()($ref, ["module","name"]);
@ -110,16 +108,16 @@ export function isSchema(v: any): v is Schema {
(
(v.length === 1) &&
(
_.Dictionary.isDictionary<_val, _ptr>(v[0]) &&
_.Dictionary.isDictionary<_ptr>(v[0]) &&
((_tmp0 = v[0].get($version)) !== void 0 && isVersion(_tmp0)) &&
((_tmp1 = v[0].get($pointer)) !== void 0 && isPointerName(_tmp1)) &&
(
(_tmp2 = v[0].get($definitions)) !== void 0 && (
_.Dictionary.isDictionary<_val, _ptr>(_tmp2) &&
_.Dictionary.isDictionary<_ptr>(_tmp2) &&
((() => {
for (const e of _tmp2) {
if (!(typeof e[0] === 'symbol')) return false;
if (!(isPattern(e[1]))) return false;
if (!(isDefinition(e[1]))) return false;
};
return true;
})())
@ -143,16 +141,16 @@ export function decodeSchema(d: _.TypedDecoder<_ptr>): Schema | undefined {
let _tmp4, _tmp5, _tmp6, _tmp7, _tmp8: any;
_tmp5 = d.next();
if (_tmp5 !== void 0 && !((
_.Dictionary.isDictionary<_val, _ptr>(_tmp5) &&
_.Dictionary.isDictionary<_ptr>(_tmp5) &&
((_tmp6 = _tmp5.get($version)) !== void 0 && isVersion(_tmp6)) &&
((_tmp7 = _tmp5.get($pointer)) !== void 0 && isPointerName(_tmp7)) &&
(
(_tmp8 = _tmp5.get($definitions)) !== void 0 && (
_.Dictionary.isDictionary<_val, _ptr>(_tmp8) &&
_.Dictionary.isDictionary<_ptr>(_tmp8) &&
((() => {
for (const e of _tmp8) {
if (!(typeof e[0] === 'symbol')) return false;
if (!(isPattern(e[1]))) return false;
if (!(isDefinition(e[1]))) return false;
};
return true;
})())
@ -167,11 +165,11 @@ export function decodeSchema(d: _.TypedDecoder<_ptr>): Schema | undefined {
{
get(k: typeof $version): Version;
get(k: typeof $pointer): PointerName;
get(k: typeof $definitions): _.KeyedDictionary<symbol, Pattern, _ptr>;
get(k: typeof $definitions): _.KeyedDictionary<symbol, Definition, _ptr>;
has(k: typeof $version): true;
has(k: typeof $pointer): true;
has(k: typeof $definitions): true;
} & _.Dictionary<_val, _ptr>
} & _.Dictionary<_ptr>
)
]
>(_tmp3 as any, _tmp4 as any);
@ -203,50 +201,136 @@ export function decodePointerName(d: _.TypedDecoder<_ptr>): PointerName | undefi
return result;
}
export function isDefinition(v: any): v is Definition {
return (
(
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
_.is(v.label, $or) &&
(
(v.length === 1) &&
(
_.Array.isArray(v[0]) &&
!_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[0]) &&
(v[0].length >= 0) &&
v[0].every(v => (
(
_.Array.isArray(v) &&
!_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
(v.length === 2) &&
typeof v[0] === 'symbol' &&
isAlternative(v[1])
)
))
)
)
) ||
isAlternative(v)
);
}
export function asDefinition(v: any): Definition {
if (!isDefinition(v)) {throw new TypeError(`Invalid Definition: ${_.stringify(v)}`);} else {return v;};
}
export function decodeDefinition(d: _.TypedDecoder<_ptr>): Definition | undefined {
let _tmp10: any;
let result;
_tmp10 = d.mark();
if (d.openRecord()) {
let _tmp11: any;
_tmp11 = _.asLiteral(d.nextSymbol(), $or);
if (_tmp11 !== void 0) {
let _tmp12, _tmp13: any;
if (d.openSequence()) {
let _tmp14: any;
{
let vN: Array<[symbol, Alternative]> | undefined = [];
while (!d.closeCompound()) {
let _tmp15, _tmp16: any;
_tmp14 = void 0;
if (d.openSequence()) {
_tmp15 = d.nextSymbol();
if (_tmp15 !== void 0) {
_tmp16 = decodeAlternative(d);
if (_tmp16 !== void 0) {if (d.closeCompound()) _tmp14 = [_tmp15, _tmp16];};
};
};
if (_tmp14 === void 0) {vN = void 0; break;};
vN.push(_tmp14);
};
_tmp13 = vN;
};
};
if (_tmp13 !== void 0) {if (d.closeCompound()) _tmp12 = [_tmp13];};
if (_tmp12 !== void 0) result = _.Record<(typeof $or), [Array<[symbol, Alternative]>]>(_tmp11 as any, _tmp12 as any);
};
};
if (result === void 0) {d.restoreMark(_tmp10); result = decodeAlternative(d);};
return result;
}
export function isAlternative(v: any): v is Alternative {
return (
(
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
_.is(v.label, $and) &&
(
(v.length === 1) &&
(
_.Array.isArray(v[0]) &&
!_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[0]) &&
(v[0].length >= 0) &&
v[0].every(v => (isPattern(v)))
)
)
) ||
isPattern(v)
);
}
export function asAlternative(v: any): Alternative {
if (!isAlternative(v)) {throw new TypeError(`Invalid Alternative: ${_.stringify(v)}`);} else {return v;};
}
export function decodeAlternative(d: _.TypedDecoder<_ptr>): Alternative | undefined {
let _tmp17: any;
let result;
_tmp17 = d.mark();
if (d.openRecord()) {
let _tmp18: any;
_tmp18 = _.asLiteral(d.nextSymbol(), $and);
if (_tmp18 !== void 0) {
let _tmp19, _tmp20: any;
if (d.openSequence()) {
let _tmp21: any;
{
let vN: Array<Pattern> | undefined = [];
while (!d.closeCompound()) {
_tmp21 = void 0;
_tmp21 = decodePattern(d);
if (_tmp21 === void 0) {vN = void 0; break;};
vN.push(_tmp21);
};
_tmp20 = vN;
};
};
if (_tmp20 !== void 0) {if (d.closeCompound()) _tmp19 = [_tmp20];};
if (_tmp19 !== void 0) result = _.Record<(typeof $and), [Array<Pattern>]>(_tmp18 as any, _tmp19 as any);
};
};
if (result === void 0) {d.restoreMark(_tmp17); result = decodePattern(d);};
return result;
}
export function isPattern(v: any): v is Pattern {
return _.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) && (
(
(
_.is(v.label, $atom) && (
(v.length === 1) &&
(
_.is(v[0], $Boolean) ||
_.is(v[0], $Float) ||
_.is(v[0], $Double) ||
_.is(v[0], $SignedInteger) ||
_.is(v[0], $String) ||
_.is(v[0], $ByteString) ||
_.is(v[0], $Symbol)
)
)
) ||
(_.is(v.label, $atom) && ((v.length === 1) && isAtomKind(v[0]))) ||
(_.is(v.label, $pointer) && ((v.length === 0))) ||
(_.is(v.label, $lit) && ((v.length === 1) && true)) ||
(
_.is(v.label, $ref) && ((v.length === 2) && isModulePath(v[0]) && typeof v[1] === 'symbol')
) ||
(
_.is(v.label, $or) && (
(v.length === 1) &&
(
_.Array.isArray(v[0]) &&
!_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[0]) &&
(v[0].length >= 0) &&
v[0].every(v => (isPattern(v)))
)
)
) ||
(
_.is(v.label, $and) && (
(v.length === 1) &&
(
_.Array.isArray(v[0]) &&
!_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[0]) &&
(v[0].length >= 0) &&
v[0].every(v => (isPattern(v)))
)
)
) ||
(
_.is(v.label, $rec) && ((v.length === 2) && isPattern(v[0]) && isPattern(v[1]))
) ||
@ -281,7 +365,7 @@ export function isPattern(v: any): v is Pattern {
_.is(v.label, $dict) && (
(v.length === 1) &&
(
_.Dictionary.isDictionary<_val, _ptr>(v[0]) &&
_.Dictionary.isDictionary<_ptr>(v[0]) &&
((() => {
for (const e of v[0]) {if (!(true)) return false; if (!(isPattern(e[1]))) return false;};
return true;
@ -300,210 +384,133 @@ export function asPattern(v: any): Pattern {
export function decodePattern(d: _.TypedDecoder<_ptr>): Pattern | undefined {
let result;
if (d.openRecord()) {
let _tmp10, _tmp11: any;
_tmp10 = d.next();
_tmp11 = d.mark();
if (_.is(_tmp10, $atom)) {
let _tmp12, _tmp13, _tmp14: any;
_tmp14 = d.mark();
_tmp13 = _.asLiteral(d.nextSymbol(), $Boolean);
if (_tmp13 === void 0) {
d.restoreMark(_tmp14);
_tmp13 = _.asLiteral(d.nextSymbol(), $Float);
if (_tmp13 === void 0) {
d.restoreMark(_tmp14);
_tmp13 = _.asLiteral(d.nextSymbol(), $Double);
if (_tmp13 === void 0) {
d.restoreMark(_tmp14);
_tmp13 = _.asLiteral(d.nextSymbol(), $SignedInteger);
if (_tmp13 === void 0) {
d.restoreMark(_tmp14);
_tmp13 = _.asLiteral(d.nextSymbol(), $String);
if (_tmp13 === void 0) {
d.restoreMark(_tmp14);
_tmp13 = _.asLiteral(d.nextSymbol(), $ByteString);
if (_tmp13 === void 0) {d.restoreMark(_tmp14); _tmp13 = _.asLiteral(d.nextSymbol(), $Symbol);};
};
};
};
};
};
if (_tmp13 !== void 0) {if (d.closeCompound()) _tmp12 = [_tmp13];};
if (_tmp12 !== void 0) result = _.Record<
(typeof $atom),
[
(
(typeof $Boolean) |
(typeof $Float) |
(typeof $Double) |
(typeof $SignedInteger) |
(typeof $String) |
(typeof $ByteString) |
(typeof $Symbol)
)
]
>(_tmp10 as any, _tmp12 as any);
let _tmp22, _tmp23: any;
_tmp22 = d.next();
_tmp23 = d.mark();
if (_.is(_tmp22, $atom)) {
let _tmp24, _tmp25: any;
_tmp25 = decodeAtomKind(d);
if (_tmp25 !== void 0) {if (d.closeCompound()) _tmp24 = [_tmp25];};
if (_tmp24 !== void 0) result = _.Record<(typeof $atom), [AtomKind]>(_tmp22 as any, _tmp24 as any);
};
if (result === void 0) {
d.restoreMark(_tmp11);
if (_.is(_tmp10, $pointer)) {
let _tmp15: any;
if (d.closeCompound()) _tmp15 = [];
if (_tmp15 !== void 0) result = _.Record<(typeof $pointer), []>(_tmp10 as any, _tmp15 as any);
d.restoreMark(_tmp23);
if (_.is(_tmp22, $pointer)) {
let _tmp26: any;
if (d.closeCompound()) _tmp26 = [];
if (_tmp26 !== void 0) result = _.Record<(typeof $pointer), []>(_tmp22 as any, _tmp26 as any);
};
if (result === void 0) {
d.restoreMark(_tmp11);
if (_.is(_tmp10, $lit)) {
let _tmp16, _tmp17: any;
_tmp17 = d.next();
if (_tmp17 !== void 0) {if (d.closeCompound()) _tmp16 = [_tmp17];};
if (_tmp16 !== void 0) result = _.Record<(typeof $lit), [_val]>(_tmp10 as any, _tmp16 as any);
d.restoreMark(_tmp23);
if (_.is(_tmp22, $lit)) {
let _tmp27, _tmp28: any;
_tmp28 = d.next();
if (_tmp28 !== void 0) {if (d.closeCompound()) _tmp27 = [_tmp28];};
if (_tmp27 !== void 0) result = _.Record<(typeof $lit), [_val]>(_tmp22 as any, _tmp27 as any);
};
if (result === void 0) {
d.restoreMark(_tmp11);
if (_.is(_tmp10, $ref)) {
let _tmp18, _tmp19, _tmp20: any;
_tmp19 = decodeModulePath(d);
if (_tmp19 !== void 0) {
_tmp20 = d.nextSymbol();
if (_tmp20 !== void 0) {if (d.closeCompound()) _tmp18 = [_tmp19, _tmp20];};
d.restoreMark(_tmp23);
if (_.is(_tmp22, $ref)) {
let _tmp29, _tmp30, _tmp31: any;
_tmp30 = decodeModulePath(d);
if (_tmp30 !== void 0) {
_tmp31 = d.nextSymbol();
if (_tmp31 !== void 0) {if (d.closeCompound()) _tmp29 = [_tmp30, _tmp31];};
};
if (_tmp18 !== void 0) result = _.Record<(typeof $ref), [ModulePath, symbol]>(_tmp10 as any, _tmp18 as any);
if (_tmp29 !== void 0) result = _.Record<(typeof $ref), [ModulePath, symbol]>(_tmp22 as any, _tmp29 as any);
};
if (result === void 0) {
d.restoreMark(_tmp11);
if (_.is(_tmp10, $or)) {
let _tmp21, _tmp22: any;
if (d.openSequence()) {
let _tmp23: any;
{
let vN: Array<Pattern> | undefined = [];
while (!d.closeCompound()) {
_tmp23 = void 0;
_tmp23 = decodePattern(d);
if (_tmp23 === void 0) {vN = void 0; break;};
vN.push(_tmp23);
};
_tmp22 = vN;
};
d.restoreMark(_tmp23);
if (_.is(_tmp22, $rec)) {
let _tmp32, _tmp33, _tmp34: any;
_tmp33 = decodePattern(d);
if (_tmp33 !== void 0) {
_tmp34 = decodePattern(d);
if (_tmp34 !== void 0) {if (d.closeCompound()) _tmp32 = [_tmp33, _tmp34];};
};
if (_tmp22 !== void 0) {if (d.closeCompound()) _tmp21 = [_tmp22];};
if (_tmp21 !== void 0) result = _.Record<(typeof $or), [Array<Pattern>]>(_tmp10 as any, _tmp21 as any);
if (_tmp32 !== void 0) result = _.Record<(typeof $rec), [Pattern, Pattern]>(_tmp22 as any, _tmp32 as any);
};
if (result === void 0) {
d.restoreMark(_tmp11);
if (_.is(_tmp10, $and)) {
let _tmp24, _tmp25: any;
d.restoreMark(_tmp23);
if (_.is(_tmp22, $tuple)) {
let _tmp35, _tmp36: any;
if (d.openSequence()) {
let _tmp26: any;
let _tmp37: any;
{
let vN: Array<Pattern> | undefined = [];
let vN: Array<NamedPattern> | undefined = [];
while (!d.closeCompound()) {
_tmp26 = void 0;
_tmp26 = decodePattern(d);
if (_tmp26 === void 0) {vN = void 0; break;};
vN.push(_tmp26);
_tmp37 = void 0;
_tmp37 = decodeNamedPattern(d);
if (_tmp37 === void 0) {vN = void 0; break;};
vN.push(_tmp37);
};
_tmp25 = vN;
_tmp36 = vN;
};
};
if (_tmp25 !== void 0) {if (d.closeCompound()) _tmp24 = [_tmp25];};
if (_tmp24 !== void 0) result = _.Record<(typeof $and), [Array<Pattern>]>(_tmp10 as any, _tmp24 as any);
if (_tmp36 !== void 0) {if (d.closeCompound()) _tmp35 = [_tmp36];};
if (_tmp35 !== void 0) result = _.Record<(typeof $tuple), [Array<NamedPattern>]>(_tmp22 as any, _tmp35 as any);
};
if (result === void 0) {
d.restoreMark(_tmp11);
if (_.is(_tmp10, $rec)) {
let _tmp27, _tmp28, _tmp29: any;
_tmp28 = decodePattern(d);
if (_tmp28 !== void 0) {
_tmp29 = decodePattern(d);
if (_tmp29 !== void 0) {if (d.closeCompound()) _tmp27 = [_tmp28, _tmp29];};
d.restoreMark(_tmp23);
if (_.is(_tmp22, $tuple_STAR_)) {
let _tmp38, _tmp39, _tmp40: any;
if (d.openSequence()) {
let _tmp41: any;
{
let vN: Array<NamedPattern> | undefined = [];
while (!d.closeCompound()) {
_tmp41 = void 0;
_tmp41 = decodeNamedPattern(d);
if (_tmp41 === void 0) {vN = void 0; break;};
vN.push(_tmp41);
};
_tmp39 = vN;
};
};
if (_tmp27 !== void 0) result = _.Record<(typeof $rec), [Pattern, Pattern]>(_tmp10 as any, _tmp27 as any);
if (_tmp39 !== void 0) {
_tmp40 = decodeNamedPattern(d);
if (_tmp40 !== void 0) {if (d.closeCompound()) _tmp38 = [_tmp39, _tmp40];};
};
if (_tmp38 !== void 0) result = _.Record<(typeof $tuple_STAR_), [Array<NamedPattern>, NamedPattern]>(_tmp22 as any, _tmp38 as any);
};
if (result === void 0) {
d.restoreMark(_tmp11);
if (_.is(_tmp10, $tuple)) {
let _tmp30, _tmp31: any;
if (d.openSequence()) {
let _tmp32: any;
{
let vN: Array<NamedPattern> | undefined = [];
while (!d.closeCompound()) {
_tmp32 = void 0;
_tmp32 = decodeNamedPattern(d);
if (_tmp32 === void 0) {vN = void 0; break;};
vN.push(_tmp32);
};
_tmp31 = vN;
};
};
if (_tmp31 !== void 0) {if (d.closeCompound()) _tmp30 = [_tmp31];};
if (_tmp30 !== void 0) result = _.Record<(typeof $tuple), [Array<NamedPattern>]>(_tmp10 as any, _tmp30 as any);
d.restoreMark(_tmp23);
if (_.is(_tmp22, $setof)) {
let _tmp42, _tmp43: any;
_tmp43 = decodePattern(d);
if (_tmp43 !== void 0) {if (d.closeCompound()) _tmp42 = [_tmp43];};
if (_tmp42 !== void 0) result = _.Record<(typeof $setof), [Pattern]>(_tmp22 as any, _tmp42 as any);
};
if (result === void 0) {
d.restoreMark(_tmp11);
if (_.is(_tmp10, $tuple_STAR_)) {
let _tmp33, _tmp34, _tmp35: any;
if (d.openSequence()) {
let _tmp36: any;
{
let vN: Array<NamedPattern> | undefined = [];
while (!d.closeCompound()) {
_tmp36 = void 0;
_tmp36 = decodeNamedPattern(d);
if (_tmp36 === void 0) {vN = void 0; break;};
vN.push(_tmp36);
};
_tmp34 = vN;
};
d.restoreMark(_tmp23);
if (_.is(_tmp22, $dictof)) {
let _tmp44, _tmp45, _tmp46: any;
_tmp45 = decodePattern(d);
if (_tmp45 !== void 0) {
_tmp46 = decodePattern(d);
if (_tmp46 !== void 0) {if (d.closeCompound()) _tmp44 = [_tmp45, _tmp46];};
};
if (_tmp34 !== void 0) {
_tmp35 = decodeNamedPattern(d);
if (_tmp35 !== void 0) {if (d.closeCompound()) _tmp33 = [_tmp34, _tmp35];};
};
if (_tmp33 !== void 0) result = _.Record<(typeof $tuple_STAR_), [Array<NamedPattern>, NamedPattern]>(_tmp10 as any, _tmp33 as any);
if (_tmp44 !== void 0) result = _.Record<(typeof $dictof), [Pattern, Pattern]>(_tmp22 as any, _tmp44 as any);
};
if (result === void 0) {
d.restoreMark(_tmp11);
if (_.is(_tmp10, $setof)) {
let _tmp37, _tmp38: any;
_tmp38 = decodePattern(d);
if (_tmp38 !== void 0) {if (d.closeCompound()) _tmp37 = [_tmp38];};
if (_tmp37 !== void 0) result = _.Record<(typeof $setof), [Pattern]>(_tmp10 as any, _tmp37 as any);
};
if (result === void 0) {
d.restoreMark(_tmp11);
if (_.is(_tmp10, $dictof)) {
let _tmp39, _tmp40, _tmp41: any;
_tmp40 = decodePattern(d);
if (_tmp40 !== void 0) {
_tmp41 = decodePattern(d);
if (_tmp41 !== void 0) {if (d.closeCompound()) _tmp39 = [_tmp40, _tmp41];};
};
if (_tmp39 !== void 0) result = _.Record<(typeof $dictof), [Pattern, Pattern]>(_tmp10 as any, _tmp39 as any);
};
if (result === void 0) {
d.restoreMark(_tmp11);
if (_.is(_tmp10, $dict)) {
let _tmp42, _tmp43: any;
if (d.openDictionary()) {
let r: _.KeyedDictionary<_val, Pattern, _ptr> | undefined = new _.KeyedDictionary();
while (!d.closeCompound()) {
let K: undefined | _val = void 0;
K = d.next();
if (K === void 0) { r = void 0; break; };
let V: undefined | Pattern = void 0;
V = decodePattern(d);
if (V === void 0) { r = void 0; break; };
r.set(K, V);
};
_tmp43 = r;
};
if (_tmp43 !== void 0) {if (d.closeCompound()) _tmp42 = [_tmp43];};
if (_tmp42 !== void 0) result = _.Record<(typeof $dict), [_.KeyedDictionary<_val, Pattern, _ptr>]>(_tmp10 as any, _tmp42 as any);
d.restoreMark(_tmp23);
if (_.is(_tmp22, $dict)) {
let _tmp47, _tmp48: any;
if (d.openDictionary()) {
let r: _.KeyedDictionary<_val, Pattern, _ptr> | undefined = new _.KeyedDictionary();
while (!d.closeCompound()) {
let K: undefined | _val = void 0;
K = d.next();
if (K === void 0) { r = void 0; break; };
let V: undefined | Pattern = void 0;
V = decodePattern(d);
if (V === void 0) { r = void 0; break; };
r.set(K, V);
};
_tmp48 = r;
};
if (_tmp48 !== void 0) {if (d.closeCompound()) _tmp47 = [_tmp48];};
if (_tmp47 !== void 0) result = _.Record<(typeof $dict), [_.KeyedDictionary<_val, Pattern, _ptr>]>(_tmp22 as any, _tmp47 as any);
};
};
};
@ -518,6 +525,51 @@ export function decodePattern(d: _.TypedDecoder<_ptr>): Pattern | undefined {
return result;
}
export function isAtomKind(v: any): v is AtomKind {
return (
_.is(v, $Boolean) ||
_.is(v, $Float) ||
_.is(v, $Double) ||
_.is(v, $SignedInteger) ||
_.is(v, $String) ||
_.is(v, $ByteString) ||
_.is(v, $Symbol)
);
}
export function asAtomKind(v: any): AtomKind {
if (!isAtomKind(v)) {throw new TypeError(`Invalid AtomKind: ${_.stringify(v)}`);} else {return v;};
}
export function decodeAtomKind(d: _.TypedDecoder<_ptr>): AtomKind | undefined {
let _tmp49: any;
let result;
_tmp49 = d.mark();
result = _.asLiteral(d.nextSymbol(), $Boolean);
if (result === void 0) {
d.restoreMark(_tmp49);
result = _.asLiteral(d.nextSymbol(), $Float);
if (result === void 0) {
d.restoreMark(_tmp49);
result = _.asLiteral(d.nextSymbol(), $Double);
if (result === void 0) {
d.restoreMark(_tmp49);
result = _.asLiteral(d.nextSymbol(), $SignedInteger);
if (result === void 0) {
d.restoreMark(_tmp49);
result = _.asLiteral(d.nextSymbol(), $String);
if (result === void 0) {
d.restoreMark(_tmp49);
result = _.asLiteral(d.nextSymbol(), $ByteString);
if (result === void 0) {d.restoreMark(_tmp49); result = _.asLiteral(d.nextSymbol(), $Symbol);};
};
};
};
};
};
return result;
}
export function isNamedPattern(v: any): v is NamedPattern {
return (
(
@ -534,23 +586,23 @@ export function asNamedPattern(v: any): NamedPattern {
}
export function decodeNamedPattern(d: _.TypedDecoder<_ptr>): NamedPattern | undefined {
let _tmp44: any;
let _tmp50: any;
let result;
_tmp44 = d.mark();
_tmp50 = d.mark();
if (d.openRecord()) {
let _tmp45: any;
_tmp45 = _.asLiteral(d.nextSymbol(), $named);
if (_tmp45 !== void 0) {
let _tmp46, _tmp47, _tmp48: any;
_tmp47 = d.nextSymbol();
if (_tmp47 !== void 0) {
_tmp48 = decodePattern(d);
if (_tmp48 !== void 0) {if (d.closeCompound()) _tmp46 = [_tmp47, _tmp48];};
let _tmp51: any;
_tmp51 = _.asLiteral(d.nextSymbol(), $named);
if (_tmp51 !== void 0) {
let _tmp52, _tmp53, _tmp54: any;
_tmp53 = d.nextSymbol();
if (_tmp53 !== void 0) {
_tmp54 = decodePattern(d);
if (_tmp54 !== void 0) {if (d.closeCompound()) _tmp52 = [_tmp53, _tmp54];};
};
if (_tmp46 !== void 0) result = _.Record<(typeof $named), [symbol, Pattern]>(_tmp45 as any, _tmp46 as any);
if (_tmp52 !== void 0) result = _.Record<(typeof $named), [symbol, Pattern]>(_tmp51 as any, _tmp52 as any);
};
};
if (result === void 0) {d.restoreMark(_tmp44); result = decodePattern(d);};
if (result === void 0) {d.restoreMark(_tmp50); result = decodePattern(d);};
return result;
}
@ -569,16 +621,16 @@ export function asRef(v: any): Ref {
export function decodeRef(d: _.TypedDecoder<_ptr>): Ref | undefined {
let result;
if (d.openRecord()) {
let _tmp49: any;
_tmp49 = _.asLiteral(d.nextSymbol(), $ref);
if (_tmp49 !== void 0) {
let _tmp50, _tmp51, _tmp52: any;
_tmp51 = decodeModulePath(d);
if (_tmp51 !== void 0) {
_tmp52 = d.nextSymbol();
if (_tmp52 !== void 0) {if (d.closeCompound()) _tmp50 = [_tmp51, _tmp52];};
let _tmp55: any;
_tmp55 = _.asLiteral(d.nextSymbol(), $ref);
if (_tmp55 !== void 0) {
let _tmp56, _tmp57, _tmp58: any;
_tmp57 = decodeModulePath(d);
if (_tmp57 !== void 0) {
_tmp58 = d.nextSymbol();
if (_tmp58 !== void 0) {if (d.closeCompound()) _tmp56 = [_tmp57, _tmp58];};
};
if (_tmp50 !== void 0) result = _.Record<(typeof $ref), [ModulePath, symbol]>(_tmp49 as any, _tmp50 as any);
if (_tmp56 !== void 0) result = _.Record<(typeof $ref), [ModulePath, symbol]>(_tmp55 as any, _tmp56 as any);
};
};
return result;
@ -600,14 +652,14 @@ export function asModulePath(v: any): ModulePath {
export function decodeModulePath(d: _.TypedDecoder<_ptr>): ModulePath | undefined {
let result;
if (d.openSequence()) {
let _tmp53: any;
let _tmp59: any;
{
let vN: Array<symbol> | undefined = [];
while (!d.closeCompound()) {
_tmp53 = void 0;
_tmp53 = d.nextSymbol();
if (_tmp53 === void 0) {vN = void 0; break;};
vN.push(_tmp53);
_tmp59 = void 0;
_tmp59 = d.nextSymbol();
if (_tmp59 === void 0) {vN = void 0; break;};
vN.push(_tmp59);
};
result = vN;
};

View File

@ -1,5 +1,5 @@
import { Value, is, Position } from '@preserves/core';
import { ModulePath, Ref, Schema, Pattern, $definitions } from './gen/schema';
import { ModulePath, Ref, Schema, $definitions, Definition } from './gen/schema';
import { BASE } from './base';
import { SchemaSyntaxError } from './error';
@ -41,9 +41,9 @@ function modsymFor(e: SchemaEnvEntry): string {
export function lookup<R>(namePos: Position | null,
name: Ref,
env: Environment,
kLocal: (p: Pattern) => R,
kBase: (p: Pattern) => R,
kOther: (mod: string, modPath: string, p: Pattern | null) => R): R
kLocal: (p: Definition) => R,
kBase: (p: Definition) => R,
kOther: (mod: string, modPath: string, p: Definition | null) => R): R
{
for (const e of env) {
if (is(e.schemaModulePath, Ref._.module(name)) ||

View File

@ -1,5 +1,5 @@
import { Reader, Annotated, Dictionary, is, peel, preserves, Record, strip, Tuple, Value, Position, position, ReaderOptions, stringify } from '@preserves/core';
import { Input, NamedPattern, Pattern, Schema } from './meta';
import { Reader, Annotated, Dictionary, is, peel, preserves, Record, strip, Tuple, Position, position, ReaderOptions, stringify } from '@preserves/core';
import { Input, NamedPattern, Pattern, Schema, Alternative, Definition } from './meta';
import * as M from './meta';
import { SchemaSyntaxError } from './error';
@ -66,7 +66,7 @@ export function parseSchema(toplevelTokens: Array<Input>,
{
let version: M.Version | undefined = void 0;
let pointer: M.PointerName = false;
let definitions = new Dictionary<Pattern, never>();
let definitions = new Dictionary<never, Definition>();
function process(toplevelTokens: Array<Input>): void {
const toplevelClauses = splitBy(peel(toplevelTokens) as Array<Input>, M.DOT);
@ -115,25 +115,53 @@ export function parseSchema(toplevelTokens: Array<Input>,
throw new SchemaSyntaxError("Schema: missing version declaration.", null);
}
return M.asSchema(Record(M.$schema, [new Dictionary<Value>([
return M.asSchema(Record(M.$schema, [new Dictionary<never>([
[M.$version, version],
[M.$pointer, pointer],
[M.$definitions, definitions],
])]));
}
function parseDefinition(name: symbol, body: Array<Input>): Pattern {
return parseOp(body, M.ORSYM, p => parseOp(p, M.ANDSYM, p => parseBase(name, p)));
function parseDefinition(name: symbol, body: Array<Input>): Definition {
let nextAnonymousFieldNumber = 0;
function alternativeName([input, p]: readonly [Array<Input>, Alternative])
: [symbol, Alternative]
{
const n = findName(input) || findName(input[0]);
if (n !== false) {
return [n, p];
}
if (p.label === M.$rec && p[0].label === M.$lit && typeof p[0][0] === 'symbol') {
return [p[0][0], p];
}
if (p.label === M.$ref) {
return [p[1], p];
}
if (p.label === M.$lit && typeof p[0] === 'symbol') {
return [p[0], p];
}
return [Symbol.for('_anonymous' + nextAnonymousFieldNumber++), p];
}
return parseOp(body,
M.ORSYM,
p => [p, parseOp(p,
M.ANDSYM,
p => parseBase(name, p),
ps => Record(M.$and, [ps]),
p => p as Alternative)] as const,
ps => Record(M.$or, [ps.map(alternativeName)]),
p => p[1] as Definition);
}
function parseOp(body: Array<Input>, op: Input, k: (p: Array<Input>) => Pattern): Pattern {
const pieces = splitBy(body, op);
if (pieces.length === 1) return k(pieces[0]);
switch (op) {
case M.ORSYM: return Record(M.$or, [pieces.map(k)]);
case M.ANDSYM: return Record(M.$and, [pieces.map(k)]);
default: throw new Error("Internal error: unexpected operator");
}
function parseOp<Each, Combined>(body: Array<Input>,
op: Input,
each: (p: Array<Input>) => Each,
combineN: (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);
}
function findName(x: Input): symbol | false {
@ -145,6 +173,14 @@ function findName(x: Input): symbol | false {
return false;
}
function namedwrap(f: (b: Input) => Pattern): (b: Input) => NamedPattern {
return (b: Input) => {
const name = findName(b);
if (name === false) return f(b);
return Record(M.$named, [name, f(b)]);
}
}
function parseRef(name: string, pos: Position | null, item: symbol): Pattern {
const s = item.description;
if (s === void 0) invalidPattern(name, item, pos);
@ -166,16 +202,6 @@ function parseBase(name: symbol, body: Array<Input>): Pattern {
const item = peel(body[0]);
const walk = (b: Input): Pattern => parseBase(name, [b]);
const namedwalk = (b: Input): NamedPattern => {
const name = findName(b);
if (name === false) return walk(b);
return Record(M.$named, [name, walk(b)]);
};
const walkitems = (b: Input): Pattern[] => {
b = peel(b);
if (!Array.isArray(b)) complain();
return b.map(walk);
};
function complain(): never {
invalidPattern(stringify(name), item, pos);
@ -191,12 +217,6 @@ function parseBase(name: symbol, body: Array<Input>): Pattern {
case M.$lit:
if (item.length !== 1) complain();
return Record(M.$lit, [item[0]]);
case M.$or:
if (item.length !== 1) complain();
return Record(M.$or, [walkitems(item[0])]);
case M.$and:
if (item.length !== 1) complain();
return Record(M.$and, [walkitems(item[0])]);
case M.$rec:
if (item.length !== 2) complain();
return Record(M.$rec, [walk(item[0]), walk(item[1])]);
@ -204,19 +224,19 @@ function parseBase(name: symbol, body: Array<Input>): Pattern {
complain();
}
} else {
return Record(M.$rec, [Record(M.$lit, [label]), Record(M.$tuple, [item.map(namedwalk)])]);
return Record(M.$rec, [Record(M.$lit, [label]), Record(M.$tuple, [item.map(namedwrap(walk))])]);
}
} else if (Array.isArray(item)) {
if (is(item[item.length - 1], M.DOTDOTDOT)) {
if (item.length < 2) complain();
return Record(M.$tuple_STAR_, [
item.slice(0, item.length - 2).map(namedwalk),
namedwalk(item[item.length - 2]),
item.slice(0, item.length - 2).map(namedwrap(walk)),
namedwrap(walk)(item[item.length - 2]),
]);
} else {
return Record(M.$tuple, [item.map(namedwalk)]);
return Record(M.$tuple, [item.map(namedwrap(walk))]);
}
} else if (Dictionary.isDictionary<Input, never>(item)) {
} else if (Dictionary.isDictionary<never, Input>(item)) {
if (item.size === 2 && item.has(M.DOTDOTDOT)) {
const v = item.clone();
v.delete(M.DOTDOTDOT);

View File

@ -5,7 +5,7 @@ version 1 .
Schema = <schema @details {
version: Version
pointer: PointerName
definitions: { symbol: Pattern ...:... }
definitions: { symbol: Definition ...:... }
}>.
; version 1 .
@ -13,51 +13,51 @@ Version = 1 .
PointerName = Ref / #f.
Pattern = <<or> [
; special builtins or <<atom> symbol>
<atom @atomKind <<or> [=Boolean =Float =Double =SignedInteger =String =ByteString =Symbol]>>
; Pattern / Pattern / ...
; and the empty pattern is <or []>
Definition = <or @patterns [[@name symbol Alternative] ...]> / Alternative .
; Pattern & Pattern & ...
; and the universal pattern, "any", is <and []>
Alternative = <and @patterns [Pattern ...]> / Pattern .
Pattern =
; special builtins or <<atom> AtomKind>
/ <atom @atomKind AtomKind>
; matches a pointer in the input
<pointer>
/ <pointer>
; =symbol, <<lit> any>, or plain non-symbol atom
<lit @value any>
/ <lit @value any>
; symbol, symbol.symbol, symbol.symbol.symbol, ...
Ref
; Pattern / Pattern / ...
; <<or> [Pattern Pattern ...]>
; and the empty pattern is <<or> []>
<or @patterns [Pattern ...]>
; Pattern & Pattern & ...
; <<and> [Pattern Pattern ...]>
; and the universal pattern, "any", is <<and> []>
<and @patterns [Pattern ...]>
/ Ref
; <label a b c> ----> <rec <lit label> <tuple [<ref a> <ref b> <ref c>]>>
; except for record labels
; <<rec> x y> ---> <rec <ref x> <ref y>>
<rec @label Pattern @fields Pattern>
/ <rec @label Pattern @fields Pattern>
; [a b c] ----> <tuple [<ref a> <ref b> <ref c>]>
<tuple @patterns [NamedPattern ...]>
/ <tuple @patterns [NamedPattern ...]>
; [a b c ...] ----> <tuple* [<ref a> <ref b>] <ref c>]>
<tuple* @fixed [NamedPattern ...] @variable NamedPattern>
/ <tuple* @fixed [NamedPattern ...] @variable NamedPattern>
; #{p} ----> <setof <ref p>>
<setof @pattern Pattern>
/ <setof @pattern Pattern>
; {k: v, ...:...} ----> <dictof <ref k> <ref v>>
<dictof @key Pattern @value Pattern>
/ <dictof @key Pattern @value Pattern>
; {a: b, c: d} ----> <dict {a: <ref b>, c: <ref d>}>
<dict @entries { any: Pattern ...:... }>
]>.
/ <dict @entries { any: Pattern ...:... }>
.
NamedPattern = <named @name symbol @pattern Pattern> / Pattern .
AtomKind = =Boolean / =Float / =Double / =SignedInteger / =String / =ByteString / =Symbol .
NamedPattern = <named @name symbol @pattern Pattern> / @anonymous Pattern .
Ref = <ref @module ModulePath @name symbol>.
ModulePath = [symbol ...].