Cut over to new representation
This commit is contained in:
parent
0304c2631b
commit
4814790d8e
|
@ -11,17 +11,17 @@ import { genConstructor } from "./compiler/genctor";
|
||||||
export function compile(env: M.Environment, schema: M.Schema, options: CompilerOptions = {}): string {
|
export function compile(env: M.Environment, schema: M.Schema, options: CompilerOptions = {}): string {
|
||||||
const mod = new ModuleContext(env, schema, options);
|
const mod = new ModuleContext(env, schema, options);
|
||||||
|
|
||||||
const pointerName = M.Schema._._field0(schema).get(M.$pointer);
|
const pointerName = schema.pointer;
|
||||||
mod.defineType(seq(`export type _ptr = `,
|
mod.defineType(seq(`export type _ptr = `,
|
||||||
renderType(pointerName === false
|
renderType(pointerName._variant === 'false'
|
||||||
? EMPTY_TYPE
|
? EMPTY_TYPE
|
||||||
: typeForDefinition(mod, pointerName)),
|
: typeForDefinition(mod, M.Definition.Alternative(M.Alternative.Pattern(M.Pattern.SimplePattern(M.SimplePattern.Ref(pointerName.value)))))),
|
||||||
`;`));
|
`;`));
|
||||||
mod.defineType(`export type _val = _.Value<_ptr>;`);
|
mod.defineType(`export type _val = _.Value<_ptr>;`);
|
||||||
|
|
||||||
mod.defineFunction(ctx =>
|
mod.defineFunction(ctx =>
|
||||||
seq(`export const _decodePtr = `,
|
seq(`export const _decodePtr = `,
|
||||||
(pointerName === false
|
(pointerName._variant === 'false'
|
||||||
? '() => { throw new _.DecodeError("Pointers forbidden"); }'
|
? '() => { throw new _.DecodeError("Pointers forbidden"); }'
|
||||||
: seq(`(d: _.TypedDecoder<_ptr>) => `, ctx.block(() => [
|
: seq(`(d: _.TypedDecoder<_ptr>) => `, ctx.block(() => [
|
||||||
seq(`let result`),
|
seq(`let result`),
|
||||||
|
@ -30,7 +30,7 @@ export function compile(env: M.Environment, schema: M.Schema, options: CompilerO
|
||||||
seq(`return result`)]))),
|
seq(`return result`)]))),
|
||||||
`;`));
|
`;`));
|
||||||
|
|
||||||
for (const [name, def] of M.Schema._._field0(schema).get(M.$definitions)) {
|
for (const [name, def] of schema.definitions) {
|
||||||
const t = typeForDefinition(mod, def);
|
const t = typeForDefinition(mod, def);
|
||||||
const nameStr = stringify(name);
|
const nameStr = stringify(name);
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ export function compile(env: M.Environment, schema: M.Schema, options: CompilerO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [name0, def] of M.Schema._._field0(schema).get(M.$definitions)) {
|
for (const [name0, def] of schema.definitions) {
|
||||||
const name = name0 as symbol;
|
const name = name0 as symbol;
|
||||||
|
|
||||||
mod.defineFunction(ctx =>
|
mod.defineFunction(ctx =>
|
||||||
|
|
|
@ -41,12 +41,16 @@ export class ModuleContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
derefPattern([_name, p]: [string, M.Alternative]): M.Definition {
|
derefPattern([_name, p]: [string, M.Alternative]): M.Definition {
|
||||||
if (p.label === M.$ref) {
|
if (p._variant === 'Pattern' &&
|
||||||
return M.lookup(refPosition(p), p, this.env,
|
p.value._variant === 'SimplePattern' &&
|
||||||
|
p.value.value._variant === 'Ref')
|
||||||
|
{
|
||||||
|
return M.lookup(refPosition(p.value.value.value), p.value.value.value, this.env,
|
||||||
(p) => p,
|
(p) => p,
|
||||||
(_modId, _modPath, pp) => pp ?? p);
|
(_modId, _modPath, pp) => pp ?? M.Definition.Alternative(
|
||||||
|
M.Alternative.Pattern(p.value)));
|
||||||
} else {
|
} else {
|
||||||
return p;
|
return M.Definition.Alternative(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,11 @@ export function converterForDefinition(
|
||||||
src: string,
|
src: string,
|
||||||
dest: string): Item[]
|
dest: string): Item[]
|
||||||
{
|
{
|
||||||
if (p.label === M.$or) {
|
if (p._variant === 'or') {
|
||||||
const alts = p[0];
|
const alts = p.patterns;
|
||||||
function loop(i: number): Item[] {
|
function loop(i: number): Item[] {
|
||||||
ctx.variantName = alts[i][0];
|
ctx.variantName = alts[i].variantLabel;
|
||||||
return [... converterForAlternative(ctx, alts[i][1], src, dest),
|
return [... converterForAlternative(ctx, alts[i].alternative, src, dest),
|
||||||
... ((i < alts.length - 1)
|
... ((i < alts.length - 1)
|
||||||
? [seq(`if (${dest} === void 0) `, ctx.block(() => loop(i + 1)))]
|
? [seq(`if (${dest} === void 0) `, ctx.block(() => loop(i + 1)))]
|
||||||
: [])];
|
: [])];
|
||||||
|
@ -23,7 +23,7 @@ export function converterForDefinition(
|
||||||
return alts.length === 0 ? [] : loop(0);
|
return alts.length === 0 ? [] : loop(0);
|
||||||
} else {
|
} else {
|
||||||
ctx.variantName = void 0;
|
ctx.variantName = void 0;
|
||||||
return converterForAlternative(ctx, p, src, dest);
|
return converterForAlternative(ctx, p.value, src, dest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,8 +33,8 @@ function converterForAlternative(
|
||||||
src: string,
|
src: string,
|
||||||
dest: string): Item[]
|
dest: string): Item[]
|
||||||
{
|
{
|
||||||
if (p.label === M.$and) {
|
if (p._variant === 'and') {
|
||||||
const alts = p[0];
|
const alts = 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))
|
||||||
|
@ -42,11 +42,11 @@ function converterForAlternative(
|
||||||
}
|
}
|
||||||
return alts.length === 0 ? [seq(`${dest} = ${src}`)] : loop(0);
|
return alts.length === 0 ? [seq(`${dest} = ${src}`)] : loop(0);
|
||||||
} else {
|
} else {
|
||||||
return converterFor(ctx, p, src, simpleValue => {
|
return converterFor(ctx, M.NamedPattern.anonymous(p.value), src, simpleValue => {
|
||||||
if (simpleValue === void 0) {
|
if (simpleValue === void 0) {
|
||||||
return [ctx.buildCapturedCompound(dest)];
|
return [ctx.buildCapturedCompound(dest)];
|
||||||
} else if (ctx.variantName !== void 0) {
|
} else if (ctx.variantName !== void 0) {
|
||||||
if (typeFor(ctx.mod, p).kind === 'unit') {
|
if (typeFor(ctx.mod, p.value).kind === 'unit') {
|
||||||
return [ctx.buildCapturedCompound(dest)];
|
return [ctx.buildCapturedCompound(dest)];
|
||||||
} else {
|
} else {
|
||||||
return [ctx.withCapture('value',
|
return [ctx.withCapture('value',
|
||||||
|
@ -97,12 +97,13 @@ function converterForArray(ctx: FunctionContext,
|
||||||
k: (dest: string) => Item[]): Item
|
k: (dest: string) => Item[]): Item
|
||||||
{
|
{
|
||||||
const postCheck = () => {
|
const postCheck = () => {
|
||||||
const r = ctx.gentemp(Type.array(simpleType(ctx.mod, M.unname(arrayType))));
|
const r = ctx.gentemp(Type.array(simpleType(ctx.mod, M.unnameSimplePattern(arrayType))));
|
||||||
const v = ctx.gentempname();
|
const v = ctx.gentempname();
|
||||||
return [
|
return [
|
||||||
seq(`${r} = []`),
|
seq(`${r} = []`),
|
||||||
seq(`for (const ${v} of ${src}) `, ctx.block(() => [
|
seq(`for (const ${v} of ${src}) `, ctx.block(() => [
|
||||||
... converterFor(ctx, arrayType, v, vv => [`${r}.push(${vv})`, `continue`]),
|
... converterFor(ctx, M.promoteNamedSimplePattern(arrayType), v, vv =>
|
||||||
|
[`${r}.push(${vv})`, `continue`]),
|
||||||
seq(`${r} = void 0`),
|
seq(`${r} = void 0`),
|
||||||
seq(`break`)])),
|
seq(`break`)])),
|
||||||
ctx.convertCapture(M.nameFor(arrayType), r, k)];
|
ctx.convertCapture(M.nameFor(arrayType), r, k)];
|
||||||
|
@ -119,32 +120,32 @@ function converterFor(
|
||||||
ks: (dest: string | undefined) => Item[],
|
ks: (dest: string | undefined) => Item[],
|
||||||
recordFields = false): Item[]
|
recordFields = false): Item[]
|
||||||
{
|
{
|
||||||
let p = M.unname(np);
|
let p = M.unnamePattern(np);
|
||||||
let maybeName = M.nameFor(np);
|
let maybeName = M.nameFor(np);
|
||||||
|
|
||||||
if (M.isSimplePattern(p)) {
|
if (p._variant === 'SimplePattern') {
|
||||||
const dest = ctx.gentemp(simpleType(ctx.mod, p));
|
const dest = ctx.gentemp(simpleType(ctx.mod, p.value));
|
||||||
return [... converterForSimple(ctx, p, src, dest),
|
return [... converterForSimple(ctx, p.value, src, dest),
|
||||||
ctx.convertCapture(maybeName, dest, ks)];
|
ctx.convertCapture(maybeName, dest, ks)];
|
||||||
} else {
|
} else {
|
||||||
switch (p.label) {
|
switch (p.value._variant) {
|
||||||
case M.$setof: {
|
case 'setof': {
|
||||||
const setPattern = p[0];
|
const setPattern = p.value.pattern;
|
||||||
const r = ctx.gentemp(setType(ctx.mod, setPattern));
|
const r = ctx.gentemp(setType(ctx.mod, setPattern));
|
||||||
const v = ctx.gentempname();
|
const v = ctx.gentempname();
|
||||||
return [
|
return [
|
||||||
seq(`if (_.Set.isSet<_ptr>(${src})) `, ctx.block(() => [
|
seq(`if (_.Set.isSet<_ptr>(${src})) `, ctx.block(() => [
|
||||||
seq(`${r} = new _.KeyedSet()`),
|
seq(`${r} = new _.KeyedSet()`),
|
||||||
seq(`for (const ${v} of ${src}) `, ctx.block(() => [
|
seq(`for (const ${v} of ${src}) `, ctx.block(() => [
|
||||||
... converterFor(ctx, setPattern, v, vv =>
|
... converterFor(ctx, M.anonymousSimplePattern(setPattern), v, vv =>
|
||||||
[`${r}.add(${vv})`, `continue`]),
|
[`${r}.add(${vv})`, `continue`]),
|
||||||
seq(`${r} = void 0`),
|
seq(`${r} = void 0`),
|
||||||
seq(`break`)])),
|
seq(`break`)])),
|
||||||
ctx.convertCapture(maybeName, r, ks)]))];
|
ctx.convertCapture(maybeName, r, ks)]))];
|
||||||
}
|
}
|
||||||
case M.$dictof: {
|
case 'dictof': {
|
||||||
const keyPattern = p[0];
|
const keyPattern = p.value.key;
|
||||||
const valPattern = p[1];
|
const valPattern = p.value.value;
|
||||||
const r = ctx.gentemp(dictionaryType(ctx.mod, keyPattern, valPattern));
|
const r = ctx.gentemp(dictionaryType(ctx.mod, keyPattern, valPattern));
|
||||||
const v = ctx.gentempname();
|
const v = ctx.gentempname();
|
||||||
const k = ctx.gentempname();
|
const k = ctx.gentempname();
|
||||||
|
@ -152,19 +153,20 @@ function converterFor(
|
||||||
seq(`if (_.Dictionary.isDictionary<_ptr>(${src})) `, ctx.block(() => [
|
seq(`if (_.Dictionary.isDictionary<_ptr>(${src})) `, ctx.block(() => [
|
||||||
seq(`${r} = new _.KeyedDictionary()`),
|
seq(`${r} = new _.KeyedDictionary()`),
|
||||||
seq(`for (const [${k}, ${v}] of ${src}) `, ctx.block(() => [
|
seq(`for (const [${k}, ${v}] of ${src}) `, ctx.block(() => [
|
||||||
... converterFor(ctx, keyPattern, k, kk =>
|
... converterFor(ctx, M.anonymousSimplePattern(keyPattern), k, kk =>
|
||||||
converterFor(ctx, valPattern, v, vv =>
|
converterFor(ctx, M.anonymousSimplePattern(valPattern), v, vv =>
|
||||||
[`${r}.set(${kk}, ${vv})`, `continue`])),
|
[`${r}.set(${kk}, ${vv})`, `continue`])),
|
||||||
seq(`${r} = void 0`),
|
seq(`${r} = void 0`),
|
||||||
seq(`break`)])),
|
seq(`break`)])),
|
||||||
ctx.convertCapture(maybeName, r, ks)]))];
|
ctx.convertCapture(maybeName, r, ks)]))];
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
const arrayType = M.simpleArray(p);
|
const arrayType = M.simpleArray(p.value);
|
||||||
if (arrayType === void 0) {
|
if (arrayType === void 0) {
|
||||||
return converterForCompound(ctx, p, src, recordFields, () => ks(void 0));
|
return converterForCompound(ctx, p.value, src, recordFields, () => ks(void 0));
|
||||||
} else {
|
} else {
|
||||||
return [converterForArray(ctx, arrayType, src, !recordFields, ks)];
|
return [converterForArray(
|
||||||
|
ctx, M.NamedSimplePattern.anonymous(arrayType), src, !recordFields, ks)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,32 +179,32 @@ function converterForSimple(
|
||||||
src: string,
|
src: string,
|
||||||
dest: string): Item[]
|
dest: string): Item[]
|
||||||
{
|
{
|
||||||
switch (p.label) {
|
switch (p._variant) {
|
||||||
case M.$any:
|
case 'any':
|
||||||
return [`${dest} = ${src}`];
|
return [`${dest} = ${src}`];
|
||||||
case M.$atom: {
|
case 'atom': {
|
||||||
let test: Item;
|
let test: Item;
|
||||||
switch (p[0]) {
|
switch (p.atomKind._variant) {
|
||||||
case M.$Boolean: test = `typeof ${src} === 'boolean'`; break;
|
case 'Boolean': test = `typeof ${src} === 'boolean'`; break;
|
||||||
case M.$Float: test = `_.Float.isSingle(${src})`; break;
|
case 'Float': test = `_.Float.isSingle(${src})`; break;
|
||||||
case M.$Double: test =`_.Float.isDouble(${src})`; break;
|
case 'Double': test =`_.Float.isDouble(${src})`; break;
|
||||||
case M.$SignedInteger: test = `typeof ${src} === 'number'`; break;
|
case 'SignedInteger': test = `typeof ${src} === 'number'`; break;
|
||||||
case M.$String: test = `typeof ${src} === 'string'`; break;
|
case 'String': test = `typeof ${src} === 'string'`; break;
|
||||||
case M.$ByteString: test = `_.Bytes.isBytes(${src})`; break;
|
case 'ByteString': test = `_.Bytes.isBytes(${src})`; break;
|
||||||
case M.$Symbol: test = `typeof ${src} === 'symbol'`; break;
|
case 'Symbol': test = `typeof ${src} === 'symbol'`; break;
|
||||||
}
|
}
|
||||||
return [seq(`${dest} = `, test, ` ? ${src} : void 0`)];
|
return [seq(`${dest} = `, test, ` ? ${src} : void 0`)];
|
||||||
}
|
}
|
||||||
case M.$lit:
|
case 'lit':
|
||||||
return [`${dest} = _.is(${src}, ${ctx.mod.literal(p[0])}) ? null : void 0`];
|
return [`${dest} = _.is(${src}, ${ctx.mod.literal(p.value)}) ? null : void 0`];
|
||||||
case M.$ref:
|
case 'Ref':
|
||||||
return M.lookup(refPosition(p), p, ctx.mod.env,
|
return M.lookup(refPosition(p.value), p.value, ctx.mod.env,
|
||||||
(_p) => [`${dest} = to${p[1].description!}(${src})`],
|
(_p) => [`${dest} = to${p.value.name.description!}(${src})`],
|
||||||
(modId, modPath,_p) => {
|
(modId, modPath,_p) => {
|
||||||
ctx.mod.imports.add([modId, modPath]);
|
ctx.mod.imports.add([modId, modPath]);
|
||||||
return [`${dest} = ${modId}.decode${p[1].description!}(${src})`];
|
return [`${dest} = ${modId}.decode${p.value.name.description!}(${src})`];
|
||||||
});
|
});
|
||||||
case M.$pointer:
|
case 'pointer':
|
||||||
return [`${dest} = _toPtr(${src})`];
|
return [`${dest} = _toPtr(${src})`];
|
||||||
default:
|
default:
|
||||||
((_p: never) => {})(p);
|
((_p: never) => {})(p);
|
||||||
|
@ -217,28 +219,31 @@ function converterForCompound(
|
||||||
recordFields: boolean,
|
recordFields: boolean,
|
||||||
ks: () => Item[]): Item[]
|
ks: () => Item[]): Item[]
|
||||||
{
|
{
|
||||||
switch (p.label) {
|
switch (p._variant) {
|
||||||
case M.$rec:
|
case 'rec':
|
||||||
return [seq(`if (_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(${src})) `, ctx.block(() =>
|
return [seq(`if (_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(${src})) `, ctx.block(() =>
|
||||||
converterFor(ctx, p[0], `${src}.label`, () =>
|
converterFor(ctx, p.label, `${src}.label`, () =>
|
||||||
converterFor(ctx, p[1], src, ks, true))))];
|
converterFor(ctx, p.fields, src, ks, true))))];
|
||||||
case M.$tuple:
|
case 'tuple':
|
||||||
return converterForTuple(ctx, p[0], src, recordFields, void 0, ks);
|
return converterForTuple(ctx, p.patterns, src, recordFields, void 0, ks);
|
||||||
case M.$tuple_STAR_:
|
case 'tuple*':
|
||||||
return converterForTuple(ctx, p[0], src, recordFields, p[1], ks);
|
return converterForTuple(ctx, p.fixed, src, recordFields, p.variable, ks);
|
||||||
case M.$setof:
|
case 'setof':
|
||||||
case M.$dictof:
|
case 'dictof':
|
||||||
throw new Error('Internal error: setof and dictof are handled in converterFor()');
|
throw new Error('Internal error: setof and dictof are handled in converterFor()');
|
||||||
case M.$dict: {
|
case 'dict': {
|
||||||
const entries = Array.from(p[0]);
|
const entries = Array.from(p.entries);
|
||||||
function loop(i: number): Item[] {
|
function loop(i: number): Item[] {
|
||||||
if (i < entries.length) {
|
if (i < entries.length) {
|
||||||
const [k, n] = entries[i];
|
const [k, n] = entries[i];
|
||||||
const tmpSrc = ctx.gentemp();
|
const tmpSrc = ctx.gentemp();
|
||||||
return [seq(`if ((${tmpSrc} = ${src}.get(${ctx.mod.literal(k)})) !== void 0) `,
|
return [seq(`if ((${tmpSrc} = ${src}.get(${ctx.mod.literal(k)})) !== void 0) `,
|
||||||
ctx.block(() =>
|
ctx.block(() =>
|
||||||
converterFor(ctx, M.addNameIfAbsent(n, k), tmpSrc, () =>
|
converterFor(
|
||||||
loop(i + 1))))];
|
ctx,
|
||||||
|
M.promoteNamedSimplePattern(M.addNameIfAbsent(n, k)),
|
||||||
|
tmpSrc,
|
||||||
|
() => loop(i + 1))))];
|
||||||
} else {
|
} else {
|
||||||
return ks();
|
return ks();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,21 +4,21 @@ import { ModuleContext } from "./context";
|
||||||
import { ANY_TYPE, AtomicType, CollectionType, FieldMap, SimpleType, Type } from "./type";
|
import { ANY_TYPE, AtomicType, CollectionType, FieldMap, SimpleType, Type } from "./type";
|
||||||
|
|
||||||
export function typeForDefinition(mod: ModuleContext, d: M.Definition): Type {
|
export function typeForDefinition(mod: ModuleContext, d: M.Definition): Type {
|
||||||
if (d.label === M.$or) {
|
if (d._variant === 'or') {
|
||||||
return Type.union(
|
return Type.union(
|
||||||
new Map(d[0].map(a => [a[0], typeForAlternative(mod, a[1])])));
|
new Map(d.patterns.map(a => [a.variantLabel, typeForAlternative(mod, a.alternative)])));
|
||||||
} else {
|
} else {
|
||||||
return typeForAlternative(mod, d);
|
return typeForAlternative(mod, d.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function typeForAlternative(mod: ModuleContext, a: M.Alternative): SimpleType {
|
function typeForAlternative(mod: ModuleContext, a: M.Alternative): SimpleType {
|
||||||
if (a.label === M.$and) {
|
if (a._variant === 'and') {
|
||||||
const fs = new Map();
|
const fs = new Map();
|
||||||
a[0].forEach(n => gatherFields(fs, mod, n));
|
a.patterns.forEach(n => gatherFields(fs, mod, n));
|
||||||
return Type.record(fs);
|
return Type.record(fs);
|
||||||
} else {
|
} else {
|
||||||
return typeFor(mod, a);
|
return typeFor(mod, a.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,19 +34,19 @@ export function dictionaryType(mod: ModuleContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function typeFor(mod: ModuleContext, p: M.Pattern): SimpleType {
|
export function typeFor(mod: ModuleContext, p: M.Pattern): SimpleType {
|
||||||
if (M.isSimplePattern(p)) {
|
if (p._variant === 'SimplePattern') {
|
||||||
return simpleType(mod, p);
|
return simpleType(mod, p.value);
|
||||||
} else {
|
} else {
|
||||||
switch (p.label) {
|
switch (p.value._variant) {
|
||||||
case M.$setof:
|
case 'setof':
|
||||||
return setType(mod, p[0]);
|
return setType(mod, p.value.pattern);
|
||||||
case M.$dictof:
|
case 'dictof':
|
||||||
return dictionaryType(mod, p[0], p[1]);
|
return dictionaryType(mod, p.value.key, p.value.value);
|
||||||
default: {
|
default: {
|
||||||
const arrayType = M.simpleArray(p);
|
const arrayType = M.simpleArray(p.value);
|
||||||
if (arrayType === void 0) {
|
if (arrayType === void 0) {
|
||||||
const fs = new Map();
|
const fs = new Map();
|
||||||
compoundFields(fs, mod, p);
|
compoundFields(fs, mod, p.value);
|
||||||
return Type.record(fs);
|
return Type.record(fs);
|
||||||
} else {
|
} else {
|
||||||
return Type.array(simpleType(mod, arrayType));
|
return Type.array(simpleType(mod, arrayType));
|
||||||
|
@ -57,29 +57,29 @@ export function typeFor(mod: ModuleContext, p: M.Pattern): SimpleType {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function simpleType(mod: ModuleContext, p: M.SimplePattern): AtomicType {
|
export function simpleType(mod: ModuleContext, p: M.SimplePattern): AtomicType {
|
||||||
switch (p.label) {
|
switch (p._variant) {
|
||||||
case M.$any:
|
case 'any':
|
||||||
return ANY_TYPE;
|
return ANY_TYPE;
|
||||||
case M.$atom:
|
case 'atom':
|
||||||
switch (p[0]) {
|
switch (p.atomKind._variant) {
|
||||||
case M.$Boolean: return Type.ref(`boolean`);
|
case 'Boolean': return Type.ref(`boolean`);
|
||||||
case M.$Float: return Type.ref(`_.SingleFloat`);
|
case 'Float': return Type.ref(`_.SingleFloat`);
|
||||||
case M.$Double: return Type.ref(`_.DoubleFloat`);
|
case 'Double': return Type.ref(`_.DoubleFloat`);
|
||||||
case M.$SignedInteger: return Type.ref(`number`);
|
case 'SignedInteger': return Type.ref(`number`);
|
||||||
case M.$String: return Type.ref(`string`);
|
case 'String': return Type.ref(`string`);
|
||||||
case M.$ByteString: return Type.ref(`_.Bytes`);
|
case 'ByteString': return Type.ref(`_.Bytes`);
|
||||||
case M.$Symbol: return Type.ref(`symbol`);
|
case 'Symbol': return Type.ref(`symbol`);
|
||||||
}
|
}
|
||||||
case M.$pointer:
|
case 'pointer':
|
||||||
return Type.ref(`_ptr`);
|
return Type.ref(`_ptr`);
|
||||||
case M.$lit:
|
case 'lit':
|
||||||
return Type.unit();
|
return Type.unit();
|
||||||
case M.$ref:
|
case 'Ref':
|
||||||
return M.lookup(refPosition(p), p, mod.env,
|
return M.lookup(refPosition(p.value), p.value, mod.env,
|
||||||
(_p) => Type.ref(p[1].description!),
|
(_p) => Type.ref(p.value.name.description!),
|
||||||
(modId, modPath,_p) => {
|
(modId, modPath,_p) => {
|
||||||
mod.imports.add([modId, modPath]);
|
mod.imports.add([modId, modPath]);
|
||||||
return Type.ref(`${modId}.${p[1].description!}`);
|
return Type.ref(`${modId}.${p.value.name.description!}`);
|
||||||
});
|
});
|
||||||
default:
|
default:
|
||||||
((_p: never) => {})(p);
|
((_p: never) => {})(p);
|
||||||
|
@ -88,27 +88,28 @@ export function simpleType(mod: ModuleContext, p: M.SimplePattern): AtomicType {
|
||||||
}
|
}
|
||||||
|
|
||||||
function compoundFields(fs: FieldMap, mod: ModuleContext, p: M.CompoundPattern): void {
|
function compoundFields(fs: FieldMap, mod: ModuleContext, p: M.CompoundPattern): void {
|
||||||
switch (p.label) {
|
switch (p._variant) {
|
||||||
case M.$rec:
|
case 'rec':
|
||||||
gatherFields(fs, mod, p[0]);
|
gatherFields(fs, mod, p.label);
|
||||||
gatherFields(fs, mod, p[1]);
|
gatherFields(fs, mod, p.fields);
|
||||||
break;
|
break;
|
||||||
case M.$tuple:
|
case 'tuple':
|
||||||
p[0].forEach(pp => gatherFields(fs, mod, pp));
|
p.patterns.forEach(pp => gatherFields(fs, mod, pp));
|
||||||
break;
|
break;
|
||||||
case M.$tuple_STAR_: {
|
case 'tuple*': {
|
||||||
p[0].forEach(pp => gatherFields(fs, mod, pp));
|
p.fixed.forEach(pp => gatherFields(fs, mod, pp));
|
||||||
const n = p[1];
|
const n = p.variable;
|
||||||
if (n.label === M.$named) {
|
if (n._variant === 'named') {
|
||||||
fs.set(n[0].description!, Type.array(simpleType(mod, n[1])));
|
fs.set(n.value.name.description!, Type.array(simpleType(mod, n.value.pattern)));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case M.$setof:
|
case 'setof':
|
||||||
case M.$dictof:
|
case 'dictof':
|
||||||
break;
|
break;
|
||||||
case M.$dict:
|
case 'dict':
|
||||||
p[0].forEach((n, k) => gatherFields(fs, mod, M.addNameIfAbsent(n, k)));
|
p.entries.forEach((n, k) =>
|
||||||
|
gatherFields(fs, mod, M.promoteNamedSimplePattern(M.addNameIfAbsent(n, k))));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
((_p: never) => {})(p);
|
((_p: never) => {})(p);
|
||||||
|
@ -117,9 +118,9 @@ function compoundFields(fs: FieldMap, mod: ModuleContext, p: M.CompoundPattern):
|
||||||
}
|
}
|
||||||
|
|
||||||
function gatherFields(fs: FieldMap, mod: ModuleContext, n: M.NamedPattern): void {
|
function gatherFields(fs: FieldMap, mod: ModuleContext, n: M.NamedPattern): void {
|
||||||
if (n.label === M.$named) {
|
if (n._variant === 'named') {
|
||||||
fs.set(n[0].description!, simpleType(mod, n[1]));
|
fs.set(n.value.name.description!, simpleType(mod, n.value.pattern));
|
||||||
} else if (M.isCompoundPattern(n)) {
|
} else if (n.value._variant === 'CompoundPattern') {
|
||||||
compoundFields(fs, mod, n);
|
compoundFields(fs, mod, n.value.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -58,14 +58,14 @@ export function lookup<R>(namePos: Position | null,
|
||||||
kOther: (modId: string, modPath: string, p: M.Definition | null) => R): R
|
kOther: (modId: string, modPath: string, p: M.Definition | null) => R): R
|
||||||
{
|
{
|
||||||
for (const e of env) {
|
for (const e of env) {
|
||||||
if (is(e.schemaModulePath, M.Ref._.module(name)) ||
|
if (is(e.schemaModulePath, name.module) ||
|
||||||
(e.typescriptModulePath === null && M.Ref._.module(name).length === 0))
|
(e.typescriptModulePath === null && name.module.length === 0))
|
||||||
{
|
{
|
||||||
if (e.schema === null) {
|
if (e.schema === null) {
|
||||||
// It's an artificial module, not from a schema. Assume the identifier is present.
|
// It's an artificial module, not from a schema. Assume the identifier is present.
|
||||||
return kOther(modsymFor(e), e.typescriptModulePath, null);
|
return kOther(modsymFor(e), e.typescriptModulePath, null);
|
||||||
} else {
|
} else {
|
||||||
const p = M.Schema._._field0(e.schema).get(M.$definitions).get(M.Ref._.name(name));
|
const p = e.schema.definitions.get(name.name);
|
||||||
if (p !== void 0) {
|
if (p !== void 0) {
|
||||||
if (e.typescriptModulePath === null) {
|
if (e.typescriptModulePath === null) {
|
||||||
return kLocal(p);
|
return kLocal(p);
|
||||||
|
@ -81,28 +81,36 @@ export function lookup<R>(namePos: Position | null,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatRef(r: M.Ref): string {
|
export function formatRef(r: M.Ref): string {
|
||||||
return [... r[0], r[1]].map(s => s.description!).join('.');
|
return [... r.module, r.name].map(s => s.description!).join('.');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function unname<R extends M.Pattern | M.SimplePattern>(
|
export function unnamePattern(p: M.NamedPattern): M.Pattern {
|
||||||
p: M.NamedSimplePattern_ | R): M.SimplePattern | R
|
return (p._variant === 'named') ? M.Pattern.SimplePattern(p.value.pattern) : p.value;
|
||||||
{
|
|
||||||
return (p.label === M.$named) ? p[1] : p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function nameFor<R extends M.Pattern | M.SimplePattern>(
|
export function unnameSimplePattern(p: M.NamedSimplePattern): M.SimplePattern {
|
||||||
p: M.NamedSimplePattern_ | R): string | undefined
|
return (p._variant === 'named') ? p.value.pattern : p.value;
|
||||||
{
|
|
||||||
return (p.label === M.$named) ? p[0].description! : void 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addNameIfAbsent(p: M.NamedSimplePattern, k: Input): M.NamedSimplePattern {
|
export function promoteNamedSimplePattern(p: M.NamedSimplePattern): M.NamedPattern {
|
||||||
if (p.label === M.$named) {
|
return (p._variant === 'named') ? p : M.NamedPattern.anonymous(M.Pattern.SimplePattern(p.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function nameFor(p: M.NamedSimplePattern | M.NamedPattern) : string | undefined {
|
||||||
|
return (p._variant === 'named') ? p.value.name.description! : void 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function anonymousSimplePattern(p: M.SimplePattern): M.NamedPattern {
|
||||||
|
return M.NamedPattern.anonymous(M.Pattern.SimplePattern(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addNameIfAbsent(p: M.NamedSimplePattern, k: M._val): M.NamedSimplePattern {
|
||||||
|
if (p._variant === 'named') {
|
||||||
return p;
|
return p;
|
||||||
} else {
|
} else {
|
||||||
const s = namelike(k);
|
const s = namelike(k);
|
||||||
if (s !== void 0) {
|
if (s !== void 0) {
|
||||||
return M.NamedSimplePattern_(Symbol.for(s), p);
|
return M.NamedSimplePattern.named(M.NamedSimplePattern__(Symbol.for(s), p.value));
|
||||||
} else {
|
} else {
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -112,8 +120,8 @@ export function addNameIfAbsent(p: M.NamedSimplePattern, k: Input): M.NamedSimpl
|
||||||
// Simple arrays at toplevel for convenience
|
// Simple arrays at toplevel for convenience
|
||||||
//
|
//
|
||||||
export function simpleArray(p: M.CompoundPattern): M.SimplePattern | undefined {
|
export function simpleArray(p: M.CompoundPattern): M.SimplePattern | undefined {
|
||||||
if (p.label === M.$tuple_STAR_ && p[0].length === 0 && p[1].label !== M.$named) {
|
if (p._variant === 'tuple*' && p.fixed.length === 0 && p.variable._variant !== 'named') {
|
||||||
return p[1];
|
return p.variable.value;
|
||||||
} else {
|
} else {
|
||||||
return void 0;
|
return void 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import { Reader, Annotated, Dictionary, is, peel, preserves, Record, strip, Tuple, Position, position, ReaderOptions, stringify, isCompound } from '@preserves/core';
|
import { Reader, Annotated, Dictionary, is, peel, preserves, Record, strip, Tuple, Position, position, ReaderOptions, stringify, isCompound, KeyedDictionary } from '@preserves/core';
|
||||||
import { Input, Pattern, Schema, Alternative, Definition, CompoundPattern, SimplePattern } from './meta';
|
import { Input, Pattern, Schema, Alternative, Definition, CompoundPattern, SimplePattern } from './meta';
|
||||||
import * as M from './meta';
|
import * as M from './meta';
|
||||||
import { SchemaSyntaxError } from './error';
|
import { SchemaSyntaxError } from './error';
|
||||||
|
|
||||||
const positionTable = new WeakMap<Input & object, Position>();
|
const positionTable = new WeakMap<object, Position>();
|
||||||
|
|
||||||
export function recordPosition<X extends Input & object>(v: X, pos: Position | null): X {
|
export function recordPosition<X extends object>(v: X, pos: Position | null): X {
|
||||||
if (pos === null) { console.error('Internal error in Schema reader: null source position for', v); }
|
if (pos === null) { console.error('Internal error in Schema reader: null source position for', v); }
|
||||||
if (pos !== null) positionTable.set(v, pos);
|
if (pos !== null) positionTable.set(v, pos);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function refPosition(v: Input & object): Position | null {
|
export function refPosition(v: object): Position | null {
|
||||||
return positionTable.get(v) ?? null;
|
return positionTable.get(v) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,8 +65,8 @@ export function parseSchema(toplevelTokens: Array<Input>,
|
||||||
options: ReaderOptions<never> & SchemaReaderOptions): Schema
|
options: ReaderOptions<never> & SchemaReaderOptions): Schema
|
||||||
{
|
{
|
||||||
let version: M.Version | undefined = void 0;
|
let version: M.Version | undefined = void 0;
|
||||||
let pointer: M.PointerName = false;
|
let pointer: M.PointerName = M.PointerName.$false();
|
||||||
let definitions = new Dictionary<never, Definition>();
|
let definitions = new KeyedDictionary<symbol, Definition, M._ptr>();
|
||||||
|
|
||||||
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);
|
||||||
|
@ -89,10 +89,13 @@ export function parseSchema(toplevelTokens: Array<Input>,
|
||||||
} else if (clause.length === 2 && is(clause[0], M.$pointer)) {
|
} else if (clause.length === 2 && is(clause[0], M.$pointer)) {
|
||||||
const pos = position(clause[1]);
|
const pos = position(clause[1]);
|
||||||
const stx = peel(clause[1]);
|
const stx = peel(clause[1]);
|
||||||
const quasiName = 'pointer name specification';
|
if (stx === false) {
|
||||||
pointer = M.asPointerName((stx === false) ? stx
|
pointer = M.PointerName.$false();
|
||||||
: (typeof stx === 'symbol') ? parseRef(quasiName, pos, stx)
|
} else if (typeof stx === 'symbol') {
|
||||||
: invalidPattern(quasiName, stx, pos));
|
pointer = M.PointerName.Ref(parseRef(stx.description!, pos));
|
||||||
|
} else {
|
||||||
|
invalidPattern('pointer name specification', stx, pos);
|
||||||
|
}
|
||||||
} else if (clause.length === 2 && is(clause[0], M.INCLUDE)) {
|
} else if (clause.length === 2 && is(clause[0], M.INCLUDE)) {
|
||||||
const pos = position(clause[1]);
|
const pos = position(clause[1]);
|
||||||
const path = peel(clause[1]);
|
const path = peel(clause[1]);
|
||||||
|
@ -115,11 +118,7 @@ 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<never>([
|
return M.Schema(M.Version(), pointer, definitions);
|
||||||
[M.$version, version],
|
|
||||||
[M.$pointer, pointer],
|
|
||||||
[M.$definitions, definitions],
|
|
||||||
])]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function namedMustBeSimple(p: Position | null): never {
|
function namedMustBeSimple(p: Position | null): never {
|
||||||
|
@ -129,32 +128,45 @@ function namedMustBeSimple(p: Position | null): never {
|
||||||
function parseDefinition(name: symbol, body: Array<Input>): Definition {
|
function parseDefinition(name: symbol, 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])
|
||||||
: [string, Alternative]
|
: M.NamedAlternative
|
||||||
{
|
{
|
||||||
const n = findName(input) || findName(input[0]);
|
const n = findName(input) || findName(input[0]);
|
||||||
if (n !== false) {
|
if (n !== false) {
|
||||||
return [n.description!, p];
|
return M.NamedAlternative(n.description!, p);
|
||||||
}
|
}
|
||||||
if (p.label === M.$rec && p[0].label === M.$lit && typeof p[0][0] === 'symbol') {
|
if (p._variant === 'Pattern' &&
|
||||||
return [p[0][0].description!, p];
|
p.value._variant === 'CompoundPattern' &&
|
||||||
|
p.value.value._variant === 'rec' &&
|
||||||
|
p.value.value.label._variant === 'anonymous' &&
|
||||||
|
p.value.value.label.value._variant === 'SimplePattern' &&
|
||||||
|
p.value.value.label.value.value._variant === 'lit' &&
|
||||||
|
typeof p.value.value.label.value.value.value === 'symbol')
|
||||||
|
{
|
||||||
|
return M.NamedAlternative(p.value.value.label.value.value.value.description!, p);
|
||||||
}
|
}
|
||||||
if (p.label === M.$ref) {
|
if (p._variant === 'Pattern' &&
|
||||||
return [p[1].description!, p];
|
p.value._variant === 'SimplePattern' &&
|
||||||
|
p.value.value._variant === 'Ref')
|
||||||
|
{
|
||||||
|
return M.NamedAlternative(p.value.value.value.name.description!, p);
|
||||||
}
|
}
|
||||||
if (p.label === M.$lit) {
|
if (p._variant === 'Pattern' &&
|
||||||
const s = M.namelike(p[0]);
|
p.value._variant === 'SimplePattern' &&
|
||||||
if (s !== void 0) return [s, p];
|
p.value.value._variant === 'lit')
|
||||||
|
{
|
||||||
|
const s = M.namelike(p.value.value.value);
|
||||||
|
if (s !== void 0) return M.NamedAlternative(s, p);
|
||||||
}
|
}
|
||||||
return ['_anonymous' + nextAnonymousAlternativeNumber++, p];
|
return M.NamedAlternative('_anonymous' + nextAnonymousAlternativeNumber++, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
function patternName([input, p]: readonly [Array<Input>, Pattern]) : M.NamedPattern {
|
function patternName([input, p]: readonly [Array<Input>, Pattern]) : M.NamedPattern {
|
||||||
const n = findName(input) || findName(input[0]);
|
const n = findName(input) || findName(input[0]);
|
||||||
if (n !== false) {
|
if (n !== false) {
|
||||||
if (!M.isSimplePattern(p)) namedMustBeSimple(position(input[0]));
|
if (p._variant !== 'SimplePattern') namedMustBeSimple(position(input[0]));
|
||||||
return Record(M.$named, [n, p]);
|
return M.NamedPattern.named(M.NamedSimplePattern__(n, p.value));
|
||||||
}
|
}
|
||||||
return p;
|
return M.NamedPattern.anonymous(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: deal with situation where there's an or of ands, where
|
// TODO: deal with situation where there's an or of ands, where
|
||||||
|
@ -167,29 +179,32 @@ function parseDefinition(name: symbol, body: Array<Input>): Definition {
|
||||||
p => [p, parseOp(p,
|
p => [p, parseOp(p,
|
||||||
M.ANDSYM,
|
M.ANDSYM,
|
||||||
p => [p, parsePattern(name, p)] as const,
|
p => [p, parsePattern(name, p)] as const,
|
||||||
ps => Record(M.$and, [ps.map(patternName)]),
|
ps => M.Alternative.and(ps.map(patternName)),
|
||||||
p => p[1] as Alternative)] as const,
|
p => M.Alternative.Pattern(p[1]))] as const,
|
||||||
ps => Record(M.$or, [ps.map(alternativeName)]),
|
ps => M.Definition.or(ps.map(alternativeName)),
|
||||||
p => p[1] as Definition);
|
p => M.Definition.Alternative(p[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
function parsePattern(name: symbol, body0: Array<Input>): Pattern {
|
function parsePattern(name: symbol, body0: Array<Input>): Pattern {
|
||||||
function parseSimple<A>(item0: Input, kf: () => A): SimplePattern | A {
|
function parseSimple<A>(item0: Input, ks: (p: SimplePattern) => A, kf: () => A): A {
|
||||||
const pos = position(item0);
|
const pos = position(item0);
|
||||||
const item = peel(item0);
|
const item = peel(item0);
|
||||||
function complain(): never { invalidPattern(stringify(name), item, pos); }
|
function complain(): never { invalidPattern(stringify(name), item, pos); }
|
||||||
if (typeof item === 'symbol') {
|
if (typeof item === 'symbol') {
|
||||||
switch (item) {
|
const str = item.description!;
|
||||||
case Symbol.for('any'): return Record<typeof M.$any, []>(M.$any, []);
|
switch (str) {
|
||||||
case Symbol.for('bool'): return Record<typeof M.$atom, [M.AtomKind]>(M.$atom, [M.$Boolean]);
|
case 'any': return ks(M.SimplePattern.any());
|
||||||
case Symbol.for('float'): return Record<typeof M.$atom, [M.AtomKind]>(M.$atom, [M.$Float]);
|
case 'bool': return ks(M.SimplePattern.atom(M.AtomKind.Boolean()));
|
||||||
case Symbol.for('double'): return Record<typeof M.$atom, [M.AtomKind]>(M.$atom, [M.$Double]);
|
case 'float': return ks(M.SimplePattern.atom(M.AtomKind.Float()));
|
||||||
case Symbol.for('int'): return Record<typeof M.$atom, [M.AtomKind]>(M.$atom, [M.$SignedInteger]);
|
case 'double': return ks(M.SimplePattern.atom(M.AtomKind.Double()));
|
||||||
case Symbol.for('string'): return Record<typeof M.$atom, [M.AtomKind]>(M.$atom, [M.$String]);
|
case 'int': return ks(M.SimplePattern.atom(M.AtomKind.SignedInteger()));
|
||||||
case Symbol.for('bytes'): return Record<typeof M.$atom, [M.AtomKind]>(M.$atom, [M.$ByteString]);
|
case 'string': return ks(M.SimplePattern.atom(M.AtomKind.String()));
|
||||||
case Symbol.for('symbol'): return Record<typeof M.$atom, [M.AtomKind]>(M.$atom, [M.$Symbol]);
|
case 'bytes': return ks(M.SimplePattern.atom(M.AtomKind.ByteString()));
|
||||||
case Symbol.for('ref'): return Record<typeof M.$pointer, []>(M.$pointer, []);
|
case 'symbol': return ks(M.SimplePattern.atom(M.AtomKind.Symbol()));
|
||||||
default: return parseRef(stringify(name), pos, item);
|
case 'ref': return ks(M.SimplePattern.pointer());
|
||||||
|
default: return ks((str[0] === '=')
|
||||||
|
? M.SimplePattern.lit(Symbol.for(str.slice(1)))
|
||||||
|
: M.SimplePattern.Ref(parseRef(str, pos)));
|
||||||
}
|
}
|
||||||
} else if (Record.isRecord<Input, Tuple<Input>, never>(item)) {
|
} else if (Record.isRecord<Input, Tuple<Input>, never>(item)) {
|
||||||
const label = item.label;
|
const label = item.label;
|
||||||
|
@ -198,7 +213,7 @@ function parsePattern(name: symbol, body0: Array<Input>): Pattern {
|
||||||
switch (label.label) {
|
switch (label.label) {
|
||||||
case M.$lit:
|
case M.$lit:
|
||||||
if (item.length !== 1) complain();
|
if (item.length !== 1) complain();
|
||||||
return Record(M.$lit, [item[0]]);
|
return ks(M.SimplePattern.lit(item[0]));
|
||||||
default:
|
default:
|
||||||
return kf();
|
return kf();
|
||||||
}
|
}
|
||||||
|
@ -208,7 +223,7 @@ function parsePattern(name: symbol, body0: Array<Input>): Pattern {
|
||||||
} else if (isCompound(item)) {
|
} else if (isCompound(item)) {
|
||||||
return kf();
|
return kf();
|
||||||
} else {
|
} else {
|
||||||
return Record(M.$lit, [strip(item)]);
|
return ks(M.SimplePattern.lit(strip(item)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,14 +232,16 @@ function parsePattern(name: symbol, body0: Array<Input>): Pattern {
|
||||||
const item = peel(item0);
|
const item = peel(item0);
|
||||||
function complain(): never { invalidPattern(stringify(name), item, pos); }
|
function complain(): never { invalidPattern(stringify(name), item, pos); }
|
||||||
|
|
||||||
const walkSimple = (b: Input): SimplePattern => parseSimple(b, () => {
|
const walkSimple = (b: Input): SimplePattern => parseSimple(b, p => p, () => {
|
||||||
throw new SchemaSyntaxError(`Compound patterns not accepted here`, position(b));
|
throw new SchemaSyntaxError(`Compound patterns not accepted here`, position(b));
|
||||||
});
|
});
|
||||||
const walk = (b: Input): Pattern => parsePattern(name, [b]);
|
const walk = (b: Input): Pattern => parsePattern(name, [b]);
|
||||||
|
|
||||||
function _maybeNamed<R>(
|
function _maybeNamed<R,P>(
|
||||||
recur: (b: Input) => R,
|
named: (p: M.NamedSimplePattern_) => R,
|
||||||
literalName?: Input): (b: Input) => M.NamedSimplePattern_ | R
|
anonymous: (p: P) => R,
|
||||||
|
recur: (b: Input) => P,
|
||||||
|
literalName?: Input): (b: Input) => R
|
||||||
{
|
{
|
||||||
return (b: Input) => {
|
return (b: Input) => {
|
||||||
let name = findName(b);
|
let name = findName(b);
|
||||||
|
@ -234,14 +251,15 @@ function parsePattern(name: symbol, body0: Array<Input>): Pattern {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (name === false) {
|
if (name === false) {
|
||||||
return recur(b);
|
return anonymous(recur(b));
|
||||||
}
|
}
|
||||||
return Record(M.$named, [name, parseSimple(b, () =>
|
return named(M.NamedSimplePattern__(name, parseSimple(b, p => p, () =>
|
||||||
namedMustBeSimple(position(b)))]);
|
namedMustBeSimple(position(b)))));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const maybeNamed = _maybeNamed(walk);
|
const maybeNamed = _maybeNamed(M.NamedPattern.named, M.NamedPattern.anonymous, walk);
|
||||||
const maybeNamedSimple = _maybeNamed(walkSimple);
|
const maybeNamedSimple =
|
||||||
|
_maybeNamed(M.NamedSimplePattern.named, M.NamedSimplePattern.anonymous, walkSimple);
|
||||||
|
|
||||||
if (Record.isRecord<Input, Tuple<Input>, never>(item)) {
|
if (Record.isRecord<Input, Tuple<Input>, never>(item)) {
|
||||||
const label = item.label;
|
const label = item.label;
|
||||||
|
@ -250,37 +268,47 @@ function parsePattern(name: symbol, body0: Array<Input>): Pattern {
|
||||||
switch (label.label) {
|
switch (label.label) {
|
||||||
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 M.CompoundPattern.rec(maybeNamed(item[0]), maybeNamed(item[1]));
|
||||||
default:
|
default:
|
||||||
complain();
|
complain();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Record(M.$rec, [Record(M.$lit, [label]), Record(M.$tuple, [item.map(maybeNamed)])]);
|
return M.CompoundPattern.rec(
|
||||||
|
M.NamedPattern.anonymous(M.Pattern.SimplePattern(M.SimplePattern.lit(label))),
|
||||||
|
M.NamedPattern.anonymous(M.Pattern.CompoundPattern(
|
||||||
|
M.CompoundPattern.tuple(item.map(maybeNamed)))));
|
||||||
}
|
}
|
||||||
} 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 M.CompoundPattern.tuple_STAR_(
|
||||||
item.slice(0, item.length - 2).map(maybeNamed),
|
item.slice(0, item.length - 2).map(maybeNamed),
|
||||||
maybeNamedSimple(item[item.length - 2]),
|
maybeNamedSimple(item[item.length - 2]));
|
||||||
]);
|
|
||||||
} else {
|
} else {
|
||||||
return Record(M.$tuple, [item.map(maybeNamed)]);
|
return M.CompoundPattern.tuple(item.map(maybeNamed));
|
||||||
}
|
}
|
||||||
} else if (Dictionary.isDictionary<never, Input>(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);
|
||||||
const [[kp, vp]] = v.entries();
|
const [[kp, vp]] = v.entries();
|
||||||
return Record(M.$dictof, [walkSimple(kp), walkSimple(vp)]);
|
return M.CompoundPattern.dictof(walkSimple(kp), walkSimple(vp));
|
||||||
} else {
|
} else {
|
||||||
return Record(M.$dict, [item.mapEntries<M.NamedSimplePattern, Input, never>(
|
return M.CompoundPattern.dict(
|
||||||
([k, vp]) => [strip(k), _maybeNamed(walkSimple, k)(vp)])]);
|
M.DictionaryEntries(item.mapEntries<M.NamedSimplePattern, Input, M._ptr>(
|
||||||
|
([k, vp]) => [
|
||||||
|
strip(k),
|
||||||
|
_maybeNamed(
|
||||||
|
M.NamedSimplePattern.named,
|
||||||
|
M.NamedSimplePattern.anonymous,
|
||||||
|
walkSimple,
|
||||||
|
k)(vp)
|
||||||
|
])));
|
||||||
}
|
}
|
||||||
} else if (Set.isSet<never>(item)) {
|
} else if (Set.isSet<never>(item)) {
|
||||||
if (item.size !== 1) complain();
|
if (item.size !== 1) complain();
|
||||||
const [vp] = item.entries();
|
const [vp] = item.entries();
|
||||||
return Record(M.$setof, [walkSimple(vp)]);
|
return M.CompoundPattern.setof(walkSimple(vp));
|
||||||
} else {
|
} else {
|
||||||
complain();
|
complain();
|
||||||
}
|
}
|
||||||
|
@ -290,7 +318,9 @@ function parsePattern(name: symbol, body0: Array<Input>): Pattern {
|
||||||
if (body.length !== 1) {
|
if (body.length !== 1) {
|
||||||
invalidPattern(stringify(name), body, body.length > 0 ? position(body[0]) : position(body));
|
invalidPattern(stringify(name), body, body.length > 0 ? position(body[0]) : position(body));
|
||||||
}
|
}
|
||||||
return parseSimple(body[0], () => parseCompound(body[0]));
|
return parseSimple(body[0],
|
||||||
|
M.Pattern.SimplePattern,
|
||||||
|
() => M.Pattern.CompoundPattern(parseCompound(body[0])));
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseOp<Each, Combined>(body: Array<Input>,
|
function parseOp<Each, Combined>(body: Array<Input>,
|
||||||
|
@ -312,13 +342,9 @@ function findName(x: Input): symbol | false {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseRef(name: string, pos: Position | null, item: symbol): SimplePattern {
|
function parseRef(s: string, pos: Position | null): M.Ref {
|
||||||
const s = item.description;
|
|
||||||
if (s === void 0) invalidPattern(name, item, pos);
|
|
||||||
if (s[0] === '=') return Record(M.$lit, [Symbol.for(s.slice(1))]);
|
|
||||||
const pieces = s.split('.');
|
const pieces = s.split('.');
|
||||||
return recordPosition(Record(M.$ref, [
|
return recordPosition(M.Ref(
|
||||||
pieces.slice(0, pieces.length - 1).map(Symbol.for),
|
M.ModulePath(pieces.slice(0, pieces.length - 1).map(Symbol.for)),
|
||||||
Symbol.for(pieces[pieces.length - 1])
|
Symbol.for(pieces[pieces.length - 1])), pos);
|
||||||
]), pos);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue