Compare commits
79 Commits
0.994.0-r2
...
main
Author | SHA1 | Date |
---|---|---|
Tony Garnock-Jones | 685302f547 | |
Tony Garnock-Jones | f83e67899e | |
Tony Garnock-Jones | f2331c0e1e | |
Tony Garnock-Jones | f628e7d31f | |
Tony Garnock-Jones | b767fa4eb0 | |
Tony Garnock-Jones | 58110e7c0c | |
Tony Garnock-Jones | 58ebc93eb5 | |
Tony Garnock-Jones | f18ba9c9d4 | |
Tony Garnock-Jones | 87ecdb7efe | |
Tony Garnock-Jones | 0533840bc0 | |
Tony Garnock-Jones | 77c16df89b | |
Tony Garnock-Jones | 35e6ba2e82 | |
Tony Garnock-Jones | 536e32b0e8 | |
Tony Garnock-Jones | 9192bdea7e | |
Tony Garnock-Jones | 19ac8d16c8 | |
Tony Garnock-Jones | 7f284a9d52 | |
Tony Garnock-Jones | cadf54b927 | |
Tony Garnock-Jones | a8b300e57d | |
Tony Garnock-Jones | 4e5e64f0a6 | |
Tony Garnock-Jones | c8ce125192 | |
Tony Garnock-Jones | c9fa9c590b | |
Tony Garnock-Jones | d568fc56ce | |
Tony Garnock-Jones | 42f4672446 | |
Tony Garnock-Jones | 1c86d8b7c5 | |
Tony Garnock-Jones | 64c1090938 | |
Tony Garnock-Jones | dc61963e16 | |
Tony Garnock-Jones | a33786e469 | |
Tony Garnock-Jones | 23ba2e5a59 | |
Tony Garnock-Jones | 7b8e0ff4b6 | |
Tony Garnock-Jones | 3f7819fafa | |
Tony Garnock-Jones | f5d76a847b | |
Tony Garnock-Jones | 443406a7d7 | |
Tony Garnock-Jones | 05103e9825 | |
Tony Garnock-Jones | 4f75d6d5a3 | |
Tony Garnock-Jones | 07b7739d00 | |
Tony Garnock-Jones | 8f3d22adf1 | |
Tony Garnock-Jones | 8222675b6b | |
Tony Garnock-Jones | fca4b3a22e | |
Tony Garnock-Jones | c5dd2d749a | |
Tony Garnock-Jones | c986ca76cf | |
Tony Garnock-Jones | 3e67c75427 | |
Tony Garnock-Jones | 6bc159e3c6 | |
Tony Garnock-Jones | 99d1acdec7 | |
Tony Garnock-Jones | 3093b89f0d | |
Tony Garnock-Jones | 00c0de40ea | |
Tony Garnock-Jones | 7657952993 | |
Tony Garnock-Jones | 9ecbd0bdd1 | |
Tony Garnock-Jones | 297e1630a8 | |
Tony Garnock-Jones | 85ca0b6c0a | |
Tony Garnock-Jones | 7c9c410a9b | |
Tony Garnock-Jones | cbbc6c50c0 | |
Tony Garnock-Jones | eb4f456550 | |
Tony Garnock-Jones | 4f4ff6e108 | |
Tony Garnock-Jones | 055a7f90e9 | |
Tony Garnock-Jones | b2f6149042 | |
Tony Garnock-Jones | 1bd4a3cdb4 | |
Tony Garnock-Jones | dc0ddf95dd | |
Tony Garnock-Jones | eeace57670 | |
Tony Garnock-Jones | 0aa39da971 | |
Tony Garnock-Jones | f0815ce4eb | |
Tony Garnock-Jones | afba8a0bff | |
Tony Garnock-Jones | d9ec3bfb14 | |
Tony Garnock-Jones | 95ac4b13df | |
Tony Garnock-Jones | 3eeee5f090 | |
Tony Garnock-Jones | aeacce22fc | |
Tony Garnock-Jones | 0726684ab5 | |
Tony Garnock-Jones | f74c4ebaf0 | |
Tony Garnock-Jones | 48a063539a | |
Tony Garnock-Jones | db96fcc95a | |
Tony Garnock-Jones | cee4a25460 | |
Tony Garnock-Jones | 7948ad4260 | |
Tony Garnock-Jones | 3d3c79e617 | |
Tony Garnock-Jones | b925b53756 | |
Tony Garnock-Jones | c0289e0a05 | |
Tony Garnock-Jones | 41189f551d | |
Tony Garnock-Jones | cc8313cf25 | |
Tony Garnock-Jones | bfbff65bb6 | |
Tony Garnock-Jones | 442a987523 | |
Tony Garnock-Jones | f45b136ef5 |
2
NOTICE
2
NOTICE
|
@ -1,2 +1,2 @@
|
|||
Preserves: an Expressive Data Language
|
||||
Copyright 2018-2022 Tony Garnock-Jones
|
||||
Copyright 2018-2024 Tony Garnock-Jones
|
||||
|
|
|
@ -88,6 +88,6 @@ Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
|||
The contents of this repository are made available to you under the
|
||||
[Apache License, version 2.0](LICENSE)
|
||||
(<http://www.apache.org/licenses/LICENSE-2.0>), and are Copyright
|
||||
2018-2022 Tony Garnock-Jones.
|
||||
2018-2024 Tony Garnock-Jones.
|
||||
|
||||
## Notes
|
||||
|
|
|
@ -13,5 +13,5 @@ defaults:
|
|||
layout: page
|
||||
|
||||
title: "Preserves"
|
||||
version_date: "February 2024"
|
||||
version: "0.994.0"
|
||||
version_date: "March 2024"
|
||||
version: "0.995.0"
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
[
|
||||
{"version":"0.994.0","title":"0.994.0","aliases":["latest"]},
|
||||
{"version":"0.995.1","title":"0.995.1","aliases":["latest"]},
|
||||
{"version":"0.995.0","title":"0.995.0","aliases":[]},
|
||||
{"version":"0.994.0","title":"0.994.0","aliases":[]},
|
||||
{"version":"0.993.0","title":"0.993.0","aliases":[]},
|
||||
{"version":"0.992.2","title":"0.992.2","aliases":[]},
|
||||
{"version":"0.992.1","title":"0.992.1","aliases":[]},
|
||||
|
|
|
@ -17,5 +17,5 @@ Trailer := (ws Annotation)*
|
|||
|
||||
Embedded := `#:` SimpleExpr
|
||||
Annotated := Annotation SimpleExpr
|
||||
Annotation := `@` SimpleExpr | `#` ((space | tab) linecomment) (cr | lf)
|
||||
Annotation := `@` SimpleExpr | `#` ((space | tab | `!`) linecomment) (cr | lf)
|
||||
```
|
||||
|
|
|
@ -20,4 +20,4 @@ The definitions of `Atom`, `ws`, and `linecomment` are as given in the Preserves
|
|||
{:.postcard-grammar.textsyntax}
|
||||
| *Embedded* | := | `#:` *SimpleExpr*
|
||||
| *Annotated* | := | *Annotation* *SimpleExpr*
|
||||
| *Annotation* | := | `@` *SimpleExpr* | `#` ((**space** | **tab**) *linecomment*) (**cr** | **lf**)
|
||||
| *Annotation* | := | `@` *SimpleExpr* | `#` ((**space** | **tab** | `!`) *linecomment*) (**cr** | **lf**)
|
||||
|
|
|
@ -11,7 +11,7 @@ commas := (ws `,`)* ws
|
|||
|
||||
Embedded := `#:` Value
|
||||
Annotated := Annotation Value
|
||||
Annotation := `@` Value | `#` ((space | tab) linecomment) (cr | lf)
|
||||
Annotation := `@` Value | `#` ((space | tab | `!`) linecomment) (cr | lf)
|
||||
|
||||
Atom := Boolean | ByteString | String | QuotedSymbol | Symbol | Number
|
||||
Boolean := `#t` | `#f`
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
{:.postcard-grammar.textsyntax}
|
||||
| *Embedded* | := | `#:`*Value* |
|
||||
| *Annotated* | := | *Annotation* *Value* |
|
||||
| *Annotation* | := | `@`*Value* |`#` ((**space** | **tab**) *linecomment*) (**cr** | **lf**) |
|
||||
| *Annotation* | := | `@`*Value* |`#` ((**space** | **tab** | `!`) *linecomment*) (**cr** | **lf**) |
|
||||
|
||||
{:.postcard-grammar.textsyntax}
|
||||
| *Atom* | := | *Boolean* | *ByteString* | *String* | *QuotedSymbol* | *Symbol* | *Number* |
|
||||
|
|
|
@ -99,6 +99,22 @@ the usual `@`-prefixed annotation notation can also be used.
|
|||
#x"0C0D0E0F"
|
||||
]
|
||||
|
||||
## Interpreter specification lines ("shebang" lines).
|
||||
|
||||
Unix systems interpret `#!` at the beginning of an executable file specially. The text
|
||||
following `#!` on the first line is interpreted as a specification for an interpreter for the
|
||||
executable file. Preserves offers special support for `#!`, reading it similarly to a comment,
|
||||
but producing an `<interpreter ...>` annotation instead of a string.
|
||||
|
||||
For example,
|
||||
|
||||
#!/usr/bin/preserves-tool convert
|
||||
[1, 2, 3]
|
||||
|
||||
is read as
|
||||
|
||||
@<interpreter "/usr/bin/preserves-tool convert"> [1, 2, 3]
|
||||
|
||||
## MIME-type tagged binary data.
|
||||
|
||||
Many internet protocols use
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
/build.python/
|
||||
/*.deb
|
|
@ -0,0 +1,10 @@
|
|||
PYTHON_PACKAGEVERSION := $(shell ../implementations/python/print-package-version)
|
||||
|
||||
all: python3-preserves_$(PYTHON_PACKAGEVERSION)_all.deb
|
||||
|
||||
python3-preserves_%_all.deb:
|
||||
./build-python-deb
|
||||
|
||||
clean:
|
||||
rm -f *.deb
|
||||
rm -rf build.*
|
|
@ -0,0 +1,37 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
PYTHON_PACKAGEVERSION=$(../implementations/python/print-package-version)
|
||||
DIRTY=
|
||||
if ! git diff-index --quiet HEAD --
|
||||
then
|
||||
DIRTY=+
|
||||
fi
|
||||
GITSUFFIX=$(git log --date=format:%Y%m%d%H%M%S --pretty=~git%cd.%h -1)
|
||||
VERSION=${PYTHON_PACKAGEVERSION}${GITSUFFIX}${DIRTY}
|
||||
|
||||
echo "Building deb for ${VERSION}"
|
||||
(cd ../implementations/python && . ./.envrc && make build-only)
|
||||
|
||||
rm -rf build.python
|
||||
mkdir build.python
|
||||
|
||||
(
|
||||
cd build.python
|
||||
tar -zxvf ../../implementations/python/dist/preserves-${PYTHON_PACKAGEVERSION}.tar.gz
|
||||
(
|
||||
cd preserves-${PYTHON_PACKAGEVERSION}
|
||||
cp -a ../../python ./debian
|
||||
cat > ./debian/changelog <<EOF
|
||||
preserves (${VERSION}) UNRELEASED; urgency=low
|
||||
|
||||
* Unofficial debian packaging of Python Preserves
|
||||
|
||||
-- Tony Garnock-Jones <tonyg@leastfixedpoint.com> $(date --rfc-email)
|
||||
EOF
|
||||
|
||||
dpkg-buildpackage
|
||||
)
|
||||
cp *.deb ..
|
||||
)
|
|
@ -0,0 +1,14 @@
|
|||
Source: preserves
|
||||
Section: python
|
||||
Priority: optional
|
||||
Maintainer: Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||
Build-Depends: debhelper-compat (= 12), python3, dh-python, pybuild-plugin-pyproject
|
||||
Standards-Version: 3.9.3
|
||||
Homepage: https://preserves.dev/
|
||||
Vcs-Git: https://gitlab.com/preserves/preserves.git
|
||||
Vcs-Browser: https://gitlab.com/preserves/preserves
|
||||
|
||||
Package: python3-preserves
|
||||
Architecture: all
|
||||
Depends: ${python3:Depends}
|
||||
Description: Python implementation of the Preserves data language
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/make -f
|
||||
#export DH_VERBOSE=1
|
||||
export PYBUILD_NAME=preserves
|
||||
|
||||
%:
|
||||
dh $@ --with python3 --buildsystem=pybuild
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@preserves/core",
|
||||
"version": "0.994.0",
|
||||
"version": "0.995.206",
|
||||
"description": "Preserves data serialization format",
|
||||
"homepage": "https://gitlab.com/preserves/preserves",
|
||||
"license": "Apache-2.0",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Tag } from "./constants";
|
||||
import { is, isAnnotated, IsPreservesAnnotated } from "./is";
|
||||
import type { GenericEmbedded } from "./embedded";
|
||||
import type { Embeddable, GenericEmbedded } from "./embedded";
|
||||
import type { Value } from "./values";
|
||||
import type { Encoder, Preservable } from "./encoder";
|
||||
import type { Writer, PreserveWritable } from "./writer";
|
||||
|
@ -52,7 +52,7 @@ export function formatPosition(p: Position | null | string): string {
|
|||
}
|
||||
}
|
||||
|
||||
export class Annotated<T = GenericEmbedded> implements Preservable<T>, PreserveWritable<T> {
|
||||
export class Annotated<T extends Embeddable = GenericEmbedded> implements Preservable<T>, PreserveWritable<T> {
|
||||
readonly annotations: Array<Value<T>>;
|
||||
readonly pos: Position | null;
|
||||
readonly item: Value<T>;
|
||||
|
@ -67,7 +67,7 @@ export class Annotated<T = GenericEmbedded> implements Preservable<T>, PreserveW
|
|||
return this;
|
||||
}
|
||||
|
||||
static __from_preserve__<T>(v: Value<T>): undefined | Annotated<T> {
|
||||
static __from_preserve__<T extends Embeddable>(v: Value<T>): undefined | Annotated<T> {
|
||||
return isAnnotated<T>(v) ? v : void 0;
|
||||
}
|
||||
|
||||
|
@ -109,21 +109,24 @@ export class Annotated<T = GenericEmbedded> implements Preservable<T>, PreserveW
|
|||
return true;
|
||||
}
|
||||
|
||||
static isAnnotated<T = GenericEmbedded>(x: any): x is Annotated<T> {
|
||||
static isAnnotated<T extends Embeddable = GenericEmbedded>(x: any): x is Annotated<T> {
|
||||
return isAnnotated(x);
|
||||
}
|
||||
}
|
||||
|
||||
export function annotate<T = GenericEmbedded>(v0: Value<T>, ...anns: Value<T>[]): Annotated<T> {
|
||||
export function annotate<T extends Embeddable = GenericEmbedded>(
|
||||
v0: Value<T>,
|
||||
...anns: Value<T>[]
|
||||
): Annotated<T> {
|
||||
const v = Annotated.isAnnotated<T>(v0) ? v0 : new Annotated(v0);
|
||||
anns.forEach((a) => v.annotations.push(a));
|
||||
return v;
|
||||
}
|
||||
|
||||
export function annotations<T = GenericEmbedded>(v: Value<T>): Array<Value<T>> {
|
||||
export function annotations<T extends Embeddable = GenericEmbedded>(v: Value<T>): Array<Value<T>> {
|
||||
return Annotated.isAnnotated<T>(v) ? v.annotations : [];
|
||||
}
|
||||
|
||||
export function position<T = GenericEmbedded>(v: Value<T>): Position | null {
|
||||
export function position<T extends Embeddable = GenericEmbedded>(v: Value<T>): Position | null {
|
||||
return Annotated.isAnnotated<T>(v) ? v.pos : null;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Tag } from './constants';
|
||||
import { GenericEmbedded } from './embedded';
|
||||
import type { Embeddable, GenericEmbedded } from './embedded';
|
||||
import { Encoder, Preservable } from './encoder';
|
||||
import { Value } from './values';
|
||||
import type { Writer, PreserveWritable } from './writer';
|
||||
|
@ -52,6 +52,18 @@ export class Bytes implements Preservable<any>, PreserveWritable<any> {
|
|||
return new Bytes(Uint8Array.of(...bytes));
|
||||
}
|
||||
|
||||
static fromLatin1(s: string): Bytes {
|
||||
// Takes codepoints in [0..255] from s, treats them as bytes.
|
||||
// Codepoints outside that range trigger an exception.
|
||||
const result = new Bytes(s.length); // assume all the codepoints are OK
|
||||
for (let i = 0; i < s.length; i++) {
|
||||
const n = s.charCodeAt(i);
|
||||
if (n >= 256) throw new Error("Codepoint out of range for 'latin1' byte encoding");
|
||||
result._view[i] = n;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static fromBase64(s: string): Bytes {
|
||||
return new Bytes(decodeBase64(s));
|
||||
}
|
||||
|
@ -136,14 +148,18 @@ export class Bytes implements Preservable<any>, PreserveWritable<any> {
|
|||
return textDecoder.decode(this._view);
|
||||
}
|
||||
|
||||
__as_preserve__<T = GenericEmbedded>(): Value<T> {
|
||||
__as_preserve__<T extends Embeddable = GenericEmbedded>(): Value<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
static __from_preserve__<T>(v: Value<T>): undefined | Bytes {
|
||||
static __from_preserve__<T extends Embeddable>(v: Value<T>): undefined | Bytes {
|
||||
return Bytes.isBytes(v) ? v : void 0;
|
||||
}
|
||||
|
||||
toLatin1(): string {
|
||||
return String.fromCharCode.apply(null, this._view as any as number[]);
|
||||
}
|
||||
|
||||
toBase64(): string {
|
||||
return encodeBase64(this._view);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import type { Compound, Value } from "./values";
|
||||
import type { GenericEmbedded } from "./embedded";
|
||||
import type { Embeddable, GenericEmbedded } from "./embedded";
|
||||
import { Dictionary, Set } from "./dictionary";
|
||||
|
||||
export function isCompound<T = GenericEmbedded>(x: Value<T>): x is Compound<T>
|
||||
export function isCompound<T extends Embeddable = GenericEmbedded>(x: Value<T>): x is Compound<T>
|
||||
{
|
||||
return (Array.isArray(x) || Set.isSet(x) || Dictionary.isDictionary(x));
|
||||
}
|
||||
|
||||
export function isSequence<T = GenericEmbedded>(x: Value<T>): x is Array<Value<T>> {
|
||||
export function isSequence<T extends Embeddable = GenericEmbedded>(x: Value<T>): x is Array<Value<T>> {
|
||||
return (Array.isArray(x) && !('label' in x));
|
||||
}
|
||||
|
|
|
@ -1,24 +1,25 @@
|
|||
import { Annotated } from "./annotated";
|
||||
import { DecodeError, ShortPacket } from "./codec";
|
||||
import { Tag } from "./constants";
|
||||
import { Set, Dictionary } from "./dictionary";
|
||||
import { Set, Dictionary, DictionaryMap } from "./dictionary";
|
||||
import { DoubleFloat } from "./float";
|
||||
import { Record } from "./record";
|
||||
import { Bytes, BytesLike, underlying, hexDigit } from "./bytes";
|
||||
import { Value } from "./values";
|
||||
import { is } from "./is";
|
||||
import { embed, GenericEmbedded, Embedded, EmbeddedTypeDecode } from "./embedded";
|
||||
import { ReaderStateOptions } from "reader";
|
||||
import { GenericEmbedded, Embeddable, EmbeddedTypeDecode } from "./embedded";
|
||||
import { ReaderStateOptions } from "./reader";
|
||||
import { stringify } from "./text";
|
||||
|
||||
export interface DecoderOptions {
|
||||
includeAnnotations?: boolean;
|
||||
}
|
||||
|
||||
export interface DecoderEmbeddedOptions<T> extends DecoderOptions {
|
||||
export interface DecoderEmbeddedOptions<T extends Embeddable> extends DecoderOptions {
|
||||
embeddedDecode?: EmbeddedTypeDecode<T>;
|
||||
}
|
||||
|
||||
export interface TypedDecoder<T> {
|
||||
export interface TypedDecoder<T extends Embeddable> {
|
||||
atEnd(): boolean;
|
||||
|
||||
mark(): any;
|
||||
|
@ -26,13 +27,13 @@ export interface TypedDecoder<T> {
|
|||
|
||||
skip(): void;
|
||||
next(): Value<T>;
|
||||
withEmbeddedDecode<S, R>(
|
||||
withEmbeddedDecode<S extends Embeddable, R>(
|
||||
embeddedDecode: EmbeddedTypeDecode<S>,
|
||||
body: (d: TypedDecoder<S>) => R): R;
|
||||
|
||||
nextBoolean(): boolean | undefined;
|
||||
nextDouble(): DoubleFloat | undefined;
|
||||
nextEmbedded(): Embedded<T> | undefined;
|
||||
nextEmbedded(): T | undefined;
|
||||
nextSignedInteger(): number | bigint | undefined;
|
||||
nextString(): string | undefined;
|
||||
nextByteString(): Bytes | undefined;
|
||||
|
@ -46,7 +47,7 @@ export interface TypedDecoder<T> {
|
|||
closeCompound(): boolean;
|
||||
}
|
||||
|
||||
export function asLiteral<T, E extends Exclude<Value<T>, Annotated<T>>>(
|
||||
export function asLiteral<T extends Embeddable, E extends Exclude<Value<T>, Annotated<T>>>(
|
||||
actual: Value<T>,
|
||||
expected: E): E | undefined
|
||||
{
|
||||
|
@ -165,11 +166,11 @@ export class DecoderState {
|
|||
}
|
||||
}
|
||||
|
||||
wrap<T>(v: Value<T>): Value<T> {
|
||||
wrap<T extends Embeddable>(v: Value<T>): Value<T> {
|
||||
return this.includeAnnotations ? new Annotated(v) : v;
|
||||
}
|
||||
|
||||
unshiftAnnotation<T>(a: Value<T>, v: Annotated<T>): Annotated<T> {
|
||||
unshiftAnnotation<T extends Embeddable>(a: Value<T>, v: Annotated<T>): Annotated<T> {
|
||||
if (this.includeAnnotations) {
|
||||
v.annotations.unshift(a);
|
||||
}
|
||||
|
@ -187,7 +188,7 @@ export const neverEmbeddedTypeDecode: EmbeddedTypeDecode<never> = {
|
|||
},
|
||||
};
|
||||
|
||||
export class Decoder<T = never> implements TypedDecoder<T> {
|
||||
export class Decoder<T extends Embeddable = never> implements TypedDecoder<T> {
|
||||
state: DecoderState;
|
||||
embeddedDecode: EmbeddedTypeDecode<T>;
|
||||
|
||||
|
@ -217,13 +218,14 @@ export class Decoder<T = never> implements TypedDecoder<T> {
|
|||
return result;
|
||||
}
|
||||
|
||||
static dictionaryFromArray<T>(vs: Value<T>[]): Dictionary<T> {
|
||||
const d = new Dictionary<T>();
|
||||
static dictionaryFromArray<T extends Embeddable>(vs: Value<T>[]): Dictionary<T> {
|
||||
const d = new DictionaryMap<T>();
|
||||
if (vs.length % 2) throw new DecodeError("Missing dictionary value");
|
||||
for (let i = 0; i < vs.length; i += 2) {
|
||||
if (d.has(vs[i])) throw new DecodeError(`Duplicate key: ${stringify(vs[i])}`);
|
||||
d.set(vs[i], vs[i+1]);
|
||||
}
|
||||
return d;
|
||||
return d.simplifiedValue();
|
||||
}
|
||||
|
||||
next(): Value<T> {
|
||||
|
@ -237,7 +239,7 @@ export class Decoder<T = never> implements TypedDecoder<T> {
|
|||
const v = this.next() as Annotated<T>;
|
||||
return this.state.unshiftAnnotation(a, v);
|
||||
}
|
||||
case Tag.Embedded: return this.state.wrap<T>(embed(this.embeddedDecode.decode(this.state)));
|
||||
case Tag.Embedded: return this.state.wrap<T>(this.embeddedDecode.decode(this.state));
|
||||
case Tag.Ieee754:
|
||||
switch (this.state.varint()) {
|
||||
case 8: return this.state.wrap<T>(DoubleFloat.fromBytes(this.state.nextbytes(8)));
|
||||
|
@ -253,7 +255,14 @@ export class Decoder<T = never> implements TypedDecoder<T> {
|
|||
return this.state.wrap<T>(Record(vs[0], vs.slice(1)));
|
||||
}
|
||||
case Tag.Sequence: return this.state.wrap<T>(this.nextvalues());
|
||||
case Tag.Set: return this.state.wrap<T>(new Set(this.nextvalues()));
|
||||
case Tag.Set: {
|
||||
const s = new Set<T>();
|
||||
for (const v of this.nextvalues()) {
|
||||
if (s.has(v)) throw new DecodeError(`Duplicate value: ${stringify(v)}`);
|
||||
s.add(v);
|
||||
}
|
||||
return this.state.wrap<T>(s);
|
||||
}
|
||||
case Tag.Dictionary: return this.state.wrap<T>(Decoder.dictionaryFromArray(this.nextvalues()));
|
||||
default: throw new DecodeError("Unsupported Preserves tag: " + tag);
|
||||
}
|
||||
|
@ -280,7 +289,7 @@ export class Decoder<T = never> implements TypedDecoder<T> {
|
|||
this.next();
|
||||
}
|
||||
|
||||
withEmbeddedDecode<S, R>(
|
||||
withEmbeddedDecode<S extends Embeddable, R>(
|
||||
embeddedDecode: EmbeddedTypeDecode<S>,
|
||||
body: (d: TypedDecoder<S>) => R): R
|
||||
{
|
||||
|
@ -314,10 +323,10 @@ export class Decoder<T = never> implements TypedDecoder<T> {
|
|||
});
|
||||
}
|
||||
|
||||
nextEmbedded(): Embedded<T> | undefined {
|
||||
nextEmbedded(): T | undefined {
|
||||
return this.skipAnnotations((reset) => {
|
||||
switch (this.state.nextbyte()) {
|
||||
case Tag.Embedded: return embed(this.embeddedDecode.decode(this.state));
|
||||
case Tag.Embedded: return this.embeddedDecode.decode(this.state);
|
||||
default: return reset();
|
||||
}
|
||||
});
|
||||
|
@ -386,11 +395,16 @@ export class Decoder<T = never> implements TypedDecoder<T> {
|
|||
}
|
||||
}
|
||||
|
||||
export function decode<T>(bs: BytesLike, options: DecoderEmbeddedOptions<T> = {}): Value<T> {
|
||||
export function decode<T extends Embeddable>(
|
||||
bs: BytesLike,
|
||||
options: DecoderEmbeddedOptions<T> = {},
|
||||
): Value<T> {
|
||||
return new Decoder(bs, options).next();
|
||||
}
|
||||
|
||||
export function decodeWithAnnotations<T>(bs: BytesLike,
|
||||
options: DecoderEmbeddedOptions<T> = {}): Annotated<T> {
|
||||
export function decodeWithAnnotations<T extends Embeddable>(
|
||||
bs: BytesLike,
|
||||
options: DecoderEmbeddedOptions<T> = {},
|
||||
): Annotated<T> {
|
||||
return decode(bs, { ... options, includeAnnotations: true }) as Annotated<T>;
|
||||
}
|
||||
|
|
|
@ -1,19 +1,22 @@
|
|||
import { Encoder, canonicalString } from "./encoder";
|
||||
import { Tag } from "./constants";
|
||||
import { FlexMap, FlexSet, _iterMap, IdentitySet } from "./flex";
|
||||
import { FlexMap, FlexSet, _iterMap, IdentitySet, Equivalence, IsMap } from "./flex";
|
||||
import { Value } from "./values";
|
||||
import { Bytes } from './bytes';
|
||||
import { GenericEmbedded } from "./embedded";
|
||||
import { Embeddable, GenericEmbedded, isEmbedded } from "./embedded";
|
||||
import type { Preservable } from "./encoder";
|
||||
import type { Writer, PreserveWritable } from "./writer";
|
||||
import { annotations, Annotated } from "./annotated";
|
||||
import { Float } from "./float";
|
||||
import { JsDictionary } from "./jsdictionary";
|
||||
import { unannotate } from "./strip";
|
||||
|
||||
export type DictionaryType = 'Dictionary' | 'Set';
|
||||
export const DictionaryType = Symbol.for('DictionaryType');
|
||||
|
||||
export type CompoundKey<T> = Value<T> | (Preservable<T> & PreserveWritable<T>);
|
||||
export type CompoundKey<T extends Embeddable> = Value<T> | (Preservable<T> & PreserveWritable<T>);
|
||||
|
||||
export class EncodableDictionary<K, V, T = GenericEmbedded> extends FlexMap<K, V>
|
||||
export class EncodableDictionary<T extends Embeddable, K, V> extends FlexMap<K, V>
|
||||
implements Preservable<T>, PreserveWritable<T>
|
||||
{
|
||||
constructor(
|
||||
|
@ -39,16 +42,16 @@ export class EncodableDictionary<K, V, T = GenericEmbedded> extends FlexMap<K, V
|
|||
}
|
||||
}
|
||||
|
||||
export class KeyedDictionary<K extends CompoundKey<T>, V, T = GenericEmbedded>
|
||||
extends EncodableDictionary<K, V, T>
|
||||
export class KeyedDictionary<T extends Embeddable = GenericEmbedded, K extends CompoundKey<T> = Value<T>, V = Value<T>>
|
||||
extends EncodableDictionary<T, K, V>
|
||||
{
|
||||
get [DictionaryType](): DictionaryType {
|
||||
return 'Dictionary';
|
||||
}
|
||||
|
||||
static isKeyedDictionary<K extends CompoundKey<T>, V, T = GenericEmbedded>(
|
||||
static isKeyedDictionary<T extends Embeddable = GenericEmbedded, K extends CompoundKey<T> = Value<T>, V = Value<T>>(
|
||||
x: any,
|
||||
): x is KeyedDictionary<K, V, T> {
|
||||
): x is KeyedDictionary<T, K, V> {
|
||||
return x?.[DictionaryType] === 'Dictionary';
|
||||
}
|
||||
|
||||
|
@ -58,33 +61,204 @@ export class KeyedDictionary<K extends CompoundKey<T>, V, T = GenericEmbedded>
|
|||
super(k => k, v => v as CompoundKey<T>, items);
|
||||
}
|
||||
|
||||
mapEntries<W, S extends Value<R>, R = GenericEmbedded>(f: (entry: [K, V]) => [S, W]): KeyedDictionary<S, W, R> {
|
||||
const result = new KeyedDictionary<S, W, R>();
|
||||
for (let oldEntry of this.entries()) {
|
||||
const newEntry = f(oldEntry);
|
||||
result.set(newEntry[0], newEntry[1])
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
clone(): KeyedDictionary<K, V, T> {
|
||||
clone(): KeyedDictionary<T, K, V> {
|
||||
return new KeyedDictionary(this);
|
||||
}
|
||||
|
||||
get [Symbol.toStringTag]() { return 'Dictionary'; }
|
||||
|
||||
equals(otherAny: any, eqv: Equivalence<V> = (v1, v2) => v1 === v2): boolean {
|
||||
const otherMap = Dictionary.asMap(otherAny);
|
||||
if (!otherMap) return false;
|
||||
return super.equals(otherMap, eqv);
|
||||
}
|
||||
}
|
||||
|
||||
export class Dictionary<T = GenericEmbedded, V = Value<T>> extends KeyedDictionary<Value<T>, V, T> {
|
||||
static isDictionary<T = GenericEmbedded, V = Value<T>>(x: any): x is Dictionary<T, V> {
|
||||
return x?.[DictionaryType] === 'Dictionary';
|
||||
export type Dictionary<T extends Embeddable = GenericEmbedded, V = Value<T>> =
|
||||
JsDictionary<V> | KeyedDictionary<T, Value<T>, V>;
|
||||
|
||||
export class DictionaryMap<T extends Embeddable = GenericEmbedded, V = Value<T>> implements Map<Value<T>, V> {
|
||||
get [IsMap](): boolean { return true; }
|
||||
|
||||
j: JsDictionary<V> | undefined;
|
||||
k: KeyedDictionary<T, Value<T>, V> | undefined;
|
||||
|
||||
constructor(input?: Dictionary<T, V>) {
|
||||
if (input === void 0) {
|
||||
this.j = {};
|
||||
this.k = void 0;
|
||||
} else if (DictionaryType in input) {
|
||||
this.j = void 0;
|
||||
this.k = input;
|
||||
} else {
|
||||
this.j = input;
|
||||
this.k = void 0;
|
||||
}
|
||||
}
|
||||
|
||||
static __from_preserve__<T>(v: Value<T>): undefined | Dictionary<T> {
|
||||
static from<T extends Embeddable = GenericEmbedded, V = Value<T>>(
|
||||
entries: [Value<T>, V][] | Iterable<[Value<T>, V]>,
|
||||
): DictionaryMap<T, V> {
|
||||
const r = new DictionaryMap<T, V>();
|
||||
for (const [key, value] of entries) r.set(key, value);
|
||||
return r;
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
if (this.j) {
|
||||
JsDictionary.clear(this.j);
|
||||
} else {
|
||||
this.k!.clear();
|
||||
}
|
||||
}
|
||||
|
||||
delete(key: Value<T>): boolean {
|
||||
if (this.j) {
|
||||
key = unannotate(key);
|
||||
if (typeof key !== 'symbol') return false;
|
||||
return JsDictionary.remove(this.j, key);
|
||||
} else {
|
||||
return this.k!.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
forEach(callbackfn: (value: V, key: Value<T>, map: Map<Value<T>, V>) => void, thisArg?: any): void {
|
||||
if (this.j) {
|
||||
JsDictionary.forEach(this.j, (v, k) => callbackfn.call(thisArg, v, k, this));
|
||||
} else {
|
||||
this.k!.forEach(callbackfn, thisArg);
|
||||
}
|
||||
}
|
||||
|
||||
get(key: Value<T>): V | undefined {
|
||||
if (this.j) {
|
||||
key = unannotate(key);
|
||||
if (typeof key !== 'symbol') return void 0;
|
||||
return JsDictionary.get(this.j, key);
|
||||
} else {
|
||||
return this.k!.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
has(key: Value<T>): boolean {
|
||||
if (this.j) {
|
||||
key = unannotate(key);
|
||||
if (typeof key !== 'symbol') return false;
|
||||
return JsDictionary.has(this.j, key);
|
||||
} else {
|
||||
return this.k!.has(key);
|
||||
}
|
||||
}
|
||||
|
||||
set(key: Value<T>, value: V): this {
|
||||
if (this.j) {
|
||||
if (typeof key === 'symbol') {
|
||||
JsDictionary.set(this.j, key, value);
|
||||
return this;
|
||||
}
|
||||
this.k = new KeyedDictionary<T, Value<T>, V>(JsDictionary.entries(this.j));
|
||||
this.j = void 0;
|
||||
}
|
||||
this.k!.set(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
get size(): number {
|
||||
return this.j ? JsDictionary.size(this.j) : this.k!.size;
|
||||
}
|
||||
|
||||
entries(): IterableIterator<[Value<T>, V]> {
|
||||
return this.j ? JsDictionary.entries(this.j) : this.k!.entries();
|
||||
}
|
||||
|
||||
keys(): IterableIterator<Value<T>> {
|
||||
return this.j ? JsDictionary.keys(this.j) : this.k!.keys();
|
||||
}
|
||||
|
||||
values(): IterableIterator<V> {
|
||||
return this.j ? JsDictionary.values(this.j) : this.k!.values();
|
||||
}
|
||||
|
||||
[Symbol.iterator](): IterableIterator<[Value<T>, V]> {
|
||||
return this.entries();
|
||||
}
|
||||
|
||||
get [Symbol.toStringTag](): string {
|
||||
return 'DictionaryMap';
|
||||
}
|
||||
|
||||
clone(): DictionaryMap<T, V> {
|
||||
return new DictionaryMap<T, V>(this.j ? JsDictionary.clone(this.j) : this.k!.clone());
|
||||
}
|
||||
|
||||
get value(): Dictionary<T, V> {
|
||||
return this.j ?? this.k!;
|
||||
}
|
||||
|
||||
simplify(): void {
|
||||
if (!this.j) {
|
||||
const r: JsDictionary<V> = {};
|
||||
for (const [key, value] of this.k!.entries()) {
|
||||
if (typeof key !== 'symbol') return;
|
||||
r[key.description!] = value;
|
||||
}
|
||||
this.j = r;
|
||||
this.k = void 0;
|
||||
}
|
||||
}
|
||||
|
||||
simplifiedValue(): Dictionary<T, V> {
|
||||
this.simplify();
|
||||
return this.value;
|
||||
}
|
||||
|
||||
asJsDictionary(): JsDictionary<V> {
|
||||
this.simplify();
|
||||
if (!this.j) throw new Error("Cannot represent general dictionary as JsDictionary");
|
||||
return this.j;
|
||||
}
|
||||
|
||||
asKeyedDictionary(): KeyedDictionary<T, Value<T>, V> {
|
||||
return this.k ?? new KeyedDictionary<T, Value<T>, V>(JsDictionary.entries(this.j!));
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Dictionary {
|
||||
export function isDictionary<T extends Embeddable = GenericEmbedded, V = Value<T>>(
|
||||
x: any
|
||||
): x is Dictionary<T, V> {
|
||||
if (typeof x !== 'object' || x === null) return false;
|
||||
switch (x[DictionaryType]) {
|
||||
case 'Dictionary': return true;
|
||||
case void 0: return JsDictionary.isJsDictionary(x);
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function asMap<T extends Embeddable = GenericEmbedded, V = Value<T>>(
|
||||
x: Dictionary<T, V>
|
||||
): DictionaryMap<T, V>;
|
||||
export function asMap<T extends Embeddable = GenericEmbedded, V = Value<T>>(
|
||||
x: any
|
||||
): DictionaryMap<T, V> | undefined;
|
||||
export function asMap<T extends Embeddable = GenericEmbedded, V = Value<T>>(
|
||||
x: any
|
||||
): DictionaryMap<T, V> | undefined {
|
||||
return isDictionary<T, V>(x) ? new DictionaryMap(x) : void 0;
|
||||
}
|
||||
|
||||
export function from<T extends Embeddable = GenericEmbedded, V = Value<T>>(
|
||||
entries: [Value<T>, V][] | Iterable<[Value<T>, V]>,
|
||||
): Dictionary<T, V> {
|
||||
return DictionaryMap.from(entries).simplifiedValue();
|
||||
}
|
||||
|
||||
export function __from_preserve__<T extends Embeddable>(v: Value<T>): undefined | Dictionary<T> {
|
||||
return Dictionary.isDictionary<T>(v) ? v : void 0;
|
||||
}
|
||||
}
|
||||
|
||||
export function encodeDictionaryOn<K, V, T>(
|
||||
export function encodeDictionaryOn<T extends Embeddable, K, V>(
|
||||
dict: Map<K, V>,
|
||||
encoder: Encoder<T>,
|
||||
encodeK: (k: K, encoder: Encoder<T>) => void,
|
||||
|
@ -114,7 +288,7 @@ export function encodeDictionaryOn<K, V, T>(
|
|||
}
|
||||
}
|
||||
|
||||
export function writeDictionaryOn<K, V, T>(
|
||||
export function writeDictionaryOn<T extends Embeddable, K, V>(
|
||||
dict: Map<K, V>,
|
||||
w: Writer<T>,
|
||||
writeK: (k: K, w: Writer<T>) => void,
|
||||
|
@ -135,7 +309,7 @@ export function writeDictionaryOn<K, V, T>(
|
|||
});
|
||||
}
|
||||
|
||||
export class EncodableSet<V, T = GenericEmbedded> extends FlexSet<V>
|
||||
export class EncodableSet<T extends Embeddable, V> extends FlexSet<V>
|
||||
implements Preservable<T>, PreserveWritable<T>
|
||||
{
|
||||
constructor(
|
||||
|
@ -154,16 +328,16 @@ export class EncodableSet<V, T = GenericEmbedded> extends FlexSet<V>
|
|||
}
|
||||
}
|
||||
|
||||
export class KeyedSet<K extends CompoundKey<T>, T = GenericEmbedded>
|
||||
extends EncodableSet<K, T>
|
||||
export class KeyedSet<T extends Embeddable = GenericEmbedded, K extends CompoundKey<T> = Value<T>>
|
||||
extends EncodableSet<T, K>
|
||||
{
|
||||
get [DictionaryType](): DictionaryType {
|
||||
return 'Set';
|
||||
}
|
||||
|
||||
static isKeyedSet<K extends CompoundKey<T>, T = GenericEmbedded>(
|
||||
static isKeyedSet<T extends Embeddable = GenericEmbedded, K extends CompoundKey<T> = Value<T>>(
|
||||
x: any,
|
||||
): x is KeyedSet<K, T> {
|
||||
): x is KeyedSet<T, K> {
|
||||
return x?.[DictionaryType] === 'Set';
|
||||
}
|
||||
|
||||
|
@ -171,34 +345,36 @@ export class KeyedSet<K extends CompoundKey<T>, T = GenericEmbedded>
|
|||
super(k => k, items);
|
||||
}
|
||||
|
||||
map<S extends Value<R>, R = GenericEmbedded>(f: (value: K) => S): KeyedSet<S, R> {
|
||||
map<R extends Embeddable = GenericEmbedded, S extends Value<R> = Value<R>>(
|
||||
f: (value: K) => S,
|
||||
): KeyedSet<R, S> {
|
||||
return new KeyedSet(_iterMap(this[Symbol.iterator](), f));
|
||||
}
|
||||
|
||||
filter(f: (value: K) => boolean): KeyedSet<K, T> {
|
||||
const result = new KeyedSet<K, T>();
|
||||
filter(f: (value: K) => boolean): KeyedSet<T, K> {
|
||||
const result = new KeyedSet<T, K>();
|
||||
for (let k of this) if (f(k)) result.add(k);
|
||||
return result;
|
||||
}
|
||||
|
||||
clone(): KeyedSet<K, T> {
|
||||
clone(): KeyedSet<T, K> {
|
||||
return new KeyedSet(this);
|
||||
}
|
||||
|
||||
get [Symbol.toStringTag]() { return 'Set'; }
|
||||
}
|
||||
|
||||
export class Set<T = GenericEmbedded> extends KeyedSet<Value<T>, T> {
|
||||
static isSet<T = GenericEmbedded>(x: any): x is Set<T> {
|
||||
export class Set<T extends Embeddable = GenericEmbedded> extends KeyedSet<T> {
|
||||
static isSet<T extends Embeddable = GenericEmbedded>(x: any): x is Set<T> {
|
||||
return x?.[DictionaryType] === 'Set';
|
||||
}
|
||||
|
||||
static __from_preserve__<T>(v: Value<T>): undefined | Set<T> {
|
||||
static __from_preserve__<T extends Embeddable>(v: Value<T>): undefined | Set<T> {
|
||||
return Set.isSet<T>(v) ? v : void 0;
|
||||
}
|
||||
}
|
||||
|
||||
export function encodeSetOn<V, T>(
|
||||
export function encodeSetOn<T extends Embeddable, V>(
|
||||
s: IdentitySet<V>,
|
||||
encoder: Encoder<T>,
|
||||
encodeV: (v: V, encoder: Encoder<T>) => void,
|
||||
|
@ -219,7 +395,7 @@ export function encodeSetOn<V, T>(
|
|||
}
|
||||
}
|
||||
|
||||
export function writeSetOn<V, T>(
|
||||
export function writeSetOn<T extends Embeddable, V>(
|
||||
s: IdentitySet<V>,
|
||||
w: Writer<T>,
|
||||
writeV: (v: V, w: Writer<T>) => void,
|
||||
|
|
|
@ -3,7 +3,17 @@ import type { EncoderState } from "./encoder";
|
|||
import type { Value } from "./values";
|
||||
import { ReaderStateOptions } from "./reader";
|
||||
|
||||
export type EmbeddedTypeEncode<T> = {
|
||||
export const IsEmbedded = Symbol.for('IsEmbedded');
|
||||
|
||||
export interface Embeddable {
|
||||
readonly [IsEmbedded]: true;
|
||||
}
|
||||
|
||||
export function isEmbedded<T extends Embeddable>(v: any): v is T {
|
||||
return !!v?.[IsEmbedded];
|
||||
}
|
||||
|
||||
export type EmbeddedTypeEncode<T extends Embeddable> = {
|
||||
encode(s: EncoderState, v: T): void;
|
||||
}
|
||||
|
||||
|
@ -12,46 +22,22 @@ export type EmbeddedTypeDecode<T> = {
|
|||
fromValue(v: Value<GenericEmbedded>, options: ReaderStateOptions): T;
|
||||
}
|
||||
|
||||
export type EmbeddedType<T> = EmbeddedTypeEncode<T> & EmbeddedTypeDecode<T>;
|
||||
export type EmbeddedType<T extends Embeddable> = EmbeddedTypeEncode<T> & EmbeddedTypeDecode<T>;
|
||||
|
||||
export class Embedded<T> {
|
||||
embeddedValue: T;
|
||||
get [IsEmbedded](): true { return true; }
|
||||
|
||||
constructor(embeddedValue: T) {
|
||||
this.embeddedValue = embeddedValue;
|
||||
constructor(public readonly value: T) {}
|
||||
|
||||
equals(other: any): boolean {
|
||||
return typeof other === 'object' && 'value' in other && Object.is(this.value, other.value);
|
||||
}
|
||||
|
||||
equals(other: any, is: (a: any, b: any) => boolean) {
|
||||
return isEmbedded<T>(other) && is(this.embeddedValue, other.embeddedValue);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return '#:' + (this.embeddedValue as any).toString();
|
||||
}
|
||||
|
||||
__as_preserve__<R>(): T extends R ? Value<R> : never {
|
||||
return this as any;
|
||||
}
|
||||
|
||||
static __from_preserve__<T>(v: Value<T>): undefined | Embedded<T> {
|
||||
return isEmbedded<T>(v) ? v : void 0;
|
||||
}
|
||||
}
|
||||
|
||||
export function embed<T>(embeddedValue: T): Embedded<T> {
|
||||
return new Embedded(embeddedValue);
|
||||
}
|
||||
|
||||
export function isEmbedded<T>(v: Value<T>): v is Embedded<T> {
|
||||
return typeof v === 'object' && 'embeddedValue' in v;
|
||||
}
|
||||
|
||||
export class GenericEmbedded {
|
||||
generic: Value;
|
||||
get [IsEmbedded](): true { return true; }
|
||||
|
||||
constructor(generic: Value) {
|
||||
this.generic = generic;
|
||||
}
|
||||
constructor(public readonly generic: Value) {}
|
||||
|
||||
equals(other: any, is: (a: any, b: any) => boolean) {
|
||||
return typeof other === 'object' && 'generic' in other && is(this.generic, other.generic);
|
||||
|
|
|
@ -3,17 +3,18 @@ import { Bytes, unhexDigit } from "./bytes";
|
|||
import { Value } from "./values";
|
||||
import { EncodeError } from "./codec";
|
||||
import { Record, Tuple } from "./record";
|
||||
import { EmbeddedTypeEncode } from "./embedded";
|
||||
import type { Embedded } from "./embedded";
|
||||
import { EmbeddedTypeEncode, isEmbedded } from "./embedded";
|
||||
import type { Embeddable } from "./embedded";
|
||||
import { DictionaryMap, encodeDictionaryOn } from "./dictionary";
|
||||
|
||||
export type Encodable<T> =
|
||||
export type Encodable<T extends Embeddable> =
|
||||
Value<T> | Preservable<T> | Iterable<Value<T>> | ArrayBufferView;
|
||||
|
||||
export interface Preservable<T> {
|
||||
export interface Preservable<T extends Embeddable> {
|
||||
__preserve_on__(encoder: Encoder<T>): void;
|
||||
}
|
||||
|
||||
export function isPreservable<T>(v: any): v is Preservable<T> {
|
||||
export function isPreservable<T extends Embeddable>(v: any): v is Preservable<T> {
|
||||
return typeof v === 'object' && v !== null && '__preserve_on__' in v && typeof v.__preserve_on__ === 'function';
|
||||
}
|
||||
|
||||
|
@ -22,11 +23,11 @@ export interface EncoderOptions {
|
|||
includeAnnotations?: boolean;
|
||||
}
|
||||
|
||||
export interface EncoderEmbeddedOptions<T> extends EncoderOptions {
|
||||
export interface EncoderEmbeddedOptions<T extends Embeddable> extends EncoderOptions {
|
||||
embeddedEncode?: EmbeddedTypeEncode<T>;
|
||||
}
|
||||
|
||||
export function asLatin1(bs: Uint8Array): string {
|
||||
function asLatin1(bs: Uint8Array): string {
|
||||
return String.fromCharCode.apply(null, bs as any as number[]);
|
||||
}
|
||||
|
||||
|
@ -199,7 +200,7 @@ export class EncoderState {
|
|||
}
|
||||
}
|
||||
|
||||
export class Encoder<T = object> {
|
||||
export class Encoder<T extends Embeddable> {
|
||||
state: EncoderState;
|
||||
embeddedEncode: EmbeddedTypeEncode<T>;
|
||||
|
||||
|
@ -218,7 +219,7 @@ export class Encoder<T = object> {
|
|||
}
|
||||
}
|
||||
|
||||
withEmbeddedEncode<S>(
|
||||
withEmbeddedEncode<S extends Embeddable>(
|
||||
embeddedEncode: EmbeddedTypeEncode<S>,
|
||||
body: (e: Encoder<S>) => void): this
|
||||
{
|
||||
|
@ -249,7 +250,7 @@ export class Encoder<T = object> {
|
|||
}
|
||||
|
||||
push(v: Encodable<T>) {
|
||||
if (isPreservable<unknown>(v)) {
|
||||
if (isPreservable<any>(v)) {
|
||||
v.__preserve_on__(this);
|
||||
}
|
||||
else if (isPreservable<T>(v)) {
|
||||
|
@ -288,17 +289,21 @@ export class Encoder<T = object> {
|
|||
for (let i of v) this.push(i);
|
||||
});
|
||||
}
|
||||
else if (isEmbedded<T>(v)) {
|
||||
this.state.emitbyte(Tag.Embedded);
|
||||
this.embeddedEncode.encode(this.state, v);
|
||||
}
|
||||
else {
|
||||
((v: Embedded<T>) => {
|
||||
this.state.emitbyte(Tag.Embedded);
|
||||
this.embeddedEncode.encode(this.state, v.embeddedValue);
|
||||
})(v);
|
||||
encodeDictionaryOn(new DictionaryMap<T>(v),
|
||||
this,
|
||||
(k, e) => e.push(k),
|
||||
(v, e) => e.push(v));
|
||||
}
|
||||
return this; // for chaining
|
||||
}
|
||||
}
|
||||
|
||||
export function encode<T>(
|
||||
export function encode<T extends Embeddable>(
|
||||
v: Encodable<T>,
|
||||
options: EncoderEmbeddedOptions<T> = {}): Bytes
|
||||
{
|
||||
|
@ -332,7 +337,9 @@ export function canonicalString(v: Encodable<any>): string {
|
|||
}
|
||||
}
|
||||
|
||||
export function encodeWithAnnotations<T>(v: Encodable<T>,
|
||||
options: EncoderEmbeddedOptions<T> = {}): Bytes {
|
||||
export function encodeWithAnnotations<T extends Embeddable>(
|
||||
v: Encodable<T>,
|
||||
options: EncoderEmbeddedOptions<T> = {},
|
||||
): Bytes {
|
||||
return encode(v, { ... options, includeAnnotations: true });
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Tag } from "./constants";
|
||||
import { Value } from "./values";
|
||||
import type { GenericEmbedded } from "./embedded";
|
||||
import type { Embeddable, GenericEmbedded } from "./embedded";
|
||||
import type { Encoder, Preservable } from "./encoder";
|
||||
import type { Writer, PreserveWritable } from "./writer";
|
||||
import { Bytes, dataview } from "./bytes";
|
||||
|
@ -93,7 +93,7 @@ export function floatlikeString(f: number): string {
|
|||
// }
|
||||
|
||||
export class DoubleFloat extends Float implements Preservable<any>, PreserveWritable<any> {
|
||||
__as_preserve__<T = GenericEmbedded>(): Value<T> {
|
||||
__as_preserve__<T extends Embeddable = GenericEmbedded>(): Value<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,7 @@ export class DoubleFloat extends Float implements Preservable<any>, PreserveWrit
|
|||
return new DoubleFloat(dataview(bs).getFloat64(0, false));
|
||||
}
|
||||
|
||||
static __from_preserve__<T>(v: Value<T>): undefined | DoubleFloat {
|
||||
static __from_preserve__<T extends Embeddable>(v: Value<T>): undefined | DoubleFloat {
|
||||
return Float.isDouble(v) ? v : void 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { Record, Tuple } from "./record";
|
||||
import { Bytes } from "./bytes";
|
||||
import { Value } from "./values";
|
||||
import { Set, Dictionary } from "./dictionary";
|
||||
import { Set, KeyedDictionary, Dictionary, DictionaryMap } from "./dictionary";
|
||||
import { annotate, Annotated } from "./annotated";
|
||||
import { Double, Float } from "./float";
|
||||
import { Embedded } from "./embedded";
|
||||
import { Embeddable, isEmbedded } from "./embedded";
|
||||
|
||||
export enum ValueClass {
|
||||
Boolean,
|
||||
|
@ -21,9 +21,9 @@ export enum ValueClass {
|
|||
Annotated, // quasi-class
|
||||
}
|
||||
|
||||
export type Fold<T, R = Value<T>> = (v: Value<T>) => R;
|
||||
export type Fold<T extends Embeddable, R = Value<T>> = (v: Value<T>) => R;
|
||||
|
||||
export interface FoldMethods<T, R> {
|
||||
export interface FoldMethods<T extends Embeddable, R> {
|
||||
boolean(b: boolean): R;
|
||||
double(f: number): R;
|
||||
integer(i: number | bigint): R;
|
||||
|
@ -34,39 +34,39 @@ export interface FoldMethods<T, R> {
|
|||
record(r: Record<Value<T>, Tuple<Value<T>>, T>, k: Fold<T, R>): R;
|
||||
array(a: Array<Value<T>>, k: Fold<T, R>): R;
|
||||
set(s: Set<T>, k: Fold<T, R>): R;
|
||||
dictionary(d: Dictionary<T>, k: Fold<T, R>): R;
|
||||
dictionary(d: DictionaryMap<T>, k: Fold<T, R>): R;
|
||||
|
||||
annotated(a: Annotated<T>, k: Fold<T, R>): R;
|
||||
|
||||
embedded(t: Embedded<T>, k: Fold<T, R>): R;
|
||||
embedded(t: T, k: Fold<T, R>): R;
|
||||
}
|
||||
|
||||
export class VoidFold<T> implements FoldMethods<T, void> {
|
||||
boolean(b: boolean): void {}
|
||||
double(f: number): void {}
|
||||
integer(i: number | bigint): void {}
|
||||
string(s: string): void {}
|
||||
bytes(b: Bytes): void {}
|
||||
symbol(s: symbol): void {}
|
||||
export class VoidFold<T extends Embeddable> implements FoldMethods<T, void> {
|
||||
boolean(_b: boolean): void {}
|
||||
double(_f: number): void {}
|
||||
integer(_i: number | bigint): void {}
|
||||
string(_s: string): void {}
|
||||
bytes(_b: Bytes): void {}
|
||||
symbol(_s: symbol): void {}
|
||||
record(r: Record<Value<T>, Tuple<Value<T>>, T>, k: Fold<T, void>): void {
|
||||
k(r.label);
|
||||
r.forEach(k);
|
||||
}
|
||||
array(a: Value<T>[], k: Fold<T, void>): void { a.forEach(k); }
|
||||
set(s: Set<T>, k: Fold<T, void>): void { s.forEach(k); }
|
||||
dictionary(d: Dictionary<T>, k: Fold<T, void>): void {
|
||||
dictionary(d: DictionaryMap<T>, k: Fold<T, void>): void {
|
||||
d.forEach((value, key) => { k(key); k(value); });
|
||||
}
|
||||
annotated(a: Annotated<T>, k: Fold<T, void>): void { k(a.item); a.annotations.forEach(k); }
|
||||
embedded(_t: Embedded<T>, _k: Fold<T, void>): void {}
|
||||
embedded(_t: T, _k: Fold<T, void>): void {}
|
||||
}
|
||||
|
||||
export class ForEachEmbedded<T> extends VoidFold<T> {
|
||||
export class ForEachEmbedded<T extends Embeddable> extends VoidFold<T> {
|
||||
constructor(public readonly f: (t: T, k: Fold<T, void>) => void) { super(); }
|
||||
embedded(t: Embedded<T>, k: Fold<T, void>): void { this.f(t.embeddedValue, k); }
|
||||
embedded(t: T, k: Fold<T, void>): void { this.f(t, k); }
|
||||
}
|
||||
|
||||
export abstract class ValueFold<T, R = T> implements FoldMethods<T, Value<R>> {
|
||||
export abstract class ValueFold<T extends Embeddable, R extends Embeddable = T> implements FoldMethods<T, Value<R>> {
|
||||
boolean(b: boolean): Value<R> {
|
||||
return b;
|
||||
}
|
||||
|
@ -94,22 +94,24 @@ export abstract class ValueFold<T, R = T> implements FoldMethods<T, Value<R>> {
|
|||
set(s: Set<T>, k: Fold<T, Value<R>>): Value<R> {
|
||||
return s.map(k);
|
||||
}
|
||||
dictionary(d: Dictionary<T>, k: Fold<T, Value<R>>): Value<R> {
|
||||
return d.mapEntries(([key, value]) => [k(key), k(value)]);
|
||||
dictionary(d: DictionaryMap<T>, k: Fold<T, Value<R>>): Value<R> {
|
||||
const result = new DictionaryMap<R>();
|
||||
d.forEach((value, key) => result.set(k(key), k(value)));
|
||||
return result.simplifiedValue();
|
||||
}
|
||||
annotated(a: Annotated<T>, k: Fold<T, Value<R>>): Value<R> {
|
||||
return annotate(k(a.item), ...a.annotations.map(k));
|
||||
}
|
||||
abstract embedded(t: Embedded<T>, k: Fold<T, Value<R>>): Value<R>;
|
||||
abstract embedded(t: T, k: Fold<T, Value<R>>): Value<R>;
|
||||
}
|
||||
|
||||
export class IdentityFold<T> extends ValueFold<T, T> {
|
||||
embedded(t: Embedded<T>, _k: Fold<T, Value<T>>): Value<T> {
|
||||
export class IdentityFold<T extends Embeddable> extends ValueFold<T, T> {
|
||||
embedded(t: T, _k: Fold<T, Value<T>>): Value<T> {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
export class MapFold<T, R> extends ValueFold<T, R> {
|
||||
export class MapFold<T extends Embeddable, R extends Embeddable> extends ValueFold<T, R> {
|
||||
readonly f: (t: T) => Value<R>;
|
||||
|
||||
constructor(f: (t: T) => Value<R>) {
|
||||
|
@ -117,12 +119,12 @@ export class MapFold<T, R> extends ValueFold<T, R> {
|
|||
this.f = f;
|
||||
}
|
||||
|
||||
embedded(t: Embedded<T>, _k: Fold<T, Value<R>>): Value<R> {
|
||||
return this.f(t.embeddedValue);
|
||||
embedded(t: T, _k: Fold<T, Value<R>>): Value<R> {
|
||||
return this.f(t);
|
||||
}
|
||||
}
|
||||
|
||||
export function valueClass<T>(v: Value<T>): ValueClass {
|
||||
export function valueClass<T extends Embeddable>(v: Value<T>): ValueClass {
|
||||
switch (typeof v) {
|
||||
case 'boolean':
|
||||
return ValueClass.Boolean;
|
||||
|
@ -154,7 +156,7 @@ export function valueClass<T>(v: Value<T>): ValueClass {
|
|||
} else if (Float.isDouble(v)) {
|
||||
return ValueClass.Double;
|
||||
} else {
|
||||
return ValueClass.Embedded;
|
||||
return ((_v: T) => ValueClass.Embedded)(v);
|
||||
}
|
||||
default:
|
||||
((_v: never): never => { throw new Error("Internal error"); })(v);
|
||||
|
@ -163,7 +165,7 @@ export function valueClass<T>(v: Value<T>): ValueClass {
|
|||
|
||||
export const IDENTITY_FOLD = new IdentityFold<any>();
|
||||
|
||||
export function fold<T, R>(v: Value<T>, o: FoldMethods<T, R>): R {
|
||||
export function fold<T extends Embeddable, R>(v: Value<T>, o: FoldMethods<T, R>): R {
|
||||
const walk = (v: Value<T>): R => {
|
||||
switch (typeof v) {
|
||||
case 'boolean':
|
||||
|
@ -188,16 +190,16 @@ export function fold<T, R>(v: Value<T>, o: FoldMethods<T, R>): R {
|
|||
return o.array(v, walk);
|
||||
} else if (Set.isSet<T>(v)) {
|
||||
return o.set(v, walk);
|
||||
} else if (Dictionary.isDictionary<T>(v)) {
|
||||
return o.dictionary(v, walk);
|
||||
} else if (isEmbedded(v)) {
|
||||
return o.embedded(v, walk);
|
||||
} else if (Annotated.isAnnotated<T>(v)) {
|
||||
return o.annotated(v, walk);
|
||||
} else if (Bytes.isBytes(v)) {
|
||||
return o.bytes(v);
|
||||
} else if (Float.isDouble(v)) {
|
||||
return o.double(v.value);
|
||||
} else {
|
||||
return o.embedded(v, walk);
|
||||
} else if (Dictionary.isDictionary<T>(v)) {
|
||||
return o.dictionary(new DictionaryMap(v), walk);
|
||||
}
|
||||
default:
|
||||
((_v: never): never => { throw new Error("Internal error"); })(v);
|
||||
|
@ -206,7 +208,7 @@ export function fold<T, R>(v: Value<T>, o: FoldMethods<T, R>): R {
|
|||
return walk(v);
|
||||
}
|
||||
|
||||
export function mapEmbeddeds<T, R>(
|
||||
export function mapEmbeddeds<T extends Embeddable, R extends Embeddable>(
|
||||
v: Value<T>,
|
||||
f: (t: T) => Value<R>,
|
||||
): Value<R>
|
||||
|
@ -214,6 +216,9 @@ export function mapEmbeddeds<T, R>(
|
|||
return fold(v, new MapFold(f));
|
||||
}
|
||||
|
||||
export function forEachEmbedded<T>(v: Value<T>, f: (t: T, k: Fold<T, void>) => void): void {
|
||||
export function forEachEmbedded<T extends Embeddable>(
|
||||
v: Value<T>,
|
||||
f: (t: T, k: Fold<T, void>) => void,
|
||||
): void {
|
||||
return fold(v, new ForEachEmbedded(f));
|
||||
}
|
||||
|
|
|
@ -1,72 +1,97 @@
|
|||
import { embed, GenericEmbedded } from "./embedded";
|
||||
import { Embeddable, GenericEmbedded, isEmbedded } from "./embedded";
|
||||
import { Bytes } from "./bytes";
|
||||
import { Record, Tuple } from "./record";
|
||||
import { Value } from "./values";
|
||||
import { Dictionary, Set } from "./dictionary";
|
||||
import { Dictionary, KeyedDictionary, Set } from "./dictionary";
|
||||
import { JsDictionary } from "./jsdictionary";
|
||||
|
||||
export function fromJS<T = GenericEmbedded>(x: any): Value<T> {
|
||||
switch (typeof x) {
|
||||
case 'number':
|
||||
if (!Number.isInteger(x)) {
|
||||
// We require that clients be explicit about integer vs. non-integer types.
|
||||
throw new TypeError("Refusing to autoconvert non-integer number to Double");
|
||||
}
|
||||
export interface FromJSOptions<T extends Embeddable = GenericEmbedded> {
|
||||
onNonInteger?(n: number): Value<T> | undefined;
|
||||
}
|
||||
|
||||
export function fromJS<T extends Embeddable = GenericEmbedded>(x: any): Value<T> {
|
||||
return fromJS_options(x);
|
||||
}
|
||||
|
||||
export function fromJS_options<T extends Embeddable = GenericEmbedded>(x: any, options?: FromJSOptions<T>): Value<T> {
|
||||
function walk(x: any): Value<T> {
|
||||
switch (typeof x) {
|
||||
case 'number':
|
||||
if (!Number.isInteger(x)) {
|
||||
// We require that clients be explicit about integer vs. non-integer types.
|
||||
const converted = options?.onNonInteger?.(x) ?? void 0;
|
||||
if (converted !== void 0) return converted;
|
||||
throw new TypeError("Refusing to autoconvert non-integer number to Double");
|
||||
}
|
||||
// FALL THROUGH
|
||||
case 'bigint':
|
||||
case 'string':
|
||||
case 'symbol':
|
||||
case 'boolean':
|
||||
return x;
|
||||
|
||||
case 'undefined':
|
||||
case 'function':
|
||||
break;
|
||||
|
||||
case 'object':
|
||||
if (x === null) {
|
||||
break;
|
||||
}
|
||||
if (typeof x.__as_preserve__ === 'function') {
|
||||
return x.__as_preserve__();
|
||||
}
|
||||
if (Record.isRecord<Value<T>, Tuple<Value<T>>, T>(x)) {
|
||||
case 'bigint':
|
||||
case 'string':
|
||||
case 'symbol':
|
||||
case 'boolean':
|
||||
return x;
|
||||
}
|
||||
if (Array.isArray(x)) {
|
||||
return x.map<Value<T>>(fromJS);
|
||||
}
|
||||
if (ArrayBuffer.isView(x) || x instanceof ArrayBuffer) {
|
||||
return Bytes.from(x);
|
||||
}
|
||||
if (Map.isMap(x)) {
|
||||
const d = new Dictionary<T>();
|
||||
x.forEach((v, k) => d.set(fromJS(k), fromJS(v)));
|
||||
return d;
|
||||
}
|
||||
if (Set.isSet(x)) {
|
||||
const s = new Set<T>();
|
||||
x.forEach(v => s.add(fromJS(v)));
|
||||
return s;
|
||||
}
|
||||
// Just... assume it's a T.
|
||||
return embed(x as T);
|
||||
|
||||
default:
|
||||
break;
|
||||
case 'undefined':
|
||||
case 'function':
|
||||
break;
|
||||
|
||||
case 'object':
|
||||
if (x === null) {
|
||||
break;
|
||||
}
|
||||
if (typeof x.__as_preserve__ === 'function') {
|
||||
return x.__as_preserve__();
|
||||
}
|
||||
if (Record.isRecord<Value<T>, Tuple<Value<T>>, T>(x)) {
|
||||
return x;
|
||||
}
|
||||
if (Array.isArray(x)) {
|
||||
return x.map<Value<T>>(walk);
|
||||
}
|
||||
if (ArrayBuffer.isView(x) || x instanceof ArrayBuffer) {
|
||||
return Bytes.from(x);
|
||||
}
|
||||
if (Map.isMap(x)) {
|
||||
const d = new KeyedDictionary<T>();
|
||||
x.forEach((v, k) => d.set(walk(k), walk(v)));
|
||||
return d;
|
||||
}
|
||||
if (Set.isSet(x)) {
|
||||
const s = new Set<T>();
|
||||
x.forEach(v => s.add(walk(v)));
|
||||
return s;
|
||||
}
|
||||
if (isEmbedded<T>(x)) {
|
||||
return x;
|
||||
}
|
||||
// Handle plain JS objects to build a JsDictionary
|
||||
{
|
||||
const r: JsDictionary<Value<T>> = {};
|
||||
Object.entries(x).forEach(([k, v]) => r[k] = walk(v));
|
||||
return r;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
throw new TypeError("Cannot represent JavaScript value as Preserves: " + x);
|
||||
}
|
||||
|
||||
throw new TypeError("Cannot represent JavaScript value as Preserves: " + x);
|
||||
return walk(x);
|
||||
}
|
||||
|
||||
declare module "./dictionary" {
|
||||
namespace Dictionary {
|
||||
export function fromJS<T = GenericEmbedded, V = GenericEmbedded>(x: object): Dictionary<T, Value<V>>;
|
||||
export function stringMap<T extends Embeddable = GenericEmbedded>(
|
||||
x: object
|
||||
): KeyedDictionary<T, string, Value<T>>;
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary.fromJS = function <T = GenericEmbedded, V = GenericEmbedded>(x: object): Dictionary<T, Value<V>> {
|
||||
if (Dictionary.isDictionary<T, Value<V>>(x)) return x;
|
||||
const d = new Dictionary<T, Value<V>>();
|
||||
Object.entries(x).forEach(([key, value]) => d.set(key, fromJS(value)));
|
||||
return d;
|
||||
Dictionary.stringMap = function <T extends Embeddable = GenericEmbedded>(
|
||||
x: object
|
||||
): KeyedDictionary<T, string, Value<T>> {
|
||||
const r = new KeyedDictionary<T, string, Value<T>>();
|
||||
Object.entries(x).forEach(([key, value]) => r.set(key, fromJS(value)));
|
||||
return r;
|
||||
};
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
export * from './runtime';
|
||||
export * as Constants from './constants';
|
||||
export * as Pexpr from './pexpr';
|
||||
|
||||
import type { Embeddable } from './embedded';
|
||||
import type { Value } from './values';
|
||||
|
||||
declare global {
|
||||
interface ArrayConstructor {
|
||||
__from_preserve__<T>(v: Value<T>): undefined | Array<Value<T>>;
|
||||
__from_preserve__<T extends Embeddable>(v: Value<T>): undefined | Array<Value<T>>;
|
||||
}
|
||||
}
|
||||
|
||||
Array.__from_preserve__ = <T>(v: Value<T>) => {
|
||||
Array.__from_preserve__ = <T extends Embeddable>(v: Value<T>) => {
|
||||
return Array.isArray(v) ? v : void 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import type { GenericEmbedded } from "./embedded";
|
||||
import type { Embeddable, GenericEmbedded } from "./embedded";
|
||||
import type { Annotated } from "./annotated";
|
||||
import { Dictionary } from "./dictionary";
|
||||
|
||||
export const IsPreservesAnnotated = Symbol.for('IsPreservesAnnotated');
|
||||
|
||||
export function isAnnotated<T = GenericEmbedded>(x: any): x is Annotated<T>
|
||||
export function isAnnotated<T extends Embeddable = GenericEmbedded>(x: any): x is Annotated<T>
|
||||
{
|
||||
return !!x?.[IsPreservesAnnotated];
|
||||
}
|
||||
|
@ -30,6 +31,17 @@ export function is(a: any, b: any): boolean {
|
|||
for (let i = 0; i < a.length; i++) if (!is(a[i], b[i])) return false;
|
||||
return true;
|
||||
}
|
||||
{
|
||||
const aMap = Dictionary.asMap(a);
|
||||
const bMap = Dictionary.asMap(b);
|
||||
if (!aMap || !bMap) return false;
|
||||
if (aMap.size !== bMap.size) return false;
|
||||
for (const k of aMap.keys()) {
|
||||
if (!bMap.has(k)) return false;
|
||||
if (!is(aMap.get(k), bMap.get(k))) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
import { isEmbedded } from './embedded';
|
||||
import { Equivalence, _iterMap } from './flex';
|
||||
|
||||
export interface JsDictionary<V> {
|
||||
[key: string]: V;
|
||||
}
|
||||
|
||||
export namespace JsDictionary {
|
||||
export function isJsDictionary<V>(x: any): x is JsDictionary<V> {
|
||||
// We accept only literal objects and objects created via `new Object` as dictionaries.
|
||||
// Furthermore, we require no function-valued `__as_preserve__` property to exist.
|
||||
return typeof x === 'object'
|
||||
&& x !== null
|
||||
&& Object.getPrototypeOf(Object.getPrototypeOf(x)) === null
|
||||
&& typeof x.__as_preserve__ !== 'function'
|
||||
&& !isEmbedded(x);
|
||||
}
|
||||
|
||||
export function from<V>(entries: Iterable<[symbol, V]>): JsDictionary<V> {
|
||||
const r: JsDictionary<V> = {};
|
||||
for (const [key, value] of entries) r[key.description!] = value;
|
||||
return r;
|
||||
}
|
||||
|
||||
export function clear<V>(j: JsDictionary<V>): void {
|
||||
for (const key in j) delete j[key];
|
||||
}
|
||||
|
||||
export function remove<V>(j: JsDictionary<V>, key: symbol): boolean {
|
||||
const result = has(j, key);
|
||||
delete j[key.description!];
|
||||
return result;
|
||||
}
|
||||
|
||||
export function forEach<V>(
|
||||
j: JsDictionary<V>,
|
||||
callbackfn: (value: V, key: symbol) => void,
|
||||
): void {
|
||||
Object.entries(j).forEach(([key, val]) => callbackfn(val, Symbol.for(key)));
|
||||
}
|
||||
|
||||
export function get<V>(j: JsDictionary<V>, key: symbol): V | undefined {
|
||||
return j[key.description!];
|
||||
}
|
||||
|
||||
export function has<V>(j: JsDictionary<V>, key: symbol): boolean {
|
||||
return Object.hasOwnProperty.call(j, key.description!);
|
||||
}
|
||||
|
||||
export function set<V>(j: JsDictionary<V>, key: symbol, value: V): JsDictionary<V> {
|
||||
j[key.description!] = value;
|
||||
return j;
|
||||
}
|
||||
|
||||
export function size<V>(j: JsDictionary<V>): number {
|
||||
return Object.keys(j).length;
|
||||
}
|
||||
|
||||
export function entries<V>(j: JsDictionary<V>): IterableIterator<[symbol, V]> {
|
||||
return _iterMap(Object.entries(j).values(), ([k, v]) => [Symbol.for(k), v]);
|
||||
}
|
||||
|
||||
export function keys<V>(j: JsDictionary<V>): IterableIterator<symbol> {
|
||||
return _iterMap(Object.keys(j).values(), k => Symbol.for(k));
|
||||
}
|
||||
|
||||
export function values<V>(j: JsDictionary<V>): IterableIterator<V> {
|
||||
return Object.values(j).values();
|
||||
}
|
||||
|
||||
export function clone<V>(j: JsDictionary<V>): JsDictionary<V> {
|
||||
const r: JsDictionary<V> = {};
|
||||
Object.keys(j).forEach(k => r[k] = j[k]);
|
||||
return r;
|
||||
}
|
||||
|
||||
export function equals<V>(
|
||||
j1: JsDictionary<V>,
|
||||
j2: JsDictionary<V>,
|
||||
eqv: Equivalence<V> = (v1, v2) => v1 === v2,
|
||||
): boolean {
|
||||
if (size(j1) !== size(j2)) return false;
|
||||
for (let [k, v] of entries(j1)) {
|
||||
if (!has(j2, k)) return false;
|
||||
if (!eqv(v, get(j2, k)!)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -3,13 +3,15 @@ import { Bytes } from "./bytes";
|
|||
import { fold } from "./fold";
|
||||
import { is } from "./is";
|
||||
import { Value } from "./values";
|
||||
import { Set, Dictionary } from "./dictionary";
|
||||
import { Set, Dictionary, KeyedDictionary, DictionaryMap } from "./dictionary";
|
||||
import { Annotated } from "./annotated";
|
||||
import { unannotate } from "./strip";
|
||||
import { embed, isEmbedded, Embedded } from "./embedded";
|
||||
import { isEmbedded } from "./embedded";
|
||||
import { isCompound } from "./compound";
|
||||
import type { Embeddable } from "./embedded";
|
||||
import { JsDictionary } from "./jsdictionary";
|
||||
|
||||
export function merge<T>(
|
||||
export function merge<T extends Embeddable>(
|
||||
mergeEmbeddeds: (a: T, b: T) => T | undefined,
|
||||
item0: Value<T>,
|
||||
... items: Array<Value<T>>): Value<T>
|
||||
|
@ -42,33 +44,38 @@ export function merge<T>(
|
|||
if (!Record.isRecord<Value<T>, Tuple<Value<T>>, T>(b)) die();
|
||||
return Record(walk(r.label, b.label), walkMany(r, b));
|
||||
},
|
||||
|
||||
array(a: Array<Value<T>>) {
|
||||
if (!Array.isArray(b) || Record.isRecord(b)) die();
|
||||
return walkMany(a, b);
|
||||
},
|
||||
|
||||
set(_s: Set<T>) { die(); },
|
||||
dictionary(d: Dictionary<T>) {
|
||||
if (!Dictionary.isDictionary<T>(b)) die();
|
||||
const r = new Dictionary<T>();
|
||||
d.forEach((av,ak) => {
|
||||
const bv = b.get(ak);
|
||||
|
||||
dictionary(aMap: DictionaryMap<T>) {
|
||||
const bMap = Dictionary.asMap<T>(b);
|
||||
if (bMap === void 0) die();
|
||||
|
||||
const r = new DictionaryMap<T>();
|
||||
aMap.forEach((av,ak) => {
|
||||
const bv = bMap.get(ak);
|
||||
r.set(ak, bv === void 0 ? av : walk(av, bv));
|
||||
});
|
||||
b.forEach((bv, bk) => {
|
||||
if (!d.has(bk)) r.set(bk, bv);
|
||||
bMap.forEach((bv, bk) => {
|
||||
if (!aMap.has(bk)) r.set(bk, bv);
|
||||
});
|
||||
return r;
|
||||
return r.simplifiedValue();
|
||||
},
|
||||
|
||||
annotated(a: Annotated<T>) {
|
||||
return walk(a, unannotate(b));
|
||||
},
|
||||
|
||||
embedded(t: Embedded<T>) {
|
||||
embedded(t: T) {
|
||||
if (!isEmbedded<T>(b)) die();
|
||||
const r = mergeEmbeddeds(t.embeddedValue, b.embeddedValue);
|
||||
const r = mergeEmbeddeds(t, b);
|
||||
if (r === void 0) die();
|
||||
return embed(r);
|
||||
return r;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
import { Annotated } from './annotated';
|
||||
import { Bytes } from './bytes';
|
||||
import { Set, Dictionary } from './dictionary';
|
||||
import { Set, EncodableDictionary } from './dictionary';
|
||||
import { stringify } from './text';
|
||||
|
||||
import * as util from 'util';
|
||||
|
||||
[Bytes, Annotated, Set, Dictionary].forEach((C) => {
|
||||
[Bytes, Annotated, Set, EncodableDictionary].forEach((C) => {
|
||||
(C as any).prototype[util.inspect.custom] =
|
||||
function (_depth: any, _options: any) {
|
||||
return stringify(this, { indent: 2 });
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import { is, isAnnotated } from './is';
|
||||
import { Bytes } from './bytes';
|
||||
import { Set, Dictionary } from './dictionary';
|
||||
import { Embedded, isEmbedded } from './embedded';
|
||||
import { isEmbedded } from './embedded';
|
||||
import { Float } from './float';
|
||||
import { Value } from './values';
|
||||
import { Record } from './record';
|
||||
import type { Embeddable } from './embedded';
|
||||
|
||||
export function typeCode<V>(v: Value<V>): number {
|
||||
if (isAnnotated<V>(v)) v = v.item;
|
||||
export function typeCode<T extends Embeddable>(v: Value<T>): number {
|
||||
if (isAnnotated<T>(v)) v = v.item;
|
||||
switch (typeof v) {
|
||||
case 'boolean':
|
||||
return 0;
|
||||
|
@ -24,23 +25,23 @@ export function typeCode<V>(v: Value<V>): number {
|
|||
if (Array.isArray(v)) {
|
||||
return ('label' in v) ? 7 : 8;
|
||||
}
|
||||
if (Set.isSet<V>(v)) return 9;
|
||||
if (Dictionary.isDictionary<V>(v)) return 10;
|
||||
if (Set.isSet<T>(v)) return 9;
|
||||
if (Dictionary.isDictionary<T>(v)) return 10;
|
||||
if (isEmbedded(v)) return 11;
|
||||
/* fall through */
|
||||
default:
|
||||
throw new Error("Invalid Value<V> in typeCode");
|
||||
throw new Error("Invalid Value<T> in typeCode");
|
||||
}
|
||||
}
|
||||
|
||||
export function compare<V>(
|
||||
a: Value<V>,
|
||||
b: Value<V>,
|
||||
compare_embedded: (a: V, b: V) => number = (a, b) => is(a, b) ? 0 : a < b ? -1 : 1,
|
||||
export function compare<T extends Embeddable>(
|
||||
a: Value<T>,
|
||||
b: Value<T>,
|
||||
compare_embedded: (a: T, b: T) => number = (a, b) => is(a, b) ? 0 : a < b ? -1 : 1,
|
||||
): number {
|
||||
function cmp(a: Value<V>, b: Value<V>): number {
|
||||
if (isAnnotated<V>(a)) a = a.item;
|
||||
if (isAnnotated<V>(b)) b = b.item;
|
||||
function cmp(a: Value<T>, b: Value<T>): number {
|
||||
if (isAnnotated<T>(a)) a = a.item;
|
||||
if (isAnnotated<T>(b)) b = b.item;
|
||||
const ta = typeCode(a);
|
||||
const tb = typeCode(b);
|
||||
if (ta < tb) return -1;
|
||||
|
@ -67,14 +68,14 @@ export function compare<V>(
|
|||
return va < vb ? -1 : va > vb ? 1 : 0;
|
||||
}
|
||||
case 7: {
|
||||
const lr = cmp((a as Record<Value<V>, Value<V>[], V>).label,
|
||||
(b as Record<Value<V>, Value<V>[], V>).label);
|
||||
const lr = cmp((a as Record<Value<T>, Value<T>[], T>).label,
|
||||
(b as Record<Value<T>, Value<T>[], T>).label);
|
||||
if (lr !== 0) return lr;
|
||||
/* fall through */
|
||||
}
|
||||
case 8: {
|
||||
const va = a as Value<V>[];
|
||||
const vb = b as Value<V>[];
|
||||
const va = a as Value<T>[];
|
||||
const vb = b as Value<T>[];
|
||||
const l = Math.min(va.length, vb.length)
|
||||
for (let i = 0; i < l; i++) {
|
||||
const c = cmp(va[i], vb[i]);
|
||||
|
@ -83,18 +84,17 @@ export function compare<V>(
|
|||
return va.length < vb.length ? -1 : va.length > vb.length ? 1 : 0;
|
||||
}
|
||||
case 9: {
|
||||
const va = Array.from(a as Set<V>).sort(cmp);
|
||||
const vb = Array.from(b as Set<V>).sort(cmp);
|
||||
const va = Array.from(a as Set<T>).sort(cmp);
|
||||
const vb = Array.from(b as Set<T>).sort(cmp);
|
||||
return cmp(va, vb);
|
||||
}
|
||||
case 10: {
|
||||
const va = Array.from(a as Dictionary<V>).sort(cmp);
|
||||
const vb = Array.from(b as Dictionary<V>).sort(cmp);
|
||||
const va = Array.from(Dictionary.asMap<T>(a)!.entries()).sort(cmp);
|
||||
const vb = Array.from(Dictionary.asMap<T>(b)!.entries()).sort(cmp);
|
||||
return cmp(va, vb);
|
||||
}
|
||||
case 11:
|
||||
return compare_embedded((a as Embedded<V>).embeddedValue,
|
||||
(b as Embedded<V>).embeddedValue);
|
||||
return compare_embedded(a as T, b as T);
|
||||
default:
|
||||
throw new Error("Invalid typeCode: " + ta);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,353 @@
|
|||
// Preserves-Expressions. https://preserves.dev/preserves-expressions.html
|
||||
|
||||
import { ReaderBase } from './reader';
|
||||
import { Atom, Value } from './values';
|
||||
import { Position, annotate, formatPosition } from './annotated';
|
||||
import { Record as VRecord } from './record';
|
||||
import { Embeddable, GenericEmbedded } from './embedded';
|
||||
import { fromJS } from './fromjs';
|
||||
import { DictionaryMap, Set as VSet } from './dictionary';
|
||||
|
||||
export type Expr = SimpleExpr | Punct;
|
||||
export type SimpleExpr = Atom | Compound | Embedded;
|
||||
|
||||
export type Positioned<I> = { position: Position, item: I, annotations?: Annotations };
|
||||
|
||||
export class Punct {
|
||||
constructor(public text: string) {}
|
||||
__as_preserve__(): Value { return VRecord(Symbol.for('p'), [Symbol.for(this.text)]); }
|
||||
|
||||
isComma(): boolean { return this.text === ','; }
|
||||
static isComma(v: Expr): boolean { return v instanceof Punct && v.isComma(); }
|
||||
|
||||
isColon(n = 1): boolean { return this.text === ':'.repeat(n); }
|
||||
static isColon(v: Expr, n = 1): boolean { return v instanceof Punct && v.isColon(n); }
|
||||
}
|
||||
|
||||
export class Embedded {
|
||||
constructor(public expr: SimpleExpr, public annotations?: Annotations) {}
|
||||
__as_preserve__(): Value {
|
||||
const v = fromJS(this.expr);
|
||||
return new GenericEmbedded(this.annotations?.wrap(v) ?? v);
|
||||
}
|
||||
}
|
||||
|
||||
export class BaseCompound<I> {
|
||||
positions: Position[] = [];
|
||||
exprs: I[] = [];
|
||||
annotations?: Annotations[] = void 0; // sparse array when non-void
|
||||
|
||||
get(i: number): Positioned<I> | undefined {
|
||||
if (i >= this.exprs.length) return void 0;
|
||||
return {
|
||||
position: this.positions[i],
|
||||
item: this.exprs[i],
|
||||
annotations: this.annotations && this.annotations[i],
|
||||
};
|
||||
}
|
||||
|
||||
push(p: Positioned<I>): true;
|
||||
push(expr: I, position: Position, annotations?: Annotations): true;
|
||||
push(v: Positioned<I> | I, position?: Position, annotations?: Annotations) {
|
||||
if (position === void 0) {
|
||||
const p = v as Positioned<I>;
|
||||
if (p.annotations) this._ensureAnnotations()[this.exprs.length] = p.annotations;
|
||||
this.positions.push(p.position);
|
||||
this.exprs.push(p.item);
|
||||
} else {
|
||||
if (annotations) this._ensureAnnotations()[this.exprs.length] = annotations;
|
||||
this.positions.push(position);
|
||||
this.exprs.push(v as I);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
_ensureAnnotations(): Annotations[] {
|
||||
if (this.annotations === void 0) this.annotations = [];
|
||||
return this.annotations;
|
||||
}
|
||||
|
||||
_annotationsAt(index: number): Annotations {
|
||||
return this._ensureAnnotations()[index] ??= new Annotations();
|
||||
}
|
||||
|
||||
preservesValues(): Value[] {
|
||||
return this.exprs.map((p, i) => {
|
||||
const v = fromJS(p);
|
||||
if (this.annotations?.[i] !== void 0) {
|
||||
return this.annotations[i].wrap(v);
|
||||
} else {
|
||||
return v;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
__as_preserve__(): Value {
|
||||
return this.preservesValues();
|
||||
}
|
||||
|
||||
map<R>(f: (item: Positioned<I>, index: number) => R, offset = 0): R[] {
|
||||
const result: R[] = [];
|
||||
for (let i = offset; i < this.exprs.length; i++) {
|
||||
result.push(f(this.get(i)!, i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[Symbol.iterator](): IterableIterator<Positioned<I>> {
|
||||
let c = this;
|
||||
let i = 0;
|
||||
return {
|
||||
next(): IteratorResult<Positioned<I>> {
|
||||
if (i < c.exprs.length) {
|
||||
return { done: false, value: c.get(i++)! };
|
||||
} else {
|
||||
return { done: true, value: void 0 };
|
||||
}
|
||||
},
|
||||
[Symbol.iterator]() { return c[Symbol.iterator](); }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class Document extends BaseCompound<Expr> {}
|
||||
|
||||
export class Annotations extends BaseCompound<SimpleExpr> {
|
||||
wrap(v: Value): Value {
|
||||
return annotate(v, ... this.preservesValues());
|
||||
}
|
||||
}
|
||||
|
||||
export type CompoundVariant = 'sequence' | 'record' | 'block' | 'group' | 'set';
|
||||
|
||||
export abstract class Compound extends BaseCompound<Expr> {
|
||||
abstract get variant(): CompoundVariant;
|
||||
__as_preserve__(): Value {
|
||||
const vs = this.preservesValues();
|
||||
switch (this.variant) {
|
||||
case 'sequence': return vs;
|
||||
case 'record': return VRecord(Symbol.for('r'), vs);
|
||||
case 'block': return VRecord(Symbol.for('b'), vs);
|
||||
case 'group': return VRecord(Symbol.for('g'), vs);
|
||||
case 'set': return VRecord(Symbol.for('s'), vs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Sequence extends Compound {
|
||||
get variant(): CompoundVariant { return 'sequence'; }
|
||||
}
|
||||
|
||||
export class Record extends Compound {
|
||||
get variant(): CompoundVariant { return 'record'; }
|
||||
}
|
||||
|
||||
export class Block extends Compound {
|
||||
get variant(): CompoundVariant { return 'block'; }
|
||||
}
|
||||
|
||||
export class Group extends Compound {
|
||||
get variant(): CompoundVariant { return 'group'; }
|
||||
}
|
||||
|
||||
export class Set extends Compound {
|
||||
get variant(): CompoundVariant { return 'set'; }
|
||||
}
|
||||
|
||||
export class Reader extends ReaderBase<never> {
|
||||
nextDocument(howMany: 'all' | 'one' = 'all'): Document {
|
||||
const doc = new Document();
|
||||
this.readExpr(doc);
|
||||
if (howMany === 'all') {
|
||||
while (this.readExpr(doc)) {}
|
||||
}
|
||||
return doc;
|
||||
}
|
||||
|
||||
readCompound(c: Compound, terminator: string): Compound {
|
||||
while (this.readExpr(c, terminator)) {}
|
||||
return c;
|
||||
}
|
||||
|
||||
readSimpleExpr(c: BaseCompound<SimpleExpr>): boolean {
|
||||
return this._readInto(c, false);
|
||||
}
|
||||
|
||||
readExpr(c: BaseCompound<Expr>, terminator: string | null = null): boolean {
|
||||
return this._readInto(c as BaseCompound<SimpleExpr> /* yuck */, true, terminator);
|
||||
}
|
||||
|
||||
_checkTerminator(actual: string, expected: string | null, startPos: Position): false {
|
||||
if (actual === expected) return false;
|
||||
this.state.error('Unexpected ' + actual, startPos);
|
||||
}
|
||||
|
||||
_readInto(c: BaseCompound<SimpleExpr>, acceptPunct: boolean, terminator: string | null = null): boolean {
|
||||
while (true) {
|
||||
this.state.skipws();
|
||||
if (this.state.atEnd() && terminator === null) return false;
|
||||
const startPos = this.state.copyPos();
|
||||
const ch = this.state.nextchar();
|
||||
switch (ch) {
|
||||
case '"':
|
||||
return c.push(this.state.readString('"'), startPos);
|
||||
case '|':
|
||||
return c.push(Symbol.for(this.state.readString('|')), startPos);
|
||||
case ';':
|
||||
if (acceptPunct) {
|
||||
return (c as BaseCompound<Expr>).push(new Punct(';'), startPos);
|
||||
} else {
|
||||
this.state.error('Semicolon is not permitted at this location', startPos);
|
||||
}
|
||||
case '@':
|
||||
if (!this.readSimpleExpr(c._annotationsAt(c.exprs.length))) {
|
||||
this.state.error('Missing annotation', startPos);
|
||||
}
|
||||
continue;
|
||||
case ':': {
|
||||
let colons: string = ch;
|
||||
while (!this.state.atEnd() && this.state.peek() === ':') {
|
||||
colons = colons + ':';
|
||||
this.state.advance();
|
||||
}
|
||||
if (acceptPunct) {
|
||||
return (c as BaseCompound<Expr>).push(new Punct(colons), startPos);
|
||||
} else {
|
||||
this.state.error('Colons are not permitted at this location', startPos);
|
||||
}
|
||||
}
|
||||
case '#': {
|
||||
const ch = this.state.nextchar();
|
||||
switch (ch) {
|
||||
case ' ': case '\t': {
|
||||
const here = this.state.copyPos();
|
||||
c._annotationsAt(c.exprs.length).push(this.state.readCommentLine(), here);
|
||||
continue;
|
||||
}
|
||||
case '\n': case '\r': {
|
||||
const here = this.state.copyPos();
|
||||
c._annotationsAt(c.exprs.length).push('', here);
|
||||
continue;
|
||||
}
|
||||
case '!': {
|
||||
const here = this.state.copyPos();
|
||||
const r = new Record();
|
||||
r.push(Symbol.for('interpreter'), here);
|
||||
r.push(this.state.readCommentLine(), here);
|
||||
c._annotationsAt(c.exprs.length).push(r, here);
|
||||
continue;
|
||||
}
|
||||
case 'f': this.state.requireDelimiter('#f'); return c.push(false, startPos);
|
||||
case 't': this.state.requireDelimiter('#t'); return c.push(true, startPos);
|
||||
case '{': return c.push(this.readCompound(new Set(), '}'), startPos);
|
||||
case '"': return c.push(this.state.readLiteralBinary(), startPos);
|
||||
case 'x': switch (this.state.nextchar()) {
|
||||
case '"': return c.push(this.state.readHexBinary(), startPos);
|
||||
case 'd': return c.push(this.state.readHexFloat(), startPos);
|
||||
default: this.state.error('Invalid #x syntax', startPos);
|
||||
}
|
||||
case '[': return c.push(this.state.readBase64Binary(), startPos);
|
||||
case ':': {
|
||||
const r = new BaseCompound<SimpleExpr>();
|
||||
if (!this.readSimpleExpr(r)) return false;
|
||||
const e = new Embedded(r.exprs[0], r.annotations && r.annotations[0]);
|
||||
return c.push(e, startPos);
|
||||
}
|
||||
default:
|
||||
this.state.error(`Invalid # syntax: ${ch}`, startPos);
|
||||
}
|
||||
}
|
||||
case '(': return c.push(this.readCompound(new Group(), ')'), startPos);
|
||||
case '<': return c.push(this.readCompound(new Record(), '>'), startPos);
|
||||
case '[': return c.push(this.readCompound(new Sequence(), ']'), startPos);
|
||||
case '{': return c.push(this.readCompound(new Block(), '}'), startPos);
|
||||
case ')': return this._checkTerminator(ch, terminator, startPos);
|
||||
case '>': return this._checkTerminator(ch, terminator, startPos);
|
||||
case ']': return this._checkTerminator(ch, terminator, startPos);
|
||||
case '}': return this._checkTerminator(ch, terminator, startPos);
|
||||
case ',':
|
||||
if (acceptPunct) {
|
||||
return (c as BaseCompound<Expr>).push(new Punct(','), startPos);
|
||||
} else {
|
||||
this.state.error('Comma is not permitted at this location', startPos);
|
||||
}
|
||||
default:
|
||||
return c.push(this.state.readRawSymbolOrNumber(ch), startPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface AsPreservesOptions<T extends Embeddable> {
|
||||
onGroup?: (g: Positioned<Group>) => Value<T>;
|
||||
onEmbedded?: (e: Positioned<Expr>, walk: (p: Positioned<Expr>) => Value<T>) => Value<T>;
|
||||
error?: (tag: string, position: Position) => Value<T>;
|
||||
}
|
||||
|
||||
export function asPreserves<T extends Embeddable>(
|
||||
p: Positioned<Expr>,
|
||||
options: AsPreservesOptions<T> = {},
|
||||
): Value<T> {
|
||||
const error = options.error ?? ((tag, position) => {
|
||||
throw new Error(formatPosition(position) + ": " + tag);
|
||||
});
|
||||
|
||||
function nonCommas(p: Compound): Positioned<Expr>[] {
|
||||
return Array.from(p).filter(p => !Punct.isComma(p.item));
|
||||
}
|
||||
|
||||
function walk(p: Positioned<Expr>): Value<T> {
|
||||
if (p.item instanceof Punct) {
|
||||
return error('invalid-punctuation', p.position);
|
||||
} else if (p.item instanceof Embedded) {
|
||||
if (options.onEmbedded) {
|
||||
return options.onEmbedded({ position: p.position, item: p.item.expr }, walk);
|
||||
} else {
|
||||
return error('unexpected-embedded', p.position);
|
||||
}
|
||||
} else if (p.item instanceof Compound) {
|
||||
switch (p.item.variant) {
|
||||
case 'sequence':
|
||||
return nonCommas(p.item).map(walk);
|
||||
case 'record': {
|
||||
const vs = nonCommas(p.item).map(walk);
|
||||
if (vs.length < 1) {
|
||||
return error('invalid-record', p.position);
|
||||
}
|
||||
const r = vs.slice(1) as unknown as VRecord<Value<T>, Value<T>[], T>;
|
||||
r.label = vs[0];
|
||||
return r;
|
||||
}
|
||||
case 'block': {
|
||||
const d = new DictionaryMap<T>();
|
||||
const vs = nonCommas(p.item);
|
||||
if ((vs.length % 3) !== 0) {
|
||||
return error('invalid-dictionary', p.position);
|
||||
}
|
||||
for (let i = 0; i < vs.length; i += 3) {
|
||||
if (!Punct.isColon(vs[i + 1].item)) {
|
||||
return error('missing-colon', vs[i + 1].position);
|
||||
}
|
||||
const k = walk(vs[i]);
|
||||
const v = walk(vs[i + 2]);
|
||||
d.set(k, v);
|
||||
}
|
||||
return d.simplifiedValue();
|
||||
}
|
||||
case 'group': {
|
||||
if (options.onGroup) {
|
||||
return options.onGroup(p as Positioned<Group>);
|
||||
} else {
|
||||
return error('unexpected-group', p.position);
|
||||
}
|
||||
}
|
||||
case 'set':
|
||||
return new VSet(nonCommas(p.item).map(walk));
|
||||
}
|
||||
} else {
|
||||
return p.item;
|
||||
}
|
||||
}
|
||||
|
||||
return walk(p);
|
||||
}
|
|
@ -2,15 +2,15 @@
|
|||
|
||||
import type { Value } from './values';
|
||||
import { DecodeError, ShortPacket } from './codec';
|
||||
import { Dictionary, Set } from './dictionary';
|
||||
import { Dictionary, DictionaryMap, Set } from './dictionary';
|
||||
import { strip } from './strip';
|
||||
import { Bytes, unhexDigit } from './bytes';
|
||||
import { Decoder, DecoderState, neverEmbeddedTypeDecode } from './decoder';
|
||||
import { Record } from './record';
|
||||
import { Annotated, newPosition, Position, updatePosition } from './annotated';
|
||||
import { Double, DoubleFloat, FloatType } from './float';
|
||||
import { Double, DoubleFloat } from './float';
|
||||
import { stringify } from './text';
|
||||
import { embed, GenericEmbedded, EmbeddedTypeDecode } from './embedded';
|
||||
import { Embeddable, GenericEmbedded, EmbeddedTypeDecode } from './embedded';
|
||||
|
||||
export interface ReaderStateOptions {
|
||||
includeAnnotations?: boolean;
|
||||
|
@ -155,13 +155,15 @@ export class ReaderState {
|
|||
this.error(`Delimiter must follow ${prefix}`, this.pos);
|
||||
}
|
||||
|
||||
static readonly DELIMITERS = '(){}[]<>";,@#:|';
|
||||
|
||||
delimiterFollows(): boolean {
|
||||
if (this.atEnd()) return true;
|
||||
const ch = this.peek();
|
||||
return ('(){}[]<>";,@#:|'.indexOf(ch) !== -1) || isSpace(ch);
|
||||
return (ReaderState.DELIMITERS.indexOf(ch) !== -1) || isSpace(ch);
|
||||
}
|
||||
|
||||
readRawSymbolOrNumber<T>(acc: string): Value<T> {
|
||||
readRawSymbolOrNumber(acc: string): number | bigint | symbol | DoubleFloat {
|
||||
while (!this.delimiterFollows()) acc = acc + this.nextchar();
|
||||
const m = NUMBER_RE.exec(acc);
|
||||
if (m) {
|
||||
|
@ -248,6 +250,16 @@ export class ReaderState {
|
|||
'x',
|
||||
() => this.readHex2());
|
||||
}
|
||||
|
||||
readCommentLine(): string {
|
||||
let acc = '';
|
||||
while (true) {
|
||||
if (this.atEnd()) return acc;
|
||||
const c = this.nextchar();
|
||||
if (c === '\n' || c === '\r') return acc;
|
||||
acc = acc + c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const genericEmbeddedTypeDecode: EmbeddedTypeDecode<GenericEmbedded> = {
|
||||
|
@ -260,7 +272,7 @@ export const genericEmbeddedTypeDecode: EmbeddedTypeDecode<GenericEmbedded> = {
|
|||
},
|
||||
};
|
||||
|
||||
export class Reader<T> {
|
||||
export class ReaderBase<T extends Embeddable> {
|
||||
state: ReaderState;
|
||||
embeddedType: EmbeddedTypeDecode<T>;
|
||||
|
||||
|
@ -283,17 +295,13 @@ export class Reader<T> {
|
|||
write(data: string) {
|
||||
this.state.write(data);
|
||||
}
|
||||
}
|
||||
|
||||
export class Reader<T extends Embeddable> extends ReaderBase<T> {
|
||||
|
||||
readCommentLine(): Value<T> {
|
||||
const startPos = this.state.copyPos();
|
||||
let acc = '';
|
||||
while (true) {
|
||||
const c = this.state.nextchar();
|
||||
if (c === '\n' || c === '\r') {
|
||||
return this.wrap(acc, startPos);
|
||||
}
|
||||
acc = acc + c;
|
||||
}
|
||||
return this.wrap(this.state.readCommentLine(), startPos);
|
||||
}
|
||||
|
||||
wrap(v: Value<T>, pos: Position): Value<T> {
|
||||
|
@ -344,6 +352,9 @@ export class Reader<T> {
|
|||
switch (c) {
|
||||
case ' ': case '\t': return this.annotateNextWith(this.readCommentLine());
|
||||
case '\n': case '\r': return this.annotateNextWith('');
|
||||
case '!':
|
||||
return this.annotateNextWith(
|
||||
Record(Symbol.for('interpreter'), [this.readCommentLine()]));
|
||||
case 'f': this.state.requireDelimiter('#f'); return false;
|
||||
case 't': this.state.requireDelimiter('#t'); return true;
|
||||
case '{': return this.readSet();
|
||||
|
@ -354,9 +365,9 @@ export class Reader<T> {
|
|||
default: this.state.error('Invalid #x syntax', startPos);
|
||||
}
|
||||
case '[': return this.state.readBase64Binary();
|
||||
case ':': return embed(this.embeddedType.fromValue(
|
||||
case ':': return this.embeddedType.fromValue(
|
||||
new Reader<GenericEmbedded>(this.state, genericEmbeddedTypeDecode).next(),
|
||||
this.state.options));
|
||||
this.state.options);
|
||||
default:
|
||||
this.state.error(`Invalid # syntax: ${c}`, startPos);
|
||||
}
|
||||
|
@ -395,22 +406,18 @@ export class Reader<T> {
|
|||
}
|
||||
|
||||
readDictionary(): Dictionary<T> {
|
||||
return this.seq(true,
|
||||
new Dictionary<T>(),
|
||||
(k, acc) => {
|
||||
this.state.skipws();
|
||||
switch (this.state.peek()) {
|
||||
case ':':
|
||||
if (acc.has(k)) this.state.error(
|
||||
`Duplicate key: ${stringify(k)}`, this.state.pos);
|
||||
this.state.advance();
|
||||
acc.set(k, this.next());
|
||||
break;
|
||||
default:
|
||||
this.state.error('Missing key/value separator', this.state.pos);
|
||||
}
|
||||
},
|
||||
'}');
|
||||
return this.seq(true, new DictionaryMap<T>(), (k, acc) => {
|
||||
this.state.skipws();
|
||||
switch (this.state.peek()) {
|
||||
case ':':
|
||||
this.state.advance();
|
||||
if (acc.has(k)) this.state.error(`Duplicate key: ${stringify(k)}`, this.state.pos);
|
||||
acc.set(k, this.next());
|
||||
break;
|
||||
default:
|
||||
this.state.error('Missing key/value separator', this.state.pos);
|
||||
}
|
||||
}, '}').simplifiedValue();
|
||||
}
|
||||
|
||||
readSet(): Set<T> {
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import { GenericEmbedded } from "./embedded";
|
||||
import { Embeddable, GenericEmbedded } from "./embedded";
|
||||
import { is } from "./is";
|
||||
import { Value } from "./values";
|
||||
import { Writer } from "./writer";
|
||||
|
||||
export type Tuple<T> = Array<T> | [T];
|
||||
|
||||
export type Record<LabelType extends Value<T>, FieldsType extends Tuple<Value<T>>, T = GenericEmbedded>
|
||||
export type Record<LabelType extends Value<T>, FieldsType extends Tuple<Value<T>>, T extends Embeddable = GenericEmbedded>
|
||||
= FieldsType & { label: LabelType };
|
||||
|
||||
export type RecordGetters<Fs, R> = {
|
||||
|
@ -15,7 +14,7 @@ export type RecordGetters<Fs, R> = {
|
|||
export type CtorTypes<Fs, Names extends Tuple<keyof Fs>> =
|
||||
{ [K in keyof Names]: Fs[keyof Fs & Names[K]] } & any[];
|
||||
|
||||
export interface RecordConstructor<L extends Value<T>, Fs, Names extends Tuple<keyof Fs>, T = GenericEmbedded> {
|
||||
export interface RecordConstructor<L extends Value<T>, Fs, Names extends Tuple<keyof Fs>, T extends Embeddable = GenericEmbedded> {
|
||||
(...fields: CtorTypes<Fs, Names>): Record<L, CtorTypes<Fs, Names>, T>;
|
||||
constructorInfo: RecordConstructorInfo<L, T>;
|
||||
isClassOf(v: any): v is Record<L, CtorTypes<Fs, Names>, T>;
|
||||
|
@ -23,7 +22,7 @@ export interface RecordConstructor<L extends Value<T>, Fs, Names extends Tuple<k
|
|||
fieldNumbers: { [K in string & keyof Fs]: number };
|
||||
};
|
||||
|
||||
export interface RecordConstructorInfo<L extends Value<T>, T = GenericEmbedded> {
|
||||
export interface RecordConstructorInfo<L extends Value<T>, T extends Embeddable = GenericEmbedded> {
|
||||
label: L;
|
||||
arity: number;
|
||||
}
|
||||
|
@ -48,23 +47,23 @@ export function Record<L, FieldsType extends Tuple<any>>(
|
|||
}
|
||||
|
||||
export namespace Record {
|
||||
export function isRecord<L extends Value<T>, FieldsType extends Tuple<Value<T>>, T = GenericEmbedded>(x: any): x is Record<L, FieldsType, T> {
|
||||
export function isRecord<L extends Value<T>, FieldsType extends Tuple<Value<T>>, T extends Embeddable = GenericEmbedded>(x: any): x is Record<L, FieldsType, T> {
|
||||
return Array.isArray(x) && 'label' in x;
|
||||
}
|
||||
|
||||
export function constructorInfo<L extends Value<T>, FieldsType extends Tuple<Value<T>>, T = GenericEmbedded>(
|
||||
export function constructorInfo<L extends Value<T>, FieldsType extends Tuple<Value<T>>, T extends Embeddable = GenericEmbedded>(
|
||||
r: Record<L, FieldsType, T>): RecordConstructorInfo<L, T>
|
||||
{
|
||||
return { label: r.label, arity: r.length };
|
||||
}
|
||||
|
||||
export function isClassOf<L extends Value<T>, FieldsType extends Tuple<Value<T>>, T = GenericEmbedded>(
|
||||
export function isClassOf<L extends Value<T>, FieldsType extends Tuple<Value<T>>, T extends Embeddable = GenericEmbedded>(
|
||||
ci: RecordConstructorInfo<L, T>, v: any): v is Record<L, FieldsType, T>
|
||||
{
|
||||
return (Record.isRecord(v)) && is(ci.label, v.label) && (ci.arity === v.length);
|
||||
}
|
||||
|
||||
export function makeConstructor<Fs, T = GenericEmbedded>()
|
||||
export function makeConstructor<Fs, T extends Embeddable = GenericEmbedded>()
|
||||
: (<L extends Value<T>, Names extends Tuple<keyof Fs>>(label: L, fieldNames: Names) =>
|
||||
RecordConstructor<L, Fs, Names, T>)
|
||||
{
|
||||
|
|
|
@ -13,6 +13,7 @@ export * from './float';
|
|||
export * from './fold';
|
||||
export * from './fromjs';
|
||||
export * from './is';
|
||||
export * from './jsdictionary';
|
||||
export * from './merge';
|
||||
export * from './order';
|
||||
export * from './reader';
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
import { Value } from "./values";
|
||||
import { Annotated } from "./annotated";
|
||||
import { Record, Tuple } from "./record";
|
||||
import { Set, Dictionary } from "./dictionary";
|
||||
import type { GenericEmbedded } from "./embedded";
|
||||
import { Set, Dictionary, DictionaryMap } from "./dictionary";
|
||||
import type { Embeddable, GenericEmbedded } from "./embedded";
|
||||
|
||||
export function unannotate<T = GenericEmbedded>(v: Value<T>): Value<T> {
|
||||
export function unannotate<T extends Embeddable = GenericEmbedded>(v: Value<T>): Value<T> {
|
||||
return Annotated.isAnnotated<T>(v) ? v.item : v;
|
||||
}
|
||||
|
||||
export function peel<T = GenericEmbedded>(v: Value<T>): Value<T> {
|
||||
export function peel<T extends Embeddable = GenericEmbedded>(v: Value<T>): Value<T> {
|
||||
return strip(v, 1);
|
||||
}
|
||||
|
||||
export function strip<T = GenericEmbedded>(
|
||||
export function strip<T extends Embeddable = GenericEmbedded>(
|
||||
v: Value<T>,
|
||||
depth: number = Infinity): Value<T>
|
||||
{
|
||||
|
@ -34,7 +34,9 @@ export function strip<T = GenericEmbedded>(
|
|||
} else if (Set.isSet<T>(v.item)) {
|
||||
return v.item.map(walk);
|
||||
} else if (Dictionary.isDictionary<T>(v.item)) {
|
||||
return v.item.mapEntries((e) => [walk(e[0]), walk(e[1])]);
|
||||
const result = new DictionaryMap<T>();
|
||||
new DictionaryMap<T>(v.item).forEach((val, key) => result.set(walk(key), walk(val)));
|
||||
return result.simplifiedValue();
|
||||
} else {
|
||||
return v.item;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Embedded, GenericEmbedded } from './embedded';
|
||||
import { Embeddable, GenericEmbedded, isEmbedded } from './embedded';
|
||||
import type { Value } from './values';
|
||||
|
||||
import { Annotated } from './annotated';
|
||||
|
@ -8,22 +8,28 @@ import { Writer, WriterOptions, EmbeddedWriter, WriterState } from './writer';
|
|||
import { fromJS } from './fromjs';
|
||||
import { Reader, ReaderOptions } from './reader';
|
||||
|
||||
export function parse<T = GenericEmbedded>(buffer: string, options?: ReaderOptions<T>): Value<T> {
|
||||
export function parse<T extends Embeddable = GenericEmbedded>(
|
||||
buffer: string,
|
||||
options?: ReaderOptions<T>,
|
||||
): Value<T> {
|
||||
return new Reader<T>(buffer, options).next();
|
||||
}
|
||||
|
||||
export function parseAll<T = GenericEmbedded>(buffer: string, options?: ReaderOptions<T>): Value<T>[] {
|
||||
export function parseAll<T extends Embeddable = GenericEmbedded>(
|
||||
buffer: string,
|
||||
options?: ReaderOptions<T>,
|
||||
): Value<T>[] {
|
||||
return new Reader<T>(buffer, options).readToEnd();
|
||||
}
|
||||
|
||||
export const stringifyEmbeddedWrite: EmbeddedWriter<any> = {
|
||||
export const stringifyEmbeddedWrite = {
|
||||
write(s: WriterState, v: any): void {
|
||||
if (v instanceof GenericEmbedded) {
|
||||
new Writer(s, this).push(v.generic);
|
||||
} else {
|
||||
try {
|
||||
const j = fromJS(v);
|
||||
if (!(j instanceof Embedded)) {
|
||||
if (!isEmbedded(j)) {
|
||||
new Writer(s, this).push(j);
|
||||
return;
|
||||
}
|
||||
|
@ -37,7 +43,7 @@ export const stringifyEmbeddedWrite: EmbeddedWriter<any> = {
|
|||
}
|
||||
};
|
||||
|
||||
export function stringify<T = GenericEmbedded>(x: any, options?: WriterOptions<T>): string {
|
||||
export function stringify<T extends Embeddable = GenericEmbedded>(x: any, options?: WriterOptions<T>): string {
|
||||
options = { ... (options ?? {}) };
|
||||
options.embeddedWrite = options.embeddedWrite ?? stringifyEmbeddedWrite;
|
||||
return Writer.stringify(fromJS<T>(x), options);
|
||||
|
|
|
@ -3,13 +3,14 @@
|
|||
import type { Bytes } from './bytes';
|
||||
import type { DoubleFloat } from './float';
|
||||
import type { Annotated } from './annotated';
|
||||
import type { Set, Dictionary } from './dictionary';
|
||||
import type { Embedded, GenericEmbedded } from './embedded';
|
||||
import type { JsDictionary } from './jsdictionary';
|
||||
import { Set, KeyedDictionary } from './dictionary';
|
||||
import type { Embeddable, GenericEmbedded } from './embedded';
|
||||
|
||||
export type Value<T = GenericEmbedded> =
|
||||
export type Value<T extends Embeddable = GenericEmbedded> =
|
||||
| Atom
|
||||
| Compound<T>
|
||||
| Embedded<T>
|
||||
| T
|
||||
| Annotated<T>;
|
||||
export type Atom =
|
||||
| boolean
|
||||
|
@ -18,7 +19,7 @@ export type Atom =
|
|||
| string
|
||||
| Bytes
|
||||
| symbol;
|
||||
export type Compound<T = GenericEmbedded> =
|
||||
export type Compound<T extends Embeddable = GenericEmbedded> =
|
||||
| (Array<Value<T>> | [Value<T>]) & { label: Value<T> }
|
||||
// ^ expanded from definition of Record<> in record.ts,
|
||||
// because if we use Record<Value<T>, Tuple<Value<T>>, T>,
|
||||
|
@ -27,4 +28,7 @@ export type Compound<T = GenericEmbedded> =
|
|||
// Value<T> to any.
|
||||
| Array<Value<T>>
|
||||
| Set<T>
|
||||
| Dictionary<T>;
|
||||
// v Expanded from definition of Dictionary<> in dictionary.ts,
|
||||
// because of circular-use-of-Value<T> issues.
|
||||
| JsDictionary<Value<T>>
|
||||
| KeyedDictionary<T>;
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
import { isAnnotated } from './is';
|
||||
import { Record, Tuple } from "./record";
|
||||
import type { GenericEmbedded, Embedded, EmbeddedTypeEncode } from "./embedded";
|
||||
import { Embeddable, GenericEmbedded, EmbeddedTypeEncode, isEmbedded } from "./embedded";
|
||||
import { Encoder, EncoderState } from "./encoder";
|
||||
import type { Value } from "./values";
|
||||
import { NUMBER_RE } from './reader';
|
||||
import { encodeBase64 } from './base64';
|
||||
import { DictionaryMap, writeDictionaryOn } from './dictionary';
|
||||
|
||||
export type Writable<T> =
|
||||
export type Writable<T extends Embeddable> =
|
||||
Value<T> | PreserveWritable<T> | Iterable<Value<T>> | ArrayBufferView;
|
||||
|
||||
export interface PreserveWritable<T> {
|
||||
export interface PreserveWritable<T extends Embeddable> {
|
||||
__preserve_text_on__(writer: Writer<T>): void;
|
||||
}
|
||||
|
||||
export function isPreserveWritable<T>(v: any): v is PreserveWritable<T> {
|
||||
export function isPreserveWritable<T extends Embeddable>(v: any): v is PreserveWritable<T> {
|
||||
return typeof v === 'object' && v !== null && '__preserve_text_on__' in v && typeof v.__preserve_text_on__ === 'function';
|
||||
}
|
||||
|
||||
|
@ -191,7 +192,7 @@ export class WriterState {
|
|||
this.pieces.push(buf + '"');
|
||||
}
|
||||
|
||||
couldBeFlat<T>(vs: Writable<T>[]): boolean {
|
||||
couldBeFlat<T extends Embeddable>(vs: Writable<T>[]): boolean {
|
||||
let seenCompound = false;
|
||||
for (let v of vs) {
|
||||
if (Array.isArray(v) || Set.isSet(v) || Map.isMap(v)) {
|
||||
|
@ -206,7 +207,7 @@ export class WriterState {
|
|||
}
|
||||
}
|
||||
|
||||
export class Writer<T> {
|
||||
export class Writer<T extends Embeddable> {
|
||||
state: WriterState;
|
||||
embeddedWrite: EmbeddedWriter<T>;
|
||||
|
||||
|
@ -225,7 +226,7 @@ export class Writer<T> {
|
|||
}
|
||||
}
|
||||
|
||||
static stringify<T>(v: Writable<T>, options?: WriterOptions<T>): string {
|
||||
static stringify<T extends Embeddable>(v: Writable<T>, options?: WriterOptions<T>): string {
|
||||
const w = new Writer(options);
|
||||
w.push(v);
|
||||
return w.contents();
|
||||
|
@ -262,7 +263,10 @@ export class Writer<T> {
|
|||
this.state.pieces.push('' + v);
|
||||
break;
|
||||
case 'object':
|
||||
if (isPreserveWritable<unknown>(v)) {
|
||||
if (v === null) {
|
||||
throw new Error("Cannot encode null in Preserves Writer.push");
|
||||
}
|
||||
else if (isPreserveWritable<any>(v)) {
|
||||
v.__preserve_text_on__(this);
|
||||
}
|
||||
else if (isPreserveWritable<T>(v)) {
|
||||
|
@ -295,16 +299,19 @@ export class Writer<T> {
|
|||
else if (isIterable(v)) {
|
||||
this.state.writeSeq('[', ']', v, vv => this.push(vv));
|
||||
}
|
||||
else {
|
||||
((v: Embedded<T>) => {
|
||||
this.state.pieces.push('#:');
|
||||
if ('write' in this.embeddedWrite) {
|
||||
this.embeddedWrite.write(this.state, v.embeddedValue);
|
||||
} else {
|
||||
new Writer(this.state, genericEmbeddedTypeEncode)
|
||||
.push(this.embeddedWrite.toValue(v.embeddedValue));
|
||||
}
|
||||
})(v);
|
||||
else if (isEmbedded(v)) {
|
||||
this.state.pieces.push('#:');
|
||||
if ('write' in this.embeddedWrite) {
|
||||
this.embeddedWrite.write(this.state, v);
|
||||
} else {
|
||||
new Writer(this.state, genericEmbeddedTypeEncode)
|
||||
.push(this.embeddedWrite.toValue(v));
|
||||
}
|
||||
} else {
|
||||
writeDictionaryOn(new DictionaryMap<T>(v),
|
||||
this,
|
||||
(k, w) => w.push(k),
|
||||
(v, w) => w.push(v));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -118,3 +118,11 @@ describe('base64 decoder', () => {
|
|||
it('gQ==', () => expect(d64('gQ==')).is(Bytes.of(0x81)));
|
||||
});
|
||||
});
|
||||
|
||||
describe('latin1 quasi-decoder', () => {
|
||||
it('decodes ascii', () => expect(Bytes.fromLatin1('abc')).is(Bytes.of(97, 98, 99)));
|
||||
it('encodes ascii', () => expect(Bytes.of(97, 98, 99).toLatin1()).is('abc'));
|
||||
it('decodes unprintables', () => expect(Bytes.fromLatin1('\x00\x01a\xfe\xff')).is(Bytes.of(0, 1, 97, 254, 255)));
|
||||
it('encodes unprintables', () => expect(Bytes.of(0, 1, 97, 254, 255).toLatin1()).is('\x00\x01a\xfe\xff'));
|
||||
it('rejects out-of-bounds', () => expect(() => Bytes.fromLatin1('ac╔b')).toThrowError('Codepoint out of range'));
|
||||
});
|
||||
|
|
|
@ -4,7 +4,6 @@ import {
|
|||
decode, decodeWithAnnotations, encode, canonicalEncode,
|
||||
DecodeError, ShortPacket,
|
||||
Bytes, Record,
|
||||
annotate,
|
||||
strip, peel,
|
||||
preserves,
|
||||
stringify,
|
||||
|
@ -16,11 +15,11 @@ import {
|
|||
EmbeddedType,
|
||||
DecoderState,
|
||||
Decoder,
|
||||
Embedded,
|
||||
embed,
|
||||
genericEmbeddedTypeDecode,
|
||||
genericEmbeddedTypeEncode,
|
||||
parse,
|
||||
Embedded,
|
||||
KeyedDictionary,
|
||||
} from '../src/index';
|
||||
const { Tag } = Constants;
|
||||
import './test-utils';
|
||||
|
@ -78,7 +77,7 @@ describe('parsing from subarray', () => {
|
|||
|
||||
describe('reusing buffer space', () => {
|
||||
it('should be done safely, even with nested dictionaries', () => {
|
||||
expect(canonicalEncode(fromJS(['aaa', Dictionary.fromJS({a: 1}), 'zzz'])).toHex()).is(
|
||||
expect(canonicalEncode(fromJS(['aaa', Dictionary.stringMap({a: 1}), 'zzz'])).toHex()).is(
|
||||
`b5
|
||||
b103616161
|
||||
b7
|
||||
|
@ -90,33 +89,29 @@ describe('reusing buffer space', () => {
|
|||
});
|
||||
|
||||
describe('encoding and decoding embeddeds', () => {
|
||||
class LookasideEmbeddedType implements EmbeddedType<object> {
|
||||
readonly objects: object[];
|
||||
class LookasideEmbeddedType implements EmbeddedType<Embedded<object>> {
|
||||
readonly objects: Embedded<object>[];
|
||||
|
||||
constructor(objects: object[]) {
|
||||
constructor(objects: Embedded<object>[]) {
|
||||
this.objects = objects;
|
||||
}
|
||||
|
||||
decode(d: DecoderState): object {
|
||||
decode(d: DecoderState): Embedded<object> {
|
||||
return this.fromValue(new Decoder<GenericEmbedded>(d).next());
|
||||
}
|
||||
|
||||
encode(e: EncoderState, v: object): void {
|
||||
encode(e: EncoderState, v: Embedded<object>): void {
|
||||
new Encoder(e).push(this.toValue(v));
|
||||
}
|
||||
|
||||
equals(a: object, b: object): boolean {
|
||||
return Object.is(a, b);
|
||||
}
|
||||
|
||||
fromValue(v: Value<GenericEmbedded>): object {
|
||||
fromValue(v: Value<GenericEmbedded>): Embedded<object> {
|
||||
if (typeof v !== 'number' || v < 0 || v >= this.objects.length) {
|
||||
throw new Error("Unknown embedded target");
|
||||
throw new Error(`Unknown embedded target: ${stringify(v)}`);
|
||||
}
|
||||
return this.objects[v];
|
||||
}
|
||||
|
||||
toValue(v: object): number {
|
||||
toValue(v: Embedded<object>): number {
|
||||
let i = this.objects.indexOf(v);
|
||||
if (i !== -1) return i;
|
||||
this.objects.push(v);
|
||||
|
@ -125,8 +120,8 @@ describe('encoding and decoding embeddeds', () => {
|
|||
}
|
||||
|
||||
it('should encode using embeddedId when no function has been supplied', () => {
|
||||
const A1 = embed({a: 1});
|
||||
const A2 = embed({a: 1});
|
||||
const A1 = new Embedded({a: 1});
|
||||
const A2 = new Embedded({a: 1});
|
||||
const bs1 = canonicalEncode(A1);
|
||||
const bs2 = canonicalEncode(A2);
|
||||
const bs3 = canonicalEncode(A1);
|
||||
|
@ -143,24 +138,24 @@ describe('encoding and decoding embeddeds', () => {
|
|||
.toThrow("Embeddeds not permitted at this point in Preserves document");
|
||||
});
|
||||
it('should encode properly', () => {
|
||||
const objects: object[] = [];
|
||||
const objects: Embedded<object>[] = [];
|
||||
const pt = new LookasideEmbeddedType(objects);
|
||||
const A = embed({a: 1});
|
||||
const B = embed({b: 2});
|
||||
const A = new Embedded({a: 1});
|
||||
const B = new Embedded({b: 2});
|
||||
expect(encode([A, B], { embeddedEncode: pt })).is(
|
||||
Bytes.from([Tag.Sequence,
|
||||
Tag.Embedded, Tag.SignedInteger, 0,
|
||||
Tag.Embedded, Tag.SignedInteger, 1, 1,
|
||||
Tag.End]));
|
||||
expect(objects).toEqual([A.embeddedValue, B.embeddedValue]);
|
||||
expect(objects).toEqual([A, B]);
|
||||
});
|
||||
it('should decode properly', () => {
|
||||
const objects: object[] = [];
|
||||
const objects: Embedded<object>[] = [];
|
||||
const pt = new LookasideEmbeddedType(objects);
|
||||
const X: Embedded<object> = embed({x: 123});
|
||||
const Y: Embedded<object> = embed({y: 456});
|
||||
objects.push(X.embeddedValue);
|
||||
objects.push(Y.embeddedValue);
|
||||
const X = new Embedded({x: 123});
|
||||
const Y = new Embedded({y: 456});
|
||||
objects.push(X);
|
||||
objects.push(Y);
|
||||
expect(decode(Bytes.from([
|
||||
Tag.Sequence,
|
||||
Tag.Embedded, Tag.SignedInteger, 0,
|
||||
|
@ -169,17 +164,17 @@ describe('encoding and decoding embeddeds', () => {
|
|||
]), { embeddedDecode: pt })).is([X, Y]);
|
||||
});
|
||||
it('should store embeddeds embedded in map keys correctly', () => {
|
||||
const A1a = {a: 1};
|
||||
const A1: Embedded<object> = embed(A1a);
|
||||
const A2: Embedded<object> = embed({a: 1});
|
||||
const m = new Dictionary<object, number>();
|
||||
const A1a = new Embedded({a: 1});
|
||||
const A1 = A1a;
|
||||
const A2 = new Embedded({a: 1});
|
||||
const m = new KeyedDictionary<Embedded<object>, Value<Embedded<object>>, number>();
|
||||
m.set([A1], 1);
|
||||
m.set([A2], 2);
|
||||
expect(m.get(A1)).toBeUndefined();
|
||||
expect(m.get([A1])).toBe(1);
|
||||
expect(m.get([A2])).toBe(2);
|
||||
expect(m.get([embed({a: 1})])).toBeUndefined();
|
||||
A1a.a = 3;
|
||||
expect(m.get([{a: 1}])).toBeUndefined();
|
||||
A1a.value.a = 3;
|
||||
expect(m.get([A1])).toBe(1);
|
||||
});
|
||||
});
|
||||
|
@ -309,7 +304,7 @@ describe('common test suite', () => {
|
|||
|
||||
const tests = (peel(TestCases._.cases(peel(samples) as TestCases)) as
|
||||
Dictionary<GenericEmbedded>);
|
||||
tests.forEach((t0: Value<GenericEmbedded>, tName0: Value<GenericEmbedded>) => {
|
||||
Dictionary.asMap(tests).forEach((t0, tName0) => {
|
||||
const tName = Symbol.keyFor(strip(tName0) as symbol)!;
|
||||
const t = peel(t0) as Record<symbol, any, GenericEmbedded>;
|
||||
switch (t.label) {
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
import { Pexpr, Value, fromJS, parse, stringify } from '../src/index';
|
||||
import './test-utils';
|
||||
|
||||
function P(s: string): Value<any>[] {
|
||||
return parse(s, { includeAnnotations: true });
|
||||
}
|
||||
|
||||
describe('basics', () => {
|
||||
it('simple example', () => {
|
||||
const r = new Pexpr.Reader('#!foo\n<bar {zot ::quux}, [a; b; c;]>');
|
||||
const d = r.nextDocument();
|
||||
expect(fromJS(d)).is(P(`[\n#!foo\n
|
||||
<r bar <b zot <p |::|> quux> <p |,|> [a <p |;|> b <p |;|> c <p |;|>]>]`));
|
||||
});
|
||||
|
||||
it('simple group', () => {
|
||||
const r = new Pexpr.Reader('(+ 1 2)');
|
||||
expect(fromJS(r.nextDocument())).is(P('[<g + 1 2>]'));
|
||||
});
|
||||
|
||||
it('asPreserves', () => {
|
||||
const s = '{a: b, c: d, e: [1, 2 <r 3 4>]}';
|
||||
const d = new Pexpr.Reader(s).nextDocument();
|
||||
const v = Pexpr.asPreserves(d.get(0)!);
|
||||
expect(v).is(P(s));
|
||||
});
|
||||
});
|
||||
|
||||
describe('trailing comments', () => {
|
||||
it('basics 1', () => {
|
||||
const d = new Pexpr.Reader('# a comment with nothing after').nextDocument();
|
||||
expect(d.annotations?.[d.exprs.length].get(0)?.item).toBe('a comment with nothing after');
|
||||
});
|
||||
|
||||
it('basics 2', () => {
|
||||
const d = new Pexpr.Reader('# a comment with nothing after\n').nextDocument();
|
||||
expect(d.annotations?.[d.exprs.length].get(0)?.item).toBe('a comment with nothing after');
|
||||
});
|
||||
|
||||
it('inside a sequence', () => {
|
||||
const d = new Pexpr.Reader('[\n1\n# a comment with nothing after\n]\n').nextDocument();
|
||||
const seq = d.get(0)?.item as Pexpr.Compound;
|
||||
expect(seq.annotations?.[seq.exprs.length].get(0)?.item).toBe('a comment with nothing after');
|
||||
});
|
||||
});
|
|
@ -1,4 +1,4 @@
|
|||
import { Bytes, Decoder, genericEmbeddedType, encode, Reader, Double } from '../src/index';
|
||||
import { Bytes, Decoder, genericEmbeddedType, encode, Reader, Double, KeyedDictionary, Value } from '../src/index';
|
||||
import './test-utils';
|
||||
|
||||
import * as fs from 'fs';
|
||||
|
@ -36,4 +36,23 @@ describe('reading common test suite', () => {
|
|||
expect(new Reader('123.0').next()).toEqual(Double(123.0));
|
||||
expect(new Reader('123.00').next()).toEqual(Double(123.0));
|
||||
});
|
||||
|
||||
it('should produce a sensible JS object for symbol-keyed dictionaries', () => {
|
||||
expect(new Reader('{a: 1, b: 2}').next()).toEqual({a: 1, b: 2});
|
||||
});
|
||||
|
||||
it('should produce a sensible dictionary for mixed-keyed dictionaries', () => {
|
||||
expect(new Reader('{a: 1, "b": 2}').next()).is(
|
||||
new KeyedDictionary([[Symbol.for('a'), 1], ["b", 2]] as [Value, Value][]));
|
||||
});
|
||||
|
||||
it('should produce a sensible dictionary for string-keyed dictionaries', () => {
|
||||
expect(new Reader('{"a": 1, "b": 2}').next()).is(
|
||||
new KeyedDictionary([["a", 1], ["b", 2]] as [Value, Value][]));
|
||||
});
|
||||
|
||||
it('should produce a sensible dictionary for integer-keyed dictionaries', () => {
|
||||
expect(new Reader('{9: 1, 8: 2}').next()).is(
|
||||
new KeyedDictionary([[9, 1], [8, 2]] as [Value, Value][]));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { Value, is, preserves } from '../src/index';
|
||||
import { Value, is, preserves, Embeddable } from '../src/index';
|
||||
import '../src/node_support';
|
||||
|
||||
declare global {
|
||||
namespace jest {
|
||||
interface Matchers<R> {
|
||||
is<T>(expected: Value<T>): R;
|
||||
is<T extends Embeddable>(expected: Value<T>): R;
|
||||
toThrowFilter(f: (e: Error) => boolean): R;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Double, fromJS, Dictionary, IDENTITY_FOLD, fold, mapEmbeddeds, Value, embed, preserves } from '../src/index';
|
||||
import { Double, fromJS, IDENTITY_FOLD, fold, mapEmbeddeds, Value, preserves, KeyedDictionary, Embeddable, Embedded } from '../src/index';
|
||||
import './test-utils';
|
||||
|
||||
describe('Double', () => {
|
||||
|
@ -8,13 +8,13 @@ describe('Double', () => {
|
|||
});
|
||||
|
||||
describe('fold', () => {
|
||||
function mkv<T extends object>(t: T): Value<T> {
|
||||
function mkv<T extends Embeddable>(t: T): Value<T> {
|
||||
return fromJS<T>([
|
||||
1,
|
||||
2,
|
||||
new Dictionary([[[3, 4], fromJS([5, 6])],
|
||||
['a', 1],
|
||||
['b', true]]),
|
||||
new KeyedDictionary<T>([[[3, 4], fromJS([5, 6])],
|
||||
['a', 1],
|
||||
['b', true]]),
|
||||
Double(3.4),
|
||||
t,
|
||||
]);
|
||||
|
@ -22,12 +22,12 @@ describe('fold', () => {
|
|||
|
||||
it('should support identity', () => {
|
||||
const w = new Date();
|
||||
const v = mkv(w);
|
||||
const v = mkv(new Embedded(w));
|
||||
expect(fold(v, IDENTITY_FOLD)).is(v);
|
||||
const w1 = new Date();
|
||||
const v1 = mkv(w1);
|
||||
const v1 = mkv(new Embedded(w1));
|
||||
expect(fold(v, IDENTITY_FOLD)).not.is(v1);
|
||||
expect(mapEmbeddeds(v, _t => embed(w1))).is(v1);
|
||||
expect(mapEmbeddeds(v, _t => new Embedded(w1))).is(v1);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -69,6 +69,12 @@ describe('is()', () => {
|
|||
expect(c).not.toBe(3);
|
||||
expect(c).not.is(3);
|
||||
});
|
||||
it('should compare equivalent JsDictionary and KeyedDictionary values sensibly', () => {
|
||||
const a = {a: 1, b: 2};
|
||||
const b = new KeyedDictionary(
|
||||
[[Symbol.for('a'), 1], [Symbol.for('b'), 2]] as [Value, Value][]);
|
||||
expect(a).is(b);
|
||||
});
|
||||
});
|
||||
|
||||
describe('`preserves` formatter', () => {
|
||||
|
@ -82,4 +88,18 @@ describe('`preserves` formatter', () => {
|
|||
expect(preserves`>${BigInt("12345678123456781234567812345678")}<`)
|
||||
.toBe('>12345678123456781234567812345678<');
|
||||
});
|
||||
it('should format regular JS objects', () => {
|
||||
expect(preserves`>${({a: 1, b: 2})}<`)
|
||||
.toBe('>{a: 1 b: 2}<');
|
||||
});
|
||||
it('should format dictionaries with string keys', () => {
|
||||
const v = new KeyedDictionary([["a", 1], ["b", 2]]);
|
||||
expect(preserves`>${v}<`)
|
||||
.toBe('>{"a": 1 "b": 2}<');
|
||||
});
|
||||
it('should format dictionaries with symbol keys', () => {
|
||||
const v = new KeyedDictionary([[Symbol.for("a"), 1], [Symbol.for("b"), 2]]);
|
||||
expect(preserves`>${v}<`)
|
||||
.toBe('>{a: 1 b: 2}<');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@preserves/schema-cli",
|
||||
"version": "0.994.0",
|
||||
"version": "0.995.206",
|
||||
"description": "Command-line tools for Preserves Schema",
|
||||
"homepage": "https://gitlab.com/preserves/preserves",
|
||||
"license": "Apache-2.0",
|
||||
|
@ -26,8 +26,8 @@
|
|||
"@types/minimatch": "^3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@preserves/core": "^0.994.0",
|
||||
"@preserves/schema": "^0.994.0",
|
||||
"@preserves/core": "^0.995.206",
|
||||
"@preserves/schema": "^0.995.206",
|
||||
"chalk": "^4.1",
|
||||
"chokidar": "^3.5",
|
||||
"commander": "^7.2",
|
||||
|
|
|
@ -25,7 +25,7 @@ export function run(options: CommandLineArguments): void {
|
|||
if (failures.length === 0) {
|
||||
if (options.bundle) {
|
||||
fs.writeSync(1, underlying(canonicalEncode(M.fromBundle(M.Bundle(
|
||||
new KeyedDictionary<M.ModulePath, M.Schema, M.InputEmbedded>(
|
||||
new KeyedDictionary<M.InputEmbedded, M.ModulePath, M.Schema>(
|
||||
inputFiles.map(i => [i.modulePath, i.schema])))))));
|
||||
} else {
|
||||
fs.writeSync(1, underlying(canonicalEncode(M.fromSchema(inputFiles[0].schema))));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@preserves/schema",
|
||||
"version": "0.994.0",
|
||||
"version": "0.995.206",
|
||||
"description": "Schema support for Preserves data serialization format",
|
||||
"homepage": "https://gitlab.com/preserves/preserves",
|
||||
"license": "Apache-2.0",
|
||||
|
@ -26,6 +26,10 @@
|
|||
"veryclean": "yarn run clean && rm -rf node_modules"
|
||||
},
|
||||
"dependencies": {
|
||||
"@preserves/core": "^0.994.0"
|
||||
"@preserves/core": "^0.995.206"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/js-beautify": "1.14",
|
||||
"js-beautify": "1.15"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,33 +68,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
// I.env.forEach((_schema, path) => console.log(PreservesSchema.Meta.formatModulePath(path)));
|
||||
|
||||
for (const [modulePath, schema] of I.env) {
|
||||
let container = Schema;
|
||||
modulePath.slice(0, -1).forEach(n => {
|
||||
if (!(n.description in container)) container[n.description] = {};
|
||||
container = container[n.description];
|
||||
});
|
||||
container[modulePath[modulePath.length - 1].description] = moduleFor(modulePath, schema);
|
||||
}
|
||||
|
||||
I.moduleTree(Schema);
|
||||
schemaReady();
|
||||
}
|
||||
|
||||
function moduleFor(modulePath, schema) {
|
||||
const { Meta, GenType, Type } = PreservesSchema;
|
||||
const mod = {};
|
||||
schema.definitions.forEach((d, n) => {
|
||||
const definitionName = n.description;
|
||||
const definitionId = Meta.jsId(definitionName);
|
||||
mod[`${definitionId}`] = I.definitionConstructor(modulePath, n);
|
||||
mod[`from${definitionId}`] = I.unparser(modulePath, n);
|
||||
mod[`to${definitionId}`] = v => I.tryParse(modulePath, n, v);
|
||||
mod[`as${definitionId}`] = v => I.parse(modulePath, n, v);
|
||||
});
|
||||
return mod;
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', translateScripts);
|
||||
})();
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { stringify } from '@preserves/core';
|
||||
import { JsDictionary, stringify } from '@preserves/core';
|
||||
import * as M from './meta';
|
||||
|
||||
export function checkSchema(schema: M.Schema): (
|
||||
{ ok: true, schema: M.Schema } | { ok: false, problems: Array<string> })
|
||||
{
|
||||
const checker = new Checker();
|
||||
schema.definitions.forEach(checker.checkDefinition.bind(checker));
|
||||
JsDictionary.forEach(schema.definitions, checker.checkDefinition.bind(checker));
|
||||
if (checker.problems.length > 0) {
|
||||
return { ok: false, problems: checker.problems };
|
||||
} else {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { encode, stringify } from "@preserves/core";
|
||||
import { encode, JsDictionary, stringify } from "@preserves/core";
|
||||
import * as M from "./meta";
|
||||
import { CompilerOptions, ModuleContext } from "./compiler/context";
|
||||
import { Formatter, block, seq, braces } from "./compiler/block";
|
||||
|
@ -29,7 +29,7 @@ export function compile(
|
|||
mod.defineType(seq(`export type _embedded = `, mod.embeddedType, `;`));
|
||||
}
|
||||
|
||||
for (const [name, def] of schema.definitions) {
|
||||
for (const [name, def] of JsDictionary.entries(schema.definitions)) {
|
||||
const t = typeForDefinition(mod.resolver(), def);
|
||||
const nameStr = stringify(name);
|
||||
const resultTypeItem = seq(nameStr, mod.genericArgsFor(t));
|
||||
|
@ -49,7 +49,7 @@ export function compile(
|
|||
}
|
||||
}
|
||||
|
||||
for (const [name0, def] of schema.definitions) {
|
||||
for (const [name0, def] of JsDictionary.entries(schema.definitions)) {
|
||||
const t = typeForDefinition(mod.resolver(), def);
|
||||
const name = name0 as symbol;
|
||||
const nameStr = name0.description!;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Dictionary, KeyedSet, FlexSet, Position, stringify } from "@preserves/core";
|
||||
import { KeyedSet, FlexSet, Position, stringify, DictionaryMap, JsDictionary } from "@preserves/core";
|
||||
import { refPosition } from "../reader";
|
||||
import * as M from "../meta";
|
||||
import { anglebrackets, block, braces, commas, formatItems, Item, keyvalue, seq } from "./block";
|
||||
|
@ -27,11 +27,11 @@ export class ModuleContext {
|
|||
readonly options: CompilerOptions;
|
||||
readonly embeddedType: Item;
|
||||
|
||||
readonly literals = new Dictionary<M.InputEmbedded, string>();
|
||||
readonly literals = new DictionaryMap<M.InputEmbedded, string>();
|
||||
readonly preamble: Item[] = [];
|
||||
readonly typedefs: Item[] = [];
|
||||
readonly functiondefs: Item[] = [];
|
||||
readonly imports = new KeyedSet<[M.ModulePath, string, string, string]>();
|
||||
readonly imports = new KeyedSet<M.InputEmbedded, [M.ModulePath, string, string, string]>();
|
||||
|
||||
constructor(
|
||||
env: M.Environment,
|
||||
|
@ -137,7 +137,7 @@ export class ModuleContext {
|
|||
null,
|
||||
null);
|
||||
} else {
|
||||
const p = e.schema.definitions.get(name.name);
|
||||
const p = JsDictionary.get(e.schema.definitions, name.name);
|
||||
if (p !== void 0) {
|
||||
let t = () => typeForDefinition(this.resolver(soughtModule), p);
|
||||
if (name.module.length) {
|
||||
|
@ -158,7 +158,7 @@ export class ModuleContext {
|
|||
}
|
||||
|
||||
genericParameters(): Item {
|
||||
return anglebrackets(seq('_embedded = ', this.embeddedType));
|
||||
return anglebrackets(seq('_embedded extends _.Embeddable = ', this.embeddedType));
|
||||
}
|
||||
|
||||
genericParametersFor(t: Type): Item {
|
||||
|
|
|
@ -2,7 +2,7 @@ import { FunctionContext } from "./context";
|
|||
import * as M from '../meta';
|
||||
import { Item, seq, parens, anglebrackets } from "./block";
|
||||
import { simpleType, typeFor } from "./gentype";
|
||||
import { ANY_TYPE, Type } from "./type";
|
||||
import { ANY_TYPE, isSymbolType, Type } from "./type";
|
||||
import { renderType } from "./rendertype";
|
||||
|
||||
export function converterForDefinition(
|
||||
|
@ -87,7 +87,7 @@ function converterForTuple(ctx: FunctionContext,
|
|||
}
|
||||
|
||||
const lengthCheck = variablePattern === void 0
|
||||
? seq(` && ${src}.length === ${ps.length}`)
|
||||
? seq(` && ${src}.length >= ${ps.length}`)
|
||||
: ((ps.length === 0) ? '' : seq(` && ${src}.length >= ${ps.length}`));
|
||||
|
||||
return knownArray
|
||||
|
@ -163,7 +163,7 @@ export function converterForSimple(
|
|||
return [seq(`${dest} = `, test, ` ? `, valexp, ` : void 0`)];
|
||||
}
|
||||
case 'embedded':
|
||||
return [`${dest} = _.isEmbedded<_embedded>(${src}) ? ${src}.embeddedValue : void 0`];
|
||||
return [`${dest} = _.isEmbedded<_embedded>(${src}) ? ${src} : void 0`];
|
||||
case 'lit':
|
||||
return [`${dest} = _.is(${src}, ${ctx.mod.literal(p.value)}) ? {} : void 0`];
|
||||
|
||||
|
@ -192,7 +192,7 @@ export function converterForSimple(
|
|||
const v = ctx.gentempname();
|
||||
return [
|
||||
seq(`${dest} = new _.EncodableSet`,
|
||||
anglebrackets(renderType(ctx.mod, vt), '_embedded'),
|
||||
anglebrackets('_embedded', renderType(ctx.mod, vt)),
|
||||
parens(encoderForSimplePattern(ctx, p.pattern) ?? `v => v`)),
|
||||
seq(`for (const ${v} of ${src}) `, ctx.block(() => [
|
||||
... converterFor(ctx, M.anonymousSimplePattern(p.pattern), v, vv =>
|
||||
|
@ -203,20 +203,30 @@ export function converterForSimple(
|
|||
case 'dictof':
|
||||
return [`${dest} = void 0`,
|
||||
seq(`if (_.Dictionary.isDictionary<_embedded>(${src})) `, ctx.block(() => {
|
||||
const srcMap = ctx.gentempname();
|
||||
const resolver = ctx.mod.resolver();
|
||||
const kt = simpleType(resolver, p.key);
|
||||
const vt = simpleType(resolver, p.value);
|
||||
const k = ctx.gentempname();
|
||||
const v = ctx.gentempname();
|
||||
const symbolKeyed = isSymbolType(kt);
|
||||
return [
|
||||
seq(`${dest} = new _.EncodableDictionary`,
|
||||
anglebrackets(renderType(ctx.mod, kt), renderType(ctx.mod, vt), '_embedded'),
|
||||
parens(encoderForSimplePattern(ctx, p.key) ?? `k => k`,
|
||||
encoderForSimplePattern(ctx, p.value) ?? `v => v`)),
|
||||
seq(`for (const [${k}, ${v}] of ${src}) `, ctx.block(() => [
|
||||
seq(`const ${srcMap} = new _.DictionaryMap(${src})`),
|
||||
(symbolKeyed
|
||||
? seq(`${dest} = {}`)
|
||||
: seq(`${dest} = new _.EncodableDictionary`,
|
||||
anglebrackets('_embedded', renderType(ctx.mod, kt), renderType(ctx.mod, vt)),
|
||||
parens(encoderForSimplePattern(ctx, p.key) ?? `k => k`,
|
||||
encoderForSimplePattern(ctx, p.value) ?? `v => v`))),
|
||||
seq(`for (const [${k}, ${v}] of ${srcMap}) `, ctx.block(() => [
|
||||
... converterFor(ctx, M.anonymousSimplePattern(p.key), k, kk =>
|
||||
converterFor(ctx, M.anonymousSimplePattern(p.value), v, vv =>
|
||||
[`${dest}.set(${kk}, ${vv})`, `continue`])),
|
||||
[
|
||||
(symbolKeyed
|
||||
? `${dest}[${kk}.description!] = ${vv}`
|
||||
: `${dest}.set(${kk}, ${vv})`),
|
||||
`continue`
|
||||
])),
|
||||
seq(`${dest} = void 0`),
|
||||
seq(`break`)]))];
|
||||
}))];
|
||||
|
@ -251,12 +261,13 @@ function converterForCompound(
|
|||
case 'tuplePrefix':
|
||||
return converterForTuple(ctx, p.fixed, src, knownArray, p.variable, ks);
|
||||
case 'dict': {
|
||||
const srcMap = ctx.gentempname();
|
||||
const entries = Array.from(p.entries);
|
||||
function loop(i: number): Item[] {
|
||||
if (i < entries.length) {
|
||||
const [k, n] = entries[i];
|
||||
const tmpSrc = ctx.gentemp();
|
||||
return [seq(`if ((${tmpSrc} = ${src}.get(${ctx.mod.literal(k)})) !== void 0) `,
|
||||
return [seq(`if ((${tmpSrc} = ${srcMap}.get(${ctx.mod.literal(k)})) !== void 0) `,
|
||||
ctx.block(() =>
|
||||
converterFor(
|
||||
ctx,
|
||||
|
@ -267,7 +278,9 @@ function converterForCompound(
|
|||
return ks();
|
||||
}
|
||||
}
|
||||
return [seq(`if (_.Dictionary.isDictionary<_embedded>(${src})) `, ctx.block(() => loop(0)))];
|
||||
return [seq(`if (_.Dictionary.isDictionary<_embedded>(${src})) `, ctx.block(() => [
|
||||
seq(`const ${srcMap} = new _.DictionaryMap(${src})`),
|
||||
... loop(0)]))];
|
||||
}
|
||||
default:
|
||||
((_p: never) => {})(p);
|
||||
|
|
|
@ -46,7 +46,7 @@ function unconverterFor(ctx: FunctionContext, p: M.Pattern, src: string): Item {
|
|||
case 'lit':
|
||||
return ctx.mod.literal(p.value);
|
||||
case 'embedded':
|
||||
return `_.embed(${src})`;
|
||||
return `${src}`;
|
||||
case 'seqof':
|
||||
return seq(`${src}.map(v => `,
|
||||
unconverterFor(ctx, M.Pattern.SimplePattern(p.pattern), 'v'),
|
||||
|
@ -57,8 +57,10 @@ function unconverterFor(ctx: FunctionContext, p: M.Pattern, src: string): Item {
|
|||
unconverterFor(ctx, M.Pattern.SimplePattern(p.pattern), 'v'),
|
||||
`)`)));
|
||||
case 'dictof':
|
||||
return seq(`new _.Dictionary<_embedded>`, parens(seq(
|
||||
`_.Array.from(${src}.entries()).map(([k, v]) => `,
|
||||
return seq(`_.Dictionary.from<_embedded>`, parens(seq(
|
||||
`_.Array.from(`,
|
||||
M.isSymbolPattern(p.key) ? `_.JsDictionary.entries(${src})` : `${src}.entries()`,
|
||||
`).map(([k, v]) => `,
|
||||
brackets(
|
||||
unconverterFor(ctx, M.Pattern.SimplePattern(p.key), 'k'),
|
||||
unconverterFor(ctx, M.Pattern.SimplePattern(p.value), 'v')),
|
||||
|
@ -95,7 +97,7 @@ function unconverterFor(ctx: FunctionContext, p: M.Pattern, src: string): Item {
|
|||
}
|
||||
}
|
||||
case 'dict':
|
||||
return seq(`new _.Dictionary<_embedded>`, parens(
|
||||
return seq(`_.Dictionary.from<_embedded>`, parens(
|
||||
brackets(... Array.from(p.entries.entries()).map(([k, n]) =>
|
||||
brackets(
|
||||
ctx.mod.literal(k),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { SimpleType, Type } from "./type";
|
||||
import { isSymbolType, SimpleType, Type } from "./type";
|
||||
import { anglebrackets, braces, Item, keyvalue, opseq, seq } from "./block";
|
||||
import { ModuleContext } from "./context";
|
||||
|
||||
|
@ -47,12 +47,17 @@ export function renderType(ctxt: ModuleContext, t: Type): Item {
|
|||
return seq(t.typeName, ctxt.genericArgsFor(t));
|
||||
}
|
||||
case 'set': return seq('_.EncodableSet', anglebrackets(
|
||||
renderType(ctxt, t.type),
|
||||
'_embedded'));
|
||||
case 'dictionary': return seq('_.EncodableDictionary', anglebrackets(
|
||||
renderType(ctxt, t.key),
|
||||
renderType(ctxt, t.value),
|
||||
'_embedded'));
|
||||
'_embedded',
|
||||
renderType(ctxt, t.type)));
|
||||
case 'dictionary':
|
||||
if (isSymbolType(t.key)) {
|
||||
return seq('_.JsDictionary', anglebrackets(renderType(ctxt, t.value)));
|
||||
} else {
|
||||
return seq('_.EncodableDictionary', anglebrackets(
|
||||
'_embedded',
|
||||
renderType(ctxt, t.key),
|
||||
renderType(ctxt, t.value)));
|
||||
}
|
||||
case 'array': return seq('Array', anglebrackets(renderType(ctxt, t.type)));
|
||||
case 'record': return braces(... simpleTypeFields(ctxt, t));
|
||||
default:
|
||||
|
|
|
@ -35,3 +35,7 @@ export namespace Type {
|
|||
}
|
||||
|
||||
export const ANY_TYPE: FieldType = Type.ref('_.Value', null);
|
||||
|
||||
export function isSymbolType(ty: FieldType): ty is { kind: 'ref', typeName: 'symbol', ref: null } {
|
||||
return ty.kind === 'ref' && ty.typeName === 'symbol' && ty.ref === null;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Annotated, Bytes, Set, Dictionary, Fold, fold, Record, Tuple, Value, stringify, Embedded } from "@preserves/core";
|
||||
import { Annotated, Bytes, Set, Fold, fold, Record, Tuple, Value, stringify, DictionaryMap } from "@preserves/core";
|
||||
import { brackets, Item, parens, seq } from "./block";
|
||||
import * as M from '../meta';
|
||||
|
||||
|
@ -22,8 +22,8 @@ export function sourceCodeFor(v: Value<M.InputEmbedded>): Item {
|
|||
set(s: Set<M.InputEmbedded>, k: Fold<M.InputEmbedded, Item>): Item {
|
||||
return seq('new _.Set<_.Value<_embedded>>', parens(brackets(... Array.from(s).map(k))));
|
||||
},
|
||||
dictionary(d: Dictionary<M.InputEmbedded>, k: Fold<M.InputEmbedded, Item>): Item {
|
||||
return seq('new _.Dictionary<_embedded>', parens(brackets(... Array.from(d).map(([kk,vv]) =>
|
||||
dictionary(d: DictionaryMap<M.InputEmbedded>, k: Fold<M.InputEmbedded, Item>): Item {
|
||||
return seq('_.Dictionary.from<_embedded>', parens(brackets(... Array.from(d).map(([kk,vv]) =>
|
||||
brackets(k(kk), k(vv))))));
|
||||
},
|
||||
|
||||
|
@ -31,7 +31,7 @@ export function sourceCodeFor(v: Value<M.InputEmbedded>): Item {
|
|||
return seq('_.annotate<_embedded>', parens(k(a.item), ... a.annotations.map(k)));
|
||||
},
|
||||
|
||||
embedded(t: Embedded<M.InputEmbedded>, _k: Fold<M.InputEmbedded, Item>): Item {
|
||||
embedded(t: M.InputEmbedded, _k: Fold<M.InputEmbedded, Item>): Item {
|
||||
throw new Error(`Cannot emit source code for construction of embedded ${stringify(t)}`);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -30,14 +30,18 @@ export type Definition = (
|
|||
) &
|
||||
_.Preservable<any> &
|
||||
_.PreserveWritable<any> &
|
||||
{__as_preserve__<_embedded = _.GenericEmbedded>(): _.Value<_embedded>}
|
||||
{
|
||||
__as_preserve__<_embedded extends _.Embeddable = _.GenericEmbedded>(): _.Value<_embedded>
|
||||
}
|
||||
);
|
||||
|
||||
export type Variant = (
|
||||
{"label": symbol, "type": Simple} &
|
||||
_.Preservable<any> &
|
||||
_.PreserveWritable<any> &
|
||||
{__as_preserve__<_embedded = _.GenericEmbedded>(): _.Value<_embedded>}
|
||||
{
|
||||
__as_preserve__<_embedded extends _.Embeddable = _.GenericEmbedded>(): _.Value<_embedded>
|
||||
}
|
||||
);
|
||||
|
||||
export type Simple = (
|
||||
|
@ -47,21 +51,27 @@ export type Simple = (
|
|||
) &
|
||||
_.Preservable<any> &
|
||||
_.PreserveWritable<any> &
|
||||
{__as_preserve__<_embedded = _.GenericEmbedded>(): _.Value<_embedded>}
|
||||
{
|
||||
__as_preserve__<_embedded extends _.Embeddable = _.GenericEmbedded>(): _.Value<_embedded>
|
||||
}
|
||||
);
|
||||
|
||||
export type Record = (
|
||||
{"fields": Array<NamedField>} &
|
||||
_.Preservable<any> &
|
||||
_.PreserveWritable<any> &
|
||||
{__as_preserve__<_embedded = _.GenericEmbedded>(): _.Value<_embedded>}
|
||||
{
|
||||
__as_preserve__<_embedded extends _.Embeddable = _.GenericEmbedded>(): _.Value<_embedded>
|
||||
}
|
||||
);
|
||||
|
||||
export type NamedField = (
|
||||
{"name": symbol, "type": Field} &
|
||||
_.Preservable<any> &
|
||||
_.PreserveWritable<any> &
|
||||
{__as_preserve__<_embedded = _.GenericEmbedded>(): _.Value<_embedded>}
|
||||
{
|
||||
__as_preserve__<_embedded extends _.Embeddable = _.GenericEmbedded>(): _.Value<_embedded>
|
||||
}
|
||||
);
|
||||
|
||||
export type Field = (
|
||||
|
@ -77,7 +87,9 @@ export type Field = (
|
|||
) &
|
||||
_.Preservable<any> &
|
||||
_.PreserveWritable<any> &
|
||||
{__as_preserve__<_embedded = _.GenericEmbedded>(): _.Value<_embedded>}
|
||||
{
|
||||
__as_preserve__<_embedded extends _.Embeddable = _.GenericEmbedded>(): _.Value<_embedded>
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
@ -337,13 +349,13 @@ export namespace Field {
|
|||
};
|
||||
}
|
||||
|
||||
export function asDefinition<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): Definition {
|
||||
export function asDefinition<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): Definition {
|
||||
let result = toDefinition(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid Definition: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toDefinition<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Definition {
|
||||
export function toDefinition<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Definition {
|
||||
let result: undefined | Definition;
|
||||
if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) {
|
||||
let _tmp0: ({}) | undefined;
|
||||
|
@ -390,22 +402,22 @@ export function toDefinition<_embedded = _.GenericEmbedded>(v: _.Value<_embedded
|
|||
|
||||
export namespace Definition {export const __from_preserve__ = toDefinition;}
|
||||
|
||||
export function fromDefinition<_embedded = _.GenericEmbedded>(_v: Definition): _.Value<_embedded> {
|
||||
export function fromDefinition<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: Definition): _.Value<_embedded> {
|
||||
switch (_v._variant) {
|
||||
case "union": {return _.Record($union, [_v["variants"].map(v => fromVariant<_embedded>(v))]);};
|
||||
case "Simple": {return fromSimple<_embedded>(_v.value);};
|
||||
};
|
||||
}
|
||||
|
||||
export function asVariant<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): Variant {
|
||||
export function asVariant<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): Variant {
|
||||
let result = toVariant(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid Variant: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toVariant<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Variant {
|
||||
export function toVariant<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Variant {
|
||||
let result: undefined | Variant;
|
||||
if (_.isSequence(v) && v.length === 2) {
|
||||
if (_.isSequence(v) && v.length >= 2) {
|
||||
let _tmp0: (symbol) | undefined;
|
||||
_tmp0 = typeof v[0] === 'symbol' ? v[0] : void 0;
|
||||
if (_tmp0 !== void 0) {
|
||||
|
@ -427,15 +439,15 @@ export function toVariant<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>):
|
|||
|
||||
Variant.__from_preserve__ = toVariant;
|
||||
|
||||
export function fromVariant<_embedded = _.GenericEmbedded>(_v: Variant): _.Value<_embedded> {return [_v["label"], fromSimple<_embedded>(_v["type"])];}
|
||||
export function fromVariant<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: Variant): _.Value<_embedded> {return [_v["label"], fromSimple<_embedded>(_v["type"])];}
|
||||
|
||||
export function asSimple<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): Simple {
|
||||
export function asSimple<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): Simple {
|
||||
let result = toSimple(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid Simple: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toSimple<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Simple {
|
||||
export function toSimple<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Simple {
|
||||
let _tmp0: (Field) | undefined;
|
||||
let result: undefined | Simple;
|
||||
_tmp0 = toField(v);
|
||||
|
@ -466,20 +478,20 @@ export function toSimple<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>):
|
|||
|
||||
export namespace Simple {export const __from_preserve__ = toSimple;}
|
||||
|
||||
export function fromSimple<_embedded = _.GenericEmbedded>(_v: Simple): _.Value<_embedded> {
|
||||
export function fromSimple<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: Simple): _.Value<_embedded> {
|
||||
switch (_v._variant) {
|
||||
case "Field": {return fromField<_embedded>(_v.value);};
|
||||
case "Record": {return fromRecord<_embedded>(_v.value);};
|
||||
};
|
||||
}
|
||||
|
||||
export function asRecord<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): Record {
|
||||
export function asRecord<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): Record {
|
||||
let result = toRecord(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid Record: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toRecord<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Record {
|
||||
export function toRecord<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Record {
|
||||
let result: undefined | Record;
|
||||
if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) {
|
||||
let _tmp0: ({}) | undefined;
|
||||
|
@ -512,17 +524,17 @@ export function toRecord<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>):
|
|||
|
||||
Record.__from_preserve__ = toRecord;
|
||||
|
||||
export function fromRecord<_embedded = _.GenericEmbedded>(_v: Record): _.Value<_embedded> {return _.Record($rec, [_v["fields"].map(v => fromNamedField<_embedded>(v))]);}
|
||||
export function fromRecord<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: Record): _.Value<_embedded> {return _.Record($rec, [_v["fields"].map(v => fromNamedField<_embedded>(v))]);}
|
||||
|
||||
export function asNamedField<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): NamedField {
|
||||
export function asNamedField<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): NamedField {
|
||||
let result = toNamedField(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid NamedField: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toNamedField<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | NamedField {
|
||||
export function toNamedField<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | NamedField {
|
||||
let result: undefined | NamedField;
|
||||
if (_.isSequence(v) && v.length === 2) {
|
||||
if (_.isSequence(v) && v.length >= 2) {
|
||||
let _tmp0: (symbol) | undefined;
|
||||
_tmp0 = typeof v[0] === 'symbol' ? v[0] : void 0;
|
||||
if (_tmp0 !== void 0) {
|
||||
|
@ -544,15 +556,15 @@ export function toNamedField<_embedded = _.GenericEmbedded>(v: _.Value<_embedded
|
|||
|
||||
NamedField.__from_preserve__ = toNamedField;
|
||||
|
||||
export function fromNamedField<_embedded = _.GenericEmbedded>(_v: NamedField): _.Value<_embedded> {return [_v["name"], fromField<_embedded>(_v["type"])];}
|
||||
export function fromNamedField<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: NamedField): _.Value<_embedded> {return [_v["name"], fromField<_embedded>(_v["type"])];}
|
||||
|
||||
export function asField<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): Field {
|
||||
export function asField<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): Field {
|
||||
let result = toField(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid Field: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toField<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Field {
|
||||
export function toField<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Field {
|
||||
let _tmp0: ({}) | undefined;
|
||||
let result: undefined | Field;
|
||||
_tmp0 = _.is(v, $unit) ? {} : void 0;
|
||||
|
@ -687,7 +699,7 @@ export function toField<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): u
|
|||
|
||||
export namespace Field {export const __from_preserve__ = toField;}
|
||||
|
||||
export function fromField<_embedded = _.GenericEmbedded>(_v: Field): _.Value<_embedded> {
|
||||
export function fromField<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: Field): _.Value<_embedded> {
|
||||
switch (_v._variant) {
|
||||
case "unit": {return $unit;};
|
||||
case "any": {return $any;};
|
||||
|
|
|
@ -41,16 +41,16 @@ export function _schema() {
|
|||
export const _imports = {}
|
||||
|
||||
|
||||
export type Bundle<_embedded = _.GenericEmbedded> = (
|
||||
export type Bundle<_embedded extends _.Embeddable = _.GenericEmbedded> = (
|
||||
{"modules": Modules<_embedded>} &
|
||||
_.Preservable<_embedded> &
|
||||
_.PreserveWritable<_embedded> &
|
||||
{__as_preserve__(): _.Value<_embedded>}
|
||||
);
|
||||
|
||||
export type Modules<_embedded = _.GenericEmbedded> = _.EncodableDictionary<ModulePath, Schema<_embedded>, _embedded>;
|
||||
export type Modules<_embedded extends _.Embeddable = _.GenericEmbedded> = _.EncodableDictionary<_embedded, ModulePath, Schema<_embedded>>;
|
||||
|
||||
export type Schema<_embedded = _.GenericEmbedded> = (
|
||||
export type Schema<_embedded extends _.Embeddable = _.GenericEmbedded> = (
|
||||
{
|
||||
"version": Version,
|
||||
"embeddedType": EmbeddedTypeName,
|
||||
|
@ -65,19 +65,23 @@ export type Version = (
|
|||
{} &
|
||||
_.Preservable<any> &
|
||||
_.PreserveWritable<any> &
|
||||
{__as_preserve__<_embedded = _.GenericEmbedded>(): _.Value<_embedded>}
|
||||
{
|
||||
__as_preserve__<_embedded extends _.Embeddable = _.GenericEmbedded>(): _.Value<_embedded>
|
||||
}
|
||||
);
|
||||
|
||||
export type EmbeddedTypeName = (
|
||||
({"_variant": "false"} | {"_variant": "Ref", "value": Ref}) &
|
||||
_.Preservable<any> &
|
||||
_.PreserveWritable<any> &
|
||||
{__as_preserve__<_embedded = _.GenericEmbedded>(): _.Value<_embedded>}
|
||||
{
|
||||
__as_preserve__<_embedded extends _.Embeddable = _.GenericEmbedded>(): _.Value<_embedded>
|
||||
}
|
||||
);
|
||||
|
||||
export type Definitions<_embedded = _.GenericEmbedded> = _.EncodableDictionary<symbol, Definition<_embedded>, _embedded>;
|
||||
export type Definitions<_embedded extends _.Embeddable = _.GenericEmbedded> = _.JsDictionary<Definition<_embedded>>;
|
||||
|
||||
export type Definition<_embedded = _.GenericEmbedded> = (
|
||||
export type Definition<_embedded extends _.Embeddable = _.GenericEmbedded> = (
|
||||
(
|
||||
{
|
||||
"_variant": "or",
|
||||
|
@ -98,7 +102,7 @@ export type Definition<_embedded = _.GenericEmbedded> = (
|
|||
{__as_preserve__(): _.Value<_embedded>}
|
||||
);
|
||||
|
||||
export type Pattern<_embedded = _.GenericEmbedded> = (
|
||||
export type Pattern<_embedded extends _.Embeddable = _.GenericEmbedded> = (
|
||||
(
|
||||
{"_variant": "SimplePattern", "value": SimplePattern<_embedded>} |
|
||||
{"_variant": "CompoundPattern", "value": CompoundPattern<_embedded>}
|
||||
|
@ -108,7 +112,7 @@ export type Pattern<_embedded = _.GenericEmbedded> = (
|
|||
{__as_preserve__(): _.Value<_embedded>}
|
||||
);
|
||||
|
||||
export type SimplePattern<_embedded = _.GenericEmbedded> = (
|
||||
export type SimplePattern<_embedded extends _.Embeddable = _.GenericEmbedded> = (
|
||||
(
|
||||
{"_variant": "any"} |
|
||||
{"_variant": "atom", "atomKind": AtomKind} |
|
||||
|
@ -128,7 +132,7 @@ export type SimplePattern<_embedded = _.GenericEmbedded> = (
|
|||
{__as_preserve__(): _.Value<_embedded>}
|
||||
);
|
||||
|
||||
export type CompoundPattern<_embedded = _.GenericEmbedded> = (
|
||||
export type CompoundPattern<_embedded extends _.Embeddable = _.GenericEmbedded> = (
|
||||
(
|
||||
{
|
||||
"_variant": "rec",
|
||||
|
@ -148,7 +152,7 @@ export type CompoundPattern<_embedded = _.GenericEmbedded> = (
|
|||
{__as_preserve__(): _.Value<_embedded>}
|
||||
);
|
||||
|
||||
export type DictionaryEntries<_embedded = _.GenericEmbedded> = _.EncodableDictionary<_.Value<_embedded>, NamedSimplePattern<_embedded>, _embedded>;
|
||||
export type DictionaryEntries<_embedded extends _.Embeddable = _.GenericEmbedded> = _.EncodableDictionary<_embedded, _.Value<_embedded>, NamedSimplePattern<_embedded>>;
|
||||
|
||||
export type AtomKind = (
|
||||
(
|
||||
|
@ -161,17 +165,19 @@ export type AtomKind = (
|
|||
) &
|
||||
_.Preservable<any> &
|
||||
_.PreserveWritable<any> &
|
||||
{__as_preserve__<_embedded = _.GenericEmbedded>(): _.Value<_embedded>}
|
||||
{
|
||||
__as_preserve__<_embedded extends _.Embeddable = _.GenericEmbedded>(): _.Value<_embedded>
|
||||
}
|
||||
);
|
||||
|
||||
export type NamedAlternative<_embedded = _.GenericEmbedded> = (
|
||||
export type NamedAlternative<_embedded extends _.Embeddable = _.GenericEmbedded> = (
|
||||
{"variantLabel": string, "pattern": Pattern<_embedded>} &
|
||||
_.Preservable<_embedded> &
|
||||
_.PreserveWritable<_embedded> &
|
||||
{__as_preserve__(): _.Value<_embedded>}
|
||||
);
|
||||
|
||||
export type NamedSimplePattern<_embedded = _.GenericEmbedded> = (
|
||||
export type NamedSimplePattern<_embedded extends _.Embeddable = _.GenericEmbedded> = (
|
||||
(
|
||||
{"_variant": "named", "value": Binding<_embedded>} |
|
||||
{"_variant": "anonymous", "value": SimplePattern<_embedded>}
|
||||
|
@ -181,7 +187,7 @@ export type NamedSimplePattern<_embedded = _.GenericEmbedded> = (
|
|||
{__as_preserve__(): _.Value<_embedded>}
|
||||
);
|
||||
|
||||
export type NamedPattern<_embedded = _.GenericEmbedded> = (
|
||||
export type NamedPattern<_embedded extends _.Embeddable = _.GenericEmbedded> = (
|
||||
(
|
||||
{"_variant": "named", "value": Binding<_embedded>} |
|
||||
{"_variant": "anonymous", "value": Pattern<_embedded>}
|
||||
|
@ -191,7 +197,7 @@ export type NamedPattern<_embedded = _.GenericEmbedded> = (
|
|||
{__as_preserve__(): _.Value<_embedded>}
|
||||
);
|
||||
|
||||
export type Binding<_embedded = _.GenericEmbedded> = (
|
||||
export type Binding<_embedded extends _.Embeddable = _.GenericEmbedded> = (
|
||||
{"name": symbol, "pattern": SimplePattern<_embedded>} &
|
||||
_.Preservable<_embedded> &
|
||||
_.PreserveWritable<_embedded> &
|
||||
|
@ -202,13 +208,15 @@ export type Ref = (
|
|||
{"module": ModulePath, "name": symbol} &
|
||||
_.Preservable<any> &
|
||||
_.PreserveWritable<any> &
|
||||
{__as_preserve__<_embedded = _.GenericEmbedded>(): _.Value<_embedded>}
|
||||
{
|
||||
__as_preserve__<_embedded extends _.Embeddable = _.GenericEmbedded>(): _.Value<_embedded>
|
||||
}
|
||||
);
|
||||
|
||||
export type ModulePath = Array<symbol>;
|
||||
|
||||
|
||||
export function Bundle<_embedded = _.GenericEmbedded>(modules: Modules<_embedded>): Bundle<_embedded> {
|
||||
export function Bundle<_embedded extends _.Embeddable = _.GenericEmbedded>(modules: Modules<_embedded>): Bundle<_embedded> {
|
||||
return {
|
||||
"modules": modules,
|
||||
__as_preserve__() {return fromBundle(this);},
|
||||
|
@ -221,13 +229,13 @@ Bundle.schema = function () {
|
|||
return {schema: _schema(), imports: _imports, definitionName: _.Symbol.for("Bundle")};
|
||||
}
|
||||
|
||||
export function Modules<_embedded = _.GenericEmbedded>(value: _.EncodableDictionary<ModulePath, Schema<_embedded>, _embedded>): Modules<_embedded> {return value;}
|
||||
export function Modules<_embedded extends _.Embeddable = _.GenericEmbedded>(value: _.EncodableDictionary<_embedded, ModulePath, Schema<_embedded>>): Modules<_embedded> {return value;}
|
||||
|
||||
Modules.schema = function () {
|
||||
return {schema: _schema(), imports: _imports, definitionName: _.Symbol.for("Modules")};
|
||||
}
|
||||
|
||||
export function Schema<_embedded = _.GenericEmbedded>(
|
||||
export function Schema<_embedded extends _.Embeddable = _.GenericEmbedded>(
|
||||
{version, embeddedType, definitions}: {
|
||||
version: Version,
|
||||
embeddedType: EmbeddedTypeName,
|
||||
|
@ -296,7 +304,7 @@ export namespace EmbeddedTypeName {
|
|||
};
|
||||
}
|
||||
|
||||
export function Definitions<_embedded = _.GenericEmbedded>(value: _.EncodableDictionary<symbol, Definition<_embedded>, _embedded>): Definitions<_embedded> {return value;}
|
||||
export function Definitions<_embedded extends _.Embeddable = _.GenericEmbedded>(value: _.JsDictionary<Definition<_embedded>>): Definitions<_embedded> {return value;}
|
||||
|
||||
Definitions.schema = function () {
|
||||
return {
|
||||
|
@ -307,7 +315,7 @@ Definitions.schema = function () {
|
|||
}
|
||||
|
||||
export namespace Definition {
|
||||
export function or<_embedded = _.GenericEmbedded>(
|
||||
export function or<_embedded extends _.Embeddable = _.GenericEmbedded>(
|
||||
{pattern0, pattern1, patternN}: {
|
||||
pattern0: NamedAlternative<_embedded>,
|
||||
pattern1: NamedAlternative<_embedded>,
|
||||
|
@ -332,7 +340,7 @@ export namespace Definition {
|
|||
variant: _.Symbol.for("or")
|
||||
};
|
||||
};
|
||||
export function and<_embedded = _.GenericEmbedded>(
|
||||
export function and<_embedded extends _.Embeddable = _.GenericEmbedded>(
|
||||
{pattern0, pattern1, patternN}: {
|
||||
pattern0: NamedPattern<_embedded>,
|
||||
pattern1: NamedPattern<_embedded>,
|
||||
|
@ -357,7 +365,7 @@ export namespace Definition {
|
|||
variant: _.Symbol.for("and")
|
||||
};
|
||||
};
|
||||
export function Pattern<_embedded = _.GenericEmbedded>(value: Pattern<_embedded>): Definition<_embedded> {
|
||||
export function Pattern<_embedded extends _.Embeddable = _.GenericEmbedded>(value: Pattern<_embedded>): Definition<_embedded> {
|
||||
return {
|
||||
"_variant": "Pattern",
|
||||
"value": value,
|
||||
|
@ -377,7 +385,7 @@ export namespace Definition {
|
|||
}
|
||||
|
||||
export namespace Pattern {
|
||||
export function SimplePattern<_embedded = _.GenericEmbedded>(value: SimplePattern<_embedded>): Pattern<_embedded> {
|
||||
export function SimplePattern<_embedded extends _.Embeddable = _.GenericEmbedded>(value: SimplePattern<_embedded>): Pattern<_embedded> {
|
||||
return {
|
||||
"_variant": "SimplePattern",
|
||||
"value": value,
|
||||
|
@ -394,7 +402,7 @@ export namespace Pattern {
|
|||
variant: _.Symbol.for("SimplePattern")
|
||||
};
|
||||
};
|
||||
export function CompoundPattern<_embedded = _.GenericEmbedded>(value: CompoundPattern<_embedded>): Pattern<_embedded> {
|
||||
export function CompoundPattern<_embedded extends _.Embeddable = _.GenericEmbedded>(value: CompoundPattern<_embedded>): Pattern<_embedded> {
|
||||
return {
|
||||
"_variant": "CompoundPattern",
|
||||
"value": value,
|
||||
|
@ -414,7 +422,7 @@ export namespace Pattern {
|
|||
}
|
||||
|
||||
export namespace SimplePattern {
|
||||
export function any<_embedded = _.GenericEmbedded>(): SimplePattern<_embedded> {
|
||||
export function any<_embedded extends _.Embeddable = _.GenericEmbedded>(): SimplePattern<_embedded> {
|
||||
return {
|
||||
"_variant": "any",
|
||||
__as_preserve__() {return fromSimplePattern(this);},
|
||||
|
@ -430,7 +438,7 @@ export namespace SimplePattern {
|
|||
variant: _.Symbol.for("any")
|
||||
};
|
||||
};
|
||||
export function atom<_embedded = _.GenericEmbedded>(atomKind: AtomKind): SimplePattern<_embedded> {
|
||||
export function atom<_embedded extends _.Embeddable = _.GenericEmbedded>(atomKind: AtomKind): SimplePattern<_embedded> {
|
||||
return {
|
||||
"_variant": "atom",
|
||||
"atomKind": atomKind,
|
||||
|
@ -447,7 +455,7 @@ export namespace SimplePattern {
|
|||
variant: _.Symbol.for("atom")
|
||||
};
|
||||
};
|
||||
export function embedded<_embedded = _.GenericEmbedded>($interface: SimplePattern<_embedded>): SimplePattern<_embedded> {
|
||||
export function embedded<_embedded extends _.Embeddable = _.GenericEmbedded>($interface: SimplePattern<_embedded>): SimplePattern<_embedded> {
|
||||
return {
|
||||
"_variant": "embedded",
|
||||
"interface": $interface,
|
||||
|
@ -464,7 +472,7 @@ export namespace SimplePattern {
|
|||
variant: _.Symbol.for("embedded")
|
||||
};
|
||||
};
|
||||
export function lit<_embedded = _.GenericEmbedded>(value: _.Value<_embedded>): SimplePattern<_embedded> {
|
||||
export function lit<_embedded extends _.Embeddable = _.GenericEmbedded>(value: _.Value<_embedded>): SimplePattern<_embedded> {
|
||||
return {
|
||||
"_variant": "lit",
|
||||
"value": value,
|
||||
|
@ -481,7 +489,7 @@ export namespace SimplePattern {
|
|||
variant: _.Symbol.for("lit")
|
||||
};
|
||||
};
|
||||
export function seqof<_embedded = _.GenericEmbedded>(pattern: SimplePattern<_embedded>): SimplePattern<_embedded> {
|
||||
export function seqof<_embedded extends _.Embeddable = _.GenericEmbedded>(pattern: SimplePattern<_embedded>): SimplePattern<_embedded> {
|
||||
return {
|
||||
"_variant": "seqof",
|
||||
"pattern": pattern,
|
||||
|
@ -498,7 +506,7 @@ export namespace SimplePattern {
|
|||
variant: _.Symbol.for("seqof")
|
||||
};
|
||||
};
|
||||
export function setof<_embedded = _.GenericEmbedded>(pattern: SimplePattern<_embedded>): SimplePattern<_embedded> {
|
||||
export function setof<_embedded extends _.Embeddable = _.GenericEmbedded>(pattern: SimplePattern<_embedded>): SimplePattern<_embedded> {
|
||||
return {
|
||||
"_variant": "setof",
|
||||
"pattern": pattern,
|
||||
|
@ -515,7 +523,7 @@ export namespace SimplePattern {
|
|||
variant: _.Symbol.for("setof")
|
||||
};
|
||||
};
|
||||
export function dictof<_embedded = _.GenericEmbedded>({key, value}: {key: SimplePattern<_embedded>, value: SimplePattern<_embedded>}): SimplePattern<_embedded> {
|
||||
export function dictof<_embedded extends _.Embeddable = _.GenericEmbedded>({key, value}: {key: SimplePattern<_embedded>, value: SimplePattern<_embedded>}): SimplePattern<_embedded> {
|
||||
return {
|
||||
"_variant": "dictof",
|
||||
"key": key,
|
||||
|
@ -533,7 +541,7 @@ export namespace SimplePattern {
|
|||
variant: _.Symbol.for("dictof")
|
||||
};
|
||||
};
|
||||
export function Ref<_embedded = _.GenericEmbedded>(value: Ref): SimplePattern<_embedded> {
|
||||
export function Ref<_embedded extends _.Embeddable = _.GenericEmbedded>(value: Ref): SimplePattern<_embedded> {
|
||||
return {
|
||||
"_variant": "Ref",
|
||||
"value": value,
|
||||
|
@ -553,7 +561,7 @@ export namespace SimplePattern {
|
|||
}
|
||||
|
||||
export namespace CompoundPattern {
|
||||
export function rec<_embedded = _.GenericEmbedded>(
|
||||
export function rec<_embedded extends _.Embeddable = _.GenericEmbedded>(
|
||||
{label, fields}: {label: NamedPattern<_embedded>, fields: NamedPattern<_embedded>}
|
||||
): CompoundPattern<_embedded> {
|
||||
return {
|
||||
|
@ -573,7 +581,7 @@ export namespace CompoundPattern {
|
|||
variant: _.Symbol.for("rec")
|
||||
};
|
||||
};
|
||||
export function tuple<_embedded = _.GenericEmbedded>(patterns: Array<NamedPattern<_embedded>>): CompoundPattern<_embedded> {
|
||||
export function tuple<_embedded extends _.Embeddable = _.GenericEmbedded>(patterns: Array<NamedPattern<_embedded>>): CompoundPattern<_embedded> {
|
||||
return {
|
||||
"_variant": "tuple",
|
||||
"patterns": patterns,
|
||||
|
@ -590,7 +598,7 @@ export namespace CompoundPattern {
|
|||
variant: _.Symbol.for("tuple")
|
||||
};
|
||||
};
|
||||
export function tuplePrefix<_embedded = _.GenericEmbedded>(
|
||||
export function tuplePrefix<_embedded extends _.Embeddable = _.GenericEmbedded>(
|
||||
{fixed, variable}: {fixed: Array<NamedPattern<_embedded>>, variable: NamedSimplePattern<_embedded>}
|
||||
): CompoundPattern<_embedded> {
|
||||
return {
|
||||
|
@ -610,7 +618,7 @@ export namespace CompoundPattern {
|
|||
variant: _.Symbol.for("tuplePrefix")
|
||||
};
|
||||
};
|
||||
export function dict<_embedded = _.GenericEmbedded>(entries: DictionaryEntries<_embedded>): CompoundPattern<_embedded> {
|
||||
export function dict<_embedded extends _.Embeddable = _.GenericEmbedded>(entries: DictionaryEntries<_embedded>): CompoundPattern<_embedded> {
|
||||
return {
|
||||
"_variant": "dict",
|
||||
"entries": entries,
|
||||
|
@ -629,8 +637,8 @@ export namespace CompoundPattern {
|
|||
};
|
||||
}
|
||||
|
||||
export function DictionaryEntries<_embedded = _.GenericEmbedded>(
|
||||
value: _.EncodableDictionary<_.Value<_embedded>, NamedSimplePattern<_embedded>, _embedded>
|
||||
export function DictionaryEntries<_embedded extends _.Embeddable = _.GenericEmbedded>(
|
||||
value: _.EncodableDictionary<_embedded, _.Value<_embedded>, NamedSimplePattern<_embedded>>
|
||||
): DictionaryEntries<_embedded> {return value;}
|
||||
|
||||
DictionaryEntries.schema = function () {
|
||||
|
@ -740,7 +748,7 @@ export namespace AtomKind {
|
|||
};
|
||||
}
|
||||
|
||||
export function NamedAlternative<_embedded = _.GenericEmbedded>({variantLabel, pattern}: {variantLabel: string, pattern: Pattern<_embedded>}): NamedAlternative<_embedded> {
|
||||
export function NamedAlternative<_embedded extends _.Embeddable = _.GenericEmbedded>({variantLabel, pattern}: {variantLabel: string, pattern: Pattern<_embedded>}): NamedAlternative<_embedded> {
|
||||
return {
|
||||
"variantLabel": variantLabel,
|
||||
"pattern": pattern,
|
||||
|
@ -759,7 +767,7 @@ NamedAlternative.schema = function () {
|
|||
}
|
||||
|
||||
export namespace NamedSimplePattern {
|
||||
export function named<_embedded = _.GenericEmbedded>(value: Binding<_embedded>): NamedSimplePattern<_embedded> {
|
||||
export function named<_embedded extends _.Embeddable = _.GenericEmbedded>(value: Binding<_embedded>): NamedSimplePattern<_embedded> {
|
||||
return {
|
||||
"_variant": "named",
|
||||
"value": value,
|
||||
|
@ -776,7 +784,7 @@ export namespace NamedSimplePattern {
|
|||
variant: _.Symbol.for("named")
|
||||
};
|
||||
};
|
||||
export function anonymous<_embedded = _.GenericEmbedded>(value: SimplePattern<_embedded>): NamedSimplePattern<_embedded> {
|
||||
export function anonymous<_embedded extends _.Embeddable = _.GenericEmbedded>(value: SimplePattern<_embedded>): NamedSimplePattern<_embedded> {
|
||||
return {
|
||||
"_variant": "anonymous",
|
||||
"value": value,
|
||||
|
@ -796,7 +804,7 @@ export namespace NamedSimplePattern {
|
|||
}
|
||||
|
||||
export namespace NamedPattern {
|
||||
export function named<_embedded = _.GenericEmbedded>(value: Binding<_embedded>): NamedPattern<_embedded> {
|
||||
export function named<_embedded extends _.Embeddable = _.GenericEmbedded>(value: Binding<_embedded>): NamedPattern<_embedded> {
|
||||
return {
|
||||
"_variant": "named",
|
||||
"value": value,
|
||||
|
@ -813,7 +821,7 @@ export namespace NamedPattern {
|
|||
variant: _.Symbol.for("named")
|
||||
};
|
||||
};
|
||||
export function anonymous<_embedded = _.GenericEmbedded>(value: Pattern<_embedded>): NamedPattern<_embedded> {
|
||||
export function anonymous<_embedded extends _.Embeddable = _.GenericEmbedded>(value: Pattern<_embedded>): NamedPattern<_embedded> {
|
||||
return {
|
||||
"_variant": "anonymous",
|
||||
"value": value,
|
||||
|
@ -832,7 +840,7 @@ export namespace NamedPattern {
|
|||
};
|
||||
}
|
||||
|
||||
export function Binding<_embedded = _.GenericEmbedded>({name, pattern}: {name: symbol, pattern: SimplePattern<_embedded>}): Binding<_embedded> {
|
||||
export function Binding<_embedded extends _.Embeddable = _.GenericEmbedded>({name, pattern}: {name: symbol, pattern: SimplePattern<_embedded>}): Binding<_embedded> {
|
||||
return {
|
||||
"name": name,
|
||||
"pattern": pattern,
|
||||
|
@ -870,13 +878,13 @@ ModulePath.schema = function () {
|
|||
};
|
||||
}
|
||||
|
||||
export function asBundle<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): Bundle<_embedded> {
|
||||
export function asBundle<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): Bundle<_embedded> {
|
||||
let result = toBundle(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid Bundle: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toBundle<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Bundle<_embedded> {
|
||||
export function toBundle<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Bundle<_embedded> {
|
||||
let result: undefined | Bundle<_embedded>;
|
||||
if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) {
|
||||
let _tmp0: ({}) | undefined;
|
||||
|
@ -899,27 +907,28 @@ export function toBundle<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>):
|
|||
|
||||
Bundle.__from_preserve__ = toBundle;
|
||||
|
||||
export function fromBundle<_embedded = _.GenericEmbedded>(_v: Bundle<_embedded>): _.Value<_embedded> {return _.Record($bundle, [fromModules<_embedded>(_v["modules"])]);}
|
||||
export function fromBundle<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: Bundle<_embedded>): _.Value<_embedded> {return _.Record($bundle, [fromModules<_embedded>(_v["modules"])]);}
|
||||
|
||||
export function asModules<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): Modules<_embedded> {
|
||||
export function asModules<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): Modules<_embedded> {
|
||||
let result = toModules(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid Modules: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toModules<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Modules<_embedded> {
|
||||
let _tmp0: (_.EncodableDictionary<ModulePath, Schema<_embedded>, _embedded>) | undefined;
|
||||
export function toModules<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Modules<_embedded> {
|
||||
let _tmp0: (_.EncodableDictionary<_embedded, ModulePath, Schema<_embedded>>) | undefined;
|
||||
let result: undefined | Modules<_embedded>;
|
||||
_tmp0 = void 0;
|
||||
if (_.Dictionary.isDictionary<_embedded>(v)) {
|
||||
_tmp0 = new _.EncodableDictionary<ModulePath, Schema<_embedded>, _embedded>(fromModulePath, fromSchema<_embedded>);
|
||||
for (const [_tmp1, _tmp2] of v) {
|
||||
let _tmp3: (ModulePath) | undefined;
|
||||
_tmp3 = toModulePath(_tmp1);
|
||||
if (_tmp3 !== void 0) {
|
||||
let _tmp4: (Schema<_embedded>) | undefined;
|
||||
_tmp4 = toSchema(_tmp2);
|
||||
if (_tmp4 !== void 0) {_tmp0.set(_tmp3, _tmp4); continue;};
|
||||
const _tmp1 = new _.DictionaryMap(v);
|
||||
_tmp0 = new _.EncodableDictionary<_embedded, ModulePath, Schema<_embedded>>(fromModulePath, fromSchema<_embedded>);
|
||||
for (const [_tmp2, _tmp3] of _tmp1) {
|
||||
let _tmp4: (ModulePath) | undefined;
|
||||
_tmp4 = toModulePath(_tmp2);
|
||||
if (_tmp4 !== void 0) {
|
||||
let _tmp5: (Schema<_embedded>) | undefined;
|
||||
_tmp5 = toSchema(_tmp3);
|
||||
if (_tmp5 !== void 0) {_tmp0.set(_tmp4, _tmp5); continue;};
|
||||
};
|
||||
_tmp0 = void 0;
|
||||
break;
|
||||
|
@ -931,44 +940,45 @@ export function toModules<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>):
|
|||
|
||||
Modules.__from_preserve__ = toModules;
|
||||
|
||||
export function fromModules<_embedded = _.GenericEmbedded>(_v: Modules<_embedded>): _.Value<_embedded> {
|
||||
return new _.Dictionary<_embedded>(
|
||||
export function fromModules<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: Modules<_embedded>): _.Value<_embedded> {
|
||||
return _.Dictionary.from<_embedded>(
|
||||
_.Array.from(_v.entries()).map(([k, v]) => [fromModulePath<_embedded>(k), fromSchema<_embedded>(v)])
|
||||
);
|
||||
}
|
||||
|
||||
export function asSchema<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): Schema<_embedded> {
|
||||
export function asSchema<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): Schema<_embedded> {
|
||||
let result = toSchema(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid Schema: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toSchema<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Schema<_embedded> {
|
||||
export function toSchema<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Schema<_embedded> {
|
||||
let result: undefined | Schema<_embedded>;
|
||||
if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) {
|
||||
let _tmp0: ({}) | undefined;
|
||||
_tmp0 = _.is(v.label, $schema) ? {} : void 0;
|
||||
if (_tmp0 !== void 0) {
|
||||
if (_.Dictionary.isDictionary<_embedded>(v[0])) {
|
||||
let _tmp1: (_.Value<_embedded>) | undefined;
|
||||
if ((_tmp1 = v[0].get($version)) !== void 0) {
|
||||
let _tmp2: (Version) | undefined;
|
||||
_tmp2 = toVersion(_tmp1);
|
||||
if (_tmp2 !== void 0) {
|
||||
let _tmp3: (_.Value<_embedded>) | undefined;
|
||||
if ((_tmp3 = v[0].get($embeddedType)) !== void 0) {
|
||||
let _tmp4: (EmbeddedTypeName) | undefined;
|
||||
_tmp4 = toEmbeddedTypeName(_tmp3);
|
||||
if (_tmp4 !== void 0) {
|
||||
let _tmp5: (_.Value<_embedded>) | undefined;
|
||||
if ((_tmp5 = v[0].get($definitions)) !== void 0) {
|
||||
let _tmp6: (Definitions<_embedded>) | undefined;
|
||||
_tmp6 = toDefinitions(_tmp5);
|
||||
if (_tmp6 !== void 0) {
|
||||
let _tmp2: (_.Value<_embedded>) | undefined;
|
||||
const _tmp1 = new _.DictionaryMap(v[0]);
|
||||
if ((_tmp2 = _tmp1.get($version)) !== void 0) {
|
||||
let _tmp3: (Version) | undefined;
|
||||
_tmp3 = toVersion(_tmp2);
|
||||
if (_tmp3 !== void 0) {
|
||||
let _tmp4: (_.Value<_embedded>) | undefined;
|
||||
if ((_tmp4 = _tmp1.get($embeddedType)) !== void 0) {
|
||||
let _tmp5: (EmbeddedTypeName) | undefined;
|
||||
_tmp5 = toEmbeddedTypeName(_tmp4);
|
||||
if (_tmp5 !== void 0) {
|
||||
let _tmp6: (_.Value<_embedded>) | undefined;
|
||||
if ((_tmp6 = _tmp1.get($definitions)) !== void 0) {
|
||||
let _tmp7: (Definitions<_embedded>) | undefined;
|
||||
_tmp7 = toDefinitions(_tmp6);
|
||||
if (_tmp7 !== void 0) {
|
||||
result = {
|
||||
"version": _tmp2,
|
||||
"embeddedType": _tmp4,
|
||||
"definitions": _tmp6,
|
||||
"version": _tmp3,
|
||||
"embeddedType": _tmp5,
|
||||
"definitions": _tmp7,
|
||||
__as_preserve__() {return fromSchema(this);},
|
||||
__preserve_on__(e) { e.push(fromSchema(this)); },
|
||||
__preserve_text_on__(w) { w.push(fromSchema(this)); }
|
||||
|
@ -987,11 +997,11 @@ export function toSchema<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>):
|
|||
|
||||
Schema.__from_preserve__ = toSchema;
|
||||
|
||||
export function fromSchema<_embedded = _.GenericEmbedded>(_v: Schema<_embedded>): _.Value<_embedded> {
|
||||
export function fromSchema<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: Schema<_embedded>): _.Value<_embedded> {
|
||||
return _.Record(
|
||||
$schema,
|
||||
[
|
||||
new _.Dictionary<_embedded>(
|
||||
_.Dictionary.from<_embedded>(
|
||||
[
|
||||
[$version, fromVersion<_embedded>(_v["version"])],
|
||||
[$embeddedType, fromEmbeddedTypeName<_embedded>(_v["embeddedType"])],
|
||||
|
@ -1002,13 +1012,13 @@ export function fromSchema<_embedded = _.GenericEmbedded>(_v: Schema<_embedded>)
|
|||
);
|
||||
}
|
||||
|
||||
export function asVersion<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): Version {
|
||||
export function asVersion<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): Version {
|
||||
let result = toVersion(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid Version: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toVersion<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Version {
|
||||
export function toVersion<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Version {
|
||||
let _tmp0: ({}) | undefined;
|
||||
let result: undefined | Version;
|
||||
_tmp0 = _.is(v, $1) ? {} : void 0;
|
||||
|
@ -1024,15 +1034,15 @@ export function toVersion<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>):
|
|||
|
||||
Version.__from_preserve__ = toVersion;
|
||||
|
||||
export function fromVersion<_embedded = _.GenericEmbedded>(_v: Version): _.Value<_embedded> {return $1;}
|
||||
export function fromVersion<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: Version): _.Value<_embedded> {return $1;}
|
||||
|
||||
export function asEmbeddedTypeName<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): EmbeddedTypeName {
|
||||
export function asEmbeddedTypeName<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): EmbeddedTypeName {
|
||||
let result = toEmbeddedTypeName(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid EmbeddedTypeName: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toEmbeddedTypeName<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | EmbeddedTypeName {
|
||||
export function toEmbeddedTypeName<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | EmbeddedTypeName {
|
||||
let _tmp0: ({}) | undefined;
|
||||
let result: undefined | EmbeddedTypeName;
|
||||
_tmp0 = _.is(v, __lit6) ? {} : void 0;
|
||||
|
@ -1062,32 +1072,33 @@ export function toEmbeddedTypeName<_embedded = _.GenericEmbedded>(v: _.Value<_em
|
|||
|
||||
export namespace EmbeddedTypeName {export const __from_preserve__ = toEmbeddedTypeName;}
|
||||
|
||||
export function fromEmbeddedTypeName<_embedded = _.GenericEmbedded>(_v: EmbeddedTypeName): _.Value<_embedded> {
|
||||
export function fromEmbeddedTypeName<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: EmbeddedTypeName): _.Value<_embedded> {
|
||||
switch (_v._variant) {
|
||||
case "false": {return __lit6;};
|
||||
case "Ref": {return fromRef<_embedded>(_v.value);};
|
||||
};
|
||||
}
|
||||
|
||||
export function asDefinitions<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): Definitions<_embedded> {
|
||||
export function asDefinitions<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): Definitions<_embedded> {
|
||||
let result = toDefinitions(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid Definitions: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toDefinitions<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Definitions<_embedded> {
|
||||
let _tmp0: (_.EncodableDictionary<symbol, Definition<_embedded>, _embedded>) | undefined;
|
||||
export function toDefinitions<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Definitions<_embedded> {
|
||||
let _tmp0: (_.JsDictionary<Definition<_embedded>>) | undefined;
|
||||
let result: undefined | Definitions<_embedded>;
|
||||
_tmp0 = void 0;
|
||||
if (_.Dictionary.isDictionary<_embedded>(v)) {
|
||||
_tmp0 = new _.EncodableDictionary<symbol, Definition<_embedded>, _embedded>(k => k, fromDefinition<_embedded>);
|
||||
for (const [_tmp1, _tmp2] of v) {
|
||||
let _tmp3: (symbol) | undefined;
|
||||
_tmp3 = typeof _tmp1 === 'symbol' ? _tmp1 : void 0;
|
||||
if (_tmp3 !== void 0) {
|
||||
let _tmp4: (Definition<_embedded>) | undefined;
|
||||
_tmp4 = toDefinition(_tmp2);
|
||||
if (_tmp4 !== void 0) {_tmp0.set(_tmp3, _tmp4); continue;};
|
||||
const _tmp1 = new _.DictionaryMap(v);
|
||||
_tmp0 = {};
|
||||
for (const [_tmp2, _tmp3] of _tmp1) {
|
||||
let _tmp4: (symbol) | undefined;
|
||||
_tmp4 = typeof _tmp2 === 'symbol' ? _tmp2 : void 0;
|
||||
if (_tmp4 !== void 0) {
|
||||
let _tmp5: (Definition<_embedded>) | undefined;
|
||||
_tmp5 = toDefinition(_tmp3);
|
||||
if (_tmp5 !== void 0) {_tmp0[_tmp4.description!] = _tmp5; continue;};
|
||||
};
|
||||
_tmp0 = void 0;
|
||||
break;
|
||||
|
@ -1099,17 +1110,19 @@ export function toDefinitions<_embedded = _.GenericEmbedded>(v: _.Value<_embedde
|
|||
|
||||
Definitions.__from_preserve__ = toDefinitions;
|
||||
|
||||
export function fromDefinitions<_embedded = _.GenericEmbedded>(_v: Definitions<_embedded>): _.Value<_embedded> {
|
||||
return new _.Dictionary<_embedded>(_.Array.from(_v.entries()).map(([k, v]) => [k, fromDefinition<_embedded>(v)]));
|
||||
export function fromDefinitions<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: Definitions<_embedded>): _.Value<_embedded> {
|
||||
return _.Dictionary.from<_embedded>(
|
||||
_.Array.from(_.JsDictionary.entries(_v)).map(([k, v]) => [k, fromDefinition<_embedded>(v)])
|
||||
);
|
||||
}
|
||||
|
||||
export function asDefinition<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): Definition<_embedded> {
|
||||
export function asDefinition<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): Definition<_embedded> {
|
||||
let result = toDefinition(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid Definition: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toDefinition<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Definition<_embedded> {
|
||||
export function toDefinition<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Definition<_embedded> {
|
||||
let result: undefined | Definition<_embedded>;
|
||||
if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) {
|
||||
let _tmp0: ({}) | undefined;
|
||||
|
@ -1207,7 +1220,7 @@ export function toDefinition<_embedded = _.GenericEmbedded>(v: _.Value<_embedded
|
|||
|
||||
export namespace Definition {export const __from_preserve__ = toDefinition;}
|
||||
|
||||
export function fromDefinition<_embedded = _.GenericEmbedded>(_v: Definition<_embedded>): _.Value<_embedded> {
|
||||
export function fromDefinition<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: Definition<_embedded>): _.Value<_embedded> {
|
||||
switch (_v._variant) {
|
||||
case "or": {
|
||||
return _.Record(
|
||||
|
@ -1237,13 +1250,13 @@ export function fromDefinition<_embedded = _.GenericEmbedded>(_v: Definition<_em
|
|||
};
|
||||
}
|
||||
|
||||
export function asPattern<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): Pattern<_embedded> {
|
||||
export function asPattern<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): Pattern<_embedded> {
|
||||
let result = toPattern(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid Pattern: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toPattern<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Pattern<_embedded> {
|
||||
export function toPattern<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Pattern<_embedded> {
|
||||
let _tmp0: (SimplePattern<_embedded>) | undefined;
|
||||
let result: undefined | Pattern<_embedded>;
|
||||
_tmp0 = toSimplePattern(v);
|
||||
|
@ -1274,20 +1287,20 @@ export function toPattern<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>):
|
|||
|
||||
export namespace Pattern {export const __from_preserve__ = toPattern;}
|
||||
|
||||
export function fromPattern<_embedded = _.GenericEmbedded>(_v: Pattern<_embedded>): _.Value<_embedded> {
|
||||
export function fromPattern<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: Pattern<_embedded>): _.Value<_embedded> {
|
||||
switch (_v._variant) {
|
||||
case "SimplePattern": {return fromSimplePattern<_embedded>(_v.value);};
|
||||
case "CompoundPattern": {return fromCompoundPattern<_embedded>(_v.value);};
|
||||
};
|
||||
}
|
||||
|
||||
export function asSimplePattern<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): SimplePattern<_embedded> {
|
||||
export function asSimplePattern<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): SimplePattern<_embedded> {
|
||||
let result = toSimplePattern(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid SimplePattern: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toSimplePattern<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | SimplePattern<_embedded> {
|
||||
export function toSimplePattern<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | SimplePattern<_embedded> {
|
||||
let _tmp0: ({}) | undefined;
|
||||
let result: undefined | SimplePattern<_embedded>;
|
||||
_tmp0 = _.is(v, $any) ? {} : void 0;
|
||||
|
@ -1436,7 +1449,7 @@ export function toSimplePattern<_embedded = _.GenericEmbedded>(v: _.Value<_embed
|
|||
|
||||
export namespace SimplePattern {export const __from_preserve__ = toSimplePattern;}
|
||||
|
||||
export function fromSimplePattern<_embedded = _.GenericEmbedded>(_v: SimplePattern<_embedded>): _.Value<_embedded> {
|
||||
export function fromSimplePattern<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: SimplePattern<_embedded>): _.Value<_embedded> {
|
||||
switch (_v._variant) {
|
||||
case "any": {return $any;};
|
||||
case "atom": {return _.Record($atom, [fromAtomKind<_embedded>(_v["atomKind"])]);};
|
||||
|
@ -1457,13 +1470,13 @@ export function fromSimplePattern<_embedded = _.GenericEmbedded>(_v: SimplePatte
|
|||
};
|
||||
}
|
||||
|
||||
export function asCompoundPattern<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): CompoundPattern<_embedded> {
|
||||
export function asCompoundPattern<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): CompoundPattern<_embedded> {
|
||||
let result = toCompoundPattern(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid CompoundPattern: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toCompoundPattern<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | CompoundPattern<_embedded> {
|
||||
export function toCompoundPattern<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | CompoundPattern<_embedded> {
|
||||
let result: undefined | CompoundPattern<_embedded>;
|
||||
if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) {
|
||||
let _tmp0: ({}) | undefined;
|
||||
|
@ -1574,7 +1587,7 @@ export function toCompoundPattern<_embedded = _.GenericEmbedded>(v: _.Value<_emb
|
|||
|
||||
export namespace CompoundPattern {export const __from_preserve__ = toCompoundPattern;}
|
||||
|
||||
export function fromCompoundPattern<_embedded = _.GenericEmbedded>(_v: CompoundPattern<_embedded>): _.Value<_embedded> {
|
||||
export function fromCompoundPattern<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: CompoundPattern<_embedded>): _.Value<_embedded> {
|
||||
switch (_v._variant) {
|
||||
case "rec": {
|
||||
return _.Record(
|
||||
|
@ -1601,25 +1614,26 @@ export function fromCompoundPattern<_embedded = _.GenericEmbedded>(_v: CompoundP
|
|||
};
|
||||
}
|
||||
|
||||
export function asDictionaryEntries<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): DictionaryEntries<_embedded> {
|
||||
export function asDictionaryEntries<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): DictionaryEntries<_embedded> {
|
||||
let result = toDictionaryEntries(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid DictionaryEntries: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toDictionaryEntries<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | DictionaryEntries<_embedded> {
|
||||
let _tmp0: (_.EncodableDictionary<_.Value<_embedded>, NamedSimplePattern<_embedded>, _embedded>) | undefined;
|
||||
export function toDictionaryEntries<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | DictionaryEntries<_embedded> {
|
||||
let _tmp0: (_.EncodableDictionary<_embedded, _.Value<_embedded>, NamedSimplePattern<_embedded>>) | undefined;
|
||||
let result: undefined | DictionaryEntries<_embedded>;
|
||||
_tmp0 = void 0;
|
||||
if (_.Dictionary.isDictionary<_embedded>(v)) {
|
||||
_tmp0 = new _.EncodableDictionary<_.Value<_embedded>, NamedSimplePattern<_embedded>, _embedded>(k => k, fromNamedSimplePattern<_embedded>);
|
||||
for (const [_tmp1, _tmp2] of v) {
|
||||
let _tmp3: (_.Value<_embedded>) | undefined;
|
||||
_tmp3 = _tmp1;
|
||||
if (_tmp3 !== void 0) {
|
||||
let _tmp4: (NamedSimplePattern<_embedded>) | undefined;
|
||||
_tmp4 = toNamedSimplePattern(_tmp2);
|
||||
if (_tmp4 !== void 0) {_tmp0.set(_tmp3, _tmp4); continue;};
|
||||
const _tmp1 = new _.DictionaryMap(v);
|
||||
_tmp0 = new _.EncodableDictionary<_embedded, _.Value<_embedded>, NamedSimplePattern<_embedded>>(k => k, fromNamedSimplePattern<_embedded>);
|
||||
for (const [_tmp2, _tmp3] of _tmp1) {
|
||||
let _tmp4: (_.Value<_embedded>) | undefined;
|
||||
_tmp4 = _tmp2;
|
||||
if (_tmp4 !== void 0) {
|
||||
let _tmp5: (NamedSimplePattern<_embedded>) | undefined;
|
||||
_tmp5 = toNamedSimplePattern(_tmp3);
|
||||
if (_tmp5 !== void 0) {_tmp0.set(_tmp4, _tmp5); continue;};
|
||||
};
|
||||
_tmp0 = void 0;
|
||||
break;
|
||||
|
@ -1631,19 +1645,19 @@ export function toDictionaryEntries<_embedded = _.GenericEmbedded>(v: _.Value<_e
|
|||
|
||||
DictionaryEntries.__from_preserve__ = toDictionaryEntries;
|
||||
|
||||
export function fromDictionaryEntries<_embedded = _.GenericEmbedded>(_v: DictionaryEntries<_embedded>): _.Value<_embedded> {
|
||||
return new _.Dictionary<_embedded>(
|
||||
export function fromDictionaryEntries<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: DictionaryEntries<_embedded>): _.Value<_embedded> {
|
||||
return _.Dictionary.from<_embedded>(
|
||||
_.Array.from(_v.entries()).map(([k, v]) => [k, fromNamedSimplePattern<_embedded>(v)])
|
||||
);
|
||||
}
|
||||
|
||||
export function asAtomKind<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): AtomKind {
|
||||
export function asAtomKind<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): AtomKind {
|
||||
let result = toAtomKind(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid AtomKind: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toAtomKind<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | AtomKind {
|
||||
export function toAtomKind<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | AtomKind {
|
||||
let _tmp0: ({}) | undefined;
|
||||
let result: undefined | AtomKind;
|
||||
_tmp0 = _.is(v, $Boolean) ? {} : void 0;
|
||||
|
@ -1720,7 +1734,7 @@ export function toAtomKind<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>)
|
|||
|
||||
export namespace AtomKind {export const __from_preserve__ = toAtomKind;}
|
||||
|
||||
export function fromAtomKind<_embedded = _.GenericEmbedded>(_v: AtomKind): _.Value<_embedded> {
|
||||
export function fromAtomKind<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: AtomKind): _.Value<_embedded> {
|
||||
switch (_v._variant) {
|
||||
case "Boolean": {return $Boolean;};
|
||||
case "Double": {return $Double;};
|
||||
|
@ -1731,15 +1745,15 @@ export function fromAtomKind<_embedded = _.GenericEmbedded>(_v: AtomKind): _.Val
|
|||
};
|
||||
}
|
||||
|
||||
export function asNamedAlternative<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): NamedAlternative<_embedded> {
|
||||
export function asNamedAlternative<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): NamedAlternative<_embedded> {
|
||||
let result = toNamedAlternative(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid NamedAlternative: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toNamedAlternative<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | NamedAlternative<_embedded> {
|
||||
export function toNamedAlternative<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | NamedAlternative<_embedded> {
|
||||
let result: undefined | NamedAlternative<_embedded>;
|
||||
if (_.isSequence(v) && v.length === 2) {
|
||||
if (_.isSequence(v) && v.length >= 2) {
|
||||
let _tmp0: (string) | undefined;
|
||||
_tmp0 = typeof v[0] === 'string' ? v[0] : void 0;
|
||||
if (_tmp0 !== void 0) {
|
||||
|
@ -1761,15 +1775,15 @@ export function toNamedAlternative<_embedded = _.GenericEmbedded>(v: _.Value<_em
|
|||
|
||||
NamedAlternative.__from_preserve__ = toNamedAlternative;
|
||||
|
||||
export function fromNamedAlternative<_embedded = _.GenericEmbedded>(_v: NamedAlternative<_embedded>): _.Value<_embedded> {return [_v["variantLabel"], fromPattern<_embedded>(_v["pattern"])];}
|
||||
export function fromNamedAlternative<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: NamedAlternative<_embedded>): _.Value<_embedded> {return [_v["variantLabel"], fromPattern<_embedded>(_v["pattern"])];}
|
||||
|
||||
export function asNamedSimplePattern<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): NamedSimplePattern<_embedded> {
|
||||
export function asNamedSimplePattern<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): NamedSimplePattern<_embedded> {
|
||||
let result = toNamedSimplePattern(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid NamedSimplePattern: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toNamedSimplePattern<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | NamedSimplePattern<_embedded> {
|
||||
export function toNamedSimplePattern<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | NamedSimplePattern<_embedded> {
|
||||
let _tmp0: (Binding<_embedded>) | undefined;
|
||||
let result: undefined | NamedSimplePattern<_embedded>;
|
||||
_tmp0 = toBinding(v);
|
||||
|
@ -1800,20 +1814,20 @@ export function toNamedSimplePattern<_embedded = _.GenericEmbedded>(v: _.Value<_
|
|||
|
||||
export namespace NamedSimplePattern {export const __from_preserve__ = toNamedSimplePattern;}
|
||||
|
||||
export function fromNamedSimplePattern<_embedded = _.GenericEmbedded>(_v: NamedSimplePattern<_embedded>): _.Value<_embedded> {
|
||||
export function fromNamedSimplePattern<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: NamedSimplePattern<_embedded>): _.Value<_embedded> {
|
||||
switch (_v._variant) {
|
||||
case "named": {return fromBinding<_embedded>(_v.value);};
|
||||
case "anonymous": {return fromSimplePattern<_embedded>(_v.value);};
|
||||
};
|
||||
}
|
||||
|
||||
export function asNamedPattern<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): NamedPattern<_embedded> {
|
||||
export function asNamedPattern<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): NamedPattern<_embedded> {
|
||||
let result = toNamedPattern(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid NamedPattern: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toNamedPattern<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | NamedPattern<_embedded> {
|
||||
export function toNamedPattern<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | NamedPattern<_embedded> {
|
||||
let _tmp0: (Binding<_embedded>) | undefined;
|
||||
let result: undefined | NamedPattern<_embedded>;
|
||||
_tmp0 = toBinding(v);
|
||||
|
@ -1844,20 +1858,20 @@ export function toNamedPattern<_embedded = _.GenericEmbedded>(v: _.Value<_embedd
|
|||
|
||||
export namespace NamedPattern {export const __from_preserve__ = toNamedPattern;}
|
||||
|
||||
export function fromNamedPattern<_embedded = _.GenericEmbedded>(_v: NamedPattern<_embedded>): _.Value<_embedded> {
|
||||
export function fromNamedPattern<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: NamedPattern<_embedded>): _.Value<_embedded> {
|
||||
switch (_v._variant) {
|
||||
case "named": {return fromBinding<_embedded>(_v.value);};
|
||||
case "anonymous": {return fromPattern<_embedded>(_v.value);};
|
||||
};
|
||||
}
|
||||
|
||||
export function asBinding<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): Binding<_embedded> {
|
||||
export function asBinding<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): Binding<_embedded> {
|
||||
let result = toBinding(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid Binding: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toBinding<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Binding<_embedded> {
|
||||
export function toBinding<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Binding<_embedded> {
|
||||
let result: undefined | Binding<_embedded>;
|
||||
if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) {
|
||||
let _tmp0: ({}) | undefined;
|
||||
|
@ -1885,17 +1899,17 @@ export function toBinding<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>):
|
|||
|
||||
Binding.__from_preserve__ = toBinding;
|
||||
|
||||
export function fromBinding<_embedded = _.GenericEmbedded>(_v: Binding<_embedded>): _.Value<_embedded> {
|
||||
export function fromBinding<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: Binding<_embedded>): _.Value<_embedded> {
|
||||
return _.Record($named, [_v["name"], fromSimplePattern<_embedded>(_v["pattern"])]);
|
||||
}
|
||||
|
||||
export function asRef<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): Ref {
|
||||
export function asRef<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): Ref {
|
||||
let result = toRef(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid Ref: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toRef<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Ref {
|
||||
export function toRef<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Ref {
|
||||
let result: undefined | Ref;
|
||||
if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) {
|
||||
let _tmp0: ({}) | undefined;
|
||||
|
@ -1923,15 +1937,15 @@ export function toRef<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): und
|
|||
|
||||
Ref.__from_preserve__ = toRef;
|
||||
|
||||
export function fromRef<_embedded = _.GenericEmbedded>(_v: Ref): _.Value<_embedded> {return _.Record($ref, [fromModulePath<_embedded>(_v["module"]), _v["name"]]);}
|
||||
export function fromRef<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: Ref): _.Value<_embedded> {return _.Record($ref, [fromModulePath<_embedded>(_v["module"]), _v["name"]]);}
|
||||
|
||||
export function asModulePath<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): ModulePath {
|
||||
export function asModulePath<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): ModulePath {
|
||||
let result = toModulePath(v);
|
||||
if (result === void 0) throw new TypeError(`Invalid ModulePath: ${_.stringify(v)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
export function toModulePath<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | ModulePath {
|
||||
export function toModulePath<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | ModulePath {
|
||||
let _tmp0: (Array<symbol>) | undefined;
|
||||
let result: undefined | ModulePath;
|
||||
_tmp0 = void 0;
|
||||
|
@ -1951,5 +1965,5 @@ export function toModulePath<_embedded = _.GenericEmbedded>(v: _.Value<_embedded
|
|||
|
||||
ModulePath.__from_preserve__ = toModulePath;
|
||||
|
||||
export function fromModulePath<_embedded = _.GenericEmbedded>(_v: ModulePath): _.Value<_embedded> {return _v.map(v => v);}
|
||||
export function fromModulePath<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: ModulePath): _.Value<_embedded> {return _v.map(v => v);}
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { compare } from '@preserves/core';
|
||||
import { compare, Embeddable } from '@preserves/core';
|
||||
|
||||
import * as M from './meta';
|
||||
import * as H from './gen/host';
|
||||
|
||||
export * from './gen/host';
|
||||
|
||||
export function definitionType<V>(p: M.Definition<V>): H.Definition {
|
||||
export function definitionType<V extends Embeddable>(p: M.Definition<V>): H.Definition {
|
||||
switch (p._variant) {
|
||||
case 'or': return H.Definition.union([p.pattern0, p.pattern1, ... p.patternN].map(p =>
|
||||
H.Variant({ label: Symbol.for(p.variantLabel), type: patternType(p.pattern) })));
|
||||
|
@ -16,7 +16,7 @@ export function definitionType<V>(p: M.Definition<V>): H.Definition {
|
|||
}
|
||||
}
|
||||
|
||||
export function patternType<V>(p: M.Pattern<V>): H.Simple {
|
||||
export function patternType<V extends Embeddable>(p: M.Pattern<V>): H.Simple {
|
||||
switch (p._variant) {
|
||||
case 'SimplePattern':
|
||||
return H.Simple.Field(fieldType(p.value));
|
||||
|
@ -25,7 +25,7 @@ export function patternType<V>(p: M.Pattern<V>): H.Simple {
|
|||
}
|
||||
}
|
||||
|
||||
export function fieldType<V>(p: M.SimplePattern<V>): H.Field {
|
||||
export function fieldType<V extends Embeddable>(p: M.SimplePattern<V>): H.Field {
|
||||
switch (p._variant) {
|
||||
case 'any': return H.Field.any();
|
||||
case 'atom': return H.Field.AtomKind(p.atomKind);
|
||||
|
@ -38,19 +38,19 @@ export function fieldType<V>(p: M.SimplePattern<V>): H.Field {
|
|||
}
|
||||
}
|
||||
|
||||
export function productType<V>(ps: M.NamedPattern<V>[]): H.Simple {
|
||||
export function productType<V extends Embeddable>(ps: M.NamedPattern<V>[]): H.Simple {
|
||||
const gathered: H.NamedField[] = [];
|
||||
ps.forEach(p => gather(p, gathered));
|
||||
if (gathered.length === 0) return H.Simple.Field(H.Field.unit());
|
||||
return H.Simple.Record(H.Record(gathered));
|
||||
}
|
||||
|
||||
function promote<V>(p: M.NamedSimplePattern<V>): M.NamedPattern<V> {
|
||||
function promote<V extends Embeddable>(p: M.NamedSimplePattern<V>): M.NamedPattern<V> {
|
||||
if (p._variant === 'named') return p;
|
||||
return M.NamedPattern.anonymous(M.Pattern.SimplePattern(p.value));
|
||||
}
|
||||
|
||||
function gather<V>(p: M.NamedPattern<V>, into: H.NamedField[]) {
|
||||
function gather<V extends Embeddable>(p: M.NamedPattern<V>, into: H.NamedField[]) {
|
||||
switch (p._variant) {
|
||||
case 'named': {
|
||||
const t = fieldType(p.value.pattern);
|
||||
|
|
|
@ -1,35 +1,38 @@
|
|||
import { EncodableDictionary, KeyedDictionary, Dictionary, Value, is, Record, Float, Bytes, isEmbedded, isSequence, Set, Atom, Embedded, merge as plainMerge, Preservable, PreserveWritable, _iterMap, stringify, fromJS } from '@preserves/core';
|
||||
import { EncodableDictionary, KeyedDictionary, Dictionary, Value, is, Record, Float, Bytes, isEmbedded, isSequence, Set, Atom, merge as plainMerge, Preservable, PreserveWritable, _iterMap, stringify, fromJS, Embeddable, DictionaryMap, JsDictionary } from '@preserves/core';
|
||||
import { SchemaDefinition } from './reflection';
|
||||
import * as M from './meta';
|
||||
import * as H from './host';
|
||||
|
||||
export const UNIT: true = true;
|
||||
|
||||
export type Parsed<V> = Atom | V | Parsed<V>[] | DictOf<V> | Bindings<V>;
|
||||
export type TopParsed<V> = Atom | V | Parsed<V>[] | DictOf<V> | TopBindings<V>;
|
||||
export type Parsed<V extends Embeddable> = Atom | V | Parsed<V>[] | DictOf<V> | Bindings<V>;
|
||||
export type TopParsed<V extends Embeddable> = Atom | V | Parsed<V>[] | DictOf<V> | TopBindings<V>;
|
||||
|
||||
export type Top<V> = Preservable<V> & PreserveWritable<V> & { __as_preserve__(): Value<V> };
|
||||
export type Top<V extends Embeddable> =
|
||||
& Preservable<V>
|
||||
& PreserveWritable<V>
|
||||
& { __as_preserve__(): Value<V> };
|
||||
|
||||
export type DictOf<V> = EncodableDictionary<Parsed<V>, Parsed<V>, V>;
|
||||
export type DictOf<V extends Embeddable> = EncodableDictionary<V, Parsed<V>, Parsed<V>>;
|
||||
|
||||
export type BindingName = string;
|
||||
export type Bindings<V> = { [key: BindingName]: Parsed<V> };
|
||||
export type TopBindings<V> = Bindings<V> & Top<V>;
|
||||
export type Bindings<V extends Embeddable> = { [key: BindingName]: Parsed<V> };
|
||||
export type TopBindings<V extends Embeddable> = Bindings<V> & Top<V>;
|
||||
|
||||
export type SingleConstructor<V> = ((input: any) => Parsed<V>) & { schema(): SchemaDefinition };
|
||||
export type MultipleConstructors<V> = { [key: string]: SingleConstructor<V> };
|
||||
export type DefinitionConstructors<V> = SingleConstructor<V> | MultipleConstructors<V>;
|
||||
export type SingleConstructor<V extends Embeddable> = ((input: any) => Parsed<V>) & { schema(): SchemaDefinition };
|
||||
export type MultipleConstructors<V extends Embeddable> = { [key: string]: SingleConstructor<V> };
|
||||
export type DefinitionConstructors<V extends Embeddable> = SingleConstructor<V> | MultipleConstructors<V>;
|
||||
|
||||
export namespace Bindings {
|
||||
export function empty<V>(): Bindings<V> {
|
||||
export function empty<V extends Embeddable>(): Bindings<V> {
|
||||
return {};
|
||||
}
|
||||
export function single<V>(k: BindingName, v: Parsed<V>): Bindings<V> {
|
||||
export function single<V extends Embeddable>(k: BindingName, v: Parsed<V>): Bindings<V> {
|
||||
const bs = empty<V>();
|
||||
bs[k] = v;
|
||||
return bs;
|
||||
}
|
||||
export function merge<V>(... vs: Bindings<V>[]): Bindings<V> {
|
||||
export function merge<V extends Embeddable>(... vs: Bindings<V>[]): Bindings<V> {
|
||||
const acc = empty<V>();
|
||||
for (const v of vs) {
|
||||
Object.entries(v).forEach(([kw, vw]) => acc[kw] = vw);
|
||||
|
@ -38,29 +41,29 @@ export namespace Bindings {
|
|||
}
|
||||
}
|
||||
|
||||
export type DynField<V> =
|
||||
export type DynField<V extends Embeddable> =
|
||||
| { type: 'simple', value: Parsed<V> }
|
||||
| { type: 'compound', values: Bindings<V> }
|
||||
;
|
||||
export namespace DynField {
|
||||
export function unwrap<V>(f: DynField<V>): Parsed<V> {
|
||||
export function unwrap<V extends Embeddable>(f: DynField<V>): Parsed<V> {
|
||||
if (f.type === 'simple') return f.value;
|
||||
return f.values;
|
||||
}
|
||||
export function unwrap_compound<V>(f: DynField<V>): Bindings<V> {
|
||||
export function unwrap_compound<V extends Embeddable>(f: DynField<V>): Bindings<V> {
|
||||
if (f.type === 'simple') throw new Error("Cannot unwrap DynField.simple to compound fields");
|
||||
return f.values;
|
||||
}
|
||||
export function simple<V>(value: Parsed<V>): DynField<V> {
|
||||
export function simple<V extends Embeddable>(value: Parsed<V>): DynField<V> {
|
||||
return { type: 'simple', value };
|
||||
}
|
||||
export function maybeSimple<V>(value: Parsed<V> | null): DynField<V> {
|
||||
export function maybeSimple<V extends Embeddable>(value: Parsed<V> | null): DynField<V> {
|
||||
return value === null ? compound(Bindings.empty()) : simple(value);
|
||||
}
|
||||
export function compound<V>(values: Bindings<V>): DynField<V> {
|
||||
export function compound<V extends Embeddable>(values: Bindings<V>): DynField<V> {
|
||||
return { type: 'compound', values };
|
||||
}
|
||||
export function promote<V>(f: DynField<V>, key?: symbol): Bindings<V> {
|
||||
export function promote<V extends Embeddable>(f: DynField<V>, key?: symbol): Bindings<V> {
|
||||
if (f.type === 'compound') return f.values;
|
||||
return key ? Bindings.single(M.jsId(key.description!), f.value) : Bindings.empty();
|
||||
}
|
||||
|
@ -71,11 +74,27 @@ function optmap<A,B>(a: A | undefined, f: (a: A) => B): B | undefined {
|
|||
return f(a);
|
||||
}
|
||||
|
||||
export type Unparseable<V> = TopParsed<V>;
|
||||
export type Unparser<V> = (v: Parsed<V>) => Value<V>;
|
||||
export type UnparserCompound<V> = (v: Bindings<V>) => Value<V>;
|
||||
export type Unparseable<V extends Embeddable> = TopParsed<V>;
|
||||
export type Unparser<V extends Embeddable> = (v: Parsed<V>) => Value<V>;
|
||||
export type UnparserCompound<V extends Embeddable> = (v: Bindings<V>) => Value<V>;
|
||||
|
||||
export class SchemaInterpreter<V> {
|
||||
function attachSchema<V extends Embeddable>(
|
||||
schema: M.Schema<V>,
|
||||
name: symbol,
|
||||
f: (input: any) => Parsed<V>,
|
||||
variant?: symbol,
|
||||
): SingleConstructor<V> {
|
||||
const g = f as SingleConstructor<V>;
|
||||
g.schema = () => ({
|
||||
schema: fromJS(schema),
|
||||
imports: {}, // TODO
|
||||
definitionName: name,
|
||||
variant,
|
||||
});
|
||||
return g;
|
||||
}
|
||||
|
||||
export class SchemaInterpreter<V extends Embeddable> {
|
||||
activeModule: M.ModulePath = [];
|
||||
unparserCache: { [key: string]: [Unparser<V>] } = {};
|
||||
|
||||
|
@ -116,7 +135,7 @@ export class SchemaInterpreter<V> {
|
|||
): R {
|
||||
const { resolved, schema } = this._findModule(modulePath);
|
||||
return this._withModule(resolved, () => {
|
||||
const definition = schema.definitions.get(name);
|
||||
const definition = JsDictionary.get(schema.definitions, name);
|
||||
if (definition === void 0) {
|
||||
throw new Error(`No such preserves-schema definition: ${[... modulePath, name].map(s => s.description!).join('.')}`);
|
||||
}
|
||||
|
@ -132,65 +151,62 @@ export class SchemaInterpreter<V> {
|
|||
return result;
|
||||
}
|
||||
|
||||
buildConstructor(
|
||||
modulePath: M.ModulePath,
|
||||
name: symbol,
|
||||
schema: M.Schema<V>,
|
||||
ty: H.Simple,
|
||||
variant?: symbol,
|
||||
): SingleConstructor<V> {
|
||||
const flatName = M.formatModulePath([
|
||||
... modulePath, name, ... (variant === void 0 ? [] : [variant])]);
|
||||
const mkBase = (variant === void 0)
|
||||
? () => ({})
|
||||
: () => ({ _variant: variant.description! });
|
||||
switch (ty._variant) {
|
||||
case 'Field': {
|
||||
const tmp =
|
||||
ty.value._variant === 'unit'
|
||||
? { [flatName]: () => this.makeTop(modulePath, name, mkBase()) }
|
||||
: (variant === void 0
|
||||
? { [flatName]: (value: any) => value }
|
||||
: { [flatName]: (value: any) => this.makeTop(
|
||||
modulePath, name, { ... mkBase(), value }) });
|
||||
return attachSchema(schema, name, tmp[flatName], variant);
|
||||
}
|
||||
case 'Record': {
|
||||
const rec = ty.value;
|
||||
if (rec.fields.length > 1) {
|
||||
const tmp = { [flatName]: (fields: Bindings<V>) =>
|
||||
this.makeTop(modulePath, name, { ... mkBase(), ... fields }) };
|
||||
return attachSchema(schema, name, tmp[flatName], variant);
|
||||
} else {
|
||||
const tmp = { [flatName]: (field: Parsed<V>) =>
|
||||
this.makeTop(modulePath, name, {
|
||||
... mkBase(),
|
||||
[M.jsId(rec.fields[0].name.description!)]: field,
|
||||
}) };
|
||||
return attachSchema(schema, name, tmp[flatName], variant);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
definitionConstructor(
|
||||
modulePath: M.ModulePath,
|
||||
name: symbol,
|
||||
): DefinitionConstructors<V> {
|
||||
return this._lookup(modulePath, name, (definition, schema): DefinitionConstructors<V> => {
|
||||
function attachSchema(
|
||||
f: (input: any) => Parsed<V>,
|
||||
variant?: symbol,
|
||||
): SingleConstructor<V> {
|
||||
const g = f as SingleConstructor<V>;
|
||||
g.schema = () => ({
|
||||
schema: fromJS(schema),
|
||||
imports: {}, // TODO
|
||||
definitionName: name,
|
||||
variant,
|
||||
});
|
||||
return g;
|
||||
}
|
||||
const ty = H.definitionType(definition);
|
||||
if (ty._variant === 'union') {
|
||||
const multiple: MultipleConstructors<V> = {};
|
||||
ty.variants.forEach(v => {
|
||||
const _variant = v.label.description!;
|
||||
switch (v.type._variant) {
|
||||
case 'Field':
|
||||
multiple[_variant] = attachSchema(
|
||||
(value: any) => this.makeTop(modulePath, name, { _variant, value }),
|
||||
v.label);
|
||||
break;
|
||||
case 'Record':
|
||||
multiple[_variant] = attachSchema(
|
||||
(fields: object) => this.makeTop(modulePath, name, { _variant, ... fields }),
|
||||
v.label);
|
||||
break;
|
||||
}
|
||||
multiple[M.jsId(v.label.description!)] = this.buildConstructor(
|
||||
modulePath, name, schema, v.type, v.label);
|
||||
});
|
||||
return multiple;
|
||||
} else {
|
||||
const flatName = M.formatModulePath([... modulePath, name]);
|
||||
switch (ty.value._variant) {
|
||||
case 'Field': {
|
||||
const tmp = { [flatName]: (value: any) => value };
|
||||
return attachSchema(tmp[flatName]);
|
||||
}
|
||||
case 'Record': {
|
||||
const rec = ty.value.value;
|
||||
if (rec.fields.length > 1) {
|
||||
const tmp = { [flatName]: (fields: Bindings<V>) =>
|
||||
this.makeTop(modulePath, name, fields) };
|
||||
return attachSchema(tmp[flatName]);
|
||||
} else {
|
||||
const tmp = { [flatName]: (field: Parsed<V>) =>
|
||||
this.makeTop(modulePath, name, {
|
||||
[M.jsId(rec.fields[0].name.description!)]: field,
|
||||
}) };
|
||||
return attachSchema(tmp[flatName]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.buildConstructor(modulePath, name, schema, ty.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -219,7 +235,11 @@ export class SchemaInterpreter<V> {
|
|||
if (ty._variant === 'union' || ty.value._variant === 'Record') {
|
||||
return this.makeTop(modulePath, name, result0 as Bindings<V>);
|
||||
} else {
|
||||
return result0 as Exclude<Parsed<V>, Bindings<V>>;
|
||||
if (ty.value.value._variant === 'unit') {
|
||||
return this.makeTop(modulePath, name, {});
|
||||
} else {
|
||||
return result0 as Exclude<Parsed<V>, Bindings<V>>;
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
@ -291,7 +311,7 @@ export class SchemaInterpreter<V> {
|
|||
case 'ByteString': return inputIf(Bytes.isBytes(input));
|
||||
case 'Symbol': return inputIf(typeof input === 'symbol');
|
||||
}
|
||||
case 'embedded': return isEmbedded(input) ? input.embeddedValue : void 0;
|
||||
case 'embedded': return isEmbedded(input) ? input : void 0;
|
||||
case 'lit': return is(input, p.value) ? null : void 0;
|
||||
case 'seqof': {
|
||||
if (!isSequence(input)) return void 0;
|
||||
|
@ -315,17 +335,29 @@ export class SchemaInterpreter<V> {
|
|||
}
|
||||
case 'dictof': {
|
||||
if (!Dictionary.isDictionary<V>(input)) return void 0;
|
||||
const result: DictOf<V> = new EncodableDictionary(
|
||||
this.unparserSimplePattern(p.key),
|
||||
this.unparserSimplePattern(p.value));
|
||||
for (const [k, v] of input) {
|
||||
const kw = this.parseSimplePattern(p.key, k);
|
||||
if (kw === void 0) return void 0;
|
||||
const vw = this.parseSimplePattern(p.value, v);
|
||||
if (vw === void 0) return void 0;
|
||||
result.set(kw === null ? UNIT : kw, vw === null ? UNIT : vw);
|
||||
if (M.isSymbolPattern(p.key)) {
|
||||
const result: Bindings<V> = {};
|
||||
for (const [k, v] of Dictionary.asMap<V>(input)) {
|
||||
const kw = this.parseSimplePattern(p.key, k);
|
||||
if (kw === void 0 || typeof kw !== 'symbol') return void 0;
|
||||
const vw = this.parseSimplePattern(p.value, v);
|
||||
if (vw === void 0) return void 0;
|
||||
result[kw.description!] = vw === null ? UNIT : vw;
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
const result: DictOf<V> = new EncodableDictionary(
|
||||
this.unparserSimplePattern(p.key),
|
||||
this.unparserSimplePattern(p.value));
|
||||
for (const [k, v] of Dictionary.asMap<V>(input)) {
|
||||
const kw = this.parseSimplePattern(p.key, k);
|
||||
if (kw === void 0) return void 0;
|
||||
const vw = this.parseSimplePattern(p.value, v);
|
||||
if (vw === void 0) return void 0;
|
||||
result.set(kw === null ? UNIT : kw, vw === null ? UNIT : vw);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
case 'Ref': return this.tryParse(p.value.module, p.value.name, input);
|
||||
}
|
||||
|
@ -340,7 +372,7 @@ export class SchemaInterpreter<V> {
|
|||
fsw => Bindings.merge(lw, fsw)));
|
||||
case 'tuple': {
|
||||
if (!isSequence(input)) return void 0;
|
||||
if (input.length !== p.patterns.length) return void 0;
|
||||
if (input.length < p.patterns.length) return void 0;
|
||||
let results: Bindings<V>[] = [];
|
||||
for (let i = 0; i < p.patterns.length; i++) {
|
||||
const w = this.parseNamedPattern(p.patterns[i], input[i]);
|
||||
|
@ -365,10 +397,11 @@ export class SchemaInterpreter<V> {
|
|||
});
|
||||
}
|
||||
case 'dict': {
|
||||
if (!Dictionary.isDictionary<V>(input)) return void 0;
|
||||
const inputMap = Dictionary.asMap<V>(input);
|
||||
if (!inputMap) return void 0;
|
||||
const results: Bindings<V>[] = [];
|
||||
for (const [key, vp] of p.entries) {
|
||||
const v = input.get(key);
|
||||
const v = inputMap.get(key);
|
||||
if (v === void 0) return void 0;
|
||||
const vw = this.parseNamedSimplePattern(vp, v);
|
||||
if (vw === void 0) return void 0;
|
||||
|
@ -467,7 +500,7 @@ export class SchemaInterpreter<V> {
|
|||
switch (p._variant) {
|
||||
case 'any': return v => v as Value<V>; // ?!
|
||||
case 'atom': return v => v as Atom;
|
||||
case 'embedded': return v => new Embedded(v as V);
|
||||
case 'embedded': return v => v as V;
|
||||
case 'lit': return _v => p.value;
|
||||
case 'seqof': {
|
||||
const up = this.unparserSimplePattern(p.pattern);
|
||||
|
@ -480,8 +513,17 @@ export class SchemaInterpreter<V> {
|
|||
case 'dictof': {
|
||||
const kp = this.unparserSimplePattern(p.key);
|
||||
const vp = this.unparserSimplePattern(p.value);
|
||||
return vs => new Dictionary<V>(_iterMap(
|
||||
(vs as DictOf<V>).entries(), ([k, v]) => [kp(k), vp(v)]));
|
||||
return vs => {
|
||||
const d = new DictionaryMap<V>();
|
||||
for (const [k, v] of
|
||||
(Map.isMap(vs)
|
||||
? vs.entries()
|
||||
: JsDictionary.entries(vs as Bindings<V>)))
|
||||
{
|
||||
d.set(kp(k), vp(v));
|
||||
}
|
||||
return M.isSymbolPattern(p.key) ? d.asJsDictionary() : d.asKeyedDictionary();
|
||||
};
|
||||
}
|
||||
case 'Ref': {
|
||||
const up = this._unparser(p.value.module, p.value.name);
|
||||
|
@ -510,11 +552,11 @@ export class SchemaInterpreter<V> {
|
|||
const ups: [Value<V>, Unparser<V>][] = Array.from(p.entries.entries()).map(
|
||||
([key, vp]) => [key, this.unparserNamedSimplePattern(vp)]);
|
||||
return bs => {
|
||||
const result = new Dictionary<V>();
|
||||
const result = new DictionaryMap<V>();
|
||||
for (const [key, up] of ups) {
|
||||
result.set(key, up(bs));
|
||||
}
|
||||
return result;
|
||||
return result.simplifiedValue();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -531,4 +573,32 @@ export class SchemaInterpreter<V> {
|
|||
return this.unparserSimplePattern(p.value);
|
||||
}
|
||||
}
|
||||
|
||||
moduleFor(modulePath: M.ModulePath): { [key: string]: any } | undefined {
|
||||
const schema = this.env.get(modulePath);
|
||||
if (schema === void 0) return void 0;
|
||||
const mod: { [key: string]: any } = {};
|
||||
JsDictionary.forEach(schema.definitions, (_d, n) => {
|
||||
const definitionName = n.description!;
|
||||
const definitionId = M.jsId(definitionName);
|
||||
mod[`${definitionId}`] = this.definitionConstructor(modulePath, n);
|
||||
mod[`from${definitionId}`] = this.unparser(modulePath, n);
|
||||
mod[`to${definitionId}`] = (v: Value<V>) => this.tryParse(modulePath, n, v);
|
||||
mod[`as${definitionId}`] = (v: Value<V>) => this.parse(modulePath, n, v);
|
||||
});
|
||||
return mod;
|
||||
}
|
||||
|
||||
moduleTree(tree: { [key: string]: any } = {}): { [key: string]: any } {
|
||||
for (const modulePath of this.env.keys()) {
|
||||
let container = tree;
|
||||
modulePath.slice(0, -1).forEach(n => {
|
||||
if (!(n.description! in container)) container[n.description!] = {};
|
||||
container = container[n.description!];
|
||||
});
|
||||
container[modulePath[modulePath.length - 1].description!] =
|
||||
this.moduleFor(modulePath)!;
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { GenericEmbedded, is, Value } from '@preserves/core';
|
||||
import { Embeddable, GenericEmbedded, is, Value } from '@preserves/core';
|
||||
import * as M from './gen/schema';
|
||||
import { isJsKeyword } from './compiler/jskw';
|
||||
|
||||
|
@ -98,3 +98,8 @@ export function namelike(x: Input): string | undefined {
|
|||
if (typeof x === 'boolean') return x ? 'true' : 'false';
|
||||
return void 0;
|
||||
}
|
||||
|
||||
export function isSymbolPattern<T extends Embeddable>(p: M.SimplePattern<T>): boolean {
|
||||
return p._variant === 'atom'
|
||||
&& p.atomKind._variant === 'Symbol';
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Reader, Annotated, Dictionary, is, peel, preserves, Record, strip, Tuple, Position, position, stringify, isCompound, EncodableDictionary, annotate, annotations, isEmbedded, GenericEmbedded, genericEmbeddedTypeDecode } from '@preserves/core';
|
||||
import { Reader, Annotated, Dictionary, is, peel, preserves, Record, strip, Tuple, Position, position, stringify, isCompound, EncodableDictionary, annotate, annotations, isEmbedded, GenericEmbedded, genericEmbeddedTypeDecode, JsDictionary, KeyedDictionary } from '@preserves/core';
|
||||
import { Input, Pattern, Schema, Definition, CompoundPattern, SimplePattern } from './meta';
|
||||
import * as M from './meta';
|
||||
import { SchemaSyntaxError } from './error';
|
||||
|
@ -70,7 +70,7 @@ export function parseSchema(toplevelTokens: Array<Input>, options: SchemaReaderO
|
|||
{
|
||||
let version: M.Version | undefined = void 0;
|
||||
let embeddedType: M.EmbeddedTypeName = M.EmbeddedTypeName.$false();
|
||||
let definitions: M.Definitions = new EncodableDictionary(k => k, M.fromDefinition);
|
||||
let definitions: M.Definitions = {};
|
||||
|
||||
function process(toplevelTokens: Array<Input>): void {
|
||||
const toplevelClauses = splitBy(peel(toplevelTokens) as Array<Input>, M.DOT);
|
||||
|
@ -82,10 +82,10 @@ export function parseSchema(toplevelTokens: Array<Input>, options: SchemaReaderO
|
|||
if (!M.isValidToken(name.description!)) {
|
||||
throw new SchemaSyntaxError(preserves`Invalid definition name: ${name}`, pos);
|
||||
}
|
||||
if (definitions.has(name)) {
|
||||
if (JsDictionary.has(definitions, name)) {
|
||||
throw new SchemaSyntaxError(preserves`Duplicate definition: ${clause}`, pos);
|
||||
}
|
||||
definitions.set(name, parseDefinition(name, pos, clause.slice(2)));
|
||||
JsDictionary.set(definitions, name, parseDefinition(name, pos, clause.slice(2)));
|
||||
} else if (clause.length === 2 && is(clause[0], M.$version)) {
|
||||
version = M.asVersion(peel(clause[1]));
|
||||
} else if (clause.length === 2 && is(clause[0], M.$embeddedType)) {
|
||||
|
@ -232,7 +232,7 @@ function parsePattern(name: symbol, body0: Array<Input>): Pattern {
|
|||
case 'symbol': return ks(M.SimplePattern.atom(M.AtomKind.Symbol()));
|
||||
default: {
|
||||
if (str[0] === '=') {
|
||||
return ks(M.SimplePattern.lit(Symbol.for(str.slice(1))));
|
||||
return ks(M.SimplePattern.lit<GenericEmbedded>(Symbol.for(str.slice(1))));
|
||||
} else if (M.isValidQid(str)) {
|
||||
return ks(M.SimplePattern.Ref(parseRef(str, pos)));
|
||||
} else {
|
||||
|
@ -260,20 +260,20 @@ function parsePattern(name: symbol, body0: Array<Input>): Pattern {
|
|||
if (item.size !== 1) complain();
|
||||
const [vp] = item.values();
|
||||
return ks(M.SimplePattern.setof(walkSimple(vp)));
|
||||
} else if (Dictionary.isDictionary<M.InputEmbedded, Input>(item)
|
||||
&& item.size === 2
|
||||
&& item.has(M.DOTDOTDOT))
|
||||
{
|
||||
const v = item.clone();
|
||||
v.delete(M.DOTDOTDOT);
|
||||
const [[kp, vp]] = v.entries();
|
||||
return ks(M.SimplePattern.dictof({ key: walkSimple(kp), value: walkSimple(vp) }));
|
||||
} else if (isCompound(item)) {
|
||||
return kf();
|
||||
} else if (isEmbedded(item)) {
|
||||
return ks(M.SimplePattern.embedded(walkSimple(item.embeddedValue.generic)));
|
||||
} else {
|
||||
return ks(M.SimplePattern.lit(strip(item)));
|
||||
const itemMap = Dictionary.asMap<M.InputEmbedded, Input>(item);
|
||||
if (itemMap && itemMap.size === 2 && itemMap.has(M.DOTDOTDOT)) {
|
||||
const v = itemMap.clone();
|
||||
v.delete(M.DOTDOTDOT);
|
||||
const [[kp, vp]] = v.entries();
|
||||
return ks(M.SimplePattern.dictof({ key: walkSimple(kp), value: walkSimple(vp) }));
|
||||
} else if (isCompound(item)) {
|
||||
return kf();
|
||||
} else if (isEmbedded(item)) {
|
||||
return ks(M.SimplePattern.embedded(walkSimple(item.generic)));
|
||||
} else {
|
||||
return ks(M.SimplePattern.lit(strip(item)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,19 +312,20 @@ function parsePattern(name: symbol, body0: Array<Input>): Pattern {
|
|||
});
|
||||
} else if (Array.isArray(item)) {
|
||||
return M.CompoundPattern.tuple(item.map(maybeNamed));
|
||||
} else if (Dictionary.isDictionary<M.InputEmbedded, Input>(item) && !item.has(M.DOTDOTDOT)) {
|
||||
return M.CompoundPattern.dict(
|
||||
M.DictionaryEntries(item.mapEntries<M.NamedSimplePattern, Input, M.InputEmbedded>(
|
||||
([k, vp]) => [
|
||||
strip(k),
|
||||
_maybeNamed(
|
||||
M.NamedSimplePattern.named,
|
||||
M.NamedSimplePattern.anonymous,
|
||||
walkSimple,
|
||||
strip(k))(vp)
|
||||
])));
|
||||
} else {
|
||||
complain();
|
||||
const itemMap = Dictionary.asMap<M.InputEmbedded, Input>(item);
|
||||
if (itemMap && !itemMap.has(M.DOTDOTDOT)) {
|
||||
const entries = new KeyedDictionary<M.InputEmbedded, Input, M.NamedSimplePattern>();
|
||||
itemMap.forEach((vp, k) => entries.set(
|
||||
strip(k),
|
||||
_maybeNamed(M.NamedSimplePattern.named,
|
||||
M.NamedSimplePattern.anonymous,
|
||||
walkSimple,
|
||||
strip(k))(vp)));
|
||||
return M.CompoundPattern.dict(M.DictionaryEntries(entries));
|
||||
} else {
|
||||
complain();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
import { } from '@preserves/core';
|
||||
import { compile, Meta as M, readSchema } from '../src/index';
|
||||
import './test-utils';
|
||||
import { js as format } from 'js-beautify';
|
||||
|
||||
function compileSingleSchema(source: string): string {
|
||||
return format(compile([], [Symbol.for('test')], readSchema(`version 1 . ${source}`), {}));
|
||||
}
|
||||
|
||||
describe('compiler', () => {
|
||||
it('basics', () => {
|
||||
expect(compileSingleSchema(`X = int .`)).toContain(`\nexport type X = number;\n`);
|
||||
});
|
||||
|
||||
it('symbol-keyed dictionary', () => {
|
||||
const s = compileSingleSchema(`D = { symbol:any ...:... } .`);
|
||||
expect(s).toMatch(/^export type D.*= _.JsDictionary < _.Value < _embedded >> ;$/m);
|
||||
});
|
||||
|
||||
it('string-keyed dictionary', () => {
|
||||
const s = compileSingleSchema(`D = { string:any ...:... } .`);
|
||||
expect(s).toMatch(/^export type D.*= _.EncodableDictionary < _embedded, string, _.Value < _embedded >> ;$/m);
|
||||
});
|
||||
|
||||
it('any-keyed dictionary', () => {
|
||||
const s = compileSingleSchema(`D = { any:any ...:... } .`);
|
||||
expect(s).toMatch(/^export type D.*= _.EncodableDictionary < _embedded, _.Value < _embedded > , _.Value < _embedded >> ;$/m);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,111 @@
|
|||
import { GenericEmbedded, stringify, fromJS, parse, EncodableDictionary, KeyedDictionary } from '@preserves/core';
|
||||
import { SchemaInterpreter, readSchema } from '../src/index';
|
||||
import './test-utils';
|
||||
|
||||
describe('interpreter', () => {
|
||||
const I = new SchemaInterpreter<GenericEmbedded>();
|
||||
|
||||
const X_schema = readSchema(`
|
||||
version 1 .
|
||||
A = <foo> .
|
||||
B = <bar @v int> .
|
||||
C = <zot @v int @w int> .
|
||||
N = int .
|
||||
|
||||
U = <class @a int @b int> / <true @c int @d int> .
|
||||
V = <public @n int> / <private @n int> .
|
||||
W = <const> / <let> .
|
||||
|
||||
D1 = { symbol:A ...:... } .
|
||||
D2 = { any:A ...:... } .
|
||||
D3 = { string:A ...:... } .
|
||||
`);
|
||||
const X = Symbol.for('X');
|
||||
I.env.set([X], X_schema);
|
||||
|
||||
const E = I.moduleTree();
|
||||
|
||||
it('basically works', () => {
|
||||
const a = E.X.A();
|
||||
const b = E.X.B(22);
|
||||
const c = E.X.C({v: 33, w: 44});
|
||||
const n = E.X.N(22);
|
||||
expect(stringify(a)).toBe('<foo>');
|
||||
expect(stringify(b)).toBe('<bar 22>');
|
||||
expect(stringify(c)).toBe('<zot 33 44>');
|
||||
expect(stringify(n)).toBe('22');
|
||||
expect(parse('<foo>')).is(fromJS(a));
|
||||
expect(parse('<bar 22>')).is(fromJS(b));
|
||||
expect(parse('<zot 33 44>')).is(fromJS(c));
|
||||
expect(parse('22')).is(fromJS(n));
|
||||
expect(stringify(E.X.asA(fromJS(a)))).toBe('<foo>');
|
||||
expect(stringify(E.X.asB(fromJS(b)))).toBe('<bar 22>');
|
||||
expect(stringify(E.X.asC(fromJS(c)))).toBe('<zot 33 44>');
|
||||
expect(stringify(E.X.asN(fromJS(n)))).toBe('22');
|
||||
});
|
||||
|
||||
it('escapes JS keywords', () => {
|
||||
expect(Object.keys(E.X.U)).toEqual(['$class', '$true']);
|
||||
expect(Object.keys(E.X.V)).toEqual(['$public', '$private']);
|
||||
expect(Object.keys(E.X.W)).toEqual(['$const', '$let']);
|
||||
});
|
||||
|
||||
const STANDARD_METHODS = ['__as_preserve__', '__preserve_on__', '__preserve_text_on__'];
|
||||
|
||||
it('accepts correct arguments to n-ary variant ctors', () => {
|
||||
expect(stringify(E.X.U.$class({ a: 123, b: 234 }))).toBe('<class 123 234>');
|
||||
expect(stringify(E.X.U.$true({ c: 123, d: 234 }))).toBe('<true 123 234>');
|
||||
expect(Object.keys(E.X.U.$class({ a: 123, b: 234 }))).toEqual([
|
||||
'_variant', 'a', 'b', ... STANDARD_METHODS]);
|
||||
});
|
||||
|
||||
it('accepts correct arguments to unary variant ctors', () => {
|
||||
expect(stringify(E.X.V.$public(123))).toBe('<public 123>');
|
||||
expect(stringify(E.X.V.$private(123))).toBe('<private 123>');
|
||||
expect(Object.keys(E.X.V.$public(123))).toEqual([
|
||||
'_variant', 'n', ... STANDARD_METHODS]);
|
||||
});
|
||||
|
||||
it('accepts correct arguments to nullary variant ctors', () => {
|
||||
expect(stringify(E.X.W.$const())).toBe('<const>');
|
||||
expect(stringify(E.X.W.$let())).toBe('<let>');
|
||||
expect(Object.keys(E.X.W.$const())).toEqual([
|
||||
'_variant', ... STANDARD_METHODS]);
|
||||
});
|
||||
|
||||
it('produces JsDictionary for symbol-keyed dicts', () => {
|
||||
const v = E.X.asD1(parse('{ a: <foo>, b: <foo>}'));
|
||||
expect(Object.keys(v)).toEqual(['a', 'b']);
|
||||
expect(stringify(E.X.fromA(v.a))).toBe('<foo>');
|
||||
expect(stringify(E.X.fromA(v.b))).toBe('<foo>');
|
||||
});
|
||||
|
||||
it('produces EncodableDictionary for any-keyed dicts', () => {
|
||||
const d2 = E.X.asD2(parse('{ a: <foo>, b: <foo>}'));
|
||||
expect(d2 instanceof EncodableDictionary).toBe(true);
|
||||
expect(Array.from(d2.keys())).toEqual([Symbol.for('a'), Symbol.for('b')]);
|
||||
expect(fromJS(d2.get(Symbol.for('a')))).is(fromJS(E.X.A()));
|
||||
});
|
||||
|
||||
it('accepts either kind of dictionary for symbol-keyed dicts', () => {
|
||||
const v = { a: E.X.A(), b: E.X.A() };
|
||||
expect(stringify(v)).toBe('{a: <foo> b: <foo>}');
|
||||
expect(E.X.fromD1(v)).is(parse('{a: <foo> b: <foo>}'));
|
||||
expect(E.X.fromD1(E.X.D1(v))).is(parse('{a: <foo> b: <foo>}'));
|
||||
expect(E.X.fromD1(E.X.D1(new KeyedDictionary([
|
||||
[parse('a'), parse('<foo>')],
|
||||
[parse('b'), parse('<foo>')],
|
||||
])))).is(parse('{a: <foo> b: <foo>}'));
|
||||
});
|
||||
|
||||
it('accepts either kind of dictionary for any-keyed dicts', () => {
|
||||
const v = { a: E.X.A(), b: E.X.A() };
|
||||
expect(stringify(v)).toBe('{a: <foo> b: <foo>}');
|
||||
expect(E.X.fromD2(v)).is(parse('{a: <foo> b: <foo>}'));
|
||||
expect(E.X.fromD2(E.X.D2(v))).is(parse('{a: <foo> b: <foo>}'));
|
||||
expect(E.X.fromD2(E.X.D2(new KeyedDictionary([
|
||||
[parse('a'), parse('<foo>')],
|
||||
[parse('b'), parse('<foo>')],
|
||||
])))).is(parse('{a: <foo> b: <foo>}'));
|
||||
});
|
||||
});
|
|
@ -1,3 +1,4 @@
|
|||
import { JsDictionary } from '@preserves/core';
|
||||
import { readSchema, Meta } from '../src/index';
|
||||
|
||||
describe('reader schema', () => {
|
||||
|
@ -14,12 +15,12 @@ describe('reader schema', () => {
|
|||
'__preserve_on__',
|
||||
'__preserve_text_on__',
|
||||
]);
|
||||
expect(s.definitions.size).toBe(0);
|
||||
expect(JsDictionary.size(s.definitions)).toBe(0);
|
||||
expect(s.embeddedType._variant).toBe('false');
|
||||
});
|
||||
it('understands patterns under embed', () => {
|
||||
const s = readSchema('version 1 . X = #:0 .');
|
||||
const def: Meta.Definition = s.definitions.get(Symbol.for('X'))!;
|
||||
const def: Meta.Definition = JsDictionary.get(s.definitions, Symbol.for('X'))!;
|
||||
if (def._variant !== 'Pattern') fail('bad definition 1');
|
||||
if (def.value._variant !== 'SimplePattern') fail ('bad definition 2');
|
||||
if (def.value.value._variant !== 'embedded') fail('bad definition 3');
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { Value, is, preserves } from '@preserves/core';
|
||||
import { Value, is, preserves, Embeddable } from '@preserves/core';
|
||||
|
||||
declare global {
|
||||
namespace jest {
|
||||
interface Matchers<R> {
|
||||
is<T>(expected: Value<T>): R;
|
||||
is<T extends Embeddable>(expected: Value<T>): R;
|
||||
toThrowFilter(f: (e: Error) => boolean): R;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,5 @@ open "cd packages/schema; yarn run compile:watch"
|
|||
open "cd packages/schema; yarn run rollup:watch"
|
||||
open "cd packages/schema; yarn run test:watch"
|
||||
open "cd packages/schema-cli; yarn run compile:watch"
|
||||
open "cd packages/schema-cli; yarn run rollup:watch"
|
||||
|
||||
tmux select-layout even-vertical
|
||||
|
|
|
@ -308,6 +308,18 @@
|
|||
resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340"
|
||||
integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==
|
||||
|
||||
"@isaacs/cliui@^8.0.2":
|
||||
version "8.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
|
||||
integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==
|
||||
dependencies:
|
||||
string-width "^5.1.2"
|
||||
string-width-cjs "npm:string-width@^4.2.0"
|
||||
strip-ansi "^7.0.1"
|
||||
strip-ansi-cjs "npm:strip-ansi@^6.0.1"
|
||||
wrap-ansi "^8.1.0"
|
||||
wrap-ansi-cjs "npm:wrap-ansi@^7.0.0"
|
||||
|
||||
"@istanbuljs/load-nyc-config@^1.0.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
|
||||
|
@ -1417,6 +1429,16 @@
|
|||
dependencies:
|
||||
"@octokit/openapi-types" "^12.11.0"
|
||||
|
||||
"@one-ini/wasm@0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@one-ini/wasm/-/wasm-0.1.1.tgz#6013659736c9dbfccc96e8a9c2b3de317df39323"
|
||||
integrity sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==
|
||||
|
||||
"@pkgjs/parseargs@^0.11.0":
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
|
||||
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
|
||||
|
||||
"@rollup/plugin-terser@^0.4":
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-terser/-/plugin-terser-0.4.0.tgz#4c76249ad337f3eb04ab409332f23717af2c1fbf"
|
||||
|
@ -1540,6 +1562,11 @@
|
|||
jest-matcher-utils "^27.0.0"
|
||||
pretty-format "^27.0.0"
|
||||
|
||||
"@types/js-beautify@1.14":
|
||||
version "1.14.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/js-beautify/-/js-beautify-1.14.3.tgz#6ced76f79935e37e0d613110dea369881d93c1ff"
|
||||
integrity sha512-FMbQHz+qd9DoGvgLHxeqqVPaNRffpIu5ZjozwV8hf9JAGpIOzuAf4wGbRSo8LNITHqGjmmVjaMggTT5P4v4IHg==
|
||||
|
||||
"@types/minimatch@*":
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca"
|
||||
|
@ -1627,6 +1654,11 @@ abbrev@1:
|
|||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
|
||||
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
|
||||
|
||||
abbrev@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf"
|
||||
integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==
|
||||
|
||||
acorn-globals@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45"
|
||||
|
@ -1716,6 +1748,11 @@ ansi-regex@^5.0.1:
|
|||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
|
||||
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
|
||||
|
||||
ansi-regex@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a"
|
||||
integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==
|
||||
|
||||
ansi-styles@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
|
||||
|
@ -1735,6 +1772,11 @@ ansi-styles@^5.0.0:
|
|||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b"
|
||||
integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
|
||||
|
||||
ansi-styles@^6.1.0:
|
||||
version "6.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5"
|
||||
integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
|
||||
|
||||
anymatch@^3.0.3, anymatch@~3.1.2:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
|
||||
|
@ -1942,6 +1984,13 @@ brace-expansion@^1.1.7:
|
|||
balanced-match "^1.0.0"
|
||||
concat-map "0.0.1"
|
||||
|
||||
brace-expansion@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
|
||||
integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
|
||||
dependencies:
|
||||
balanced-match "^1.0.0"
|
||||
|
||||
braces@^3.0.2, braces@~3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
|
||||
|
@ -2232,6 +2281,11 @@ combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
|
|||
dependencies:
|
||||
delayed-stream "~1.0.0"
|
||||
|
||||
commander@^10.0.0:
|
||||
version "10.0.1"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06"
|
||||
integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==
|
||||
|
||||
commander@^2.20.0:
|
||||
version "2.20.3"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
|
@ -2265,7 +2319,7 @@ concat-stream@^2.0.0:
|
|||
readable-stream "^3.0.2"
|
||||
typedarray "^0.0.6"
|
||||
|
||||
config-chain@^1.1.12:
|
||||
config-chain@^1.1.12, config-chain@^1.1.13:
|
||||
version "1.1.13"
|
||||
resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4"
|
||||
integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==
|
||||
|
@ -2391,7 +2445,7 @@ create-require@^1.1.0:
|
|||
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
|
||||
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
||||
|
||||
cross-spawn@^7.0.3:
|
||||
cross-spawn@^7.0.0, cross-spawn@^7.0.3:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
||||
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
|
||||
|
@ -2601,6 +2655,11 @@ dynamic-dedupe@^0.3.0:
|
|||
dependencies:
|
||||
xtend "^4.0.0"
|
||||
|
||||
eastasianwidth@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
|
||||
integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
|
||||
|
||||
ecc-jsbn@~0.1.1:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
|
||||
|
@ -2609,6 +2668,16 @@ ecc-jsbn@~0.1.1:
|
|||
jsbn "~0.1.0"
|
||||
safer-buffer "^2.1.0"
|
||||
|
||||
editorconfig@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-1.0.4.tgz#040c9a8e9a6c5288388b87c2db07028aa89f53a3"
|
||||
integrity sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==
|
||||
dependencies:
|
||||
"@one-ini/wasm" "0.1.1"
|
||||
commander "^10.0.0"
|
||||
minimatch "9.0.1"
|
||||
semver "^7.5.3"
|
||||
|
||||
electron-to-chromium@^1.4.284:
|
||||
version "1.4.286"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.286.tgz#0e039de59135f44ab9a8ec9025e53a9135eba11f"
|
||||
|
@ -2624,6 +2693,11 @@ emoji-regex@^8.0.0:
|
|||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
|
||||
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
|
||||
|
||||
emoji-regex@^9.2.2:
|
||||
version "9.2.2"
|
||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
|
||||
integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
|
||||
|
||||
encoding@^0.1.12:
|
||||
version "0.1.13"
|
||||
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
|
||||
|
@ -2897,6 +2971,14 @@ for-each@^0.3.3:
|
|||
dependencies:
|
||||
is-callable "^1.1.3"
|
||||
|
||||
foreground-child@^3.1.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d"
|
||||
integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==
|
||||
dependencies:
|
||||
cross-spawn "^7.0.0"
|
||||
signal-exit "^4.0.1"
|
||||
|
||||
forever-agent@~0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
||||
|
@ -3103,6 +3185,17 @@ glob-parent@^5.1.1, glob-parent@^5.1.2, glob-parent@~5.1.2:
|
|||
dependencies:
|
||||
is-glob "^4.0.1"
|
||||
|
||||
glob@^10.3.3:
|
||||
version "10.3.10"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b"
|
||||
integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==
|
||||
dependencies:
|
||||
foreground-child "^3.1.0"
|
||||
jackspeak "^2.3.5"
|
||||
minimatch "^9.0.1"
|
||||
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
path-scurry "^1.10.1"
|
||||
|
||||
glob@^7.1, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
|
||||
version "7.2.3"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
|
||||
|
@ -3698,6 +3791,15 @@ istanbul-reports@^3.1.3:
|
|||
html-escaper "^2.0.0"
|
||||
istanbul-lib-report "^3.0.0"
|
||||
|
||||
jackspeak@^2.3.5:
|
||||
version "2.3.6"
|
||||
resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8"
|
||||
integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==
|
||||
dependencies:
|
||||
"@isaacs/cliui" "^8.0.2"
|
||||
optionalDependencies:
|
||||
"@pkgjs/parseargs" "^0.11.0"
|
||||
|
||||
jest-changed-files@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.5.1.tgz#a348aed00ec9bf671cc58a66fcbe7c3dfd6a68f5"
|
||||
|
@ -4103,6 +4205,22 @@ jest@^27.4:
|
|||
import-local "^3.0.2"
|
||||
jest-cli "^27.5.1"
|
||||
|
||||
js-beautify@1.15:
|
||||
version "1.15.1"
|
||||
resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.15.1.tgz#4695afb508c324e1084ee0b952a102023fc65b64"
|
||||
integrity sha512-ESjNzSlt/sWE8sciZH8kBF8BPlwXPwhR6pWKAw8bw4Bwj+iZcnKW6ONWUutJ7eObuBZQpiIb8S7OYspWrKt7rA==
|
||||
dependencies:
|
||||
config-chain "^1.1.13"
|
||||
editorconfig "^1.0.4"
|
||||
glob "^10.3.3"
|
||||
js-cookie "^3.0.5"
|
||||
nopt "^7.2.0"
|
||||
|
||||
js-cookie@^3.0.5:
|
||||
version "3.0.5"
|
||||
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-3.0.5.tgz#0b7e2fd0c01552c58ba86e0841f94dc2557dcdbc"
|
||||
integrity sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==
|
||||
|
||||
js-tokens@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||
|
@ -4370,6 +4488,11 @@ lru-cache@^6.0.0:
|
|||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
"lru-cache@^9.1.1 || ^10.0.0":
|
||||
version "10.2.0"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3"
|
||||
integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==
|
||||
|
||||
make-dir@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"
|
||||
|
@ -4507,6 +4630,13 @@ min-indent@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
|
||||
integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
|
||||
|
||||
minimatch@9.0.1:
|
||||
version "9.0.1"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.1.tgz#8a555f541cf976c622daf078bb28f29fb927c253"
|
||||
integrity sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==
|
||||
dependencies:
|
||||
brace-expansion "^2.0.1"
|
||||
|
||||
minimatch@^3.0, minimatch@^3.0.4, minimatch@^3.1.1:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
|
||||
|
@ -4514,6 +4644,13 @@ minimatch@^3.0, minimatch@^3.0.4, minimatch@^3.1.1:
|
|||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimatch@^9.0.1:
|
||||
version "9.0.3"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825"
|
||||
integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==
|
||||
dependencies:
|
||||
brace-expansion "^2.0.1"
|
||||
|
||||
minimist-options@4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619"
|
||||
|
@ -4595,6 +4732,11 @@ minipass@^4.0.0:
|
|||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.0.1.tgz#2b9408c6e81bb8b338d600fb3685e375a370a057"
|
||||
integrity sha512-V9esFpNbK0arbN3fm2sxDKqMYgIp7XtVdE4Esj+PE4Qaaxdg1wIw48ITQIOn1sc8xXSmUviVL3cyjMqPlrVkiA==
|
||||
|
||||
"minipass@^5.0.0 || ^6.0.2 || ^7.0.0":
|
||||
version "7.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c"
|
||||
integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==
|
||||
|
||||
minizlib@^1.3.3:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d"
|
||||
|
@ -4742,6 +4884,13 @@ nopt@^5.0.0:
|
|||
dependencies:
|
||||
abbrev "1"
|
||||
|
||||
nopt@^7.2.0:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.2.0.tgz#067378c68116f602f552876194fd11f1292503d7"
|
||||
integrity sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==
|
||||
dependencies:
|
||||
abbrev "^2.0.0"
|
||||
|
||||
normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
|
||||
|
@ -5158,6 +5307,14 @@ path-parse@^1.0.7:
|
|||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
|
||||
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
|
||||
|
||||
path-scurry@^1.10.1:
|
||||
version "1.10.1"
|
||||
resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698"
|
||||
integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==
|
||||
dependencies:
|
||||
lru-cache "^9.1.1 || ^10.0.0"
|
||||
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
|
||||
path-type@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
|
||||
|
@ -5667,6 +5824,13 @@ semver@^6.0.0, semver@^6.3.0:
|
|||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||
|
||||
semver@^7.5.3:
|
||||
version "7.6.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d"
|
||||
integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
serialize-javascript@^6.0.0:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c"
|
||||
|
@ -5712,6 +5876,11 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3:
|
|||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
|
||||
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
|
||||
|
||||
signal-exit@^4.0.1:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
|
||||
integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
|
||||
|
||||
sisteransi@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
|
||||
|
@ -5887,6 +6056,15 @@ string-length@^4.0.1:
|
|||
char-regex "^1.0.2"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
"string-width-cjs@npm:string-width@^4.2.0":
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
dependencies:
|
||||
emoji-regex "^8.0.0"
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.1"
|
||||
|
||||
string-width@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
|
||||
|
@ -5905,6 +6083,15 @@ string-width@^1.0.1:
|
|||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.1"
|
||||
|
||||
string-width@^5.0.1, string-width@^5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
|
||||
integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==
|
||||
dependencies:
|
||||
eastasianwidth "^0.2.0"
|
||||
emoji-regex "^9.2.2"
|
||||
strip-ansi "^7.0.1"
|
||||
|
||||
string.prototype.trimend@^1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533"
|
||||
|
@ -5937,6 +6124,13 @@ string_decoder@~1.1.1:
|
|||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
strip-ansi@^3.0.0, strip-ansi@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
|
||||
|
@ -5951,6 +6145,13 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
|||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
strip-ansi@^7.0.1:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
|
||||
integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==
|
||||
dependencies:
|
||||
ansi-regex "^6.0.1"
|
||||
|
||||
strip-bom@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
|
||||
|
@ -6605,6 +6806,15 @@ wordwrap@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
|
||||
integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==
|
||||
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
dependencies:
|
||||
ansi-styles "^4.0.0"
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
wrap-ansi@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
|
@ -6614,6 +6824,15 @@ wrap-ansi@^7.0.0:
|
|||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
wrap-ansi@^8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
|
||||
integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==
|
||||
dependencies:
|
||||
ansi-styles "^6.1.0"
|
||||
string-width "^5.0.1"
|
||||
strip-ansi "^7.0.1"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
if ! [ -d .venv ]
|
||||
then
|
||||
python -m venv .venv
|
||||
python3 -m venv .venv
|
||||
. .venv/bin/activate
|
||||
pip install -e '.[dev]'
|
||||
else
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# This used to just be
|
||||
# PACKAGEVERSION := "`python3 setup.py --version`"
|
||||
PACKAGEVERSION := $(shell python -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')
|
||||
PACKAGEVERSION := $(shell ./print-package-version)
|
||||
|
||||
all: test build-docs
|
||||
|
||||
|
|
|
@ -217,7 +217,11 @@ class Decoder(BinaryCodec):
|
|||
if not vs: raise DecodeError('Too few elements in encoded record')
|
||||
return self.wrap(Record(vs[0], vs[1:]))
|
||||
if tag == 0xb5: return self.wrap(tuple(self.nextvalues()))
|
||||
if tag == 0xb6: return self.wrap(frozenset(self.nextvalues()))
|
||||
if tag == 0xb6:
|
||||
vs = self.nextvalues()
|
||||
s = frozenset(vs)
|
||||
if len(s) != len(vs): raise DecodeError('Duplicate value')
|
||||
return self.wrap(s)
|
||||
if tag == 0xb7: return self.wrap(ImmutableDict.from_kvs(self.nextvalues()))
|
||||
raise DecodeError('Invalid tag: ' + hex(tag))
|
||||
|
||||
|
|
|
@ -59,13 +59,16 @@ The result of evaluating it on `testdata` is as follows:
|
|||
"In each test, let stripped = strip(annotatedValue),"
|
||||
" encodeBinary(·) produce canonical ordering and no annotations,"
|
||||
" looseEncodeBinary(·) produce any ordering, but with annotations,"
|
||||
" annotatedBinary(·) produce canonical ordering, but with annotations,"
|
||||
" annotatedBinary(·) produce “canonical ordering”, but with annotations,"
|
||||
" decodeBinary(·) include annotations,"
|
||||
" encodeText(·) include annotations,"
|
||||
" decodeText(·) include annotations,"
|
||||
"and check the following numbered expectations according to the table above:"
|
||||
"Implementations may vary in their treatment of the difference between expectations"
|
||||
"21/22 and 31/32, depending on how they wish to treat end-of-stream conditions."
|
||||
"The idea of canonical-ordering-with-annotations is to encode, say, sets with their elements"
|
||||
"in sorted order of their canonical annotationless binary encoding, but then actually"
|
||||
"*serialized* with the annotations present."
|
||||
|
||||
```
|
||||
|
||||
|
|
|
@ -505,7 +505,7 @@ class SchemaObject:
|
|||
return ()
|
||||
if p.key == TUPLE:
|
||||
if not sequenceish(v): raise SchemaDecodeFailed(cls, p, v)
|
||||
if len(v) != len(p[0]): raise SchemaDecodeFailed(cls, p, v)
|
||||
if len(v) < len(p[0]): raise SchemaDecodeFailed(cls, p, v)
|
||||
i = 0
|
||||
for pp in p[0]:
|
||||
cls.parse(pp, v[i], args)
|
||||
|
|
|
@ -346,6 +346,10 @@ class Parser(TextCodec):
|
|||
c = self.nextchar()
|
||||
if c in ' \t': return self.unshift_annotation(self.comment_line(), self.next())
|
||||
if c in '\n\r': return self.unshift_annotation('', self.next())
|
||||
if c == '!':
|
||||
return self.unshift_annotation(
|
||||
Record(Symbol('interpreter'), [self.comment_line()]),
|
||||
self.next())
|
||||
if c == 'f': self.require_delimiter('#f'); return self.wrap(False)
|
||||
if c == 't': self.require_delimiter('#t'); return self.wrap(True)
|
||||
if c == '{': return self.wrap(self.read_set())
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/sh
|
||||
cd "$(dirname "$0")"
|
||||
. ./.envrc
|
||||
exec python -c \
|
||||
'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])'
|
|
@ -1,6 +1,6 @@
|
|||
[project]
|
||||
name = "preserves"
|
||||
version = "0.994.0"
|
||||
version = "0.995.1"
|
||||
description = "Data serialization format"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.6, <4"
|
||||
|
|
Binary file not shown.
|
@ -14,7 +14,7 @@
|
|||
"In each test, let stripped = strip(annotatedValue),"
|
||||
" encodeBinary(·) produce canonical ordering and no annotations,"
|
||||
" looseEncodeBinary(·) produce any ordering, but with annotations,"
|
||||
" annotatedBinary(·) produce canonical ordering, but with annotations,"
|
||||
" annotatedBinary(·) produce “canonical ordering”, but with annotations,"
|
||||
" decodeBinary(·) include annotations,"
|
||||
" encodeText(·) include annotations,"
|
||||
" decodeText(·) include annotations,"
|
||||
|
@ -39,6 +39,10 @@
|
|||
}>
|
||||
"Implementations may vary in their treatment of the difference between expectations"
|
||||
"21/22 and 31/32, depending on how they wish to treat end-of-stream conditions."
|
||||
|
||||
"The idea of canonical-ordering-with-annotations is to encode, say, sets with their elements"
|
||||
"in sorted order of their canonical annotationless binary encoding, but then actually"
|
||||
"*serialized* with the annotations present."
|
||||
]>
|
||||
<TestCases {
|
||||
annotation1: <Test #x"85 B103616263 B00109" @"abc" 9>
|
||||
|
@ -62,6 +66,10 @@
|
|||
<Test #x"85 B100 85 B1066e6f726d616c B000" #
|
||||
# normal
|
||||
0>
|
||||
annotation12: @"Interpreter-specification annotations"
|
||||
<Test #"\x85\xb4\xb3\x0binterpreter\xb1\x0a/some/path\x84\xb3\x05value"
|
||||
#!/some/path
|
||||
value>
|
||||
bytes2: <Test #x"B20568656c6c6f" #"hello">
|
||||
bytes2a: <Test @"Internal whitespace is allowed, not including commas" #x"B2 05 68 65 6c 6c 6f" #"hello">
|
||||
bytes2b: @"Commas forbidden in internal whitespace" <ParseError "#x\"B2, 05, 68, 65, 6c, 6c, 6f\"">
|
||||
|
@ -88,6 +96,7 @@
|
|||
dict2: @"Missing close brace" <ParseShort "{ a: b, c: d ">
|
||||
dict2a: @"Missing close brace" <ParseShort "{">
|
||||
dict3: @"Duplicate key" <ParseError "{ a: 1, a: 2 }">
|
||||
dict3a: @"Duplicate key" <DecodeError #x"b7 b00101 b00102 b00101 b00103 84">
|
||||
dict4: @"Unexpected close brace" <ParseError "}">
|
||||
dict5: @"Missing value" <DecodeError #x"b7 b00101 b00102 b00103 84">
|
||||
dict6: @"Comma not allowed between key and colon" <ParseError "{ a,: 1, b: 2 }">
|
||||
|
@ -187,6 +196,7 @@
|
|||
set2: @"Missing close brace" <ParseShort "#{ 1 2 3 ">
|
||||
set2a: @"Missing close brace" <ParseShort "#{">
|
||||
set3: @"Duplicate value" <ParseError "#{a a}">
|
||||
set3a: @"Duplicate value" <DecodeError #x"b6 b00101 b00101 84">
|
||||
string0: <Test #x"b100" "">
|
||||
string3: <Test #x"b10568656c6c6f" "hello">
|
||||
string4: <Test #x"b1 14 616263e6b0b4e6b0b45c2f22080c0a0d0978797a" "abc\u6c34\u6C34\\/\"\b\f\n\r\txyz">
|
||||
|
@ -221,6 +231,14 @@
|
|||
symbol12: <Test #x"b3042d2d2d31" ---1>
|
||||
symbol13: <Test #x"b3042b312e78" +1.x>
|
||||
symbol14: <Test #x"b304f09d849e" |\uD834\uDD1E|>
|
||||
symbol15: @"A 130-byte symbol"
|
||||
<Test #x"b3 8201
|
||||
6161616161616161616161616161616161616161616161616161616161616161
|
||||
6161616161616161616161616161616161616161616161616161616161616161
|
||||
6161616161616161616161616161616161616161616161616161616161616161
|
||||
6161616161616161616161616161616161616161616161616161616161616161
|
||||
6161"
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>
|
||||
tag0: @"Unexpected end tag" <DecodeError #x"84">
|
||||
tag1: @"Invalid tag" <DecodeError #x"10">
|
||||
tag2: @"Invalid tag" <DecodeError #x"61b10110">
|
||||
|
|
|
@ -105,7 +105,9 @@
|
|||
'named
|
||||
(list
|
||||
(and ?name (? symbol?))
|
||||
(app parse-SimplePattern (and ?pattern (not (== eof)))))))
|
||||
(app parse-SimplePattern (and ?pattern (not (== eof))))
|
||||
_
|
||||
...)))
|
||||
(Binding ?name ?pattern))
|
||||
(_ eof)))
|
||||
(define parse-Binding! (parse-success-or-error 'parse-Binding parse-Binding))
|
||||
|
@ -126,7 +128,7 @@
|
|||
((and dest
|
||||
(record
|
||||
'bundle
|
||||
(list (app parse-Modules (and ?modules (not (== eof)))))))
|
||||
(list (app parse-Modules (and ?modules (not (== eof)))) _ ...)))
|
||||
(Bundle ?modules))
|
||||
(_ eof)))
|
||||
(define parse-Bundle! (parse-success-or-error 'parse-Bundle parse-Bundle))
|
||||
|
@ -198,28 +200,34 @@
|
|||
'rec
|
||||
(list
|
||||
(app parse-NamedPattern (and ?label (not (== eof))))
|
||||
(app parse-NamedPattern (and ?fields (not (== eof)))))))
|
||||
(app parse-NamedPattern (and ?fields (not (== eof))))
|
||||
_
|
||||
...)))
|
||||
(CompoundPattern-rec ?label ?fields))
|
||||
((and dest
|
||||
(record
|
||||
'tuple
|
||||
(list
|
||||
(list
|
||||
(app parse-NamedPattern (and ?patterns (not (== eof))))
|
||||
...))))
|
||||
(list (app parse-NamedPattern (and ?patterns (not (== eof)))) ...)
|
||||
_
|
||||
...)))
|
||||
(CompoundPattern-tuple ?patterns))
|
||||
((and dest
|
||||
(record
|
||||
'tuplePrefix
|
||||
(list
|
||||
(list (app parse-NamedPattern (and ?fixed (not (== eof)))) ...)
|
||||
(app parse-NamedSimplePattern (and ?variable (not (== eof)))))))
|
||||
(app parse-NamedSimplePattern (and ?variable (not (== eof))))
|
||||
_
|
||||
...)))
|
||||
(CompoundPattern-tuplePrefix ?fixed ?variable))
|
||||
((and dest
|
||||
(record
|
||||
'dict
|
||||
(list
|
||||
(app parse-DictionaryEntries (and ?entries (not (== eof)))))))
|
||||
(app parse-DictionaryEntries (and ?entries (not (== eof))))
|
||||
_
|
||||
...)))
|
||||
(CompoundPattern-dict ?entries))
|
||||
(_ eof)))
|
||||
(define parse-CompoundPattern!
|
||||
|
@ -283,7 +291,9 @@
|
|||
(app parse-NamedAlternative (and ?pattern1 (not (== eof))))
|
||||
(list
|
||||
(app parse-NamedAlternative (and ?patternN (not (== eof))))
|
||||
...)))))
|
||||
...))
|
||||
_
|
||||
...)))
|
||||
(Definition-or ?pattern0 ?pattern1 ?patternN))
|
||||
((and dest
|
||||
(record
|
||||
|
@ -294,7 +304,9 @@
|
|||
(app parse-NamedPattern (and ?pattern1 (not (== eof))))
|
||||
(list
|
||||
(app parse-NamedPattern (and ?patternN (not (== eof))))
|
||||
...)))))
|
||||
...))
|
||||
_
|
||||
...)))
|
||||
(Definition-and ?pattern0 ?pattern1 ?patternN))
|
||||
((app parse-Pattern (and dest (not (== eof)))) (Definition-Pattern dest))
|
||||
(_ eof)))
|
||||
|
@ -452,7 +464,9 @@
|
|||
((and dest
|
||||
(list
|
||||
(and ?variantLabel (? string?))
|
||||
(app parse-Pattern (and ?pattern (not (== eof))))))
|
||||
(app parse-Pattern (and ?pattern (not (== eof))))
|
||||
_
|
||||
...))
|
||||
(NamedAlternative ?variantLabel ?pattern))
|
||||
(_ eof)))
|
||||
(define parse-NamedAlternative!
|
||||
|
@ -569,7 +583,9 @@
|
|||
'ref
|
||||
(list
|
||||
(app parse-ModulePath (and ?module (not (== eof))))
|
||||
(and ?name (? symbol?)))))
|
||||
(and ?name (? symbol?))
|
||||
_
|
||||
...)))
|
||||
(Ref ?module ?name))
|
||||
(_ eof)))
|
||||
(define parse-Ref! (parse-success-or-error 'parse-Ref parse-Ref))
|
||||
|
@ -608,7 +624,9 @@
|
|||
(app parse-EmbeddedTypeName (and ?embeddedType (not (== eof)))))
|
||||
('version (app parse-Version (and ?version (not (== eof)))))
|
||||
(_ _)
|
||||
...))))
|
||||
...)
|
||||
_
|
||||
...)))
|
||||
(Schema ?definitions ?embeddedType ?version))
|
||||
(_ eof)))
|
||||
(define parse-Schema! (parse-success-or-error 'parse-Schema parse-Schema))
|
||||
|
@ -718,30 +736,41 @@
|
|||
((and dest
|
||||
(record
|
||||
'atom
|
||||
(list (app parse-AtomKind (and ?atomKind (not (== eof)))))))
|
||||
(list (app parse-AtomKind (and ?atomKind (not (== eof)))) _ ...)))
|
||||
(SimplePattern-atom ?atomKind))
|
||||
((and dest
|
||||
(record
|
||||
'embedded
|
||||
(list (app parse-SimplePattern (and ?interface (not (== eof)))))))
|
||||
(list
|
||||
(app parse-SimplePattern (and ?interface (not (== eof))))
|
||||
_
|
||||
...)))
|
||||
(SimplePattern-embedded ?interface))
|
||||
((and dest (record 'lit (list ?value))) (SimplePattern-lit ?value))
|
||||
((and dest (record 'lit (list ?value _ ...))) (SimplePattern-lit ?value))
|
||||
((and dest
|
||||
(record
|
||||
'seqof
|
||||
(list (app parse-SimplePattern (and ?pattern (not (== eof)))))))
|
||||
(list
|
||||
(app parse-SimplePattern (and ?pattern (not (== eof))))
|
||||
_
|
||||
...)))
|
||||
(SimplePattern-seqof ?pattern))
|
||||
((and dest
|
||||
(record
|
||||
'setof
|
||||
(list (app parse-SimplePattern (and ?pattern (not (== eof)))))))
|
||||
(list
|
||||
(app parse-SimplePattern (and ?pattern (not (== eof))))
|
||||
_
|
||||
...)))
|
||||
(SimplePattern-setof ?pattern))
|
||||
((and dest
|
||||
(record
|
||||
'dictof
|
||||
(list
|
||||
(app parse-SimplePattern (and ?key (not (== eof))))
|
||||
(app parse-SimplePattern (and ?value (not (== eof)))))))
|
||||
(app parse-SimplePattern (and ?value (not (== eof))))
|
||||
_
|
||||
...)))
|
||||
(SimplePattern-dictof ?key ?value))
|
||||
((app parse-Ref (and dest (not (== eof)))) (SimplePattern-Ref dest))
|
||||
(_ eof)))
|
||||
|
|
|
@ -58,7 +58,8 @@
|
|||
,(pattern->match-pattern fields-pat '_)))]
|
||||
[(CompoundPattern-tuple named-pats)
|
||||
(maybe-dest dest-pat-stx
|
||||
`(list ,@(map (lambda (p) (pattern->match-pattern p '_)) named-pats)))]
|
||||
`(list ,@(map (lambda (p) (pattern->match-pattern p '_)) named-pats)
|
||||
_ ...))]
|
||||
[(CompoundPattern-tuplePrefix fixed-named-pats variable-named-pat)
|
||||
(maybe-dest dest-pat-stx
|
||||
(if (null? fixed-named-pats)
|
||||
|
|
|
@ -117,6 +117,7 @@
|
|||
(match (peek-char in-port)
|
||||
[(or (? eof-object?) #\] #\> #\} #\)) *TRAILER-ANCHOR*]
|
||||
[_ (next)])))
|
||||
#:interpreter-annotation (lambda (line) (record 'r (list 'interpreter line)))
|
||||
#:on-hash (lambda (in-port source next parse-error* default)
|
||||
(match-lambda
|
||||
[#\{ (read-sequence 's in-port source next #\})]
|
||||
|
|
|
@ -83,7 +83,7 @@
|
|||
[#xB3 (string->symbol (bytes->string/utf-8 (next-bytes (next-varint))))]
|
||||
[#xB4 (apply (lambda (label . fields) (record label fields)) (next-items))]
|
||||
[#xB5 (next-items)]
|
||||
[#xB6 (list->set (next-items))]
|
||||
[#xB6 (build-set (next-items))]
|
||||
[#xB7 (build-dictionary (next-items))]
|
||||
[_ (return (on-fail "Invalid Preserves binary tag: ~v" lead-byte))]))
|
||||
|
||||
|
@ -112,9 +112,17 @@
|
|||
['#:end '()]
|
||||
[v (cons (wrap pos0 v) (next-items))]))
|
||||
|
||||
(define (build-set items)
|
||||
(define s (list->set items))
|
||||
(unless (= (set-count s) (length items)) (return (on-fail "Duplicate value in set")))
|
||||
s)
|
||||
|
||||
(define (build-dictionary items)
|
||||
(when (not (even? (length items))) (return (on-fail "Odd number of items in dictionary")))
|
||||
(apply hash items))
|
||||
(define h (apply hash items))
|
||||
(unless (= (hash-count h) (quotient (length items) 2))
|
||||
(return (on-fail "Duplicate key in dictionary")))
|
||||
h)
|
||||
|
||||
(let ((pos0 (pos)))
|
||||
(match (read-byte in-port)
|
||||
|
|
|
@ -70,9 +70,10 @@
|
|||
[(_ re pat) (app (lambda (v) (regexp-try-match re v)) pat)]))
|
||||
|
||||
(define ((make-preserve-text-reader #:reader-name reader-name
|
||||
#:interpreter-annotation interpreter-annotation
|
||||
#:read-annotated-value read-annotated-value0
|
||||
#:on-char on-char0
|
||||
#:on-hash on-hash0
|
||||
#:read-annotated-value read-annotated-value0)
|
||||
#:on-hash on-hash0)
|
||||
in-port source read-syntax? decode-embedded0)
|
||||
(define read-annotations? read-syntax?)
|
||||
(define decode-embedded (or decode-embedded0
|
||||
|
@ -106,6 +107,7 @@
|
|||
[#\# (match (next-char*)
|
||||
[(or #\space #\tab) (annotate-next-with (read-comment-line))]
|
||||
[(or #\newline #\return) (annotate-next-with "")]
|
||||
[#\! (annotate-next-with (interpreter-annotation (read-comment-line)))]
|
||||
[#\f (unless (delimiter-follows?) (parse-error* "Delimiter must follow #f")) #f]
|
||||
[#\t (unless (delimiter-follows?) (parse-error* "Delimiter must follow #t")) #t]
|
||||
[#\" (read-literal-binary)]
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
(make-preserve-text-reader
|
||||
#:reader-name *reader-name*
|
||||
#:read-annotated-value (lambda (in-port source next parse-error*) next)
|
||||
#:interpreter-annotation (lambda (line) `#s(interpreter ,line))
|
||||
#:on-hash (lambda (in-port source next parse-error* default)
|
||||
(match-lambda
|
||||
[#\{ (sequence-fold in-port
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
"In each test, let stripped = strip(annotatedValue),"
|
||||
" encodeBinary(·) produce canonical ordering and no annotations,"
|
||||
" looseEncodeBinary(·) produce any ordering, but with annotations,"
|
||||
" annotatedBinary(·) produce canonical ordering, but with annotations,"
|
||||
" annotatedBinary(·) produce “canonical ordering”, but with annotations,"
|
||||
" decodeBinary(·) include annotations,"
|
||||
" encodeText(·) include annotations,"
|
||||
" decodeText(·) include annotations,"
|
||||
|
@ -39,6 +39,10 @@
|
|||
}>
|
||||
"Implementations may vary in their treatment of the difference between expectations"
|
||||
"21/22 and 31/32, depending on how they wish to treat end-of-stream conditions."
|
||||
|
||||
"The idea of canonical-ordering-with-annotations is to encode, say, sets with their elements"
|
||||
"in sorted order of their canonical annotationless binary encoding, but then actually"
|
||||
"*serialized* with the annotations present."
|
||||
]>
|
||||
<TestCases {
|
||||
annotation1: <Test #x"85 B103616263 B00109" @"abc" 9>
|
||||
|
@ -62,6 +66,10 @@
|
|||
<Test #x"85 B100 85 B1066e6f726d616c B000" #
|
||||
# normal
|
||||
0>
|
||||
annotation12: @"Interpreter-specification annotations"
|
||||
<Test #"\x85\xb4\xb3\x0binterpreter\xb1\x0a/some/path\x84\xb3\x05value"
|
||||
#!/some/path
|
||||
value>
|
||||
bytes2: <Test #x"B20568656c6c6f" #"hello">
|
||||
bytes2a: <Test @"Internal whitespace is allowed, not including commas" #x"B2 05 68 65 6c 6c 6f" #"hello">
|
||||
bytes2b: @"Commas forbidden in internal whitespace" <ParseError "#x\"B2, 05, 68, 65, 6c, 6c, 6f\"">
|
||||
|
@ -88,6 +96,7 @@
|
|||
dict2: @"Missing close brace" <ParseShort "{ a: b, c: d ">
|
||||
dict2a: @"Missing close brace" <ParseShort "{">
|
||||
dict3: @"Duplicate key" <ParseError "{ a: 1, a: 2 }">
|
||||
dict3a: @"Duplicate key" <DecodeError #x"b7 b00101 b00102 b00101 b00103 84">
|
||||
dict4: @"Unexpected close brace" <ParseError "}">
|
||||
dict5: @"Missing value" <DecodeError #x"b7 b00101 b00102 b00103 84">
|
||||
dict6: @"Comma not allowed between key and colon" <ParseError "{ a,: 1, b: 2 }">
|
||||
|
@ -187,6 +196,7 @@
|
|||
set2: @"Missing close brace" <ParseShort "#{ 1 2 3 ">
|
||||
set2a: @"Missing close brace" <ParseShort "#{">
|
||||
set3: @"Duplicate value" <ParseError "#{a a}">
|
||||
set3a: @"Duplicate value" <DecodeError #x"b6 b00101 b00101 84">
|
||||
string0: <Test #x"b100" "">
|
||||
string3: <Test #x"b10568656c6c6f" "hello">
|
||||
string4: <Test #x"b1 14 616263e6b0b4e6b0b45c2f22080c0a0d0978797a" "abc\u6c34\u6C34\\/\"\b\f\n\r\txyz">
|
||||
|
@ -221,6 +231,14 @@
|
|||
symbol12: <Test #x"b3042d2d2d31" ---1>
|
||||
symbol13: <Test #x"b3042b312e78" +1.x>
|
||||
symbol14: <Test #x"b304f09d849e" |\uD834\uDD1E|>
|
||||
symbol15: @"A 130-byte symbol"
|
||||
<Test #x"b3 8201
|
||||
6161616161616161616161616161616161616161616161616161616161616161
|
||||
6161616161616161616161616161616161616161616161616161616161616161
|
||||
6161616161616161616161616161616161616161616161616161616161616161
|
||||
6161616161616161616161616161616161616161616161616161616161616161
|
||||
6161"
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>
|
||||
tag0: @"Unexpected end tag" <DecodeError #x"84">
|
||||
tag1: @"Invalid tag" <DecodeError #x"10">
|
||||
tag2: @"Invalid tag" <DecodeError #x"61b10110">
|
||||
|
|
|
@ -138,6 +138,16 @@ PrecType = "PREC" / "PREC_LEFT" / "PREC_RIGHT" / "PREC_DYNAMIC";
|
|||
ENDDOC
|
||||
)
|
||||
|
||||
(define U #<<ENDDOC
|
||||
#!/example/of/a/shebang
|
||||
{
|
||||
key: value
|
||||
# example of a comment at the end of a dictionary
|
||||
}
|
||||
# example of a comment at the end of the input file
|
||||
ENDDOC
|
||||
)
|
||||
|
||||
(parameterize ((pretty-print-columns 80)) (write-pexprs (string->pexprs P #:read-syntax? #t)) (newline))
|
||||
(parameterize ((pretty-print-columns 10)) (write-pexprs (string->pexprs P #:read-syntax? #t)) (newline))
|
||||
|
||||
|
@ -149,3 +159,5 @@ ENDDOC
|
|||
(parameterize ((pretty-print-columns 40)) (write-pexprs (string->pexprs S #:read-syntax? #t)) (newline))
|
||||
|
||||
(parameterize ((pretty-print-columns 40)) (write-pexprs (string->pexprs T #:read-syntax? #t)) (newline))
|
||||
|
||||
(parameterize ((pretty-print-columns 80)) (write-pexprs (string->pexprs U #:read-syntax? #t)) (newline))
|
||||
|
|
|
@ -197,7 +197,7 @@ a binary-syntax document; otherwise, it should be interpreted as text.
|
|||
86 - Embedded
|
||||
87 - Double
|
||||
|
||||
B0 - Integer
|
||||
B0 - SignedInteger
|
||||
B1 - String
|
||||
B2 - ByteString
|
||||
B3 - Symbol
|
||||
|
|
|
@ -3,7 +3,7 @@ title: "P-expressions"
|
|||
---
|
||||
|
||||
Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||
February 2024. Version 0.3.1.
|
||||
May 2024. Version 0.3.2.
|
||||
|
||||
[text syntax]: preserves-text.html
|
||||
|
||||
|
@ -58,7 +58,7 @@ in that uses of `Value` are replaced with `SimpleExpr`.
|
|||
|
||||
Embedded = "#:" SimpleExpr
|
||||
Annotated = Annotation SimpleExpr
|
||||
Annotation = "@" SimpleExpr / "#" [(%x20 / %x09) linecomment] (CR / LF)
|
||||
Annotation = "@" SimpleExpr / "#" [(%x20 / %x09/ %x21) linecomment] (CR / LF)
|
||||
linecomment = *<any unicode scalar value except CR or LF>
|
||||
|
||||
P-expression special punctuation marks are comma, semicolon, and
|
||||
|
@ -223,12 +223,14 @@ text-syntax encodings.
|
|||
### Whole `Document`s
|
||||
|
||||
```preserves
|
||||
⌜{
|
||||
⌜#!/example/of/a/shebang
|
||||
{
|
||||
key: value
|
||||
# example of a comment at the end of a dictionary
|
||||
}
|
||||
# example of a comment at the end of the input file⌝
|
||||
= [ <b
|
||||
= @<r interpreter "/example/of/a/shebang">
|
||||
[ <b
|
||||
key <p |:|> value
|
||||
@"example of a comment at the end of a dictionary" <a>
|
||||
>
|
||||
|
|
|
@ -4,7 +4,7 @@ title: "Preserves Schema"
|
|||
---
|
||||
|
||||
Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||
December 2023. Version 0.3.5.
|
||||
April 2024. Version 0.4.
|
||||
|
||||
[abnf]: https://tools.ietf.org/html/rfc7405
|
||||
[identifierlike]: #sufficiently-identifierlike-values
|
||||
|
@ -198,7 +198,15 @@ The right-hand-side of a definition may supply two or more *alternatives*.
|
|||
Alternatives are separated by any number of slashes `/`, and leading or
|
||||
trailing slashes are ignored. When parsing, the alternatives are tried in
|
||||
order; the result of the first successful alternative is the result of the
|
||||
entire parse.
|
||||
entire parse.[^extensibility-and-alternation]
|
||||
|
||||
[^extensibility-and-alternation]: This ordered choice becomes important
|
||||
when combined with the extensibility of e.g. record patterns: A pattern
|
||||
`<a @b int> / <a @b int @c int>` will always match the left branch
|
||||
because compound patterns match *prefixes* of records and tuples. A
|
||||
better way to write it would be `<a @b int @c int> / <a @b int>`, which
|
||||
tries the at-least-two-fields branch before falling back to the
|
||||
at-least-one-field branch.
|
||||
|
||||
**Host-language types.** The type corresponding to an `OrPattern` is an
|
||||
algebraic sum type, a union type, a variant type, or a concrete subclass
|
||||
|
@ -415,6 +423,18 @@ entry.
|
|||
|
||||
DictionaryPattern = "{" *(value ":" NamedSimplePattern) "}"
|
||||
|
||||
**Extensibility.** Each apparently fixed-size compound pattern over
|
||||
records, tuples or dictionaries actually only places a lower bound on the
|
||||
size of matching data. These patterns thus allow for extensibility by
|
||||
ignoring additional fields, elements, or dictionary entries. For example,
|
||||
the pattern `<a @value int>` will match not only `<a 123>` but also `<a 123
|
||||
"hello">`, while rejecting `<a>` or `<a [x y z]>`. Similarly, `{a: int, b:
|
||||
int}` matches `{a: 123, b: 234, c: [x y z]}` as well as `{a: 123, b: 234}`.
|
||||
Each compound pattern places constraints only on the *mentioned* elements
|
||||
of a datum, namely the leftmost fields of a record, the leftmost elements
|
||||
of a tuple, and the mentioned keys of a dictionary. Unmentioned elements
|
||||
are free to be present or absent.
|
||||
|
||||
### Identifiers and Bindings: NamedPattern and NamedSimplePattern
|
||||
|
||||
Compound patterns specifications contain `NamedPattern`s or
|
||||
|
|
|
@ -294,6 +294,40 @@ the end of the line is included in the string annotating the `Value`.
|
|||
Comments that are just hash `#` followed immediately by newline yield an
|
||||
empty-string annotation.
|
||||
|
||||
**Interpreter specification lines.** Unix systems specially interpret
|
||||
`#!` at the beginning of a file. For convenient use of Preserves syntax
|
||||
in Unix scripts, we define an interpretation for `#!` lines.
|
||||
|
||||
Annotation =/ "#!" linecomment (CR / LF)
|
||||
|
||||
Such annotations are read as a record with label `interpreter` and with
|
||||
a single string field containing the text following the `!` and
|
||||
preceding the end of the line.[^printing-interpreter-specifications]
|
||||
[^multiple-interpreter-specifications]
|
||||
|
||||
[^printing-interpreter-specifications]: We encourage implementations
|
||||
to *print* annotations of the form `<interpreter` *string*`>` using
|
||||
the special `#!` syntax, as well, so long as the string does not
|
||||
contain a carriage return or line feed character.
|
||||
|
||||
[^multiple-interpreter-specifications]: Annotations written with `#!`
|
||||
are otherwise ordinary. In particular, *multiple* such lines are
|
||||
nothing special. For example,
|
||||
|
||||
```
|
||||
#!/one
|
||||
#!/two
|
||||
# three
|
||||
#!/four
|
||||
five
|
||||
```
|
||||
|
||||
reads as
|
||||
|
||||
```
|
||||
@<interpreter "/one"> @<interpreter "/two"> @"three" @<interpreter "/four"> five
|
||||
```
|
||||
|
||||
**Equivalence.** Annotations appear within syntax denoting a `Value`;
|
||||
however, the annotations are not part of the denoted value. They are
|
||||
only part of the syntax. Annotations do not play a part in
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
;; Add code like the following to your .emacs to install:
|
||||
;; (autoload 'preserves-mode "~/src/preserves/preserves.el" nil t)
|
||||
;; (add-to-list 'auto-mode-alist '("\\.px\\'" . preserves-mode))
|
||||
;; (add-to-list 'auto-mode-alist '("\\.pr\\'" . preserves-mode))
|
||||
;; (add-to-list 'auto-mode-alist '("\\.prs\\'" . preserves-mode))
|
||||
|
||||
|
|
|
@ -215,7 +215,7 @@ sequences use [the Preserves binary encoding](preserves-binary.html).
|
|||
The total ordering specified [above](#total-order) means that the following statements are true:
|
||||
|
||||
- `"bzz"` < `"c"` < `"caa"` < `#:"a"`
|
||||
- `#t` < `3.0f` < `3.0` < `3` < `"3"` < `|3|` < `[]` < `#:#t`
|
||||
- `#t` < `3.0` < `3` < `"3"` < `|3|` < `[]` < `#:#t`
|
||||
- `[#f]` < `[foo]`, because `Boolean` appears before `Symbol` in the kind ordering
|
||||
- `[x]` < `[x y]`, because there is no element remaining to compare against `y`
|
||||
- `[a b]` < `[x]`, because `a` is smaller than `x`
|
||||
|
@ -240,7 +240,6 @@ The total ordering specified [above](#total-order) means that the following stat
|
|||
| `0` | B0 00 |
|
||||
| `1` | B0 01 01 |
|
||||
| `255` | B0 02 00 FF |
|
||||
| `1.0f` | 87 04 3F 80 00 00 |
|
||||
| `1.0` | 87 08 3F F0 00 00 00 00 00 00 |
|
||||
| `-1.202e300` | 87 08 FE 3C B7 B7 59 BF 04 26 |
|
||||
| `#xd"fff0000000000000"`, negative `Double` infinity | 87 08 FF F0 00 00 00 00 00 00 |
|
||||
|
@ -431,7 +430,7 @@ from each that is missing from the other. If the values are incompatible, they h
|
|||
|
||||
**Examples.**
|
||||
|
||||
- `merge [1, [2], 3] [1, [2, 99], 3, 4, 5] = merge [1, [2, 99], 3, 4, 5]`
|
||||
- `merge [1, [2], 3] [1, [2, 99], 3, 4, 5] = [1, [2, 99], 3, 4, 5]`
|
||||
- `merge [1, 2, 3] [1, 5, 3] = ⊥`
|
||||
- `merge #{a, b, c} #{a, b, c} = ⊥`
|
||||
- `merge {a: 1, b: [2]} {b: [2, 99] c: 3} = {a: 1, b: [2, 99], c: 3}`
|
||||
|
|
|
@ -0,0 +1,498 @@
|
|||
|
||||
<!doctype html>
|
||||
<html lang="en" class="no-js">
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="icon" href="/python/latest/assets/images/favicon.png">
|
||||
<meta name="generator" content="mkdocs-1.5.3, mkdocs-material-9.5.7">
|
||||
|
||||
|
||||
|
||||
<title>Python Preserves</title>
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="/python/latest/assets/stylesheets/main.f2e4d321.min.css">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
|
||||
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="/python/latest/assets/_mkdocstrings.css">
|
||||
|
||||
<script>__md_scope=new URL("/python/latest/",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
|
||||
<body dir="ltr">
|
||||
|
||||
|
||||
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
|
||||
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
|
||||
<label class="md-overlay" for="__drawer"></label>
|
||||
<div data-md-component="skip">
|
||||
|
||||
</div>
|
||||
<div data-md-component="announce">
|
||||
|
||||
</div>
|
||||
|
||||
<div data-md-color-scheme="default" data-md-component="outdated" hidden>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<header class="md-header md-header--shadow" data-md-component="header">
|
||||
<nav class="md-header__inner md-grid" aria-label="Header">
|
||||
<a href="/python/latest/." title="Python Preserves" class="md-header__button md-logo" aria-label="Python Preserves" data-md-component="logo">
|
||||
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54Z"/></svg>
|
||||
|
||||
</a>
|
||||
<label class="md-header__button md-icon" for="__drawer">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2Z"/></svg>
|
||||
</label>
|
||||
<div class="md-header__title" data-md-component="header-title">
|
||||
<div class="md-header__ellipsis">
|
||||
<div class="md-header__topic">
|
||||
<span class="md-ellipsis">
|
||||
Python Preserves
|
||||
</span>
|
||||
</div>
|
||||
<div class="md-header__topic" data-md-component="header-topic">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>var media,input,key,value,palette=__md_get("__palette");if(palette&&palette.color){"(prefers-color-scheme)"===palette.color.media&&(media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']"),palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent"));for([key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
|
||||
|
||||
|
||||
|
||||
<label class="md-header__button md-icon" for="__search">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
|
||||
</label>
|
||||
<div class="md-search" data-md-component="search" role="dialog">
|
||||
<label class="md-search__overlay" for="__search"></label>
|
||||
<div class="md-search__inner" role="search">
|
||||
<form class="md-search__form" name="search">
|
||||
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
|
||||
<label class="md-search__icon md-icon" for="__search">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
|
||||
</label>
|
||||
<nav class="md-search__options" aria-label="Search">
|
||||
|
||||
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z"/></svg>
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
</form>
|
||||
<div class="md-search__output">
|
||||
<div class="md-search__scrollwrap" data-md-scrollfix>
|
||||
<div class="md-search-result" data-md-component="search-result">
|
||||
<div class="md-search-result__meta">
|
||||
Initializing search
|
||||
</div>
|
||||
<ol class="md-search-result__list" role="presentation"></ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="md-header__source">
|
||||
<a href="https://gitlab.com/preserves/preserves" title="Go to repository" class="md-source" data-md-component="source">
|
||||
<div class="md-source__icon md-icon">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
|
||||
</div>
|
||||
<div class="md-source__repository">
|
||||
GitLab
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
|
||||
</header>
|
||||
|
||||
<div class="md-container" data-md-component="container">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<main class="md-main" data-md-component="main">
|
||||
<div class="md-main__inner md-grid">
|
||||
|
||||
|
||||
|
||||
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
|
||||
<div class="md-sidebar__scrollwrap">
|
||||
<div class="md-sidebar__inner">
|
||||
|
||||
|
||||
|
||||
|
||||
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
|
||||
<label class="md-nav__title" for="__drawer">
|
||||
<a href="/python/latest/." title="Python Preserves" class="md-nav__button md-logo" aria-label="Python Preserves" data-md-component="logo">
|
||||
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54Z"/></svg>
|
||||
|
||||
</a>
|
||||
Python Preserves
|
||||
</label>
|
||||
|
||||
<div class="md-nav__source">
|
||||
<a href="https://gitlab.com/preserves/preserves" title="Go to repository" class="md-source" data-md-component="source">
|
||||
<div class="md-source__icon md-icon">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
|
||||
</div>
|
||||
<div class="md-source__repository">
|
||||
GitLab
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul class="md-nav__list" data-md-scrollfix>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="/python/latest/." class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Overview
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="/python/latest/api/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
The top-level preserves package
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="/python/latest/binary/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Machine-oriented binary syntax
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="/python/latest/compare/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Comparing Values
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="/python/latest/error/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Codec errors
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="/python/latest/fold/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Traversing values
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="/python/latest/merge/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Merging values
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="/python/latest/path/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Preserves Path
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="/python/latest/schema/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Preserves Schema
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="/python/latest/text/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Human-readable text syntax
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="/python/latest/values/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Representations of Values
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
|
||||
<div class="md-sidebar__scrollwrap">
|
||||
<div class="md-sidebar__inner">
|
||||
|
||||
|
||||
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
|
||||
|
||||
|
||||
|
||||
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="md-content" data-md-component="content">
|
||||
<article class="md-content__inner md-typeset">
|
||||
|
||||
<h1>404 - Not found</h1>
|
||||
|
||||
</article>
|
||||
</div>
|
||||
|
||||
|
||||
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
<footer class="md-footer">
|
||||
|
||||
<div class="md-footer-meta md-typeset">
|
||||
<div class="md-footer-meta__inner md-grid">
|
||||
<div class="md-copyright">
|
||||
|
||||
|
||||
Made with
|
||||
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
|
||||
Material for MkDocs
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
<div class="md-dialog" data-md-component="dialog">
|
||||
<div class="md-dialog__inner md-typeset"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<script id="__config" type="application/json">{"base": "/python/latest/", "features": [], "search": "/python/latest/assets/javascripts/workers/search.b8dbb3d2.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": {"provider": "mike"}}</script>
|
||||
|
||||
|
||||
<script src="/python/latest/assets/javascripts/bundle.caa56a14.min.js"></script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,801 @@
|
|||
|
||||
<!doctype html>
|
||||
<html lang="en" class="no-js">
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
|
||||
|
||||
|
||||
<link rel="canonical" href="https://preserves.dev/python/latest/api/">
|
||||
|
||||
|
||||
<link rel="prev" href="..">
|
||||
|
||||
|
||||
<link rel="next" href="../binary/">
|
||||
|
||||
|
||||
<link rel="icon" href="../assets/images/favicon.png">
|
||||
<meta name="generator" content="mkdocs-1.5.3, mkdocs-material-9.5.7">
|
||||
|
||||
|
||||
|
||||
<title>The top-level preserves package - Python Preserves</title>
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../assets/stylesheets/main.f2e4d321.min.css">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
|
||||
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../assets/_mkdocstrings.css">
|
||||
|
||||
<script>__md_scope=new URL("..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
|
||||
<body dir="ltr">
|
||||
|
||||
|
||||
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
|
||||
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
|
||||
<label class="md-overlay" for="__drawer"></label>
|
||||
<div data-md-component="skip">
|
||||
|
||||
|
||||
<a href="#the-top-level-preserves-package" class="md-skip">
|
||||
Skip to content
|
||||
</a>
|
||||
|
||||
</div>
|
||||
<div data-md-component="announce">
|
||||
|
||||
</div>
|
||||
|
||||
<div data-md-color-scheme="default" data-md-component="outdated" hidden>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<header class="md-header md-header--shadow" data-md-component="header">
|
||||
<nav class="md-header__inner md-grid" aria-label="Header">
|
||||
<a href=".." title="Python Preserves" class="md-header__button md-logo" aria-label="Python Preserves" data-md-component="logo">
|
||||
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54Z"/></svg>
|
||||
|
||||
</a>
|
||||
<label class="md-header__button md-icon" for="__drawer">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2Z"/></svg>
|
||||
</label>
|
||||
<div class="md-header__title" data-md-component="header-title">
|
||||
<div class="md-header__ellipsis">
|
||||
<div class="md-header__topic">
|
||||
<span class="md-ellipsis">
|
||||
Python Preserves
|
||||
</span>
|
||||
</div>
|
||||
<div class="md-header__topic" data-md-component="header-topic">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
The top-level preserves package
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>var media,input,key,value,palette=__md_get("__palette");if(palette&&palette.color){"(prefers-color-scheme)"===palette.color.media&&(media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']"),palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent"));for([key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
|
||||
|
||||
|
||||
|
||||
<label class="md-header__button md-icon" for="__search">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
|
||||
</label>
|
||||
<div class="md-search" data-md-component="search" role="dialog">
|
||||
<label class="md-search__overlay" for="__search"></label>
|
||||
<div class="md-search__inner" role="search">
|
||||
<form class="md-search__form" name="search">
|
||||
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
|
||||
<label class="md-search__icon md-icon" for="__search">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
|
||||
</label>
|
||||
<nav class="md-search__options" aria-label="Search">
|
||||
|
||||
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z"/></svg>
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
</form>
|
||||
<div class="md-search__output">
|
||||
<div class="md-search__scrollwrap" data-md-scrollfix>
|
||||
<div class="md-search-result" data-md-component="search-result">
|
||||
<div class="md-search-result__meta">
|
||||
Initializing search
|
||||
</div>
|
||||
<ol class="md-search-result__list" role="presentation"></ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="md-header__source">
|
||||
<a href="https://gitlab.com/preserves/preserves" title="Go to repository" class="md-source" data-md-component="source">
|
||||
<div class="md-source__icon md-icon">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
|
||||
</div>
|
||||
<div class="md-source__repository">
|
||||
GitLab
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
|
||||
</header>
|
||||
|
||||
<div class="md-container" data-md-component="container">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<main class="md-main" data-md-component="main">
|
||||
<div class="md-main__inner md-grid">
|
||||
|
||||
|
||||
|
||||
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
|
||||
<div class="md-sidebar__scrollwrap">
|
||||
<div class="md-sidebar__inner">
|
||||
|
||||
|
||||
|
||||
|
||||
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
|
||||
<label class="md-nav__title" for="__drawer">
|
||||
<a href=".." title="Python Preserves" class="md-nav__button md-logo" aria-label="Python Preserves" data-md-component="logo">
|
||||
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54Z"/></svg>
|
||||
|
||||
</a>
|
||||
Python Preserves
|
||||
</label>
|
||||
|
||||
<div class="md-nav__source">
|
||||
<a href="https://gitlab.com/preserves/preserves" title="Go to repository" class="md-source" data-md-component="source">
|
||||
<div class="md-source__icon md-icon">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
|
||||
</div>
|
||||
<div class="md-source__repository">
|
||||
GitLab
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul class="md-nav__list" data-md-scrollfix>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href=".." class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Overview
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item md-nav__item--active">
|
||||
|
||||
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<label class="md-nav__link md-nav__link--active" for="__toc">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
The top-level preserves package
|
||||
</span>
|
||||
|
||||
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
</label>
|
||||
|
||||
<a href="./" class="md-nav__link md-nav__link--active">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
The top-level preserves package
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<label class="md-nav__title" for="__toc">
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
Table of contents
|
||||
</label>
|
||||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#preserves" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
preserves
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#preserves.dumps" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
dumps
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#preserves.loads" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
loads
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../binary/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Machine-oriented binary syntax
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../compare/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Comparing Values
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../error/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Codec errors
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../fold/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Traversing values
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../merge/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Merging values
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../path/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Preserves Path
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../schema/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Preserves Schema
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../text/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Human-readable text syntax
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../values/" class="md-nav__link">
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
Representations of Values
|
||||
</span>
|
||||
|
||||
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
|
||||
<div class="md-sidebar__scrollwrap">
|
||||
<div class="md-sidebar__inner">
|
||||
|
||||
|
||||
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<label class="md-nav__title" for="__toc">
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
Table of contents
|
||||
</label>
|
||||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#preserves" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
preserves
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#preserves.dumps" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
dumps
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#preserves.loads" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
loads
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="md-content" data-md-component="content">
|
||||
<article class="md-content__inner md-typeset">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h1 id="the-top-level-preserves-package">The top-level preserves package</h1>
|
||||
|
||||
|
||||
<div class="doc doc-object doc-module">
|
||||
|
||||
|
||||
|
||||
<a id="preserves"></a>
|
||||
<div class="doc doc-contents first">
|
||||
|
||||
<div class="highlight"><pre><span></span><code>import preserves
|
||||
</code></pre></div>
|
||||
<p>The main package re-exports a subset of the exports of its constituent modules:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>From <a class="autorefs autorefs-internal" href="../values/#preserves.values">preserves.values</a>:</p>
|
||||
<ul>
|
||||
<li><a class="autorefs autorefs-internal" href="../values/#preserves.values.Annotated">Annotated</a></li>
|
||||
<li><a class="autorefs autorefs-internal" href="../values/#preserves.values.Embedded">Embedded</a></li>
|
||||
<li><a class="autorefs autorefs-internal" href="../values/#preserves.values.ImmutableDict">ImmutableDict</a></li>
|
||||
<li><a class="autorefs autorefs-internal" href="../values/#preserves.values.Record">Record</a></li>
|
||||
<li><a class="autorefs autorefs-internal" href="../values/#preserves.values.Symbol">Symbol</a></li>
|
||||
<li><a class="autorefs autorefs-internal" href="../values/#preserves.values.annotate">annotate</a></li>
|
||||
<li><a class="autorefs autorefs-internal" href="../values/#preserves.values.is_annotated">is_annotated</a></li>
|
||||
<li><a class="autorefs autorefs-internal" href="../values/#preserves.values.preserve">preserve</a></li>
|
||||
<li><a class="autorefs autorefs-internal" href="../values/#preserves.values.strip_annotations">strip_annotations</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p>From <a class="autorefs autorefs-internal" href="../error/#preserves.error">preserves.error</a>:</p>
|
||||
<ul>
|
||||
<li><a class="autorefs autorefs-internal" href="../error/#preserves.error.DecodeError">DecodeError</a></li>
|
||||
<li><a class="autorefs autorefs-internal" href="../error/#preserves.error.EncodeError">EncodeError</a></li>
|
||||
<li><a class="autorefs autorefs-internal" href="../error/#preserves.error.ShortPacket">ShortPacket</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p>From <a class="autorefs autorefs-internal" href="../binary/#preserves.binary">preserves.binary</a>:</p>
|
||||
<ul>
|
||||
<li><a class="autorefs autorefs-internal" href="../binary/#preserves.binary.Decoder">Decoder</a></li>
|
||||
<li><a class="autorefs autorefs-internal" href="../binary/#preserves.binary.Encoder">Encoder</a></li>
|
||||
<li><a class="autorefs autorefs-internal" href="../binary/#preserves.binary.canonicalize">canonicalize</a></li>
|
||||
<li><a class="autorefs autorefs-internal" href="../binary/#preserves.binary.decode">decode</a></li>
|
||||
<li><a class="autorefs autorefs-internal" href="../binary/#preserves.binary.decode_with_annotations">decode_with_annotations</a></li>
|
||||
<li><a class="autorefs autorefs-internal" href="../binary/#preserves.binary.encode">encode</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p>From <a class="autorefs autorefs-internal" href="../text/#preserves.text">preserves.text</a>:</p>
|
||||
<ul>
|
||||
<li><a class="autorefs autorefs-internal" href="../text/#preserves.text.Formatter">Formatter</a></li>
|
||||
<li><a class="autorefs autorefs-internal" href="../text/#preserves.text.Parser">Parser</a></li>
|
||||
<li><a class="autorefs autorefs-internal" href="../text/#preserves.text.parse">parse</a></li>
|
||||
<li><a class="autorefs autorefs-internal" href="../text/#preserves.text.parse_with_annotations">parse_with_annotations</a></li>
|
||||
<li><a class="autorefs autorefs-internal" href="../text/#preserves.text.stringify">stringify</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p>From <a class="autorefs autorefs-internal" href="../compare/#preserves.compare">preserves.compare</a>:</p>
|
||||
<ul>
|
||||
<li><a class="autorefs autorefs-internal" href="../compare/#preserves.compare.cmp">cmp</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p>From <a class="autorefs autorefs-internal" href="../merge/#preserves.merge">preserves.merge</a>:</p>
|
||||
<ul>
|
||||
<li><a class="autorefs autorefs-internal" href="../merge/#preserves.merge.merge">merge</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>It also exports the <a class="autorefs autorefs-internal" href="../compare/#preserves.compare">compare</a> and <a class="autorefs autorefs-internal" href="../fold/#preserves.fold">fold</a> modules themselves,
|
||||
permitting patterns like</p>
|
||||
<div class="highlight"><pre><span></span><code><span class="o">>>></span> <span class="kn">from</span> <span class="nn">preserves</span> <span class="kn">import</span> <span class="o">*</span>
|
||||
<span class="o">>>></span> <span class="n">compare</span><span class="o">.</span><span class="n">cmp</span><span class="p">(</span><span class="mi">123</span><span class="p">,</span> <span class="mi">234</span><span class="p">)</span>
|
||||
<span class="o">-</span><span class="mi">1</span>
|
||||
</code></pre></div>
|
||||
<p>Finally, it provides a few utility aliases for common tasks:</p>
|
||||
|
||||
|
||||
|
||||
<div class="doc doc-children">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="doc doc-object doc-attribute">
|
||||
|
||||
|
||||
|
||||
<h2 id="preserves.dumps" class="doc doc-heading">
|
||||
<code class="highlight language-python"><span class="n">dumps</span> <span class="o">=</span> <span class="n">stringify</span></code>
|
||||
|
||||
<span class="doc doc-labels">
|
||||
<small class="doc doc-label doc-label-module-attribute"><code>module-attribute</code></small>
|
||||
</span>
|
||||
|
||||
</h2>
|
||||
|
||||
|
||||
<div class="doc doc-contents ">
|
||||
|
||||
<p>This alias for <code>stringify</code> provides a familiar pythonesque name for converting a Preserves <code>Value</code> to a string.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="doc doc-object doc-attribute">
|
||||
|
||||
|
||||
|
||||
<h2 id="preserves.loads" class="doc doc-heading">
|
||||
<code class="highlight language-python"><span class="n">loads</span> <span class="o">=</span> <span class="n">parse</span></code>
|
||||
|
||||
<span class="doc doc-labels">
|
||||
<small class="doc doc-label doc-label-module-attribute"><code>module-attribute</code></small>
|
||||
</span>
|
||||
|
||||
</h2>
|
||||
|
||||
|
||||
<div class="doc doc-contents ">
|
||||
|
||||
<p>This alias for <code>parse</code> provides a familiar pythonesque name for converting a string to a Preserves <code>Value</code>.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<aside class="md-source-file">
|
||||
|
||||
|
||||
<span class="md-source-file__fact">
|
||||
<span class="md-icon" title="Last update">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21 13.1c-.1 0-.3.1-.4.2l-1 1 2.1 2.1 1-1c.2-.2.2-.6 0-.8l-1.3-1.3c-.1-.1-.2-.2-.4-.2m-1.9 1.8-6.1 6V23h2.1l6.1-6.1-2.1-2M12.5 7v5.2l4 2.4-1 1L11 13V7h1.5M11 21.9c-5.1-.5-9-4.8-9-9.9C2 6.5 6.5 2 12 2c5.3 0 9.6 4.1 10 9.3-.3-.1-.6-.2-1-.2s-.7.1-1 .2C19.6 7.2 16.2 4 12 4c-4.4 0-8 3.6-8 8 0 4.1 3.1 7.5 7.1 7.9l-.1.2v1.8Z"/></svg>
|
||||
</span>
|
||||
<span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-date">March 16, 2023</span>
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
|
||||
<span class="md-source-file__fact">
|
||||
<span class="md-icon" title="Created">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M14.47 15.08 11 13V7h1.5v5.25l3.08 1.83c-.41.28-.79.62-1.11 1m-1.39 4.84c-.36.05-.71.08-1.08.08-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8c0 .37-.03.72-.08 1.08.69.1 1.33.32 1.92.64.1-.56.16-1.13.16-1.72 0-5.5-4.5-10-10-10S2 6.5 2 12s4.47 10 10 10c.59 0 1.16-.06 1.72-.16-.32-.59-.54-1.23-.64-1.92M18 15v3h-3v2h3v3h2v-3h3v-2h-3v-3h-2Z"/></svg>
|
||||
</span>
|
||||
<span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-date">March 16, 2023</span>
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
|
||||
</aside>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
</div>
|
||||
|
||||
|
||||
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
<footer class="md-footer">
|
||||
|
||||
<div class="md-footer-meta md-typeset">
|
||||
<div class="md-footer-meta__inner md-grid">
|
||||
<div class="md-copyright">
|
||||
|
||||
|
||||
Made with
|
||||
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
|
||||
Material for MkDocs
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
<div class="md-dialog" data-md-component="dialog">
|
||||
<div class="md-dialog__inner md-typeset"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<script id="__config" type="application/json">{"base": "..", "features": [], "search": "../assets/javascripts/workers/search.b8dbb3d2.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": {"provider": "mike"}}</script>
|
||||
|
||||
|
||||
<script src="../assets/javascripts/bundle.caa56a14.min.js"></script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,109 @@
|
|||
|
||||
/* Avoid breaking parameter names, etc. in table cells. */
|
||||
.doc-contents td code {
|
||||
word-break: normal !important;
|
||||
}
|
||||
|
||||
/* No line break before first paragraph of descriptions. */
|
||||
.doc-md-description,
|
||||
.doc-md-description>p:first-child {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* Max width for docstring sections tables. */
|
||||
.doc .md-typeset__table,
|
||||
.doc .md-typeset__table table {
|
||||
display: table !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.doc .md-typeset__table tr {
|
||||
display: table-row;
|
||||
}
|
||||
|
||||
/* Defaults in Spacy table style. */
|
||||
.doc-param-default {
|
||||
float: right;
|
||||
}
|
||||
|
||||
/* Symbols in Navigation and ToC. */
|
||||
:root,
|
||||
[data-md-color-scheme="default"] {
|
||||
--doc-symbol-attribute-fg-color: #953800;
|
||||
--doc-symbol-function-fg-color: #8250df;
|
||||
--doc-symbol-method-fg-color: #8250df;
|
||||
--doc-symbol-class-fg-color: #0550ae;
|
||||
--doc-symbol-module-fg-color: #5cad0f;
|
||||
|
||||
--doc-symbol-attribute-bg-color: #9538001a;
|
||||
--doc-symbol-function-bg-color: #8250df1a;
|
||||
--doc-symbol-method-bg-color: #8250df1a;
|
||||
--doc-symbol-class-bg-color: #0550ae1a;
|
||||
--doc-symbol-module-bg-color: #5cad0f1a;
|
||||
}
|
||||
|
||||
[data-md-color-scheme="slate"] {
|
||||
--doc-symbol-attribute-fg-color: #ffa657;
|
||||
--doc-symbol-function-fg-color: #d2a8ff;
|
||||
--doc-symbol-method-fg-color: #d2a8ff;
|
||||
--doc-symbol-class-fg-color: #79c0ff;
|
||||
--doc-symbol-module-fg-color: #baff79;
|
||||
|
||||
--doc-symbol-attribute-bg-color: #ffa6571a;
|
||||
--doc-symbol-function-bg-color: #d2a8ff1a;
|
||||
--doc-symbol-method-bg-color: #d2a8ff1a;
|
||||
--doc-symbol-class-bg-color: #79c0ff1a;
|
||||
--doc-symbol-module-bg-color: #baff791a;
|
||||
}
|
||||
|
||||
code.doc-symbol {
|
||||
border-radius: .1rem;
|
||||
font-size: .85em;
|
||||
padding: 0 .3em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
code.doc-symbol-attribute {
|
||||
color: var(--doc-symbol-attribute-fg-color);
|
||||
background-color: var(--doc-symbol-attribute-bg-color);
|
||||
}
|
||||
|
||||
code.doc-symbol-attribute::after {
|
||||
content: "attr";
|
||||
}
|
||||
|
||||
code.doc-symbol-function {
|
||||
color: var(--doc-symbol-function-fg-color);
|
||||
background-color: var(--doc-symbol-function-bg-color);
|
||||
}
|
||||
|
||||
code.doc-symbol-function::after {
|
||||
content: "func";
|
||||
}
|
||||
|
||||
code.doc-symbol-method {
|
||||
color: var(--doc-symbol-method-fg-color);
|
||||
background-color: var(--doc-symbol-method-bg-color);
|
||||
}
|
||||
|
||||
code.doc-symbol-method::after {
|
||||
content: "meth";
|
||||
}
|
||||
|
||||
code.doc-symbol-class {
|
||||
color: var(--doc-symbol-class-fg-color);
|
||||
background-color: var(--doc-symbol-class-bg-color);
|
||||
}
|
||||
|
||||
code.doc-symbol-class::after {
|
||||
content: "class";
|
||||
}
|
||||
|
||||
code.doc-symbol-module {
|
||||
color: var(--doc-symbol-module-fg-color);
|
||||
background-color: var(--doc-symbol-module-bg-color);
|
||||
}
|
||||
|
||||
code.doc-symbol-module::after {
|
||||
content: "mod";
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue