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'; 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.$version, 1],
[M.$definitions, new Dictionary<M.Pattern, never>([ [M.$pointer, false],
[Symbol.for('any'), Record(M.$and, [[]])], [M.$definitions, new Dictionary<never>([
[Symbol.for('any'), Record(M.$and, [[] as M.Pattern[]])],
[Symbol.for('bool'), Record(M.$atom, [M.$Boolean])], [Symbol.for('bool'), Record(M.$atom, [M.$Boolean])],
[Symbol.for('float'), Record(M.$atom, [M.$Float])], [Symbol.for('float'), Record(M.$atom, [M.$Float])],
[Symbol.for('double'), Record(M.$atom, [M.$Double])], [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('symbol'), Record(M.$atom, [M.$Symbol])],
[Symbol.for('ref'), Record(M.$pointer, [])], [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 { 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 { Formatter, parens, seq, Item, opseq, block, commas, brackets, anglebrackets, braces } from "./block";
import { refPosition } from "./reader"; import { refPosition } from "./reader";
import { Alternative, Definition } from "gen/schema";
export interface CompilerOptions { export interface CompilerOptions {
preservesModule?: string; preservesModule?: string;
@ -15,7 +16,7 @@ function fnblock(... items: Item[]): Item {
} }
export function compile(env: Environment, schema: Schema, options: CompilerOptions = {}): string { 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 types: Array<Item> = [];
const functions: Array<Item> = []; const functions: Array<Item> = [];
const imports = new KeyedSet<[string, string]>(); 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) { if (p.label === M.$ref) {
return lookup(refPosition(p), p, env, return lookup(refPosition(p), p, env,
(p) => p, (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) { switch (p.label) {
case M.$atom: case M.$atom:
switch (p[0]) { switch (p[0]) {
@ -188,12 +189,12 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
} else { } else {
switch (alts.length) { switch (alts.length) {
case 0: break; // assume dest is already void 0 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: { default: {
const mark = gentemp(); const mark = gentemp();
emit(`${mark} = d.mark()`); emit(`${mark} = d.mark()`);
function loop(i: number) { function loop(i: number) {
decoderFor(alts[i], dest); decoderFor(alts[i][1], dest);
if (i < alts.length - 1) { if (i < alts.length - 1) {
emit(seq(`if (${dest} === void 0) `, collectBody(() => { emit(seq(`if (${dest} === void 0) `, collectBody(() => {
emit(`d.restoreMark(${mark})`); 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) { switch (p.label) {
case M.$atom: case M.$atom:
switch (p[0]) { switch (p[0]) {
@ -310,7 +311,7 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
return `${mod}.${p[1].description!}`; return `${mod}.${p[1].description!}`;
}); });
case M.$or: 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: case M.$and:
return opseq('_val', ' & ', ... p[0].map(pp => typeFor(pp))); return opseq('_val', ' & ', ... p[0].map(pp => typeFor(pp)));
case M.$pointer: case M.$pointer:
@ -337,14 +338,14 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
seq(`get(k: typeof ${literal(k)}): `, typeFor(vp))), seq(`get(k: typeof ${literal(k)}): `, typeFor(vp))),
... Array.from(p[0]).map(([k, _vp]) => ... Array.from(p[0]).map(([k, _vp]) =>
seq(`has(k: typeof ${literal(k)}): true`))), seq(`has(k: typeof ${literal(k)}): true`))),
' & _.Dictionary<_val, _ptr>')); ' & _.Dictionary<_ptr>'));
default: default:
((_p: never) => {})(p); ((_p: never) => {})(p);
throw new Error("Unreachable"); 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) { switch (p.label) {
case M.$atom: case M.$atom:
switch (p[0]) { switch (p[0]) {
@ -379,7 +380,7 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
' && ', ' && ',
predicateFor(v, r[1], true))))))); predicateFor(v, r[1], true)))))));
} else { } 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: case M.$and:
@ -416,7 +417,7 @@ export function compile(env: Environment, schema: Schema, options: CompilerOptio
seq('return true'))); seq('return true')));
case M.$dictof: case M.$dictof:
return opseq('true', ' && ', return opseq('true', ' && ',
`_.Dictionary.isDictionary<_val, _ptr>(${v})`, `_.Dictionary.isDictionary<_ptr>(${v})`,
fnblock( fnblock(
seq(`for (const e of ${v}) `, block( seq(`for (const e of ${v}) `, block(
seq('if (!(', predicateFor('e[0]', p[0]), ')) return false'), 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'))); seq('return true')));
case M.$dict: case M.$dict:
return opseq('true', ' && ', return opseq('true', ' && ',
`_.Dictionary.isDictionary<_val, _ptr>(${v})`, `_.Dictionary.isDictionary<_ptr>(${v})`,
... Array.from(p[0]).map(([k, vp]) => { ... Array.from(p[0]).map(([k, vp]) => {
const tmp = gentemp(); const tmp = gentemp();
return parens(seq( return parens(seq(
@ -558,8 +559,8 @@ export function sourceCodeFor(v: Value<any>): Item {
set(s: Set<any>, k: Fold<any, Item>): Item { set(s: Set<any>, k: Fold<any, Item>): Item {
return seq('new _.Set<_val>', parens(brackets(... Array.from(s).map(k)))); return seq('new _.Set<_val>', parens(brackets(... Array.from(s).map(k))));
}, },
dictionary(d: Dictionary<Value<any>, any>, k: Fold<any, Item>): Item { dictionary(d: Dictionary<any>, k: Fold<any, Item>): Item {
return seq('new _.Dictionary<_val, _ptr>', parens(brackets(... Array.from(d).map(([kk,vv]) => return seq('new _.Dictionary<_ptr>', parens(brackets(... Array.from(d).map(([kk,vv]) =>
brackets(k(kk), k(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 $version): Version;
get(k: typeof $pointer): PointerName; 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 $version): true;
has(k: typeof $pointer): true; has(k: typeof $pointer): true;
has(k: typeof $definitions): true; has(k: typeof $definitions): true;
} & _.Dictionary<_val, _ptr> } & _.Dictionary<_ptr>
) )
}, _ptr>()($schema, ["details"]); }, _ptr>()($schema, ["details"]);
@ -46,11 +46,11 @@ export type Schema = _.Record<
{ {
get(k: typeof $version): Version; get(k: typeof $version): Version;
get(k: typeof $pointer): PointerName; 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 $version): true;
has(k: typeof $pointer): true; has(k: typeof $pointer): true;
has(k: typeof $definitions): true; has(k: typeof $definitions): true;
} & _.Dictionary<_val, _ptr> } & _.Dictionary<_ptr>
) )
], ],
_ptr _ptr
@ -60,27 +60,15 @@ export type Version = (typeof $1);
export type PointerName = (Ref | (typeof __lit5)); 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 = ( export type Pattern = (
_.Record< _.Record<(typeof $atom), [AtomKind], _ptr> |
(typeof $atom),
[
(
(typeof $Boolean) |
(typeof $Float) |
(typeof $Double) |
(typeof $SignedInteger) |
(typeof $String) |
(typeof $ByteString) |
(typeof $Symbol)
)
],
_ptr
> |
_.Record<(typeof $pointer), [], _ptr> | _.Record<(typeof $pointer), [], _ptr> |
_.Record<(typeof $lit), [_val], _ptr> | _.Record<(typeof $lit), [_val], _ptr> |
Ref | Ref |
_.Record<(typeof $or), [Array<Pattern>], _ptr> |
_.Record<(typeof $and), [Array<Pattern>], _ptr> |
_.Record<(typeof $rec), [Pattern, Pattern], _ptr> | _.Record<(typeof $rec), [Pattern, Pattern], _ptr> |
_.Record<(typeof $tuple), [Array<NamedPattern>], _ptr> | _.Record<(typeof $tuple), [Array<NamedPattern>], _ptr> |
_.Record<(typeof $tuple_STAR_), [Array<NamedPattern>, 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> _.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 type NamedPattern = (_.Record<(typeof $named), [symbol, Pattern], _ptr> | Pattern);
export const Ref = _.Record.makeConstructor<{"module": ModulePath, "name": symbol}, _ptr>()($ref, ["module","name"]); 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) && (v.length === 1) &&
( (
_.Dictionary.isDictionary<_val, _ptr>(v[0]) && _.Dictionary.isDictionary<_ptr>(v[0]) &&
((_tmp0 = v[0].get($version)) !== void 0 && isVersion(_tmp0)) && ((_tmp0 = v[0].get($version)) !== void 0 && isVersion(_tmp0)) &&
((_tmp1 = v[0].get($pointer)) !== void 0 && isPointerName(_tmp1)) && ((_tmp1 = v[0].get($pointer)) !== void 0 && isPointerName(_tmp1)) &&
( (
(_tmp2 = v[0].get($definitions)) !== void 0 && ( (_tmp2 = v[0].get($definitions)) !== void 0 && (
_.Dictionary.isDictionary<_val, _ptr>(_tmp2) && _.Dictionary.isDictionary<_ptr>(_tmp2) &&
((() => { ((() => {
for (const e of _tmp2) { for (const e of _tmp2) {
if (!(typeof e[0] === 'symbol')) return false; if (!(typeof e[0] === 'symbol')) return false;
if (!(isPattern(e[1]))) return false; if (!(isDefinition(e[1]))) return false;
}; };
return true; return true;
})()) })())
@ -143,16 +141,16 @@ export function decodeSchema(d: _.TypedDecoder<_ptr>): Schema | undefined {
let _tmp4, _tmp5, _tmp6, _tmp7, _tmp8: any; let _tmp4, _tmp5, _tmp6, _tmp7, _tmp8: any;
_tmp5 = d.next(); _tmp5 = d.next();
if (_tmp5 !== void 0 && !(( if (_tmp5 !== void 0 && !((
_.Dictionary.isDictionary<_val, _ptr>(_tmp5) && _.Dictionary.isDictionary<_ptr>(_tmp5) &&
((_tmp6 = _tmp5.get($version)) !== void 0 && isVersion(_tmp6)) && ((_tmp6 = _tmp5.get($version)) !== void 0 && isVersion(_tmp6)) &&
((_tmp7 = _tmp5.get($pointer)) !== void 0 && isPointerName(_tmp7)) && ((_tmp7 = _tmp5.get($pointer)) !== void 0 && isPointerName(_tmp7)) &&
( (
(_tmp8 = _tmp5.get($definitions)) !== void 0 && ( (_tmp8 = _tmp5.get($definitions)) !== void 0 && (
_.Dictionary.isDictionary<_val, _ptr>(_tmp8) && _.Dictionary.isDictionary<_ptr>(_tmp8) &&
((() => { ((() => {
for (const e of _tmp8) { for (const e of _tmp8) {
if (!(typeof e[0] === 'symbol')) return false; if (!(typeof e[0] === 'symbol')) return false;
if (!(isPattern(e[1]))) return false; if (!(isDefinition(e[1]))) return false;
}; };
return true; return true;
})()) })())
@ -167,11 +165,11 @@ export function decodeSchema(d: _.TypedDecoder<_ptr>): Schema | undefined {
{ {
get(k: typeof $version): Version; get(k: typeof $version): Version;
get(k: typeof $pointer): PointerName; 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 $version): true;
has(k: typeof $pointer): true; has(k: typeof $pointer): true;
has(k: typeof $definitions): true; has(k: typeof $definitions): true;
} & _.Dictionary<_val, _ptr> } & _.Dictionary<_ptr>
) )
] ]
>(_tmp3 as any, _tmp4 as any); >(_tmp3 as any, _tmp4 as any);
@ -203,50 +201,136 @@ export function decodePointerName(d: _.TypedDecoder<_ptr>): PointerName | undefi
return result; 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 { export function isPattern(v: any): v is Pattern {
return _.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) && ( return _.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) && (
( (
( (_.is(v.label, $atom) && ((v.length === 1) && isAtomKind(v[0]))) ||
_.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, $pointer) && ((v.length === 0))) || (_.is(v.label, $pointer) && ((v.length === 0))) ||
(_.is(v.label, $lit) && ((v.length === 1) && true)) || (_.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, $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])) _.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) && ( _.is(v.label, $dict) && (
(v.length === 1) && (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;}; for (const e of v[0]) {if (!(true)) return false; if (!(isPattern(e[1]))) return false;};
return true; return true;
@ -300,210 +384,133 @@ export function asPattern(v: any): Pattern {
export function decodePattern(d: _.TypedDecoder<_ptr>): Pattern | undefined { export function decodePattern(d: _.TypedDecoder<_ptr>): Pattern | undefined {
let result; let result;
if (d.openRecord()) { if (d.openRecord()) {
let _tmp10, _tmp11: any; let _tmp22, _tmp23: any;
_tmp10 = d.next(); _tmp22 = d.next();
_tmp11 = d.mark(); _tmp23 = d.mark();
if (_.is(_tmp10, $atom)) { if (_.is(_tmp22, $atom)) {
let _tmp12, _tmp13, _tmp14: any; let _tmp24, _tmp25: any;
_tmp14 = d.mark(); _tmp25 = decodeAtomKind(d);
_tmp13 = _.asLiteral(d.nextSymbol(), $Boolean); if (_tmp25 !== void 0) {if (d.closeCompound()) _tmp24 = [_tmp25];};
if (_tmp13 === void 0) { if (_tmp24 !== void 0) result = _.Record<(typeof $atom), [AtomKind]>(_tmp22 as any, _tmp24 as any);
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);
}; };
if (result === void 0) { if (result === void 0) {
d.restoreMark(_tmp11); d.restoreMark(_tmp23);
if (_.is(_tmp10, $pointer)) { if (_.is(_tmp22, $pointer)) {
let _tmp15: any; let _tmp26: any;
if (d.closeCompound()) _tmp15 = []; if (d.closeCompound()) _tmp26 = [];
if (_tmp15 !== void 0) result = _.Record<(typeof $pointer), []>(_tmp10 as any, _tmp15 as any); if (_tmp26 !== void 0) result = _.Record<(typeof $pointer), []>(_tmp22 as any, _tmp26 as any);
}; };
if (result === void 0) { if (result === void 0) {
d.restoreMark(_tmp11); d.restoreMark(_tmp23);
if (_.is(_tmp10, $lit)) { if (_.is(_tmp22, $lit)) {
let _tmp16, _tmp17: any; let _tmp27, _tmp28: any;
_tmp17 = d.next(); _tmp28 = d.next();
if (_tmp17 !== void 0) {if (d.closeCompound()) _tmp16 = [_tmp17];}; if (_tmp28 !== void 0) {if (d.closeCompound()) _tmp27 = [_tmp28];};
if (_tmp16 !== void 0) result = _.Record<(typeof $lit), [_val]>(_tmp10 as any, _tmp16 as any); if (_tmp27 !== void 0) result = _.Record<(typeof $lit), [_val]>(_tmp22 as any, _tmp27 as any);
}; };
if (result === void 0) { if (result === void 0) {
d.restoreMark(_tmp11); d.restoreMark(_tmp23);
if (_.is(_tmp10, $ref)) { if (_.is(_tmp22, $ref)) {
let _tmp18, _tmp19, _tmp20: any; let _tmp29, _tmp30, _tmp31: any;
_tmp19 = decodeModulePath(d); _tmp30 = decodeModulePath(d);
if (_tmp19 !== void 0) { if (_tmp30 !== void 0) {
_tmp20 = d.nextSymbol(); _tmp31 = d.nextSymbol();
if (_tmp20 !== void 0) {if (d.closeCompound()) _tmp18 = [_tmp19, _tmp20];}; 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) { if (result === void 0) {
d.restoreMark(_tmp11); d.restoreMark(_tmp23);
if (_.is(_tmp10, $or)) { if (_.is(_tmp22, $rec)) {
let _tmp21, _tmp22: any; let _tmp32, _tmp33, _tmp34: any;
if (d.openSequence()) { _tmp33 = decodePattern(d);
let _tmp23: any; if (_tmp33 !== void 0) {
{ _tmp34 = decodePattern(d);
let vN: Array<Pattern> | undefined = []; if (_tmp34 !== void 0) {if (d.closeCompound()) _tmp32 = [_tmp33, _tmp34];};
while (!d.closeCompound()) {
_tmp23 = void 0;
_tmp23 = decodePattern(d);
if (_tmp23 === void 0) {vN = void 0; break;};
vN.push(_tmp23);
};
_tmp22 = vN;
};
}; };
if (_tmp22 !== void 0) {if (d.closeCompound()) _tmp21 = [_tmp22];}; if (_tmp32 !== void 0) result = _.Record<(typeof $rec), [Pattern, Pattern]>(_tmp22 as any, _tmp32 as any);
if (_tmp21 !== void 0) result = _.Record<(typeof $or), [Array<Pattern>]>(_tmp10 as any, _tmp21 as any);
}; };
if (result === void 0) { if (result === void 0) {
d.restoreMark(_tmp11); d.restoreMark(_tmp23);
if (_.is(_tmp10, $and)) { if (_.is(_tmp22, $tuple)) {
let _tmp24, _tmp25: any; let _tmp35, _tmp36: any;
if (d.openSequence()) { if (d.openSequence()) {
let _tmp26: any; let _tmp37: any;
{ {
let vN: Array<Pattern> | undefined = []; let vN: Array<NamedPattern> | undefined = [];
while (!d.closeCompound()) { while (!d.closeCompound()) {
_tmp26 = void 0; _tmp37 = void 0;
_tmp26 = decodePattern(d); _tmp37 = decodeNamedPattern(d);
if (_tmp26 === void 0) {vN = void 0; break;}; if (_tmp37 === void 0) {vN = void 0; break;};
vN.push(_tmp26); vN.push(_tmp37);
}; };
_tmp25 = vN; _tmp36 = vN;
}; };
}; };
if (_tmp25 !== void 0) {if (d.closeCompound()) _tmp24 = [_tmp25];}; if (_tmp36 !== void 0) {if (d.closeCompound()) _tmp35 = [_tmp36];};
if (_tmp24 !== void 0) result = _.Record<(typeof $and), [Array<Pattern>]>(_tmp10 as any, _tmp24 as any); if (_tmp35 !== void 0) result = _.Record<(typeof $tuple), [Array<NamedPattern>]>(_tmp22 as any, _tmp35 as any);
}; };
if (result === void 0) { if (result === void 0) {
d.restoreMark(_tmp11); d.restoreMark(_tmp23);
if (_.is(_tmp10, $rec)) { if (_.is(_tmp22, $tuple_STAR_)) {
let _tmp27, _tmp28, _tmp29: any; let _tmp38, _tmp39, _tmp40: any;
_tmp28 = decodePattern(d); if (d.openSequence()) {
if (_tmp28 !== void 0) { let _tmp41: any;
_tmp29 = decodePattern(d); {
if (_tmp29 !== void 0) {if (d.closeCompound()) _tmp27 = [_tmp28, _tmp29];}; 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) { if (result === void 0) {
d.restoreMark(_tmp11); d.restoreMark(_tmp23);
if (_.is(_tmp10, $tuple)) { if (_.is(_tmp22, $setof)) {
let _tmp30, _tmp31: any; let _tmp42, _tmp43: any;
if (d.openSequence()) { _tmp43 = decodePattern(d);
let _tmp32: any; if (_tmp43 !== void 0) {if (d.closeCompound()) _tmp42 = [_tmp43];};
{ if (_tmp42 !== void 0) result = _.Record<(typeof $setof), [Pattern]>(_tmp22 as any, _tmp42 as 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);
}; };
if (result === void 0) { if (result === void 0) {
d.restoreMark(_tmp11); d.restoreMark(_tmp23);
if (_.is(_tmp10, $tuple_STAR_)) { if (_.is(_tmp22, $dictof)) {
let _tmp33, _tmp34, _tmp35: any; let _tmp44, _tmp45, _tmp46: any;
if (d.openSequence()) { _tmp45 = decodePattern(d);
let _tmp36: any; if (_tmp45 !== void 0) {
{ _tmp46 = decodePattern(d);
let vN: Array<NamedPattern> | undefined = []; if (_tmp46 !== void 0) {if (d.closeCompound()) _tmp44 = [_tmp45, _tmp46];};
while (!d.closeCompound()) {
_tmp36 = void 0;
_tmp36 = decodeNamedPattern(d);
if (_tmp36 === void 0) {vN = void 0; break;};
vN.push(_tmp36);
};
_tmp34 = vN;
};
}; };
if (_tmp34 !== void 0) { if (_tmp44 !== void 0) result = _.Record<(typeof $dictof), [Pattern, Pattern]>(_tmp22 as any, _tmp44 as any);
_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 (result === void 0) { if (result === void 0) {
d.restoreMark(_tmp11); d.restoreMark(_tmp23);
if (_.is(_tmp10, $setof)) { if (_.is(_tmp22, $dict)) {
let _tmp37, _tmp38: any; let _tmp47, _tmp48: any;
_tmp38 = decodePattern(d); if (d.openDictionary()) {
if (_tmp38 !== void 0) {if (d.closeCompound()) _tmp37 = [_tmp38];}; let r: _.KeyedDictionary<_val, Pattern, _ptr> | undefined = new _.KeyedDictionary();
if (_tmp37 !== void 0) result = _.Record<(typeof $setof), [Pattern]>(_tmp10 as any, _tmp37 as any); while (!d.closeCompound()) {
}; let K: undefined | _val = void 0;
if (result === void 0) { K = d.next();
d.restoreMark(_tmp11); if (K === void 0) { r = void 0; break; };
if (_.is(_tmp10, $dictof)) { let V: undefined | Pattern = void 0;
let _tmp39, _tmp40, _tmp41: any; V = decodePattern(d);
_tmp40 = decodePattern(d); if (V === void 0) { r = void 0; break; };
if (_tmp40 !== void 0) { r.set(K, V);
_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);
}; };
_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; 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 { export function isNamedPattern(v: any): v is NamedPattern {
return ( return (
( (
@ -534,23 +586,23 @@ export function asNamedPattern(v: any): NamedPattern {
} }
export function decodeNamedPattern(d: _.TypedDecoder<_ptr>): NamedPattern | undefined { export function decodeNamedPattern(d: _.TypedDecoder<_ptr>): NamedPattern | undefined {
let _tmp44: any; let _tmp50: any;
let result; let result;
_tmp44 = d.mark(); _tmp50 = d.mark();
if (d.openRecord()) { if (d.openRecord()) {
let _tmp45: any; let _tmp51: any;
_tmp45 = _.asLiteral(d.nextSymbol(), $named); _tmp51 = _.asLiteral(d.nextSymbol(), $named);
if (_tmp45 !== void 0) { if (_tmp51 !== void 0) {
let _tmp46, _tmp47, _tmp48: any; let _tmp52, _tmp53, _tmp54: any;
_tmp47 = d.nextSymbol(); _tmp53 = d.nextSymbol();
if (_tmp47 !== void 0) { if (_tmp53 !== void 0) {
_tmp48 = decodePattern(d); _tmp54 = decodePattern(d);
if (_tmp48 !== void 0) {if (d.closeCompound()) _tmp46 = [_tmp47, _tmp48];}; 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; return result;
} }
@ -569,16 +621,16 @@ export function asRef(v: any): Ref {
export function decodeRef(d: _.TypedDecoder<_ptr>): Ref | undefined { export function decodeRef(d: _.TypedDecoder<_ptr>): Ref | undefined {
let result; let result;
if (d.openRecord()) { if (d.openRecord()) {
let _tmp49: any; let _tmp55: any;
_tmp49 = _.asLiteral(d.nextSymbol(), $ref); _tmp55 = _.asLiteral(d.nextSymbol(), $ref);
if (_tmp49 !== void 0) { if (_tmp55 !== void 0) {
let _tmp50, _tmp51, _tmp52: any; let _tmp56, _tmp57, _tmp58: any;
_tmp51 = decodeModulePath(d); _tmp57 = decodeModulePath(d);
if (_tmp51 !== void 0) { if (_tmp57 !== void 0) {
_tmp52 = d.nextSymbol(); _tmp58 = d.nextSymbol();
if (_tmp52 !== void 0) {if (d.closeCompound()) _tmp50 = [_tmp51, _tmp52];}; 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; return result;
@ -600,14 +652,14 @@ export function asModulePath(v: any): ModulePath {
export function decodeModulePath(d: _.TypedDecoder<_ptr>): ModulePath | undefined { export function decodeModulePath(d: _.TypedDecoder<_ptr>): ModulePath | undefined {
let result; let result;
if (d.openSequence()) { if (d.openSequence()) {
let _tmp53: any; let _tmp59: any;
{ {
let vN: Array<symbol> | undefined = []; let vN: Array<symbol> | undefined = [];
while (!d.closeCompound()) { while (!d.closeCompound()) {
_tmp53 = void 0; _tmp59 = void 0;
_tmp53 = d.nextSymbol(); _tmp59 = d.nextSymbol();
if (_tmp53 === void 0) {vN = void 0; break;}; if (_tmp59 === void 0) {vN = void 0; break;};
vN.push(_tmp53); vN.push(_tmp59);
}; };
result = vN; result = vN;
}; };

View File

@ -1,5 +1,5 @@
import { Value, is, Position } from '@preserves/core'; 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 { BASE } from './base';
import { SchemaSyntaxError } from './error'; import { SchemaSyntaxError } from './error';
@ -41,9 +41,9 @@ function modsymFor(e: SchemaEnvEntry): string {
export function lookup<R>(namePos: Position | null, export function lookup<R>(namePos: Position | null,
name: Ref, name: Ref,
env: Environment, env: Environment,
kLocal: (p: Pattern) => R, kLocal: (p: Definition) => R,
kBase: (p: Pattern) => R, kBase: (p: Definition) => R,
kOther: (mod: string, modPath: string, p: Pattern | null) => R): R kOther: (mod: string, modPath: string, p: Definition | null) => R): R
{ {
for (const e of env) { for (const e of env) {
if (is(e.schemaModulePath, Ref._.module(name)) || 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 { Reader, Annotated, Dictionary, is, peel, preserves, Record, strip, Tuple, Position, position, ReaderOptions, stringify } from '@preserves/core';
import { Input, NamedPattern, Pattern, Schema } from './meta'; import { Input, NamedPattern, Pattern, Schema, Alternative, Definition } from './meta';
import * as M from './meta'; import * as M from './meta';
import { SchemaSyntaxError } from './error'; import { SchemaSyntaxError } from './error';
@ -66,7 +66,7 @@ export function parseSchema(toplevelTokens: Array<Input>,
{ {
let version: M.Version | undefined = void 0; let version: M.Version | undefined = void 0;
let pointer: M.PointerName = false; let pointer: M.PointerName = false;
let definitions = new Dictionary<Pattern, never>(); let definitions = new Dictionary<never, Definition>();
function process(toplevelTokens: Array<Input>): void { function process(toplevelTokens: Array<Input>): void {
const toplevelClauses = splitBy(peel(toplevelTokens) as Array<Input>, M.DOT); const toplevelClauses = splitBy(peel(toplevelTokens) as Array<Input>, M.DOT);
@ -115,25 +115,53 @@ export function parseSchema(toplevelTokens: Array<Input>,
throw new SchemaSyntaxError("Schema: missing version declaration.", null); 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.$version, version],
[M.$pointer, pointer], [M.$pointer, pointer],
[M.$definitions, definitions], [M.$definitions, definitions],
])])); ])]));
} }
function parseDefinition(name: symbol, body: Array<Input>): Pattern { function parseDefinition(name: symbol, body: Array<Input>): Definition {
return parseOp(body, M.ORSYM, p => parseOp(p, M.ANDSYM, p => parseBase(name, p))); 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 { function parseOp<Each, Combined>(body: Array<Input>,
const pieces = splitBy(body, op); op: Input,
if (pieces.length === 1) return k(pieces[0]); each: (p: Array<Input>) => Each,
switch (op) { combineN: (ps: Array<Each>) => Combined,
case M.ORSYM: return Record(M.$or, [pieces.map(k)]); finish1: (p: Each) => Combined): Combined
case M.ANDSYM: return Record(M.$and, [pieces.map(k)]); {
default: throw new Error("Internal error: unexpected operator"); const pieces = splitBy(body, op).map(each);
} return (pieces.length === 1) ? finish1(pieces[0]) : combineN(pieces);
} }
function findName(x: Input): symbol | false { function findName(x: Input): symbol | false {
@ -145,6 +173,14 @@ function findName(x: Input): symbol | false {
return 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 { function parseRef(name: string, pos: Position | null, item: symbol): Pattern {
const s = item.description; const s = item.description;
if (s === void 0) invalidPattern(name, item, pos); 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 item = peel(body[0]);
const walk = (b: Input): Pattern => parseBase(name, [b]); 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 { function complain(): never {
invalidPattern(stringify(name), item, pos); invalidPattern(stringify(name), item, pos);
@ -191,12 +217,6 @@ function parseBase(name: symbol, body: Array<Input>): Pattern {
case M.$lit: case M.$lit:
if (item.length !== 1) complain(); if (item.length !== 1) complain();
return Record(M.$lit, [item[0]]); 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: case M.$rec:
if (item.length !== 2) complain(); if (item.length !== 2) complain();
return Record(M.$rec, [walk(item[0]), walk(item[1])]); return Record(M.$rec, [walk(item[0]), walk(item[1])]);
@ -204,19 +224,19 @@ function parseBase(name: symbol, body: Array<Input>): Pattern {
complain(); complain();
} }
} else { } 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)) { } else if (Array.isArray(item)) {
if (is(item[item.length - 1], M.DOTDOTDOT)) { if (is(item[item.length - 1], M.DOTDOTDOT)) {
if (item.length < 2) complain(); if (item.length < 2) complain();
return Record(M.$tuple_STAR_, [ return Record(M.$tuple_STAR_, [
item.slice(0, item.length - 2).map(namedwalk), item.slice(0, item.length - 2).map(namedwrap(walk)),
namedwalk(item[item.length - 2]), namedwrap(walk)(item[item.length - 2]),
]); ]);
} else { } 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)) { if (item.size === 2 && item.has(M.DOTDOTDOT)) {
const v = item.clone(); const v = item.clone();
v.delete(M.DOTDOTDOT); v.delete(M.DOTDOTDOT);

View File

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