Fix types.

This commit is contained in:
Tony Garnock-Jones 2021-03-19 23:42:43 +01:00
parent c2fe82e71d
commit 889d38bbb8
10 changed files with 279 additions and 183 deletions

View File

@ -1,18 +0,0 @@
import { Record, Dictionary } from '@preserves/core';
import * as M from './gen/schema';
export const BASE: M.Schema = M.asSchema(Record(M.$schema, [new Dictionary<never>([
[M.$version, 1],
[M.$pointer, false],
[M.$definitions, new Dictionary<never, M.Alternative>([
[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])],
[Symbol.for('int'), Record(M.$atom, [M.$SignedInteger])],
[Symbol.for('string'), Record(M.$atom, [M.$String])],
[Symbol.for('bytes'), Record(M.$atom, [M.$ByteString])],
[Symbol.for('symbol'), Record(M.$atom, [M.$Symbol])],
[Symbol.for('ref'), Record(M.$pointer, [])],
])],
])]));

View File

@ -2,16 +2,19 @@ import { Annotated, Bytes, Dictionary, Fold, fold, Record, stringify, Tuple, Val
import * as M from "./meta";
import { CompilerOptions, ModuleContext } from "./compiler/context";
import { brackets, Formatter, Item, parens, seq } from "./compiler/block";
import { typeForDefinition } from "./compiler/type";
import { typeForDefinition } from "./compiler/gentype";
// import { decoderFor } from "./compiler/decoder";
import { converterForDefinition } from "./compiler/converter";
import { converterForDefinition } from "./compiler/genconverter";
import { EMPTY_TYPE, renderType } from "./compiler/type";
export function compile(env: M.Environment, schema: M.Schema, options: CompilerOptions = {}): string {
const mod = new ModuleContext(env, schema, options);
const pointerName = M.Schema._._field0(schema).get(M.$pointer);
mod.defineType(seq(`export type _ptr = `,
pointerName === false ? 'never' : typeForDefinition(mod, pointerName),
renderType(pointerName === false
? EMPTY_TYPE
: typeForDefinition(mod, pointerName)),
`;`));
mod.defineType(`export type _val = _.Value<_ptr>;`);
@ -28,7 +31,8 @@ export function compile(env: M.Environment, schema: M.Schema, options: CompilerO
for (const [name, def] of M.Schema._._field0(schema).get(M.$definitions)) {
mod.defineType(
seq(`export type ${stringify(name)} = `, typeForDefinition(mod, def), `;`));
seq(`export type ${stringify(name)} = `,
renderType(typeForDefinition(mod, def)), `;`));
}
for (const [name0, def] of M.Schema._._field0(schema).get(M.$definitions)) {

View File

@ -2,6 +2,7 @@ import { Dictionary, KeyedSet, Position } from "@preserves/core";
import { refPosition } from "../reader";
import * as M from "../meta";
import { block, braces, commas, formatItems, Item, keyvalue, seq } from "./block";
import { ANY_TYPE, renderType, Type, variantInitFor } from "./type";
export interface CompilerOptions {
preservesModule?: string;
@ -45,7 +46,6 @@ export class ModuleContext {
derefPattern([_name, p]: [string, M.Alternative]): M.Definition {
if (p.label === M.$ref) {
return M.lookup(refPosition(p), p, this.env,
(p) => p,
(p) => p,
(_modId, _modPath, pp) => pp ?? p);
} else {
@ -67,6 +67,7 @@ export class FunctionContext {
tempCounter = 0;
temps: Map<string, { type: Item, names: string[] }> = new Map();
captures: Capture[] = [];
variantName: string | undefined = void 0;
@ -78,13 +79,13 @@ export class FunctionContext {
return '_tmp' + this.tempCounter++;
}
gentemp(... vartypePieces: Item[]): string {
const vartype = vartypePieces.length === 0 ? '_val | undefined' : seq(... vartypePieces);
const typestr = formatItems([vartype], Infinity);
gentemp(vartype: Type = ANY_TYPE): string {
const typeitem = renderType(vartype);
const typestr = formatItems([typeitem], Infinity);
const varname = this.gentempname();
let e = this.temps.get(typestr);
if (e === void 0) {
e = { type: vartype, names: [] };
e = { type: typeitem, names: [] };
this.temps.set(typestr, e);
}
e.names.push(varname);
@ -99,7 +100,7 @@ export class FunctionContext {
this.temps = oldTemps;
return block(
... Array.from(ts).map(([_typestr, { type, names }]) =>
seq(`let `, commas(... names), `: `, type)),
seq(`let `, commas(... names), `: (`, type, `) | undefined`)),
... items);
}
@ -126,11 +127,3 @@ export class FunctionContext {
keyvalue(fieldName, sourceExpr))));
}
}
export function variantInitFor(variantName: string | undefined) : Item[] {
return variantName === void 0 ? [] : [variantFor(variantName)];
}
export function variantFor(variantName: string): Item {
return keyvalue('_variant', JSON.stringify(variantName));
}

View File

@ -1,8 +1,9 @@
import { FunctionContext } from "./context";
import * as M from '../meta';
import { block, Item, seq } from "./block";
import { typeFor } from "./type";
import { simpleType, dictionaryType, setType, typeFor } from "./gentype";
import { refPosition } from "../reader";
import { ANY_TYPE, Type } from "./type";
export function converterForDefinition(
ctx: FunctionContext,
@ -45,9 +46,13 @@ function converterForAlternative(
if (simpleValue === void 0) {
return [ctx.buildCapturedCompound(dest)];
} else if (ctx.variantName !== void 0) {
return [ctx.withCapture('value',
simpleValue,
() => ctx.buildCapturedCompound(dest))];
if (typeFor(ctx.mod, p).kind === 'unit') {
return [ctx.buildCapturedCompound(dest)];
} else {
return [ctx.withCapture('value',
simpleValue,
() => ctx.buildCapturedCompound(dest))];
}
} else {
return [`${dest} = ${simpleValue}`];
}
@ -69,7 +74,7 @@ function converterForTuple(ctx: FunctionContext,
if (variablePattern === void 0) {
return k();
} else {
const vN = ctx.gentemp(`Array<_val>`);
const vN = ctx.gentemp(Type.array(ANY_TYPE));
return [ps.length > 0 ? `${vN} = ${src}.slice(${ps.length})` : `${vN} = ${src}`,
converterForArray(ctx, variablePattern, vN, false, k)];
}
@ -92,8 +97,7 @@ function converterForArray(ctx: FunctionContext,
k: (dest: string) => Item[]): Item
{
const postCheck = () => {
const r = ctx.gentemp(
`Array<`, typeFor(ctx.mod, M.unname(arrayType)), `> | undefined`);
const r = ctx.gentemp(Type.array(simpleType(ctx.mod, M.unname(arrayType))));
const v = ctx.gentempname();
return [
seq(`${r} = []`),
@ -119,14 +123,14 @@ function converterFor(
let maybeName = M.nameFor(np);
if (M.isSimplePattern(p)) {
const dest = ctx.gentemp(typeFor(ctx.mod, p), ` | undefined`);
const dest = ctx.gentemp(simpleType(ctx.mod, p));
return [... converterForSimple(ctx, p, src, dest),
ctx.convertCapture(maybeName, dest, ks)];
} else {
switch (p.label) {
case M.$setof: {
const setPattern = p[0];
const r = ctx.gentemp(typeFor(ctx.mod, p), ` | undefined`);
const r = ctx.gentemp(setType(ctx.mod, setPattern));
const v = ctx.gentempname();
return [
seq(`if (_.Set.isSet<_ptr>(${src})) `, ctx.block(() => [
@ -141,7 +145,7 @@ function converterFor(
case M.$dictof: {
const keyPattern = p[0];
const valPattern = p[1];
const r = ctx.gentemp(typeFor(ctx.mod, p), ` | undefined`);
const r = ctx.gentemp(dictionaryType(ctx.mod, keyPattern, valPattern));
const v = ctx.gentempname();
const k = ctx.gentempname();
return [
@ -174,6 +178,8 @@ function converterForSimple(
dest: string): Item[]
{
switch (p.label) {
case M.$any:
return [`${dest} = ${src}`];
case M.$atom: {
let test: Item;
switch (p[0]) {
@ -188,11 +194,10 @@ function converterForSimple(
return [seq(`${dest} = `, test, ` ? ${src} : void 0`)];
}
case M.$lit:
return [`${dest} = _.is(${src}, ${ctx.mod.literal(p[0])}) ? ${ctx.mod.literal(p[0])} : void 0`];
return [`${dest} = _.is(${src}, ${ctx.mod.literal(p[0])}) ? null : void 0`];
case M.$ref:
return M.lookup(refPosition(p), p, ctx.mod.env,
(_p) => [`${dest} = to${p[1].description!}(${src})`],
(p) => converterForAlternative(ctx, p, src, dest),
(modId, modPath,_p) => {
ctx.mod.imports.add([modId, modPath]);
return [`${dest} = ${modId}.decode${p[1].description!}(${src})`];

View File

@ -0,0 +1,125 @@
import { refPosition } from "../reader";
import * as M from "../meta";
import { ModuleContext } from "./context";
import { ANY_TYPE, AtomicType, CollectionType, FieldMap, SimpleType, Type } from "./type";
export function typeForDefinition(mod: ModuleContext, d: M.Definition): Type {
if (d.label === M.$or) {
return Type.union(
new Map(d[0].map(a => [a[0], typeForAlternative(mod, a[1])])));
} else {
return typeForAlternative(mod, d);
}
}
function typeForAlternative(mod: ModuleContext, a: M.Alternative): SimpleType {
if (a.label === M.$and) {
const fs = new Map();
a[0].forEach(n => gatherFields(fs, mod, n));
return Type.record(fs);
} else {
return typeFor(mod, a);
}
}
export function setType(mod: ModuleContext, p: M.SimplePattern): CollectionType {
return Type.set(simpleType(mod, p));
}
export function dictionaryType(mod: ModuleContext,
kp: M.SimplePattern,
vp: M.SimplePattern): CollectionType
{
return Type.dictionary(simpleType(mod, kp), simpleType(mod, vp));
}
export function typeFor(mod: ModuleContext, p: M.Pattern): SimpleType {
if (M.isSimplePattern(p)) {
return simpleType(mod, p);
} else {
switch (p.label) {
case M.$setof:
return setType(mod, p[0]);
case M.$dictof:
return dictionaryType(mod, p[0], p[1]);
default: {
const arrayType = M.simpleArray(p);
if (arrayType === void 0) {
const fs = new Map();
compoundFields(fs, mod, p);
return Type.record(fs);
} else {
return Type.array(simpleType(mod, arrayType));
}
}
}
}
}
export function simpleType(mod: ModuleContext, p: M.SimplePattern): AtomicType {
switch (p.label) {
case M.$any:
return ANY_TYPE;
case M.$atom:
switch (p[0]) {
case M.$Boolean: return Type.ref(`boolean`);
case M.$Float: return Type.ref(`_.SingleFloat`);
case M.$Double: return Type.ref(`_.DoubleFloat`);
case M.$SignedInteger: return Type.ref(`number`);
case M.$String: return Type.ref(`string`);
case M.$ByteString: return Type.ref(`_.Bytes`);
case M.$Symbol: return Type.ref(`symbol`);
}
case M.$pointer:
return Type.ref(`_ptr`);
case M.$lit:
return Type.unit();
case M.$ref:
return M.lookup(refPosition(p), p, mod.env,
(_p) => Type.ref(p[1].description!),
(modId, modPath,_p) => {
mod.imports.add([modId, modPath]);
return Type.ref(`${modId}.${p[1].description!}`);
});
default:
((_p: never) => {})(p);
throw new Error("Unreachable");
}
}
function compoundFields(fs: FieldMap, mod: ModuleContext, p: M.CompoundPattern): void {
switch (p.label) {
case M.$rec:
gatherFields(fs, mod, p[0]);
gatherFields(fs, mod, p[1]);
break;
case M.$tuple:
p[0].forEach(pp => gatherFields(fs, mod, pp));
break;
case M.$tuple_STAR_: {
p[0].forEach(pp => gatherFields(fs, mod, pp));
const n = p[1];
if (n.label === M.$named) {
fs.set(n[0].description!, Type.array(simpleType(mod, n[1])));
}
break;
}
case M.$setof:
case M.$dictof:
break;
case M.$dict:
p[0].forEach((n, k) => gatherFields(fs, mod, M.addNameIfAbsent(n, k)));
break;
default:
((_p: never) => {})(p);
throw new Error("Unreachable");
}
}
function gatherFields(fs: FieldMap, mod: ModuleContext, n: M.NamedPattern): void {
if (n.label === M.$named) {
fs.set(n[0].description!, simpleType(mod, n[1]));
} else if (M.isCompoundPattern(n)) {
compoundFields(fs, mod, n);
}
}

View File

@ -1,120 +1,90 @@
import { refPosition } from "../reader";
import * as M from "../meta";
import { anglebrackets, braces, Item, keyvalue, opseq, seq } from "./block";
import { ModuleContext, variantFor, variantInitFor } from "./context";
export function typeForDefinition(mod: ModuleContext, d: M.Definition): Item {
if (d.label === M.$or) {
return opseq('never', ' | ', ... d[0].map(a => typeForAlternative(mod, a[1], a[0])));
} else {
return typeForAlternative(mod, d, void 0);
}
export type Type =
| { kind: 'union', variants: VariantMap } // zero: never
| SimpleType
export type SimpleType = AtomicType | CompoundType
export type FieldType = AtomicType | CollectionType;
export type AtomicType =
| { kind: 'unit' }
| { kind: 'ref', typeName: string } // also for base types
export type CompoundType =
| CollectionType
| { kind: 'record', fields: FieldMap }
export type CollectionType =
| { kind: 'array', type: AtomicType }
| { kind: 'set', type: AtomicType }
| { kind: 'dictionary', key: AtomicType, value: AtomicType }
export type VariantMap = Map<string, SimpleType>;
export type FieldMap = Map<string, FieldType>;
export namespace Type {
export const union = (variants: VariantMap): Type => ({ kind: 'union', variants });
export const unit = (): AtomicType => ({ kind: 'unit' });
export const ref = (typeName: string): AtomicType => ({ kind: 'ref', typeName });
export const record = (fields: FieldMap): CompoundType => ({ kind: 'record', fields });
export const array = (type: AtomicType): CollectionType => ({ kind: 'array', type });
export const set = (type: AtomicType): CollectionType => ({ kind: 'set', type });
export const dictionary = (key: AtomicType, value: AtomicType): CollectionType => (
{ kind: 'dictionary', key, value });
}
function typeForAlternative(mod: ModuleContext, a: M.Alternative, variantName: string | undefined): Item {
if (a.label === M.$and) {
return opseq('_val', ' & ',
... variantName === void 0 ? [] : [braces(variantFor(variantName))],
...a[0].map(p => typeFor(mod, M.unname(p))));
} else {
return typeFor(mod, a, variantName);
}
export const ANY_TYPE: AtomicType = Type.ref('_val');
export const EMPTY_TYPE: AtomicType = Type.ref('never');
export function variantInitFor(variantName: string | undefined) : Item[] {
return variantName === void 0 ? [] : [variantFor(variantName)];
}
export function typeFor(mod: ModuleContext, p: M.Pattern, variantName?: string): Item {
let typeItem: Item;
if (M.isSimplePattern(p)) {
typeItem = typeForSimple(mod, p);
} else {
switch (p.label) {
case M.$setof:
typeItem = seq(`_.KeyedSet`, anglebrackets(typeForSimple(mod, p[0]), '_ptr'));
break;
case M.$dictof:
typeItem = seq(`_.KeyedDictionary`, anglebrackets(typeForSimple(mod, p[0]),
typeForSimple(mod, p[1]),
'_ptr'));
break;
default: {
const arrayType = M.simpleArray(p);
if (arrayType === void 0) {
return braces(... variantInitFor(variantName),
... typeForCompound(mod, p));
} else {
typeItem = seq('Array<', typeForSimple(mod, arrayType), '>');
break;
}
}
}
}
if (variantName === void 0) {
return typeItem;
} else {
return braces(variantFor(variantName), keyvalue('value', typeItem));
}
export function variantFor(variantName: string): Item {
return keyvalue('_variant', JSON.stringify(variantName));
}
function typeForSimple(mod: ModuleContext, p: M.SimplePattern): Item {
switch (p.label) {
case M.$atom:
switch (p[0]) {
case M.$Boolean: return `boolean`;
case M.$Float: return `_.SingleFloat`;
case M.$Double: return `_.DoubleFloat`;
case M.$SignedInteger: return `number`;
case M.$String: return `string`;
case M.$ByteString: return `_.Bytes`;
case M.$Symbol: return `symbol`;
}
case M.$pointer:
return `_ptr`;
case M.$lit:
return `(typeof ${mod.literal(p[0])})`;
case M.$ref:
return M.lookup(refPosition(p), p, mod.env,
(_p) => p[1].description!,
(p) => typeForAlternative(mod, p, void 0),
(modId, modPath,_p) => {
mod.imports.add([modId, modPath]);
return `${modId}.${p[1].description!}`;
});
export function renderVariant([variantName, t]: [string, SimpleType]): Item {
let fields: Item[];
switch (t.kind) {
case 'unit':
fields = [];
break;
case 'ref':
case 'set':
case 'dictionary':
case 'array':
fields = [keyvalue('value', renderType(t))];
break;
case 'record':
fields = Array.from(t.fields).map(([nn, tt]) => keyvalue(nn, renderType(tt)));
break;
default:
((_p: never) => {})(p);
((_: never) => {})(t);
throw new Error("Unreachable");
}
return braces(variantFor(variantName), ... fields);
}
export function renderType(t: Type): Item {
switch (t.kind) {
case 'union': return opseq('never', ' | ', ...
Array.from(t.variants).flatMap(renderVariant));
case 'unit': return 'null';
case 'ref': return t.typeName;
case 'set': return seq('_.KeyedSet', anglebrackets(
renderType(t.type),
'_ptr'));
case 'dictionary': return seq('_.KeyedDictionary', anglebrackets(
renderType(t.key),
renderType(t.value),
'_ptr'));
case 'array': return seq('Array', anglebrackets(renderType(t.type)));
case 'record': return braces(... Array.from(t.fields).map(([nn, tt]) =>
keyvalue(nn, renderType(tt))));
default:
((_: never) => {})(t);
throw new Error("Unreachable");
}
}
function typeForCompound(mod: ModuleContext, p: M.CompoundPattern): Item[] {
switch (p.label) {
case M.$rec:
return [... typeField(mod, p[0]), ... typeField(mod, p[1])];
case M.$tuple:
return p[0].flatMap(pp => typeField(mod, pp));
case M.$tuple_STAR_: {
const n = p[1];
return [... p[0].flatMap(pp => typeField(mod, pp)),
... ((n.label === M.$named)
? [keyvalue(n[0].description!,
seq('Array<', typeForSimple(mod, n[1]), '>'))]
: [])];
}
case M.$setof:
case M.$dictof:
throw new Error('Internal error: setof and dictof are handled in typeFor()');
case M.$dict:
return Array.from(p[0]).flatMap(([k, n]) => typeField(mod, M.addNameIfAbsent(n, k)));
default:
((_p: never) => {})(p);
throw new Error("Unreachable");
}
}
function typeField(mod: ModuleContext, n: M.NamedPattern): Item[] {
return (n.label === M.$named)
? [keyvalue(n[0].description!, typeForSimple(mod, n[1]))]
: (M.isCompoundPattern(n)
? typeForCompound(mod, n)
: []);
}

View File

@ -1,3 +1,2 @@
export * from './reader';
export * from './compiler';
export * from './base';

View File

@ -1,10 +1,12 @@
import { Value, is, Position, stringify } from '@preserves/core';
import { Value, is, Position } from '@preserves/core';
import * as M from './gen/schema';
import { BASE } from './base';
import { SchemaSyntaxError } from './error';
import type { AtomicType } from './compiler/type';
export * from './gen/schema';
export type Builtin = { type: AtomicType, pattern: M.Alternative };
export type Input = Value<never>;
export function isValidToken(s: string, allowLeadingUnderscore = false): boolean {
@ -42,7 +44,6 @@ export function lookup<R>(namePos: Position | null,
name: M.Ref,
env: Environment,
kLocal: (p: M.Definition) => R,
kBase: (p: M.Alternative) => R,
kOther: (modId: string, modPath: string, p: M.Definition | null) => R): R
{
for (const e of env) {
@ -65,11 +66,6 @@ export function lookup<R>(namePos: Position | null,
}
}
if (M.Ref._.module(name).length === 0) {
const p = M.Schema._._field0(BASE).get(M.$definitions).get(M.Ref._.name(name));
if (p !== void 0) return kBase(p as M.Alternative);
}
throw new SchemaSyntaxError(`Undefined reference: ${formatRef(name)}`, namePos);
}
@ -86,7 +82,7 @@ export function unname<R extends M.Pattern | M.SimplePattern>(
export function nameFor<R extends M.Pattern | M.SimplePattern>(
p: M.NamedSimplePattern_ | R): string | undefined
{
return (p.label === M.$named) ? stringify(p[0]) : void 0;
return (p.label === M.$named) ? p[0].description! : void 0;
}
export function addNameIfAbsent(p: M.NamedSimplePattern, k: Input): M.NamedSimplePattern {
@ -114,7 +110,8 @@ export function simpleArray(p: M.CompoundPattern): M.SimplePattern | undefined {
export function namelike(x: Input): string | undefined {
if (typeof x === 'string') return x;
if (typeof x === 'symbol') return stringify(x);
if (typeof x === 'symbol') return x.description!;
if (typeof x === 'number') return '' + x;
if (typeof x === 'boolean') return '' + x;
return void 0;
}

View File

@ -122,6 +122,10 @@ export function parseSchema(toplevelTokens: Array<Input>,
])]));
}
function namedMustBeSimple(p: Position | null): never {
throw new SchemaSyntaxError('Named patterns must be Simple patterns', p);
}
function parseDefinition(name: symbol, body: Array<Input>): Definition {
let nextAnonymousAlternativeNumber = 0;
function alternativeName([input, p]: readonly [Array<Input>, Alternative])
@ -138,26 +142,33 @@ function parseDefinition(name: symbol, body: Array<Input>): Definition {
return [p[1].description!, p];
}
if (p.label === M.$lit) {
switch (typeof p[0]) {
case 'symbol': return [p[0].description!, p];
case 'string': return [p[0], p];
case 'boolean':
case 'number':
return ['' + p[0], p];
default:
break;
}
const s = M.namelike(p[0]);
if (s !== void 0) return [s, p];
}
return ['_anonymous' + nextAnonymousAlternativeNumber++, p];
}
function patternName([input, p]: readonly [Array<Input>, Pattern]) : M.NamedPattern {
const n = findName(input) || findName(input[0]);
if (n !== false) {
if (!M.isSimplePattern(p)) namedMustBeSimple(position(input[0]));
return Record(M.$named, [n, p]);
}
return p;
}
// TODO: deal with situation where there's an or of ands, where
// the branches of the and arenamed. The parsing is ambiguous, and
// with the current code I think (?) you end up with the same name
// attached to the or-branch as to the leftmost and-branch.
return parseOp(body,
M.ORSYM,
p => [p, parseOp(p,
M.ANDSYM,
p => parsePattern(name, p),
ps => Record(M.$and, [ps]),
p => p as Alternative)] as const,
p => [p, parsePattern(name, p)] as const,
ps => Record(M.$and, [ps.map(patternName)]),
p => p[1] as Alternative)] as const,
ps => Record(M.$or, [ps.map(alternativeName)]),
p => p[1] as Definition);
}
@ -168,7 +179,18 @@ function parsePattern(name: symbol, body0: Array<Input>): Pattern {
const item = peel(item0);
function complain(): never { invalidPattern(stringify(name), item, pos); }
if (typeof item === 'symbol') {
return parseRef(stringify(name), pos, item);
switch (item) {
case Symbol.for('any'): return Record<typeof M.$any, []>(M.$any, []);
case Symbol.for('bool'): return Record<typeof M.$atom, [M.AtomKind]>(M.$atom, [M.$Boolean]);
case Symbol.for('float'): return Record<typeof M.$atom, [M.AtomKind]>(M.$atom, [M.$Float]);
case Symbol.for('double'): return Record<typeof M.$atom, [M.AtomKind]>(M.$atom, [M.$Double]);
case Symbol.for('int'): return Record<typeof M.$atom, [M.AtomKind]>(M.$atom, [M.$SignedInteger]);
case Symbol.for('string'): return Record<typeof M.$atom, [M.AtomKind]>(M.$atom, [M.$String]);
case Symbol.for('bytes'): return Record<typeof M.$atom, [M.AtomKind]>(M.$atom, [M.$ByteString]);
case Symbol.for('symbol'): return Record<typeof M.$atom, [M.AtomKind]>(M.$atom, [M.$Symbol]);
case Symbol.for('ref'): return Record<typeof M.$pointer, []>(M.$pointer, []);
default: return parseRef(stringify(name), pos, item);
}
} else if (Record.isRecord<Input, Tuple<Input>, never>(item)) {
const label = item.label;
if (Record.isRecord<Input, [], never>(label)) {
@ -214,9 +236,8 @@ function parsePattern(name: symbol, body0: Array<Input>): Pattern {
if (name === false) {
return recur(b);
}
return Record(M.$named, [name, parseSimple(b, () => {
throw new SchemaSyntaxError(`Named patterns must be Simple patterns`, position(b));
})]);
return Record(M.$named, [name, parseSimple(b, () =>
namedMustBeSimple(position(b)))]);
};
}
const maybeNamed = _maybeNamed(walk);