Compare commits

...

80 Commits

Author SHA1 Message Date
Tony Garnock-Jones 685302f547 Fix table 2024-05-25 17:43:20 +02:00
Tony Garnock-Jones f83e67899e Update test suites 2024-05-25 17:18:07 +02:00
Tony Garnock-Jones f2331c0e1e Add a 130-byte symbol to the tests 2024-05-25 17:13:38 +02:00
Tony Garnock-Jones f628e7d31f Correct typo 2024-05-23 14:09:30 +02:00
Tony Garnock-Jones b767fa4eb0 Floats are no more 2024-05-23 13:50:34 +02:00
Tony Garnock-Jones 58110e7c0c Publish
- @preserves/core@0.995.206
 - @preserves/schema-cli@0.995.206
 - @preserves/schema@0.995.206
2024-05-15 10:49:46 +02:00
Tony Garnock-Jones 58ebc93eb5 Repair comment reading and trailing comments in pexprs 2024-05-15 10:49:30 +02:00
Tony Garnock-Jones f18ba9c9d4 Publish
- @preserves/core@0.995.205
 - @preserves/schema-cli@0.995.205
 - @preserves/schema@0.995.205
2024-05-15 09:36:17 +02:00
Tony Garnock-Jones 87ecdb7efe Make Annotations preserveable 2024-05-15 09:34:28 +02:00
Tony Garnock-Jones 0533840bc0 Publish
- @preserves/core@0.995.204
 - @preserves/schema-cli@0.995.204
 - @preserves/schema@0.995.204
2024-05-14 17:16:37 +02:00
Tony Garnock-Jones 77c16df89b Make ReaderState.DELIMITERS accessible 2024-05-14 17:16:06 +02:00
Tony Garnock-Jones 35e6ba2e82 Publish
- @preserves/core@0.995.203
 - @preserves/schema-cli@0.995.204
 - @preserves/schema@0.995.204
2024-05-14 12:16:21 +02:00
Tony Garnock-Jones 536e32b0e8 Repair isJsDictionary 2024-05-14 12:16:02 +02:00
Tony Garnock-Jones 9192bdea7e Publish
- @preserves/core@0.995.202
 - @preserves/schema-cli@0.995.203
 - @preserves/schema@0.995.203
2024-05-09 21:58:16 +02:00
Tony Garnock-Jones 19ac8d16c8 .px for P-expressions files 2024-05-08 12:53:16 +02:00
Tony Garnock-Jones 7f284a9d52 Remove type annotation on stringifyEmbeddedWrite to permit more flexible usage 2024-05-08 11:32:09 +02:00
Tony Garnock-Jones cadf54b927 Update pexpr tests 2024-05-08 11:21:05 +02:00
Tony Garnock-Jones a8b300e57d Better treatment of embedded conversion 2024-05-08 11:20:57 +02:00
Tony Garnock-Jones 4e5e64f0a6 Actually parse groups (!) 2024-05-08 11:20:46 +02:00
Tony Garnock-Jones c8ce125192 Use python3 explicitly in .envrc 2024-05-06 14:20:25 +02:00
Tony Garnock-Jones c9fa9c590b Error handling for asPreserves 2024-05-04 22:08:52 +02:00
Tony Garnock-Jones d568fc56ce Better treatment of embedded types in asPreserves 2024-05-04 21:37:05 +02:00
Tony Garnock-Jones 42f4672446 Pexpr.asPreserves 2024-05-04 13:12:00 +02:00
Tony Garnock-Jones 1c86d8b7c5 Positioned<I>; iterator 2024-05-04 10:28:18 +02:00
Tony Garnock-Jones 64c1090938 Convert P-expressions to preserves values 2024-05-02 21:26:48 +02:00
Tony Garnock-Jones dc61963e16 Core implementation of P-expressions for TypeScript 2024-05-02 17:05:40 +02:00
Tony Garnock-Jones a33786e469 Repair error wrt interpreter lines in pexpr text 2024-05-02 16:21:47 +02:00
Tony Garnock-Jones 23ba2e5a59 Clarify the strange idea of canonical-order-but-with-annotations 2024-04-18 11:30:52 +02:00
Tony Garnock-Jones 7b8e0ff4b6 Publish
- @preserves/core@0.995.201
 - @preserves/schema-cli@0.995.202
 - @preserves/schema@0.995.202
2024-04-12 13:14:09 +02:00
Tony Garnock-Jones 3f7819fafa Allow optional handling of non-integer numbers in fromJS 2024-04-12 13:13:42 +02:00
Tony Garnock-Jones f5d76a847b Repair types of Dictionary.from and DictionaryMap.from 2024-04-12 13:13:25 +02:00
Tony Garnock-Jones 443406a7d7 Publish
- @preserves/schema-cli@0.995.201
 - @preserves/schema@0.995.201
2024-04-04 13:43:40 +02:00
Tony Garnock-Jones 05103e9825 Update JavaScript implementation for schema spec 0.4 2024-04-04 13:43:20 +02:00
Tony Garnock-Jones 4f75d6d5a3 Bring racket schema impl into line with spec 0.4 2024-04-04 13:37:12 +02:00
Tony Garnock-Jones 07b7739d00 Python docs 2024-04-04 13:29:58 +02:00
Tony Garnock-Jones 8f3d22adf1 Bump python version 2024-04-04 13:29:11 +02:00
Tony Garnock-Jones 8222675b6b Update python implementation to schema spec 0.4 2024-04-04 13:28:27 +02:00
Tony Garnock-Jones fca4b3a22e Note on extensibility and alternation 2024-04-04 13:19:46 +02:00
Tony Garnock-Jones c5dd2d749a Reflow; improve language 2024-04-04 13:14:50 +02:00
Tony Garnock-Jones c986ca76cf Specify extensibility. 2024-04-04 13:05:07 +02:00
Tony Garnock-Jones 3e67c75427 Publish
- @preserves/core@0.995.200
 - @preserves/schema-cli@0.995.200
 - @preserves/schema@0.995.200
2024-04-03 22:38:54 +02:00
Tony Garnock-Jones 6bc159e3c6 Another small refinement 2024-03-29 12:28:23 +01:00
Tony Garnock-Jones 99d1acdec7 Accept fewer `Object`s as `JsDictionary` 2024-03-29 12:28:23 +01:00
Tony Garnock-Jones 3093b89f0d Bootstrap following JsDictionary support in schema 2024-03-29 12:28:23 +01:00
Tony Garnock-Jones 00c0de40ea Support for JsDictionary in schema 2024-03-29 12:28:23 +01:00
Tony Garnock-Jones 7657952993 asJsDictionary, asKeyedDictionary 2024-03-29 12:28:23 +01:00
Tony Garnock-Jones 9ecbd0bdd1 First re-bootstrap of schema 2024-03-29 12:28:23 +01:00
Tony Garnock-Jones 297e1630a8 First (pre-bootstrap) step to getting schema working with the new core 2024-03-29 12:28:23 +01:00
Tony Garnock-Jones 85ca0b6c0a Update schema-cli 2024-03-29 12:28:23 +01:00
Tony Garnock-Jones 7c9c410a9b Add simplifiedValue() and from() methods 2024-03-29 12:28:23 +01:00
Tony Garnock-Jones cbbc6c50c0 Great simplification by introducing DictionaryMap 2024-03-29 12:28:23 +01:00
Tony Garnock-Jones eb4f456550 Sensible default second type argument for Dictionary.from 2024-03-29 12:28:23 +01:00
Tony Garnock-Jones 4f4ff6e108 Mark Embeddable objects specially, so that plain JS objects can be used as symbol-to-value maps. 2024-03-29 12:28:23 +01:00
Tony Garnock-Jones 055a7f90e9 Include git revision info in debian package version 2024-03-29 12:26:35 +01:00
Tony Garnock-Jones b2f6149042 Python preserves packaging 2024-03-29 12:26:35 +01:00
Tony Garnock-Jones 1bd4a3cdb4 Factor out common constructor-building logic in interpreter 2024-03-27 14:47:14 +01:00
Tony Garnock-Jones dc0ddf95dd Remove absent script from watchall 2024-03-27 14:28:57 +01:00
Tony Garnock-Jones eeace57670 Repair schema interpreter keywords and variant constructor argument handling 2024-03-27 14:28:33 +01:00
Tony Garnock-Jones 0aa39da971 New test case and fixes 2024-03-27 10:57:19 +01:00
Tony Garnock-Jones f0815ce4eb Publish
- @preserves/core@0.995.101
 - @preserves/schema-cli@0.995.100
 - @preserves/schema@0.995.100
2024-03-23 11:14:02 +01:00
Tony Garnock-Jones afba8a0bff "latin1" quasi-encoding Bytes utility 2024-03-23 11:13:08 +01:00
Tony Garnock-Jones d9ec3bfb14 Publish
- @preserves/core@0.995.100
 - @preserves/schema-cli@0.995.100
 - @preserves/schema@0.995.100
2024-03-16 17:37:17 +01:00
Tony Garnock-Jones 95ac4b13df Add Embedded<T> 2024-03-12 22:47:50 +01:00
Tony Garnock-Jones 3eeee5f090 Repair Schema tests 2024-03-12 22:47:33 +01:00
Tony Garnock-Jones aeacce22fc Update schema 2024-03-12 20:52:28 +01:00
Tony Garnock-Jones 0726684ab5 Use bare embedded values. 2024-03-12 19:14:41 +01:00
Tony Garnock-Jones f74c4ebaf0 Publish
- @preserves/schema-cli@0.995.1
 - @preserves/schema@0.995.1
2024-03-08 15:41:02 +01:00
Tony Garnock-Jones 48a063539a Repair bugs in schema interpreter relating to unit-typed definitions 2024-03-08 15:40:28 +01:00
Tony Garnock-Jones db96fcc95a Python docs 2024-03-08 10:05:00 +01:00
Tony Garnock-Jones cee4a25460 Publish
- @preserves/core@0.995.0
 - @preserves/schema-cli@0.995.0
 - @preserves/schema@0.995.0
2024-03-08 10:00:59 +01:00
Tony Garnock-Jones 7948ad4260 Javascript interpreter-specification line implementation 2024-03-08 10:00:42 +01:00
Tony Garnock-Jones 3d3c79e617 Python interpreter-specification line implementation 2024-03-08 09:49:35 +01:00
Tony Garnock-Jones b925b53756 Racket interpreter-specification line implementation 2024-03-08 09:46:06 +01:00
Tony Garnock-Jones c0289e0a05 Add sample/test for interpreter specification line 2024-03-08 09:45:43 +01:00
Tony Garnock-Jones 41189f551d Update spec date 2024-03-08 09:32:44 +01:00
Tony Garnock-Jones cc8313cf25 Bump spec version to 0.995 2024-03-08 09:31:32 +01:00
Tony Garnock-Jones bfbff65bb6 Note about multiple #! lines 2024-03-07 18:40:59 +01:00
Tony Garnock-Jones 442a987523 Spec out interpreter-lines. 2024-03-07 14:18:22 +01:00
Tony Garnock-Jones f45b136ef5 Update years 2024-03-07 14:18:12 +01:00
Tony Garnock-Jones 73c6593f84 Python 0.994 docs 2024-02-05 23:01:01 +01:00
276 changed files with 70322 additions and 816 deletions

2
NOTICE
View File

@ -1,2 +1,2 @@
Preserves: an Expressive Data Language Preserves: an Expressive Data Language
Copyright 2018-2022 Tony Garnock-Jones Copyright 2018-2024 Tony Garnock-Jones

View File

@ -88,6 +88,6 @@ Tony Garnock-Jones <tonyg@leastfixedpoint.com>
The contents of this repository are made available to you under the The contents of this repository are made available to you under the
[Apache License, version 2.0](LICENSE) [Apache License, version 2.0](LICENSE)
(<http://www.apache.org/licenses/LICENSE-2.0>), and are Copyright (<http://www.apache.org/licenses/LICENSE-2.0>), and are Copyright
2018-2022 Tony Garnock-Jones. 2018-2024 Tony Garnock-Jones.
## Notes ## Notes

View File

@ -13,5 +13,5 @@ defaults:
layout: page layout: page
title: "Preserves" title: "Preserves"
version_date: "February 2024" version_date: "March 2024"
version: "0.994.0" version: "0.995.0"

View File

@ -1,5 +1,8 @@
[ [
{"version":"0.993.0","title":"0.993.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.2","title":"0.992.2","aliases":[]},
{"version":"0.992.1","title":"0.992.1","aliases":[]}, {"version":"0.992.1","title":"0.992.1","aliases":[]},
{"version":"0.992.0","title":"0.992.0","aliases":[]}, {"version":"0.992.0","title":"0.992.0","aliases":[]},

View File

@ -17,5 +17,5 @@ Trailer := (ws Annotation)*
Embedded := `#:` SimpleExpr Embedded := `#:` SimpleExpr
Annotated := Annotation SimpleExpr Annotated := Annotation SimpleExpr
Annotation := `@` SimpleExpr | `#` ((space | tab) linecomment) (cr | lf) Annotation := `@` SimpleExpr | `#` ((space | tab | `!`) linecomment) (cr | lf)
``` ```

View File

@ -20,4 +20,4 @@ The definitions of `Atom`, `ws`, and `linecomment` are as given in the Preserves
{:.postcard-grammar.textsyntax} {:.postcard-grammar.textsyntax}
| *Embedded* | := | `#:` *SimpleExpr* | *Embedded* | := | `#:` *SimpleExpr*
| *Annotated* | := | *Annotation* *SimpleExpr* | *Annotated* | := | *Annotation* *SimpleExpr*
| *Annotation* | := | `@` *SimpleExpr* &#124; `#` ((**space** &#124; **tab**) *linecomment*) (**cr** &#124; **lf**) | *Annotation* | := | `@` *SimpleExpr* &#124; `#` ((**space** &#124; **tab** &#124; `!`) *linecomment*) (**cr** &#124; **lf**)

View File

@ -11,7 +11,7 @@ commas := (ws `,`)* ws
Embedded := `#:` Value Embedded := `#:` Value
Annotated := Annotation 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 Atom := Boolean | ByteString | String | QuotedSymbol | Symbol | Number
Boolean := `#t` | `#f` Boolean := `#t` | `#f`

View File

@ -13,7 +13,7 @@
{:.postcard-grammar.textsyntax} {:.postcard-grammar.textsyntax}
| *Embedded* | := | `#:`*Value* | | *Embedded* | := | `#:`*Value* |
| *Annotated* | := | *Annotation* *Value* | | *Annotated* | := | *Annotation* *Value* |
| *Annotation* | := | `@`*Value* &#124;`#` ((**space** &#124; **tab**) *linecomment*) (**cr** &#124; **lf**) | | *Annotation* | := | `@`*Value* &#124;`#` ((**space** &#124; **tab** &#124; `!`) *linecomment*) (**cr** &#124; **lf**) |
{:.postcard-grammar.textsyntax} {:.postcard-grammar.textsyntax}
| *Atom* | := | *Boolean* &#124; *ByteString* &#124; *String* &#124; *QuotedSymbol* &#124; *Symbol* &#124; *Number* | | *Atom* | := | *Boolean* &#124; *ByteString* &#124; *String* &#124; *QuotedSymbol* &#124; *Symbol* &#124; *Number* |

View File

@ -99,6 +99,22 @@ the usual `@`-prefixed annotation notation can also be used.
#x"0C0D0E0F" #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. ## MIME-type tagged binary data.
Many internet protocols use Many internet protocols use

2
debian-packages/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/build.python/
/*.deb

10
debian-packages/Makefile Normal file
View File

@ -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.*

View File

@ -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 ..
)

View File

@ -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

6
debian-packages/python/rules Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/make -f
#export DH_VERBOSE=1
export PYBUILD_NAME=preserves
%:
dh $@ --with python3 --buildsystem=pybuild

View File

@ -1,6 +1,6 @@
{ {
"name": "@preserves/core", "name": "@preserves/core",
"version": "0.994.0", "version": "0.995.206",
"description": "Preserves data serialization format", "description": "Preserves data serialization format",
"homepage": "https://gitlab.com/preserves/preserves", "homepage": "https://gitlab.com/preserves/preserves",
"license": "Apache-2.0", "license": "Apache-2.0",

View File

@ -1,6 +1,6 @@
import { Tag } from "./constants"; import { Tag } from "./constants";
import { is, isAnnotated, IsPreservesAnnotated } from "./is"; import { is, isAnnotated, IsPreservesAnnotated } from "./is";
import type { GenericEmbedded } from "./embedded"; import type { Embeddable, GenericEmbedded } from "./embedded";
import type { Value } from "./values"; import type { Value } from "./values";
import type { Encoder, Preservable } from "./encoder"; import type { Encoder, Preservable } from "./encoder";
import type { Writer, PreserveWritable } from "./writer"; 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 annotations: Array<Value<T>>;
readonly pos: Position | null; readonly pos: Position | null;
readonly item: Value<T>; readonly item: Value<T>;
@ -67,7 +67,7 @@ export class Annotated<T = GenericEmbedded> implements Preservable<T>, PreserveW
return this; 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; return isAnnotated<T>(v) ? v : void 0;
} }
@ -109,21 +109,24 @@ export class Annotated<T = GenericEmbedded> implements Preservable<T>, PreserveW
return true; 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); 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); const v = Annotated.isAnnotated<T>(v0) ? v0 : new Annotated(v0);
anns.forEach((a) => v.annotations.push(a)); anns.forEach((a) => v.annotations.push(a));
return v; 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 : []; 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; return Annotated.isAnnotated<T>(v) ? v.pos : null;
} }

View File

@ -1,5 +1,5 @@
import { Tag } from './constants'; import { Tag } from './constants';
import { GenericEmbedded } from './embedded'; import type { Embeddable, GenericEmbedded } from './embedded';
import { Encoder, Preservable } from './encoder'; import { Encoder, Preservable } from './encoder';
import { Value } from './values'; import { Value } from './values';
import type { Writer, PreserveWritable } from './writer'; import type { Writer, PreserveWritable } from './writer';
@ -52,6 +52,18 @@ export class Bytes implements Preservable<any>, PreserveWritable<any> {
return new Bytes(Uint8Array.of(...bytes)); 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 { static fromBase64(s: string): Bytes {
return new Bytes(decodeBase64(s)); return new Bytes(decodeBase64(s));
} }
@ -136,14 +148,18 @@ export class Bytes implements Preservable<any>, PreserveWritable<any> {
return textDecoder.decode(this._view); return textDecoder.decode(this._view);
} }
__as_preserve__<T = GenericEmbedded>(): Value<T> { __as_preserve__<T extends Embeddable = GenericEmbedded>(): Value<T> {
return this; 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; return Bytes.isBytes(v) ? v : void 0;
} }
toLatin1(): string {
return String.fromCharCode.apply(null, this._view as any as number[]);
}
toBase64(): string { toBase64(): string {
return encodeBase64(this._view); return encodeBase64(this._view);
} }

View File

@ -1,12 +1,12 @@
import type { Compound, Value } from "./values"; import type { Compound, Value } from "./values";
import type { GenericEmbedded } from "./embedded"; import type { Embeddable, GenericEmbedded } from "./embedded";
import { Dictionary, Set } from "./dictionary"; 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)); 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)); return (Array.isArray(x) && !('label' in x));
} }

View File

@ -1,24 +1,25 @@
import { Annotated } from "./annotated"; import { Annotated } from "./annotated";
import { DecodeError, ShortPacket } from "./codec"; import { DecodeError, ShortPacket } from "./codec";
import { Tag } from "./constants"; import { Tag } from "./constants";
import { Set, Dictionary } from "./dictionary"; import { Set, Dictionary, DictionaryMap } from "./dictionary";
import { DoubleFloat } from "./float"; import { DoubleFloat } from "./float";
import { Record } from "./record"; import { Record } from "./record";
import { Bytes, BytesLike, underlying, hexDigit } from "./bytes"; import { Bytes, BytesLike, underlying, hexDigit } from "./bytes";
import { Value } from "./values"; import { Value } from "./values";
import { is } from "./is"; import { is } from "./is";
import { embed, GenericEmbedded, Embedded, EmbeddedTypeDecode } from "./embedded"; import { GenericEmbedded, Embeddable, EmbeddedTypeDecode } from "./embedded";
import { ReaderStateOptions } from "reader"; import { ReaderStateOptions } from "./reader";
import { stringify } from "./text";
export interface DecoderOptions { export interface DecoderOptions {
includeAnnotations?: boolean; includeAnnotations?: boolean;
} }
export interface DecoderEmbeddedOptions<T> extends DecoderOptions { export interface DecoderEmbeddedOptions<T extends Embeddable> extends DecoderOptions {
embeddedDecode?: EmbeddedTypeDecode<T>; embeddedDecode?: EmbeddedTypeDecode<T>;
} }
export interface TypedDecoder<T> { export interface TypedDecoder<T extends Embeddable> {
atEnd(): boolean; atEnd(): boolean;
mark(): any; mark(): any;
@ -26,13 +27,13 @@ export interface TypedDecoder<T> {
skip(): void; skip(): void;
next(): Value<T>; next(): Value<T>;
withEmbeddedDecode<S, R>( withEmbeddedDecode<S extends Embeddable, R>(
embeddedDecode: EmbeddedTypeDecode<S>, embeddedDecode: EmbeddedTypeDecode<S>,
body: (d: TypedDecoder<S>) => R): R; body: (d: TypedDecoder<S>) => R): R;
nextBoolean(): boolean | undefined; nextBoolean(): boolean | undefined;
nextDouble(): DoubleFloat | undefined; nextDouble(): DoubleFloat | undefined;
nextEmbedded(): Embedded<T> | undefined; nextEmbedded(): T | undefined;
nextSignedInteger(): number | bigint | undefined; nextSignedInteger(): number | bigint | undefined;
nextString(): string | undefined; nextString(): string | undefined;
nextByteString(): Bytes | undefined; nextByteString(): Bytes | undefined;
@ -46,7 +47,7 @@ export interface TypedDecoder<T> {
closeCompound(): boolean; 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>, actual: Value<T>,
expected: E): E | undefined 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; 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) { if (this.includeAnnotations) {
v.annotations.unshift(a); 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; state: DecoderState;
embeddedDecode: EmbeddedTypeDecode<T>; embeddedDecode: EmbeddedTypeDecode<T>;
@ -217,13 +218,14 @@ export class Decoder<T = never> implements TypedDecoder<T> {
return result; return result;
} }
static dictionaryFromArray<T>(vs: Value<T>[]): Dictionary<T> { static dictionaryFromArray<T extends Embeddable>(vs: Value<T>[]): Dictionary<T> {
const d = new Dictionary<T>(); const d = new DictionaryMap<T>();
if (vs.length % 2) throw new DecodeError("Missing dictionary value"); if (vs.length % 2) throw new DecodeError("Missing dictionary value");
for (let i = 0; i < vs.length; i += 2) { 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]); d.set(vs[i], vs[i+1]);
} }
return d; return d.simplifiedValue();
} }
next(): Value<T> { next(): Value<T> {
@ -237,7 +239,7 @@ export class Decoder<T = never> implements TypedDecoder<T> {
const v = this.next() as Annotated<T>; const v = this.next() as Annotated<T>;
return this.state.unshiftAnnotation(a, v); 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: case Tag.Ieee754:
switch (this.state.varint()) { switch (this.state.varint()) {
case 8: return this.state.wrap<T>(DoubleFloat.fromBytes(this.state.nextbytes(8))); 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))); return this.state.wrap<T>(Record(vs[0], vs.slice(1)));
} }
case Tag.Sequence: return this.state.wrap<T>(this.nextvalues()); 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())); case Tag.Dictionary: return this.state.wrap<T>(Decoder.dictionaryFromArray(this.nextvalues()));
default: throw new DecodeError("Unsupported Preserves tag: " + tag); default: throw new DecodeError("Unsupported Preserves tag: " + tag);
} }
@ -280,7 +289,7 @@ export class Decoder<T = never> implements TypedDecoder<T> {
this.next(); this.next();
} }
withEmbeddedDecode<S, R>( withEmbeddedDecode<S extends Embeddable, R>(
embeddedDecode: EmbeddedTypeDecode<S>, embeddedDecode: EmbeddedTypeDecode<S>,
body: (d: TypedDecoder<S>) => R): R 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) => { return this.skipAnnotations((reset) => {
switch (this.state.nextbyte()) { 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(); 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(); return new Decoder(bs, options).next();
} }
export function decodeWithAnnotations<T>(bs: BytesLike, export function decodeWithAnnotations<T extends Embeddable>(
options: DecoderEmbeddedOptions<T> = {}): Annotated<T> { bs: BytesLike,
options: DecoderEmbeddedOptions<T> = {},
): Annotated<T> {
return decode(bs, { ... options, includeAnnotations: true }) as Annotated<T>; return decode(bs, { ... options, includeAnnotations: true }) as Annotated<T>;
} }

View File

@ -1,19 +1,22 @@
import { Encoder, canonicalString } from "./encoder"; import { Encoder, canonicalString } from "./encoder";
import { Tag } from "./constants"; 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 { Value } from "./values";
import { Bytes } from './bytes'; import { Bytes } from './bytes';
import { GenericEmbedded } from "./embedded"; import { Embeddable, GenericEmbedded, isEmbedded } from "./embedded";
import type { Preservable } from "./encoder"; import type { Preservable } from "./encoder";
import type { Writer, PreserveWritable } from "./writer"; import type { Writer, PreserveWritable } from "./writer";
import { annotations, Annotated } from "./annotated"; import { annotations, Annotated } from "./annotated";
import { Float } from "./float";
import { JsDictionary } from "./jsdictionary";
import { unannotate } from "./strip";
export type DictionaryType = 'Dictionary' | 'Set'; export type DictionaryType = 'Dictionary' | 'Set';
export const DictionaryType = Symbol.for('DictionaryType'); 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> implements Preservable<T>, PreserveWritable<T>
{ {
constructor( 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> export class KeyedDictionary<T extends Embeddable = GenericEmbedded, K extends CompoundKey<T> = Value<T>, V = Value<T>>
extends EncodableDictionary<K, V, T> extends EncodableDictionary<T, K, V>
{ {
get [DictionaryType](): DictionaryType { get [DictionaryType](): DictionaryType {
return 'Dictionary'; 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: any,
): x is KeyedDictionary<K, V, T> { ): x is KeyedDictionary<T, K, V> {
return x?.[DictionaryType] === 'Dictionary'; 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); 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> { clone(): KeyedDictionary<T, K, V> {
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> {
return new KeyedDictionary(this); return new KeyedDictionary(this);
} }
get [Symbol.toStringTag]() { return 'Dictionary'; } 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> { export type Dictionary<T extends Embeddable = GenericEmbedded, V = Value<T>> =
static isDictionary<T = GenericEmbedded, V = Value<T>>(x: any): x is Dictionary<T, V> { JsDictionary<V> | KeyedDictionary<T, Value<T>, V>;
return x?.[DictionaryType] === 'Dictionary';
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; 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>, dict: Map<K, V>,
encoder: Encoder<T>, encoder: Encoder<T>,
encodeK: (k: K, encoder: Encoder<T>) => void, 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>, dict: Map<K, V>,
w: Writer<T>, w: Writer<T>,
writeK: (k: K, w: Writer<T>) => void, 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> implements Preservable<T>, PreserveWritable<T>
{ {
constructor( constructor(
@ -154,16 +328,16 @@ export class EncodableSet<V, T = GenericEmbedded> extends FlexSet<V>
} }
} }
export class KeyedSet<K extends CompoundKey<T>, T = GenericEmbedded> export class KeyedSet<T extends Embeddable = GenericEmbedded, K extends CompoundKey<T> = Value<T>>
extends EncodableSet<K, T> extends EncodableSet<T, K>
{ {
get [DictionaryType](): DictionaryType { get [DictionaryType](): DictionaryType {
return 'Set'; 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: any,
): x is KeyedSet<K, T> { ): x is KeyedSet<T, K> {
return x?.[DictionaryType] === 'Set'; return x?.[DictionaryType] === 'Set';
} }
@ -171,34 +345,36 @@ export class KeyedSet<K extends CompoundKey<T>, T = GenericEmbedded>
super(k => k, items); 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)); return new KeyedSet(_iterMap(this[Symbol.iterator](), f));
} }
filter(f: (value: K) => boolean): KeyedSet<K, T> { filter(f: (value: K) => boolean): KeyedSet<T, K> {
const result = new KeyedSet<K, T>(); const result = new KeyedSet<T, K>();
for (let k of this) if (f(k)) result.add(k); for (let k of this) if (f(k)) result.add(k);
return result; return result;
} }
clone(): KeyedSet<K, T> { clone(): KeyedSet<T, K> {
return new KeyedSet(this); return new KeyedSet(this);
} }
get [Symbol.toStringTag]() { return 'Set'; } get [Symbol.toStringTag]() { return 'Set'; }
} }
export class Set<T = GenericEmbedded> extends KeyedSet<Value<T>, T> { export class Set<T extends Embeddable = GenericEmbedded> extends KeyedSet<T> {
static isSet<T = GenericEmbedded>(x: any): x is Set<T> { static isSet<T extends Embeddable = GenericEmbedded>(x: any): x is Set<T> {
return x?.[DictionaryType] === 'Set'; 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; return Set.isSet<T>(v) ? v : void 0;
} }
} }
export function encodeSetOn<V, T>( export function encodeSetOn<T extends Embeddable, V>(
s: IdentitySet<V>, s: IdentitySet<V>,
encoder: Encoder<T>, encoder: Encoder<T>,
encodeV: (v: V, encoder: Encoder<T>) => void, 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>, s: IdentitySet<V>,
w: Writer<T>, w: Writer<T>,
writeV: (v: V, w: Writer<T>) => void, writeV: (v: V, w: Writer<T>) => void,

View File

@ -3,7 +3,17 @@ import type { EncoderState } from "./encoder";
import type { Value } from "./values"; import type { Value } from "./values";
import { ReaderStateOptions } from "./reader"; 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; encode(s: EncoderState, v: T): void;
} }
@ -12,46 +22,22 @@ export type EmbeddedTypeDecode<T> = {
fromValue(v: Value<GenericEmbedded>, options: ReaderStateOptions): 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> { export class Embedded<T> {
embeddedValue: T; get [IsEmbedded](): true { return true; }
constructor(embeddedValue: T) { constructor(public readonly value: T) {}
this.embeddedValue = embeddedValue;
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 { export class GenericEmbedded {
generic: Value; get [IsEmbedded](): true { return true; }
constructor(generic: Value) { constructor(public readonly generic: Value) {}
this.generic = generic;
}
equals(other: any, is: (a: any, b: any) => boolean) { equals(other: any, is: (a: any, b: any) => boolean) {
return typeof other === 'object' && 'generic' in other && is(this.generic, other.generic); return typeof other === 'object' && 'generic' in other && is(this.generic, other.generic);

View File

@ -3,17 +3,18 @@ import { Bytes, unhexDigit } from "./bytes";
import { Value } from "./values"; import { Value } from "./values";
import { EncodeError } from "./codec"; import { EncodeError } from "./codec";
import { Record, Tuple } from "./record"; import { Record, Tuple } from "./record";
import { EmbeddedTypeEncode } from "./embedded"; import { EmbeddedTypeEncode, isEmbedded } from "./embedded";
import type { Embedded } 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; Value<T> | Preservable<T> | Iterable<Value<T>> | ArrayBufferView;
export interface Preservable<T> { export interface Preservable<T extends Embeddable> {
__preserve_on__(encoder: Encoder<T>): void; __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'; return typeof v === 'object' && v !== null && '__preserve_on__' in v && typeof v.__preserve_on__ === 'function';
} }
@ -22,11 +23,11 @@ export interface EncoderOptions {
includeAnnotations?: boolean; includeAnnotations?: boolean;
} }
export interface EncoderEmbeddedOptions<T> extends EncoderOptions { export interface EncoderEmbeddedOptions<T extends Embeddable> extends EncoderOptions {
embeddedEncode?: EmbeddedTypeEncode<T>; embeddedEncode?: EmbeddedTypeEncode<T>;
} }
export function asLatin1(bs: Uint8Array): string { function asLatin1(bs: Uint8Array): string {
return String.fromCharCode.apply(null, bs as any as number[]); 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; state: EncoderState;
embeddedEncode: EmbeddedTypeEncode<T>; embeddedEncode: EmbeddedTypeEncode<T>;
@ -218,7 +219,7 @@ export class Encoder<T = object> {
} }
} }
withEmbeddedEncode<S>( withEmbeddedEncode<S extends Embeddable>(
embeddedEncode: EmbeddedTypeEncode<S>, embeddedEncode: EmbeddedTypeEncode<S>,
body: (e: Encoder<S>) => void): this body: (e: Encoder<S>) => void): this
{ {
@ -249,7 +250,7 @@ export class Encoder<T = object> {
} }
push(v: Encodable<T>) { push(v: Encodable<T>) {
if (isPreservable<unknown>(v)) { if (isPreservable<any>(v)) {
v.__preserve_on__(this); v.__preserve_on__(this);
} }
else if (isPreservable<T>(v)) { else if (isPreservable<T>(v)) {
@ -288,17 +289,21 @@ export class Encoder<T = object> {
for (let i of v) this.push(i); 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 { else {
((v: Embedded<T>) => { encodeDictionaryOn(new DictionaryMap<T>(v),
this.state.emitbyte(Tag.Embedded); this,
this.embeddedEncode.encode(this.state, v.embeddedValue); (k, e) => e.push(k),
})(v); (v, e) => e.push(v));
} }
return this; // for chaining return this; // for chaining
} }
} }
export function encode<T>( export function encode<T extends Embeddable>(
v: Encodable<T>, v: Encodable<T>,
options: EncoderEmbeddedOptions<T> = {}): Bytes options: EncoderEmbeddedOptions<T> = {}): Bytes
{ {
@ -332,7 +337,9 @@ export function canonicalString(v: Encodable<any>): string {
} }
} }
export function encodeWithAnnotations<T>(v: Encodable<T>, export function encodeWithAnnotations<T extends Embeddable>(
options: EncoderEmbeddedOptions<T> = {}): Bytes { v: Encodable<T>,
options: EncoderEmbeddedOptions<T> = {},
): Bytes {
return encode(v, { ... options, includeAnnotations: true }); return encode(v, { ... options, includeAnnotations: true });
} }

View File

@ -1,6 +1,6 @@
import { Tag } from "./constants"; import { Tag } from "./constants";
import { Value } from "./values"; import { Value } from "./values";
import type { GenericEmbedded } from "./embedded"; import type { Embeddable, GenericEmbedded } from "./embedded";
import type { Encoder, Preservable } from "./encoder"; import type { Encoder, Preservable } from "./encoder";
import type { Writer, PreserveWritable } from "./writer"; import type { Writer, PreserveWritable } from "./writer";
import { Bytes, dataview } from "./bytes"; 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> { 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; return this;
} }
@ -101,7 +101,7 @@ export class DoubleFloat extends Float implements Preservable<any>, PreserveWrit
return new DoubleFloat(dataview(bs).getFloat64(0, false)); 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; return Float.isDouble(v) ? v : void 0;
} }

View File

@ -1,10 +1,10 @@
import { Record, Tuple } from "./record"; import { Record, Tuple } from "./record";
import { Bytes } from "./bytes"; import { Bytes } from "./bytes";
import { Value } from "./values"; import { Value } from "./values";
import { Set, Dictionary } from "./dictionary"; import { Set, KeyedDictionary, Dictionary, DictionaryMap } from "./dictionary";
import { annotate, Annotated } from "./annotated"; import { annotate, Annotated } from "./annotated";
import { Double, Float } from "./float"; import { Double, Float } from "./float";
import { Embedded } from "./embedded"; import { Embeddable, isEmbedded } from "./embedded";
export enum ValueClass { export enum ValueClass {
Boolean, Boolean,
@ -21,9 +21,9 @@ export enum ValueClass {
Annotated, // quasi-class 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; boolean(b: boolean): R;
double(f: number): R; double(f: number): R;
integer(i: number | bigint): 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; record(r: Record<Value<T>, Tuple<Value<T>>, T>, k: Fold<T, R>): R;
array(a: Array<Value<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; 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; 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> { export class VoidFold<T extends Embeddable> implements FoldMethods<T, void> {
boolean(b: boolean): void {} boolean(_b: boolean): void {}
double(f: number): void {} double(_f: number): void {}
integer(i: number | bigint): void {} integer(_i: number | bigint): void {}
string(s: string): void {} string(_s: string): void {}
bytes(b: Bytes): void {} bytes(_b: Bytes): void {}
symbol(s: symbol): void {} symbol(_s: symbol): void {}
record(r: Record<Value<T>, Tuple<Value<T>>, T>, k: Fold<T, void>): void { record(r: Record<Value<T>, Tuple<Value<T>>, T>, k: Fold<T, void>): void {
k(r.label); k(r.label);
r.forEach(k); r.forEach(k);
} }
array(a: Value<T>[], k: Fold<T, void>): void { a.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); } 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); }); d.forEach((value, key) => { k(key); k(value); });
} }
annotated(a: Annotated<T>, k: Fold<T, void>): void { k(a.item); a.annotations.forEach(k); } 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(); } 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> { boolean(b: boolean): Value<R> {
return b; 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> { set(s: Set<T>, k: Fold<T, Value<R>>): Value<R> {
return s.map(k); return s.map(k);
} }
dictionary(d: Dictionary<T>, k: Fold<T, Value<R>>): Value<R> { dictionary(d: DictionaryMap<T>, k: Fold<T, Value<R>>): Value<R> {
return d.mapEntries(([key, value]) => [k(key), k(value)]); 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> { annotated(a: Annotated<T>, k: Fold<T, Value<R>>): Value<R> {
return annotate(k(a.item), ...a.annotations.map(k)); 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> { export class IdentityFold<T extends Embeddable> extends ValueFold<T, T> {
embedded(t: Embedded<T>, _k: Fold<T, Value<T>>): Value<T> { embedded(t: T, _k: Fold<T, Value<T>>): Value<T> {
return 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>; readonly f: (t: T) => Value<R>;
constructor(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; this.f = f;
} }
embedded(t: Embedded<T>, _k: Fold<T, Value<R>>): Value<R> { embedded(t: T, _k: Fold<T, Value<R>>): Value<R> {
return this.f(t.embeddedValue); 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) { switch (typeof v) {
case 'boolean': case 'boolean':
return ValueClass.Boolean; return ValueClass.Boolean;
@ -154,7 +156,7 @@ export function valueClass<T>(v: Value<T>): ValueClass {
} else if (Float.isDouble(v)) { } else if (Float.isDouble(v)) {
return ValueClass.Double; return ValueClass.Double;
} else { } else {
return ValueClass.Embedded; return ((_v: T) => ValueClass.Embedded)(v);
} }
default: default:
((_v: never): never => { throw new Error("Internal error"); })(v); ((_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 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 => { const walk = (v: Value<T>): R => {
switch (typeof v) { switch (typeof v) {
case 'boolean': case 'boolean':
@ -188,16 +190,16 @@ export function fold<T, R>(v: Value<T>, o: FoldMethods<T, R>): R {
return o.array(v, walk); return o.array(v, walk);
} else if (Set.isSet<T>(v)) { } else if (Set.isSet<T>(v)) {
return o.set(v, walk); return o.set(v, walk);
} else if (Dictionary.isDictionary<T>(v)) { } else if (isEmbedded(v)) {
return o.dictionary(v, walk); return o.embedded(v, walk);
} else if (Annotated.isAnnotated<T>(v)) { } else if (Annotated.isAnnotated<T>(v)) {
return o.annotated(v, walk); return o.annotated(v, walk);
} else if (Bytes.isBytes(v)) { } else if (Bytes.isBytes(v)) {
return o.bytes(v); return o.bytes(v);
} else if (Float.isDouble(v)) { } else if (Float.isDouble(v)) {
return o.double(v.value); return o.double(v.value);
} else { } else if (Dictionary.isDictionary<T>(v)) {
return o.embedded(v, walk); return o.dictionary(new DictionaryMap(v), walk);
} }
default: default:
((_v: never): never => { throw new Error("Internal error"); })(v); ((_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); return walk(v);
} }
export function mapEmbeddeds<T, R>( export function mapEmbeddeds<T extends Embeddable, R extends Embeddable>(
v: Value<T>, v: Value<T>,
f: (t: T) => Value<R>, f: (t: T) => Value<R>,
): Value<R> ): Value<R>
@ -214,6 +216,9 @@ export function mapEmbeddeds<T, R>(
return fold(v, new MapFold(f)); 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)); return fold(v, new ForEachEmbedded(f));
} }

View File

@ -1,72 +1,97 @@
import { embed, GenericEmbedded } from "./embedded"; import { Embeddable, GenericEmbedded, isEmbedded } from "./embedded";
import { Bytes } from "./bytes"; import { Bytes } from "./bytes";
import { Record, Tuple } from "./record"; import { Record, Tuple } from "./record";
import { Value } from "./values"; 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> { export interface FromJSOptions<T extends Embeddable = GenericEmbedded> {
switch (typeof x) { onNonInteger?(n: number): Value<T> | undefined;
case 'number': }
if (!Number.isInteger(x)) {
// We require that clients be explicit about integer vs. non-integer types. export function fromJS<T extends Embeddable = GenericEmbedded>(x: any): Value<T> {
throw new TypeError("Refusing to autoconvert non-integer number to Double"); 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 // FALL THROUGH
case 'bigint': case 'bigint':
case 'string': case 'string':
case 'symbol': case 'symbol':
case 'boolean': 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)) {
return x; 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: case 'undefined':
break; 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" { declare module "./dictionary" {
namespace 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>> { Dictionary.stringMap = function <T extends Embeddable = GenericEmbedded>(
if (Dictionary.isDictionary<T, Value<V>>(x)) return x; x: object
const d = new Dictionary<T, Value<V>>(); ): KeyedDictionary<T, string, Value<T>> {
Object.entries(x).forEach(([key, value]) => d.set(key, fromJS(value))); const r = new KeyedDictionary<T, string, Value<T>>();
return d; Object.entries(x).forEach(([key, value]) => r.set(key, fromJS(value)));
return r;
}; };

View File

@ -1,15 +1,17 @@
export * from './runtime'; export * from './runtime';
export * as Constants from './constants'; export * as Constants from './constants';
export * as Pexpr from './pexpr';
import type { Embeddable } from './embedded';
import type { Value } from './values'; import type { Value } from './values';
declare global { declare global {
interface ArrayConstructor { 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; return Array.isArray(v) ? v : void 0;
}; };

View File

@ -1,9 +1,10 @@
import type { GenericEmbedded } from "./embedded"; import type { Embeddable, GenericEmbedded } from "./embedded";
import type { Annotated } from "./annotated"; import type { Annotated } from "./annotated";
import { Dictionary } from "./dictionary";
export const IsPreservesAnnotated = Symbol.for('IsPreservesAnnotated'); 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]; 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; for (let i = 0; i < a.length; i++) if (!is(a[i], b[i])) return false;
return true; 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; return false;
} }

View File

@ -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;
}
}

View File

@ -3,13 +3,15 @@ import { Bytes } from "./bytes";
import { fold } from "./fold"; import { fold } from "./fold";
import { is } from "./is"; import { is } from "./is";
import { Value } from "./values"; import { Value } from "./values";
import { Set, Dictionary } from "./dictionary"; import { Set, Dictionary, KeyedDictionary, DictionaryMap } from "./dictionary";
import { Annotated } from "./annotated"; import { Annotated } from "./annotated";
import { unannotate } from "./strip"; import { unannotate } from "./strip";
import { embed, isEmbedded, Embedded } from "./embedded"; import { isEmbedded } from "./embedded";
import { isCompound } from "./compound"; 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, mergeEmbeddeds: (a: T, b: T) => T | undefined,
item0: Value<T>, item0: Value<T>,
... items: Array<Value<T>>): 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(); if (!Record.isRecord<Value<T>, Tuple<Value<T>>, T>(b)) die();
return Record(walk(r.label, b.label), walkMany(r, b)); return Record(walk(r.label, b.label), walkMany(r, b));
}, },
array(a: Array<Value<T>>) { array(a: Array<Value<T>>) {
if (!Array.isArray(b) || Record.isRecord(b)) die(); if (!Array.isArray(b) || Record.isRecord(b)) die();
return walkMany(a, b); return walkMany(a, b);
}, },
set(_s: Set<T>) { die(); }, set(_s: Set<T>) { die(); },
dictionary(d: Dictionary<T>) {
if (!Dictionary.isDictionary<T>(b)) die(); dictionary(aMap: DictionaryMap<T>) {
const r = new Dictionary<T>(); const bMap = Dictionary.asMap<T>(b);
d.forEach((av,ak) => { if (bMap === void 0) die();
const bv = b.get(ak);
const r = new DictionaryMap<T>();
aMap.forEach((av,ak) => {
const bv = bMap.get(ak);
r.set(ak, bv === void 0 ? av : walk(av, bv)); r.set(ak, bv === void 0 ? av : walk(av, bv));
}); });
b.forEach((bv, bk) => { bMap.forEach((bv, bk) => {
if (!d.has(bk)) r.set(bk, bv); if (!aMap.has(bk)) r.set(bk, bv);
}); });
return r; return r.simplifiedValue();
}, },
annotated(a: Annotated<T>) { annotated(a: Annotated<T>) {
return walk(a, unannotate(b)); return walk(a, unannotate(b));
}, },
embedded(t: Embedded<T>) { embedded(t: T) {
if (!isEmbedded<T>(b)) die(); if (!isEmbedded<T>(b)) die();
const r = mergeEmbeddeds(t.embeddedValue, b.embeddedValue); const r = mergeEmbeddeds(t, b);
if (r === void 0) die(); if (r === void 0) die();
return embed(r); return r;
}, },
}); });
} }

View File

@ -2,12 +2,12 @@
import { Annotated } from './annotated'; import { Annotated } from './annotated';
import { Bytes } from './bytes'; import { Bytes } from './bytes';
import { Set, Dictionary } from './dictionary'; import { Set, EncodableDictionary } from './dictionary';
import { stringify } from './text'; import { stringify } from './text';
import * as util from 'util'; import * as util from 'util';
[Bytes, Annotated, Set, Dictionary].forEach((C) => { [Bytes, Annotated, Set, EncodableDictionary].forEach((C) => {
(C as any).prototype[util.inspect.custom] = (C as any).prototype[util.inspect.custom] =
function (_depth: any, _options: any) { function (_depth: any, _options: any) {
return stringify(this, { indent: 2 }); return stringify(this, { indent: 2 });

View File

@ -1,13 +1,14 @@
import { is, isAnnotated } from './is'; import { is, isAnnotated } from './is';
import { Bytes } from './bytes'; import { Bytes } from './bytes';
import { Set, Dictionary } from './dictionary'; import { Set, Dictionary } from './dictionary';
import { Embedded, isEmbedded } from './embedded'; import { isEmbedded } from './embedded';
import { Float } from './float'; import { Float } from './float';
import { Value } from './values'; import { Value } from './values';
import { Record } from './record'; import { Record } from './record';
import type { Embeddable } from './embedded';
export function typeCode<V>(v: Value<V>): number { export function typeCode<T extends Embeddable>(v: Value<T>): number {
if (isAnnotated<V>(v)) v = v.item; if (isAnnotated<T>(v)) v = v.item;
switch (typeof v) { switch (typeof v) {
case 'boolean': case 'boolean':
return 0; return 0;
@ -24,23 +25,23 @@ export function typeCode<V>(v: Value<V>): number {
if (Array.isArray(v)) { if (Array.isArray(v)) {
return ('label' in v) ? 7 : 8; return ('label' in v) ? 7 : 8;
} }
if (Set.isSet<V>(v)) return 9; if (Set.isSet<T>(v)) return 9;
if (Dictionary.isDictionary<V>(v)) return 10; if (Dictionary.isDictionary<T>(v)) return 10;
if (isEmbedded(v)) return 11; if (isEmbedded(v)) return 11;
/* fall through */ /* fall through */
default: default:
throw new Error("Invalid Value<V> in typeCode"); throw new Error("Invalid Value<T> in typeCode");
} }
} }
export function compare<V>( export function compare<T extends Embeddable>(
a: Value<V>, a: Value<T>,
b: Value<V>, b: Value<T>,
compare_embedded: (a: V, b: V) => number = (a, b) => is(a, b) ? 0 : a < b ? -1 : 1, compare_embedded: (a: T, b: T) => number = (a, b) => is(a, b) ? 0 : a < b ? -1 : 1,
): number { ): number {
function cmp(a: Value<V>, b: Value<V>): number { function cmp(a: Value<T>, b: Value<T>): number {
if (isAnnotated<V>(a)) a = a.item; if (isAnnotated<T>(a)) a = a.item;
if (isAnnotated<V>(b)) b = b.item; if (isAnnotated<T>(b)) b = b.item;
const ta = typeCode(a); const ta = typeCode(a);
const tb = typeCode(b); const tb = typeCode(b);
if (ta < tb) return -1; if (ta < tb) return -1;
@ -67,14 +68,14 @@ export function compare<V>(
return va < vb ? -1 : va > vb ? 1 : 0; return va < vb ? -1 : va > vb ? 1 : 0;
} }
case 7: { case 7: {
const lr = cmp((a as Record<Value<V>, Value<V>[], V>).label, const lr = cmp((a as Record<Value<T>, Value<T>[], T>).label,
(b as Record<Value<V>, Value<V>[], V>).label); (b as Record<Value<T>, Value<T>[], T>).label);
if (lr !== 0) return lr; if (lr !== 0) return lr;
/* fall through */ /* fall through */
} }
case 8: { case 8: {
const va = a as Value<V>[]; const va = a as Value<T>[];
const vb = b as Value<V>[]; const vb = b as Value<T>[];
const l = Math.min(va.length, vb.length) const l = Math.min(va.length, vb.length)
for (let i = 0; i < l; i++) { for (let i = 0; i < l; i++) {
const c = cmp(va[i], vb[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; return va.length < vb.length ? -1 : va.length > vb.length ? 1 : 0;
} }
case 9: { case 9: {
const va = Array.from(a as Set<V>).sort(cmp); const va = Array.from(a as Set<T>).sort(cmp);
const vb = Array.from(b as Set<V>).sort(cmp); const vb = Array.from(b as Set<T>).sort(cmp);
return cmp(va, vb); return cmp(va, vb);
} }
case 10: { case 10: {
const va = Array.from(a as Dictionary<V>).sort(cmp); const va = Array.from(Dictionary.asMap<T>(a)!.entries()).sort(cmp);
const vb = Array.from(b as Dictionary<V>).sort(cmp); const vb = Array.from(Dictionary.asMap<T>(b)!.entries()).sort(cmp);
return cmp(va, vb); return cmp(va, vb);
} }
case 11: case 11:
return compare_embedded((a as Embedded<V>).embeddedValue, return compare_embedded(a as T, b as T);
(b as Embedded<V>).embeddedValue);
default: default:
throw new Error("Invalid typeCode: " + ta); throw new Error("Invalid typeCode: " + ta);
} }

View File

@ -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);
}

View File

@ -2,15 +2,15 @@
import type { Value } from './values'; import type { Value } from './values';
import { DecodeError, ShortPacket } from './codec'; import { DecodeError, ShortPacket } from './codec';
import { Dictionary, Set } from './dictionary'; import { Dictionary, DictionaryMap, Set } from './dictionary';
import { strip } from './strip'; import { strip } from './strip';
import { Bytes, unhexDigit } from './bytes'; import { Bytes, unhexDigit } from './bytes';
import { Decoder, DecoderState, neverEmbeddedTypeDecode } from './decoder'; import { Decoder, DecoderState, neverEmbeddedTypeDecode } from './decoder';
import { Record } from './record'; import { Record } from './record';
import { Annotated, newPosition, Position, updatePosition } from './annotated'; import { Annotated, newPosition, Position, updatePosition } from './annotated';
import { Double, DoubleFloat, FloatType } from './float'; import { Double, DoubleFloat } from './float';
import { stringify } from './text'; import { stringify } from './text';
import { embed, GenericEmbedded, EmbeddedTypeDecode } from './embedded'; import { Embeddable, GenericEmbedded, EmbeddedTypeDecode } from './embedded';
export interface ReaderStateOptions { export interface ReaderStateOptions {
includeAnnotations?: boolean; includeAnnotations?: boolean;
@ -155,13 +155,15 @@ export class ReaderState {
this.error(`Delimiter must follow ${prefix}`, this.pos); this.error(`Delimiter must follow ${prefix}`, this.pos);
} }
static readonly DELIMITERS = '(){}[]<>";,@#:|';
delimiterFollows(): boolean { delimiterFollows(): boolean {
if (this.atEnd()) return true; if (this.atEnd()) return true;
const ch = this.peek(); 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(); while (!this.delimiterFollows()) acc = acc + this.nextchar();
const m = NUMBER_RE.exec(acc); const m = NUMBER_RE.exec(acc);
if (m) { if (m) {
@ -248,6 +250,16 @@ export class ReaderState {
'x', 'x',
() => this.readHex2()); () => 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> = { 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; state: ReaderState;
embeddedType: EmbeddedTypeDecode<T>; embeddedType: EmbeddedTypeDecode<T>;
@ -283,17 +295,13 @@ export class Reader<T> {
write(data: string) { write(data: string) {
this.state.write(data); this.state.write(data);
} }
}
export class Reader<T extends Embeddable> extends ReaderBase<T> {
readCommentLine(): Value<T> { readCommentLine(): Value<T> {
const startPos = this.state.copyPos(); const startPos = this.state.copyPos();
let acc = ''; return this.wrap(this.state.readCommentLine(), startPos);
while (true) {
const c = this.state.nextchar();
if (c === '\n' || c === '\r') {
return this.wrap(acc, startPos);
}
acc = acc + c;
}
} }
wrap(v: Value<T>, pos: Position): Value<T> { wrap(v: Value<T>, pos: Position): Value<T> {
@ -344,6 +352,9 @@ export class Reader<T> {
switch (c) { switch (c) {
case ' ': case '\t': return this.annotateNextWith(this.readCommentLine()); case ' ': case '\t': return this.annotateNextWith(this.readCommentLine());
case '\n': case '\r': return this.annotateNextWith(''); 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 'f': this.state.requireDelimiter('#f'); return false;
case 't': this.state.requireDelimiter('#t'); return true; case 't': this.state.requireDelimiter('#t'); return true;
case '{': return this.readSet(); case '{': return this.readSet();
@ -354,9 +365,9 @@ export class Reader<T> {
default: this.state.error('Invalid #x syntax', startPos); default: this.state.error('Invalid #x syntax', startPos);
} }
case '[': return this.state.readBase64Binary(); case '[': return this.state.readBase64Binary();
case ':': return embed(this.embeddedType.fromValue( case ':': return this.embeddedType.fromValue(
new Reader<GenericEmbedded>(this.state, genericEmbeddedTypeDecode).next(), new Reader<GenericEmbedded>(this.state, genericEmbeddedTypeDecode).next(),
this.state.options)); this.state.options);
default: default:
this.state.error(`Invalid # syntax: ${c}`, startPos); this.state.error(`Invalid # syntax: ${c}`, startPos);
} }
@ -395,22 +406,18 @@ export class Reader<T> {
} }
readDictionary(): Dictionary<T> { readDictionary(): Dictionary<T> {
return this.seq(true, return this.seq(true, new DictionaryMap<T>(), (k, acc) => {
new Dictionary<T>(), this.state.skipws();
(k, acc) => { switch (this.state.peek()) {
this.state.skipws(); case ':':
switch (this.state.peek()) { this.state.advance();
case ':': if (acc.has(k)) this.state.error(`Duplicate key: ${stringify(k)}`, this.state.pos);
if (acc.has(k)) this.state.error( acc.set(k, this.next());
`Duplicate key: ${stringify(k)}`, this.state.pos); break;
this.state.advance(); default:
acc.set(k, this.next()); this.state.error('Missing key/value separator', this.state.pos);
break; }
default: }, '}').simplifiedValue();
this.state.error('Missing key/value separator', this.state.pos);
}
},
'}');
} }
readSet(): Set<T> { readSet(): Set<T> {

View File

@ -1,11 +1,10 @@
import { GenericEmbedded } from "./embedded"; import { Embeddable, GenericEmbedded } from "./embedded";
import { is } from "./is"; import { is } from "./is";
import { Value } from "./values"; import { Value } from "./values";
import { Writer } from "./writer";
export type Tuple<T> = Array<T> | [T]; 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 }; = FieldsType & { label: LabelType };
export type RecordGetters<Fs, R> = { export type RecordGetters<Fs, R> = {
@ -15,7 +14,7 @@ export type RecordGetters<Fs, R> = {
export type CtorTypes<Fs, Names extends Tuple<keyof Fs>> = export type CtorTypes<Fs, Names extends Tuple<keyof Fs>> =
{ [K in keyof Names]: Fs[keyof Fs & Names[K]] } & any[]; { [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>; (...fields: CtorTypes<Fs, Names>): Record<L, CtorTypes<Fs, Names>, T>;
constructorInfo: RecordConstructorInfo<L, T>; constructorInfo: RecordConstructorInfo<L, T>;
isClassOf(v: any): v is Record<L, CtorTypes<Fs, Names>, 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 }; 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; label: L;
arity: number; arity: number;
} }
@ -48,23 +47,23 @@ export function Record<L, FieldsType extends Tuple<any>>(
} }
export namespace Record { 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; 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> r: Record<L, FieldsType, T>): RecordConstructorInfo<L, T>
{ {
return { label: r.label, arity: r.length }; 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> 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); 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) => : (<L extends Value<T>, Names extends Tuple<keyof Fs>>(label: L, fieldNames: Names) =>
RecordConstructor<L, Fs, Names, T>) RecordConstructor<L, Fs, Names, T>)
{ {

View File

@ -13,6 +13,7 @@ export * from './float';
export * from './fold'; export * from './fold';
export * from './fromjs'; export * from './fromjs';
export * from './is'; export * from './is';
export * from './jsdictionary';
export * from './merge'; export * from './merge';
export * from './order'; export * from './order';
export * from './reader'; export * from './reader';

View File

@ -1,18 +1,18 @@
import { Value } from "./values"; import { Value } from "./values";
import { Annotated } from "./annotated"; import { Annotated } from "./annotated";
import { Record, Tuple } from "./record"; import { Record, Tuple } from "./record";
import { Set, Dictionary } from "./dictionary"; import { Set, Dictionary, DictionaryMap } from "./dictionary";
import type { GenericEmbedded } from "./embedded"; 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; 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); return strip(v, 1);
} }
export function strip<T = GenericEmbedded>( export function strip<T extends Embeddable = GenericEmbedded>(
v: Value<T>, v: Value<T>,
depth: number = Infinity): Value<T> depth: number = Infinity): Value<T>
{ {
@ -34,7 +34,9 @@ export function strip<T = GenericEmbedded>(
} else if (Set.isSet<T>(v.item)) { } else if (Set.isSet<T>(v.item)) {
return v.item.map(walk); return v.item.map(walk);
} else if (Dictionary.isDictionary<T>(v.item)) { } 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 { } else {
return v.item; return v.item;
} }

View File

@ -1,4 +1,4 @@
import { Embedded, GenericEmbedded } from './embedded'; import { Embeddable, GenericEmbedded, isEmbedded } from './embedded';
import type { Value } from './values'; import type { Value } from './values';
import { Annotated } from './annotated'; import { Annotated } from './annotated';
@ -8,22 +8,28 @@ import { Writer, WriterOptions, EmbeddedWriter, WriterState } from './writer';
import { fromJS } from './fromjs'; import { fromJS } from './fromjs';
import { Reader, ReaderOptions } from './reader'; 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(); 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(); return new Reader<T>(buffer, options).readToEnd();
} }
export const stringifyEmbeddedWrite: EmbeddedWriter<any> = { export const stringifyEmbeddedWrite = {
write(s: WriterState, v: any): void { write(s: WriterState, v: any): void {
if (v instanceof GenericEmbedded) { if (v instanceof GenericEmbedded) {
new Writer(s, this).push(v.generic); new Writer(s, this).push(v.generic);
} else { } else {
try { try {
const j = fromJS(v); const j = fromJS(v);
if (!(j instanceof Embedded)) { if (!isEmbedded(j)) {
new Writer(s, this).push(j); new Writer(s, this).push(j);
return; 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 = { ... (options ?? {}) };
options.embeddedWrite = options.embeddedWrite ?? stringifyEmbeddedWrite; options.embeddedWrite = options.embeddedWrite ?? stringifyEmbeddedWrite;
return Writer.stringify(fromJS<T>(x), options); return Writer.stringify(fromJS<T>(x), options);

View File

@ -3,13 +3,14 @@
import type { Bytes } from './bytes'; import type { Bytes } from './bytes';
import type { DoubleFloat } from './float'; import type { DoubleFloat } from './float';
import type { Annotated } from './annotated'; import type { Annotated } from './annotated';
import type { Set, Dictionary } from './dictionary'; import type { JsDictionary } from './jsdictionary';
import type { Embedded, GenericEmbedded } from './embedded'; import { Set, KeyedDictionary } from './dictionary';
import type { Embeddable, GenericEmbedded } from './embedded';
export type Value<T = GenericEmbedded> = export type Value<T extends Embeddable = GenericEmbedded> =
| Atom | Atom
| Compound<T> | Compound<T>
| Embedded<T> | T
| Annotated<T>; | Annotated<T>;
export type Atom = export type Atom =
| boolean | boolean
@ -18,7 +19,7 @@ export type Atom =
| string | string
| Bytes | Bytes
| symbol; | symbol;
export type Compound<T = GenericEmbedded> = export type Compound<T extends Embeddable = GenericEmbedded> =
| (Array<Value<T>> | [Value<T>]) & { label: Value<T> } | (Array<Value<T>> | [Value<T>]) & { label: Value<T> }
// ^ expanded from definition of Record<> in record.ts, // ^ expanded from definition of Record<> in record.ts,
// because if we use Record<Value<T>, Tuple<Value<T>>, T>, // because if we use Record<Value<T>, Tuple<Value<T>>, T>,
@ -27,4 +28,7 @@ export type Compound<T = GenericEmbedded> =
// Value<T> to any. // Value<T> to any.
| Array<Value<T>> | Array<Value<T>>
| Set<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>;

View File

@ -1,19 +1,20 @@
import { isAnnotated } from './is'; import { isAnnotated } from './is';
import { Record, Tuple } from "./record"; 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 { Encoder, EncoderState } from "./encoder";
import type { Value } from "./values"; import type { Value } from "./values";
import { NUMBER_RE } from './reader'; import { NUMBER_RE } from './reader';
import { encodeBase64 } from './base64'; 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; 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; __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'; 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 + '"'); this.pieces.push(buf + '"');
} }
couldBeFlat<T>(vs: Writable<T>[]): boolean { couldBeFlat<T extends Embeddable>(vs: Writable<T>[]): boolean {
let seenCompound = false; let seenCompound = false;
for (let v of vs) { for (let v of vs) {
if (Array.isArray(v) || Set.isSet(v) || Map.isMap(v)) { 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; state: WriterState;
embeddedWrite: EmbeddedWriter<T>; 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); const w = new Writer(options);
w.push(v); w.push(v);
return w.contents(); return w.contents();
@ -262,7 +263,10 @@ export class Writer<T> {
this.state.pieces.push('' + v); this.state.pieces.push('' + v);
break; break;
case 'object': 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); v.__preserve_text_on__(this);
} }
else if (isPreserveWritable<T>(v)) { else if (isPreserveWritable<T>(v)) {
@ -295,16 +299,19 @@ export class Writer<T> {
else if (isIterable(v)) { else if (isIterable(v)) {
this.state.writeSeq('[', ']', v, vv => this.push(vv)); this.state.writeSeq('[', ']', v, vv => this.push(vv));
} }
else { else if (isEmbedded(v)) {
((v: Embedded<T>) => { this.state.pieces.push('#:');
this.state.pieces.push('#:'); if ('write' in this.embeddedWrite) {
if ('write' in this.embeddedWrite) { this.embeddedWrite.write(this.state, v);
this.embeddedWrite.write(this.state, v.embeddedValue); } else {
} else { new Writer(this.state, genericEmbeddedTypeEncode)
new Writer(this.state, genericEmbeddedTypeEncode) .push(this.embeddedWrite.toValue(v));
.push(this.embeddedWrite.toValue(v.embeddedValue)); }
} } else {
})(v); writeDictionaryOn(new DictionaryMap<T>(v),
this,
(k, w) => w.push(k),
(v, w) => w.push(v));
} }
break; break;
default: default:

View File

@ -118,3 +118,11 @@ describe('base64 decoder', () => {
it('gQ==', () => expect(d64('gQ==')).is(Bytes.of(0x81))); 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'));
});

View File

@ -4,7 +4,6 @@ import {
decode, decodeWithAnnotations, encode, canonicalEncode, decode, decodeWithAnnotations, encode, canonicalEncode,
DecodeError, ShortPacket, DecodeError, ShortPacket,
Bytes, Record, Bytes, Record,
annotate,
strip, peel, strip, peel,
preserves, preserves,
stringify, stringify,
@ -16,11 +15,11 @@ import {
EmbeddedType, EmbeddedType,
DecoderState, DecoderState,
Decoder, Decoder,
Embedded,
embed,
genericEmbeddedTypeDecode, genericEmbeddedTypeDecode,
genericEmbeddedTypeEncode, genericEmbeddedTypeEncode,
parse, parse,
Embedded,
KeyedDictionary,
} from '../src/index'; } from '../src/index';
const { Tag } = Constants; const { Tag } = Constants;
import './test-utils'; import './test-utils';
@ -78,7 +77,7 @@ describe('parsing from subarray', () => {
describe('reusing buffer space', () => { describe('reusing buffer space', () => {
it('should be done safely, even with nested dictionaries', () => { 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 `b5
b103616161 b103616161
b7 b7
@ -90,33 +89,29 @@ describe('reusing buffer space', () => {
}); });
describe('encoding and decoding embeddeds', () => { describe('encoding and decoding embeddeds', () => {
class LookasideEmbeddedType implements EmbeddedType<object> { class LookasideEmbeddedType implements EmbeddedType<Embedded<object>> {
readonly objects: object[]; readonly objects: Embedded<object>[];
constructor(objects: object[]) { constructor(objects: Embedded<object>[]) {
this.objects = objects; this.objects = objects;
} }
decode(d: DecoderState): object { decode(d: DecoderState): Embedded<object> {
return this.fromValue(new Decoder<GenericEmbedded>(d).next()); 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)); new Encoder(e).push(this.toValue(v));
} }
equals(a: object, b: object): boolean { fromValue(v: Value<GenericEmbedded>): Embedded<object> {
return Object.is(a, b);
}
fromValue(v: Value<GenericEmbedded>): object {
if (typeof v !== 'number' || v < 0 || v >= this.objects.length) { 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]; return this.objects[v];
} }
toValue(v: object): number { toValue(v: Embedded<object>): number {
let i = this.objects.indexOf(v); let i = this.objects.indexOf(v);
if (i !== -1) return i; if (i !== -1) return i;
this.objects.push(v); this.objects.push(v);
@ -125,8 +120,8 @@ describe('encoding and decoding embeddeds', () => {
} }
it('should encode using embeddedId when no function has been supplied', () => { it('should encode using embeddedId when no function has been supplied', () => {
const A1 = embed({a: 1}); const A1 = new Embedded({a: 1});
const A2 = embed({a: 1}); const A2 = new Embedded({a: 1});
const bs1 = canonicalEncode(A1); const bs1 = canonicalEncode(A1);
const bs2 = canonicalEncode(A2); const bs2 = canonicalEncode(A2);
const bs3 = canonicalEncode(A1); const bs3 = canonicalEncode(A1);
@ -143,24 +138,24 @@ describe('encoding and decoding embeddeds', () => {
.toThrow("Embeddeds not permitted at this point in Preserves document"); .toThrow("Embeddeds not permitted at this point in Preserves document");
}); });
it('should encode properly', () => { it('should encode properly', () => {
const objects: object[] = []; const objects: Embedded<object>[] = [];
const pt = new LookasideEmbeddedType(objects); const pt = new LookasideEmbeddedType(objects);
const A = embed({a: 1}); const A = new Embedded({a: 1});
const B = embed({b: 2}); const B = new Embedded({b: 2});
expect(encode([A, B], { embeddedEncode: pt })).is( expect(encode([A, B], { embeddedEncode: pt })).is(
Bytes.from([Tag.Sequence, Bytes.from([Tag.Sequence,
Tag.Embedded, Tag.SignedInteger, 0, Tag.Embedded, Tag.SignedInteger, 0,
Tag.Embedded, Tag.SignedInteger, 1, 1, Tag.Embedded, Tag.SignedInteger, 1, 1,
Tag.End])); Tag.End]));
expect(objects).toEqual([A.embeddedValue, B.embeddedValue]); expect(objects).toEqual([A, B]);
}); });
it('should decode properly', () => { it('should decode properly', () => {
const objects: object[] = []; const objects: Embedded<object>[] = [];
const pt = new LookasideEmbeddedType(objects); const pt = new LookasideEmbeddedType(objects);
const X: Embedded<object> = embed({x: 123}); const X = new Embedded({x: 123});
const Y: Embedded<object> = embed({y: 456}); const Y = new Embedded({y: 456});
objects.push(X.embeddedValue); objects.push(X);
objects.push(Y.embeddedValue); objects.push(Y);
expect(decode(Bytes.from([ expect(decode(Bytes.from([
Tag.Sequence, Tag.Sequence,
Tag.Embedded, Tag.SignedInteger, 0, Tag.Embedded, Tag.SignedInteger, 0,
@ -169,17 +164,17 @@ describe('encoding and decoding embeddeds', () => {
]), { embeddedDecode: pt })).is([X, Y]); ]), { embeddedDecode: pt })).is([X, Y]);
}); });
it('should store embeddeds embedded in map keys correctly', () => { it('should store embeddeds embedded in map keys correctly', () => {
const A1a = {a: 1}; const A1a = new Embedded({a: 1});
const A1: Embedded<object> = embed(A1a); const A1 = A1a;
const A2: Embedded<object> = embed({a: 1}); const A2 = new Embedded({a: 1});
const m = new Dictionary<object, number>(); const m = new KeyedDictionary<Embedded<object>, Value<Embedded<object>>, number>();
m.set([A1], 1); m.set([A1], 1);
m.set([A2], 2); m.set([A2], 2);
expect(m.get(A1)).toBeUndefined(); expect(m.get(A1)).toBeUndefined();
expect(m.get([A1])).toBe(1); expect(m.get([A1])).toBe(1);
expect(m.get([A2])).toBe(2); expect(m.get([A2])).toBe(2);
expect(m.get([embed({a: 1})])).toBeUndefined(); expect(m.get([{a: 1}])).toBeUndefined();
A1a.a = 3; A1a.value.a = 3;
expect(m.get([A1])).toBe(1); expect(m.get([A1])).toBe(1);
}); });
}); });
@ -309,7 +304,7 @@ describe('common test suite', () => {
const tests = (peel(TestCases._.cases(peel(samples) as TestCases)) as const tests = (peel(TestCases._.cases(peel(samples) as TestCases)) as
Dictionary<GenericEmbedded>); 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 tName = Symbol.keyFor(strip(tName0) as symbol)!;
const t = peel(t0) as Record<symbol, any, GenericEmbedded>; const t = peel(t0) as Record<symbol, any, GenericEmbedded>;
switch (t.label) { switch (t.label) {

View File

@ -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');
});
});

View File

@ -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 './test-utils';
import * as fs from 'fs'; 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.0').next()).toEqual(Double(123.0));
expect(new Reader('123.00').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][]));
});
}); });

View File

@ -1,10 +1,10 @@
import { Value, is, preserves } from '../src/index'; import { Value, is, preserves, Embeddable } from '../src/index';
import '../src/node_support'; import '../src/node_support';
declare global { declare global {
namespace jest { namespace jest {
interface Matchers<R> { interface Matchers<R> {
is<T>(expected: Value<T>): R; is<T extends Embeddable>(expected: Value<T>): R;
toThrowFilter(f: (e: Error) => boolean): R; toThrowFilter(f: (e: Error) => boolean): R;
} }
} }

View File

@ -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'; import './test-utils';
describe('Double', () => { describe('Double', () => {
@ -8,13 +8,13 @@ describe('Double', () => {
}); });
describe('fold', () => { describe('fold', () => {
function mkv<T extends object>(t: T): Value<T> { function mkv<T extends Embeddable>(t: T): Value<T> {
return fromJS<T>([ return fromJS<T>([
1, 1,
2, 2,
new Dictionary([[[3, 4], fromJS([5, 6])], new KeyedDictionary<T>([[[3, 4], fromJS([5, 6])],
['a', 1], ['a', 1],
['b', true]]), ['b', true]]),
Double(3.4), Double(3.4),
t, t,
]); ]);
@ -22,12 +22,12 @@ describe('fold', () => {
it('should support identity', () => { it('should support identity', () => {
const w = new Date(); const w = new Date();
const v = mkv(w); const v = mkv(new Embedded(w));
expect(fold(v, IDENTITY_FOLD)).is(v); expect(fold(v, IDENTITY_FOLD)).is(v);
const w1 = new Date(); const w1 = new Date();
const v1 = mkv(w1); const v1 = mkv(new Embedded(w1));
expect(fold(v, IDENTITY_FOLD)).not.is(v1); 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.toBe(3);
expect(c).not.is(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', () => { describe('`preserves` formatter', () => {
@ -82,4 +88,18 @@ describe('`preserves` formatter', () => {
expect(preserves`>${BigInt("12345678123456781234567812345678")}<`) expect(preserves`>${BigInt("12345678123456781234567812345678")}<`)
.toBe('>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}<');
});
}); });

View File

@ -1,6 +1,6 @@
{ {
"name": "@preserves/schema-cli", "name": "@preserves/schema-cli",
"version": "0.994.0", "version": "0.995.206",
"description": "Command-line tools for Preserves Schema", "description": "Command-line tools for Preserves Schema",
"homepage": "https://gitlab.com/preserves/preserves", "homepage": "https://gitlab.com/preserves/preserves",
"license": "Apache-2.0", "license": "Apache-2.0",
@ -26,8 +26,8 @@
"@types/minimatch": "^3.0" "@types/minimatch": "^3.0"
}, },
"dependencies": { "dependencies": {
"@preserves/core": "^0.994.0", "@preserves/core": "^0.995.206",
"@preserves/schema": "^0.994.0", "@preserves/schema": "^0.995.206",
"chalk": "^4.1", "chalk": "^4.1",
"chokidar": "^3.5", "chokidar": "^3.5",
"commander": "^7.2", "commander": "^7.2",

View File

@ -25,7 +25,7 @@ export function run(options: CommandLineArguments): void {
if (failures.length === 0) { if (failures.length === 0) {
if (options.bundle) { if (options.bundle) {
fs.writeSync(1, underlying(canonicalEncode(M.fromBundle(M.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]))))))); inputFiles.map(i => [i.modulePath, i.schema])))))));
} else { } else {
fs.writeSync(1, underlying(canonicalEncode(M.fromSchema(inputFiles[0].schema)))); fs.writeSync(1, underlying(canonicalEncode(M.fromSchema(inputFiles[0].schema))));

View File

@ -1,6 +1,6 @@
{ {
"name": "@preserves/schema", "name": "@preserves/schema",
"version": "0.994.0", "version": "0.995.206",
"description": "Schema support for Preserves data serialization format", "description": "Schema support for Preserves data serialization format",
"homepage": "https://gitlab.com/preserves/preserves", "homepage": "https://gitlab.com/preserves/preserves",
"license": "Apache-2.0", "license": "Apache-2.0",
@ -26,6 +26,10 @@
"veryclean": "yarn run clean && rm -rf node_modules" "veryclean": "yarn run clean && rm -rf node_modules"
}, },
"dependencies": { "dependencies": {
"@preserves/core": "^0.994.0" "@preserves/core": "^0.995.206"
},
"devDependencies": {
"@types/js-beautify": "1.14",
"js-beautify": "1.15"
} }
} }

View File

@ -68,33 +68,9 @@
} }
} }
// I.env.forEach((_schema, path) => console.log(PreservesSchema.Meta.formatModulePath(path))); I.moduleTree(Schema);
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);
}
schemaReady(); 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); window.addEventListener('DOMContentLoaded', translateScripts);
})(); })();

View File

@ -1,11 +1,11 @@
import { stringify } from '@preserves/core'; import { JsDictionary, stringify } from '@preserves/core';
import * as M from './meta'; import * as M from './meta';
export function checkSchema(schema: M.Schema): ( export function checkSchema(schema: M.Schema): (
{ ok: true, schema: M.Schema } | { ok: false, problems: Array<string> }) { ok: true, schema: M.Schema } | { ok: false, problems: Array<string> })
{ {
const checker = new Checker(); const checker = new Checker();
schema.definitions.forEach(checker.checkDefinition.bind(checker)); JsDictionary.forEach(schema.definitions, checker.checkDefinition.bind(checker));
if (checker.problems.length > 0) { if (checker.problems.length > 0) {
return { ok: false, problems: checker.problems }; return { ok: false, problems: checker.problems };
} else { } else {

View File

@ -1,4 +1,4 @@
import { encode, stringify } from "@preserves/core"; import { encode, JsDictionary, stringify } from "@preserves/core";
import * as M from "./meta"; import * as M from "./meta";
import { CompilerOptions, ModuleContext } from "./compiler/context"; import { CompilerOptions, ModuleContext } from "./compiler/context";
import { Formatter, block, seq, braces } from "./compiler/block"; import { Formatter, block, seq, braces } from "./compiler/block";
@ -29,7 +29,7 @@ export function compile(
mod.defineType(seq(`export type _embedded = `, mod.embeddedType, `;`)); 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 t = typeForDefinition(mod.resolver(), def);
const nameStr = stringify(name); const nameStr = stringify(name);
const resultTypeItem = seq(nameStr, mod.genericArgsFor(t)); 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 t = typeForDefinition(mod.resolver(), def);
const name = name0 as symbol; const name = name0 as symbol;
const nameStr = name0.description!; const nameStr = name0.description!;

View File

@ -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 { refPosition } from "../reader";
import * as M from "../meta"; import * as M from "../meta";
import { anglebrackets, block, braces, commas, formatItems, Item, keyvalue, seq } from "./block"; import { anglebrackets, block, braces, commas, formatItems, Item, keyvalue, seq } from "./block";
@ -27,11 +27,11 @@ export class ModuleContext {
readonly options: CompilerOptions; readonly options: CompilerOptions;
readonly embeddedType: Item; readonly embeddedType: Item;
readonly literals = new Dictionary<M.InputEmbedded, string>(); readonly literals = new DictionaryMap<M.InputEmbedded, string>();
readonly preamble: Item[] = []; readonly preamble: Item[] = [];
readonly typedefs: Item[] = []; readonly typedefs: Item[] = [];
readonly functiondefs: 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( constructor(
env: M.Environment, env: M.Environment,
@ -137,7 +137,7 @@ export class ModuleContext {
null, null,
null); null);
} else { } else {
const p = e.schema.definitions.get(name.name); const p = JsDictionary.get(e.schema.definitions, name.name);
if (p !== void 0) { if (p !== void 0) {
let t = () => typeForDefinition(this.resolver(soughtModule), p); let t = () => typeForDefinition(this.resolver(soughtModule), p);
if (name.module.length) { if (name.module.length) {
@ -158,7 +158,7 @@ export class ModuleContext {
} }
genericParameters(): Item { genericParameters(): Item {
return anglebrackets(seq('_embedded = ', this.embeddedType)); return anglebrackets(seq('_embedded extends _.Embeddable = ', this.embeddedType));
} }
genericParametersFor(t: Type): Item { genericParametersFor(t: Type): Item {

View File

@ -2,7 +2,7 @@ import { FunctionContext } from "./context";
import * as M from '../meta'; import * as M from '../meta';
import { Item, seq, parens, anglebrackets } from "./block"; import { Item, seq, parens, anglebrackets } from "./block";
import { simpleType, typeFor } from "./gentype"; import { simpleType, typeFor } from "./gentype";
import { ANY_TYPE, Type } from "./type"; import { ANY_TYPE, isSymbolType, Type } from "./type";
import { renderType } from "./rendertype"; import { renderType } from "./rendertype";
export function converterForDefinition( export function converterForDefinition(
@ -87,7 +87,7 @@ function converterForTuple(ctx: FunctionContext,
} }
const lengthCheck = variablePattern === void 0 const lengthCheck = variablePattern === void 0
? seq(` && ${src}.length === ${ps.length}`) ? seq(` && ${src}.length >= ${ps.length}`)
: ((ps.length === 0) ? '' : seq(` && ${src}.length >= ${ps.length}`)); : ((ps.length === 0) ? '' : seq(` && ${src}.length >= ${ps.length}`));
return knownArray return knownArray
@ -163,7 +163,7 @@ export function converterForSimple(
return [seq(`${dest} = `, test, ` ? `, valexp, ` : void 0`)]; return [seq(`${dest} = `, test, ` ? `, valexp, ` : void 0`)];
} }
case 'embedded': case 'embedded':
return [`${dest} = _.isEmbedded<_embedded>(${src}) ? ${src}.embeddedValue : void 0`]; return [`${dest} = _.isEmbedded<_embedded>(${src}) ? ${src} : void 0`];
case 'lit': case 'lit':
return [`${dest} = _.is(${src}, ${ctx.mod.literal(p.value)}) ? {} : void 0`]; return [`${dest} = _.is(${src}, ${ctx.mod.literal(p.value)}) ? {} : void 0`];
@ -192,7 +192,7 @@ export function converterForSimple(
const v = ctx.gentempname(); const v = ctx.gentempname();
return [ return [
seq(`${dest} = new _.EncodableSet`, seq(`${dest} = new _.EncodableSet`,
anglebrackets(renderType(ctx.mod, vt), '_embedded'), anglebrackets('_embedded', renderType(ctx.mod, vt)),
parens(encoderForSimplePattern(ctx, p.pattern) ?? `v => v`)), parens(encoderForSimplePattern(ctx, p.pattern) ?? `v => v`)),
seq(`for (const ${v} of ${src}) `, ctx.block(() => [ seq(`for (const ${v} of ${src}) `, ctx.block(() => [
... converterFor(ctx, M.anonymousSimplePattern(p.pattern), v, vv => ... converterFor(ctx, M.anonymousSimplePattern(p.pattern), v, vv =>
@ -203,20 +203,30 @@ export function converterForSimple(
case 'dictof': case 'dictof':
return [`${dest} = void 0`, return [`${dest} = void 0`,
seq(`if (_.Dictionary.isDictionary<_embedded>(${src})) `, ctx.block(() => { seq(`if (_.Dictionary.isDictionary<_embedded>(${src})) `, ctx.block(() => {
const srcMap = ctx.gentempname();
const resolver = ctx.mod.resolver(); const resolver = ctx.mod.resolver();
const kt = simpleType(resolver, p.key); const kt = simpleType(resolver, p.key);
const vt = simpleType(resolver, p.value); const vt = simpleType(resolver, p.value);
const k = ctx.gentempname(); const k = ctx.gentempname();
const v = ctx.gentempname(); const v = ctx.gentempname();
const symbolKeyed = isSymbolType(kt);
return [ return [
seq(`${dest} = new _.EncodableDictionary`, seq(`const ${srcMap} = new _.DictionaryMap(${src})`),
anglebrackets(renderType(ctx.mod, kt), renderType(ctx.mod, vt), '_embedded'), (symbolKeyed
parens(encoderForSimplePattern(ctx, p.key) ?? `k => k`, ? seq(`${dest} = {}`)
encoderForSimplePattern(ctx, p.value) ?? `v => v`)), : seq(`${dest} = new _.EncodableDictionary`,
seq(`for (const [${k}, ${v}] of ${src}) `, ctx.block(() => [ 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.key), k, kk =>
converterFor(ctx, M.anonymousSimplePattern(p.value), v, vv => 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(`${dest} = void 0`),
seq(`break`)]))]; seq(`break`)]))];
}))]; }))];
@ -251,12 +261,13 @@ function converterForCompound(
case 'tuplePrefix': case 'tuplePrefix':
return converterForTuple(ctx, p.fixed, src, knownArray, p.variable, ks); return converterForTuple(ctx, p.fixed, src, knownArray, p.variable, ks);
case 'dict': { case 'dict': {
const srcMap = ctx.gentempname();
const entries = Array.from(p.entries); const entries = Array.from(p.entries);
function loop(i: number): Item[] { function loop(i: number): Item[] {
if (i < entries.length) { if (i < entries.length) {
const [k, n] = entries[i]; const [k, n] = entries[i];
const tmpSrc = ctx.gentemp(); const tmpSrc = ctx.gentemp();
return [seq(`if ((${tmpSrc} = ${src}.get(${ctx.mod.literal(k)})) !== void 0) `, return [seq(`if ((${tmpSrc} = ${srcMap}.get(${ctx.mod.literal(k)})) !== void 0) `,
ctx.block(() => ctx.block(() =>
converterFor( converterFor(
ctx, ctx,
@ -267,7 +278,9 @@ function converterForCompound(
return ks(); 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: default:
((_p: never) => {})(p); ((_p: never) => {})(p);

View File

@ -46,7 +46,7 @@ function unconverterFor(ctx: FunctionContext, p: M.Pattern, src: string): Item {
case 'lit': case 'lit':
return ctx.mod.literal(p.value); return ctx.mod.literal(p.value);
case 'embedded': case 'embedded':
return `_.embed(${src})`; return `${src}`;
case 'seqof': case 'seqof':
return seq(`${src}.map(v => `, return seq(`${src}.map(v => `,
unconverterFor(ctx, M.Pattern.SimplePattern(p.pattern), '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'), unconverterFor(ctx, M.Pattern.SimplePattern(p.pattern), 'v'),
`)`))); `)`)));
case 'dictof': case 'dictof':
return seq(`new _.Dictionary<_embedded>`, parens(seq( return seq(`_.Dictionary.from<_embedded>`, parens(seq(
`_.Array.from(${src}.entries()).map(([k, v]) => `, `_.Array.from(`,
M.isSymbolPattern(p.key) ? `_.JsDictionary.entries(${src})` : `${src}.entries()`,
`).map(([k, v]) => `,
brackets( brackets(
unconverterFor(ctx, M.Pattern.SimplePattern(p.key), 'k'), unconverterFor(ctx, M.Pattern.SimplePattern(p.key), 'k'),
unconverterFor(ctx, M.Pattern.SimplePattern(p.value), 'v')), unconverterFor(ctx, M.Pattern.SimplePattern(p.value), 'v')),
@ -95,7 +97,7 @@ function unconverterFor(ctx: FunctionContext, p: M.Pattern, src: string): Item {
} }
} }
case 'dict': case 'dict':
return seq(`new _.Dictionary<_embedded>`, parens( return seq(`_.Dictionary.from<_embedded>`, parens(
brackets(... Array.from(p.entries.entries()).map(([k, n]) => brackets(... Array.from(p.entries.entries()).map(([k, n]) =>
brackets( brackets(
ctx.mod.literal(k), ctx.mod.literal(k),

View File

@ -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 { anglebrackets, braces, Item, keyvalue, opseq, seq } from "./block";
import { ModuleContext } from "./context"; import { ModuleContext } from "./context";
@ -47,12 +47,17 @@ export function renderType(ctxt: ModuleContext, t: Type): Item {
return seq(t.typeName, ctxt.genericArgsFor(t)); return seq(t.typeName, ctxt.genericArgsFor(t));
} }
case 'set': return seq('_.EncodableSet', anglebrackets( case 'set': return seq('_.EncodableSet', anglebrackets(
renderType(ctxt, t.type), '_embedded',
'_embedded')); renderType(ctxt, t.type)));
case 'dictionary': return seq('_.EncodableDictionary', anglebrackets( case 'dictionary':
renderType(ctxt, t.key), if (isSymbolType(t.key)) {
renderType(ctxt, t.value), return seq('_.JsDictionary', anglebrackets(renderType(ctxt, t.value)));
'_embedded')); } 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 'array': return seq('Array', anglebrackets(renderType(ctxt, t.type)));
case 'record': return braces(... simpleTypeFields(ctxt, t)); case 'record': return braces(... simpleTypeFields(ctxt, t));
default: default:

View File

@ -35,3 +35,7 @@ export namespace Type {
} }
export const ANY_TYPE: FieldType = Type.ref('_.Value', null); 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;
}

View File

@ -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 { brackets, Item, parens, seq } from "./block";
import * as M from '../meta'; 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 { set(s: Set<M.InputEmbedded>, k: Fold<M.InputEmbedded, Item>): Item {
return seq('new _.Set<_.Value<_embedded>>', parens(brackets(... Array.from(s).map(k)))); return seq('new _.Set<_.Value<_embedded>>', parens(brackets(... Array.from(s).map(k))));
}, },
dictionary(d: Dictionary<M.InputEmbedded>, k: Fold<M.InputEmbedded, Item>): Item { dictionary(d: DictionaryMap<M.InputEmbedded>, k: Fold<M.InputEmbedded, Item>): Item {
return seq('new _.Dictionary<_embedded>', parens(brackets(... Array.from(d).map(([kk,vv]) => return seq('_.Dictionary.from<_embedded>', parens(brackets(... Array.from(d).map(([kk,vv]) =>
brackets(k(kk), k(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))); 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)}`); throw new Error(`Cannot emit source code for construction of embedded ${stringify(t)}`);
}, },
}); });

View File

@ -30,14 +30,18 @@ export type Definition = (
) & ) &
_.Preservable<any> & _.Preservable<any> &
_.PreserveWritable<any> & _.PreserveWritable<any> &
{__as_preserve__<_embedded = _.GenericEmbedded>(): _.Value<_embedded>} {
__as_preserve__<_embedded extends _.Embeddable = _.GenericEmbedded>(): _.Value<_embedded>
}
); );
export type Variant = ( export type Variant = (
{"label": symbol, "type": Simple} & {"label": symbol, "type": Simple} &
_.Preservable<any> & _.Preservable<any> &
_.PreserveWritable<any> & _.PreserveWritable<any> &
{__as_preserve__<_embedded = _.GenericEmbedded>(): _.Value<_embedded>} {
__as_preserve__<_embedded extends _.Embeddable = _.GenericEmbedded>(): _.Value<_embedded>
}
); );
export type Simple = ( export type Simple = (
@ -47,21 +51,27 @@ export type Simple = (
) & ) &
_.Preservable<any> & _.Preservable<any> &
_.PreserveWritable<any> & _.PreserveWritable<any> &
{__as_preserve__<_embedded = _.GenericEmbedded>(): _.Value<_embedded>} {
__as_preserve__<_embedded extends _.Embeddable = _.GenericEmbedded>(): _.Value<_embedded>
}
); );
export type Record = ( export type Record = (
{"fields": Array<NamedField>} & {"fields": Array<NamedField>} &
_.Preservable<any> & _.Preservable<any> &
_.PreserveWritable<any> & _.PreserveWritable<any> &
{__as_preserve__<_embedded = _.GenericEmbedded>(): _.Value<_embedded>} {
__as_preserve__<_embedded extends _.Embeddable = _.GenericEmbedded>(): _.Value<_embedded>
}
); );
export type NamedField = ( export type NamedField = (
{"name": symbol, "type": Field} & {"name": symbol, "type": Field} &
_.Preservable<any> & _.Preservable<any> &
_.PreserveWritable<any> & _.PreserveWritable<any> &
{__as_preserve__<_embedded = _.GenericEmbedded>(): _.Value<_embedded>} {
__as_preserve__<_embedded extends _.Embeddable = _.GenericEmbedded>(): _.Value<_embedded>
}
); );
export type Field = ( export type Field = (
@ -77,7 +87,9 @@ export type Field = (
) & ) &
_.Preservable<any> & _.Preservable<any> &
_.PreserveWritable<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); let result = toDefinition(v);
if (result === void 0) throw new TypeError(`Invalid Definition: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid Definition: ${_.stringify(v)}`);
return result; 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; let result: undefined | Definition;
if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) { if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) {
let _tmp0: ({}) | undefined; let _tmp0: ({}) | undefined;
@ -390,22 +402,22 @@ export function toDefinition<_embedded = _.GenericEmbedded>(v: _.Value<_embedded
export namespace Definition {export const __from_preserve__ = toDefinition;} 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) { switch (_v._variant) {
case "union": {return _.Record($union, [_v["variants"].map(v => fromVariant<_embedded>(v))]);}; case "union": {return _.Record($union, [_v["variants"].map(v => fromVariant<_embedded>(v))]);};
case "Simple": {return fromSimple<_embedded>(_v.value);}; 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); let result = toVariant(v);
if (result === void 0) throw new TypeError(`Invalid Variant: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid Variant: ${_.stringify(v)}`);
return result; 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; let result: undefined | Variant;
if (_.isSequence(v) && v.length === 2) { if (_.isSequence(v) && v.length >= 2) {
let _tmp0: (symbol) | undefined; let _tmp0: (symbol) | undefined;
_tmp0 = typeof v[0] === 'symbol' ? v[0] : void 0; _tmp0 = typeof v[0] === 'symbol' ? v[0] : void 0;
if (_tmp0 !== void 0) { if (_tmp0 !== void 0) {
@ -427,15 +439,15 @@ export function toVariant<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>):
Variant.__from_preserve__ = toVariant; 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); let result = toSimple(v);
if (result === void 0) throw new TypeError(`Invalid Simple: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid Simple: ${_.stringify(v)}`);
return result; 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 _tmp0: (Field) | undefined;
let result: undefined | Simple; let result: undefined | Simple;
_tmp0 = toField(v); _tmp0 = toField(v);
@ -466,20 +478,20 @@ export function toSimple<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>):
export namespace Simple {export const __from_preserve__ = toSimple;} 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) { switch (_v._variant) {
case "Field": {return fromField<_embedded>(_v.value);}; case "Field": {return fromField<_embedded>(_v.value);};
case "Record": {return fromRecord<_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); let result = toRecord(v);
if (result === void 0) throw new TypeError(`Invalid Record: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid Record: ${_.stringify(v)}`);
return result; 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; let result: undefined | Record;
if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) { if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) {
let _tmp0: ({}) | undefined; let _tmp0: ({}) | undefined;
@ -512,17 +524,17 @@ export function toRecord<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>):
Record.__from_preserve__ = toRecord; 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); let result = toNamedField(v);
if (result === void 0) throw new TypeError(`Invalid NamedField: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid NamedField: ${_.stringify(v)}`);
return result; 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; let result: undefined | NamedField;
if (_.isSequence(v) && v.length === 2) { if (_.isSequence(v) && v.length >= 2) {
let _tmp0: (symbol) | undefined; let _tmp0: (symbol) | undefined;
_tmp0 = typeof v[0] === 'symbol' ? v[0] : void 0; _tmp0 = typeof v[0] === 'symbol' ? v[0] : void 0;
if (_tmp0 !== void 0) { if (_tmp0 !== void 0) {
@ -544,15 +556,15 @@ export function toNamedField<_embedded = _.GenericEmbedded>(v: _.Value<_embedded
NamedField.__from_preserve__ = toNamedField; 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); let result = toField(v);
if (result === void 0) throw new TypeError(`Invalid Field: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid Field: ${_.stringify(v)}`);
return result; 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 _tmp0: ({}) | undefined;
let result: undefined | Field; let result: undefined | Field;
_tmp0 = _.is(v, $unit) ? {} : void 0; _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 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) { switch (_v._variant) {
case "unit": {return $unit;}; case "unit": {return $unit;};
case "any": {return $any;}; case "any": {return $any;};

View File

@ -41,16 +41,16 @@ export function _schema() {
export const _imports = {} export const _imports = {}
export type Bundle<_embedded = _.GenericEmbedded> = ( export type Bundle<_embedded extends _.Embeddable = _.GenericEmbedded> = (
{"modules": Modules<_embedded>} & {"modules": Modules<_embedded>} &
_.Preservable<_embedded> & _.Preservable<_embedded> &
_.PreserveWritable<_embedded> & _.PreserveWritable<_embedded> &
{__as_preserve__(): _.Value<_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, "version": Version,
"embeddedType": EmbeddedTypeName, "embeddedType": EmbeddedTypeName,
@ -65,19 +65,23 @@ export type Version = (
{} & {} &
_.Preservable<any> & _.Preservable<any> &
_.PreserveWritable<any> & _.PreserveWritable<any> &
{__as_preserve__<_embedded = _.GenericEmbedded>(): _.Value<_embedded>} {
__as_preserve__<_embedded extends _.Embeddable = _.GenericEmbedded>(): _.Value<_embedded>
}
); );
export type EmbeddedTypeName = ( export type EmbeddedTypeName = (
({"_variant": "false"} | {"_variant": "Ref", "value": Ref}) & ({"_variant": "false"} | {"_variant": "Ref", "value": Ref}) &
_.Preservable<any> & _.Preservable<any> &
_.PreserveWritable<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", "_variant": "or",
@ -98,7 +102,7 @@ export type Definition<_embedded = _.GenericEmbedded> = (
{__as_preserve__(): _.Value<_embedded>} {__as_preserve__(): _.Value<_embedded>}
); );
export type Pattern<_embedded = _.GenericEmbedded> = ( export type Pattern<_embedded extends _.Embeddable = _.GenericEmbedded> = (
( (
{"_variant": "SimplePattern", "value": SimplePattern<_embedded>} | {"_variant": "SimplePattern", "value": SimplePattern<_embedded>} |
{"_variant": "CompoundPattern", "value": CompoundPattern<_embedded>} {"_variant": "CompoundPattern", "value": CompoundPattern<_embedded>}
@ -108,7 +112,7 @@ export type Pattern<_embedded = _.GenericEmbedded> = (
{__as_preserve__(): _.Value<_embedded>} {__as_preserve__(): _.Value<_embedded>}
); );
export type SimplePattern<_embedded = _.GenericEmbedded> = ( export type SimplePattern<_embedded extends _.Embeddable = _.GenericEmbedded> = (
( (
{"_variant": "any"} | {"_variant": "any"} |
{"_variant": "atom", "atomKind": AtomKind} | {"_variant": "atom", "atomKind": AtomKind} |
@ -128,7 +132,7 @@ export type SimplePattern<_embedded = _.GenericEmbedded> = (
{__as_preserve__(): _.Value<_embedded>} {__as_preserve__(): _.Value<_embedded>}
); );
export type CompoundPattern<_embedded = _.GenericEmbedded> = ( export type CompoundPattern<_embedded extends _.Embeddable = _.GenericEmbedded> = (
( (
{ {
"_variant": "rec", "_variant": "rec",
@ -148,7 +152,7 @@ export type CompoundPattern<_embedded = _.GenericEmbedded> = (
{__as_preserve__(): _.Value<_embedded>} {__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 = ( export type AtomKind = (
( (
@ -161,17 +165,19 @@ export type AtomKind = (
) & ) &
_.Preservable<any> & _.Preservable<any> &
_.PreserveWritable<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>} & {"variantLabel": string, "pattern": Pattern<_embedded>} &
_.Preservable<_embedded> & _.Preservable<_embedded> &
_.PreserveWritable<_embedded> & _.PreserveWritable<_embedded> &
{__as_preserve__(): _.Value<_embedded>} {__as_preserve__(): _.Value<_embedded>}
); );
export type NamedSimplePattern<_embedded = _.GenericEmbedded> = ( export type NamedSimplePattern<_embedded extends _.Embeddable = _.GenericEmbedded> = (
( (
{"_variant": "named", "value": Binding<_embedded>} | {"_variant": "named", "value": Binding<_embedded>} |
{"_variant": "anonymous", "value": SimplePattern<_embedded>} {"_variant": "anonymous", "value": SimplePattern<_embedded>}
@ -181,7 +187,7 @@ export type NamedSimplePattern<_embedded = _.GenericEmbedded> = (
{__as_preserve__(): _.Value<_embedded>} {__as_preserve__(): _.Value<_embedded>}
); );
export type NamedPattern<_embedded = _.GenericEmbedded> = ( export type NamedPattern<_embedded extends _.Embeddable = _.GenericEmbedded> = (
( (
{"_variant": "named", "value": Binding<_embedded>} | {"_variant": "named", "value": Binding<_embedded>} |
{"_variant": "anonymous", "value": Pattern<_embedded>} {"_variant": "anonymous", "value": Pattern<_embedded>}
@ -191,7 +197,7 @@ export type NamedPattern<_embedded = _.GenericEmbedded> = (
{__as_preserve__(): _.Value<_embedded>} {__as_preserve__(): _.Value<_embedded>}
); );
export type Binding<_embedded = _.GenericEmbedded> = ( export type Binding<_embedded extends _.Embeddable = _.GenericEmbedded> = (
{"name": symbol, "pattern": SimplePattern<_embedded>} & {"name": symbol, "pattern": SimplePattern<_embedded>} &
_.Preservable<_embedded> & _.Preservable<_embedded> &
_.PreserveWritable<_embedded> & _.PreserveWritable<_embedded> &
@ -202,13 +208,15 @@ export type Ref = (
{"module": ModulePath, "name": symbol} & {"module": ModulePath, "name": symbol} &
_.Preservable<any> & _.Preservable<any> &
_.PreserveWritable<any> & _.PreserveWritable<any> &
{__as_preserve__<_embedded = _.GenericEmbedded>(): _.Value<_embedded>} {
__as_preserve__<_embedded extends _.Embeddable = _.GenericEmbedded>(): _.Value<_embedded>
}
); );
export type ModulePath = Array<symbol>; 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 { return {
"modules": modules, "modules": modules,
__as_preserve__() {return fromBundle(this);}, __as_preserve__() {return fromBundle(this);},
@ -221,13 +229,13 @@ Bundle.schema = function () {
return {schema: _schema(), imports: _imports, definitionName: _.Symbol.for("Bundle")}; 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 () { Modules.schema = function () {
return {schema: _schema(), imports: _imports, definitionName: _.Symbol.for("Modules")}; 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, embeddedType, definitions}: {
version: Version, version: Version,
embeddedType: EmbeddedTypeName, 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 () { Definitions.schema = function () {
return { return {
@ -307,7 +315,7 @@ Definitions.schema = function () {
} }
export namespace Definition { export namespace Definition {
export function or<_embedded = _.GenericEmbedded>( export function or<_embedded extends _.Embeddable = _.GenericEmbedded>(
{pattern0, pattern1, patternN}: { {pattern0, pattern1, patternN}: {
pattern0: NamedAlternative<_embedded>, pattern0: NamedAlternative<_embedded>,
pattern1: NamedAlternative<_embedded>, pattern1: NamedAlternative<_embedded>,
@ -332,7 +340,7 @@ export namespace Definition {
variant: _.Symbol.for("or") variant: _.Symbol.for("or")
}; };
}; };
export function and<_embedded = _.GenericEmbedded>( export function and<_embedded extends _.Embeddable = _.GenericEmbedded>(
{pattern0, pattern1, patternN}: { {pattern0, pattern1, patternN}: {
pattern0: NamedPattern<_embedded>, pattern0: NamedPattern<_embedded>,
pattern1: NamedPattern<_embedded>, pattern1: NamedPattern<_embedded>,
@ -357,7 +365,7 @@ export namespace Definition {
variant: _.Symbol.for("and") 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 { return {
"_variant": "Pattern", "_variant": "Pattern",
"value": value, "value": value,
@ -377,7 +385,7 @@ export namespace Definition {
} }
export namespace Pattern { 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 { return {
"_variant": "SimplePattern", "_variant": "SimplePattern",
"value": value, "value": value,
@ -394,7 +402,7 @@ export namespace Pattern {
variant: _.Symbol.for("SimplePattern") 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 { return {
"_variant": "CompoundPattern", "_variant": "CompoundPattern",
"value": value, "value": value,
@ -414,7 +422,7 @@ export namespace Pattern {
} }
export namespace SimplePattern { export namespace SimplePattern {
export function any<_embedded = _.GenericEmbedded>(): SimplePattern<_embedded> { export function any<_embedded extends _.Embeddable = _.GenericEmbedded>(): SimplePattern<_embedded> {
return { return {
"_variant": "any", "_variant": "any",
__as_preserve__() {return fromSimplePattern(this);}, __as_preserve__() {return fromSimplePattern(this);},
@ -430,7 +438,7 @@ export namespace SimplePattern {
variant: _.Symbol.for("any") 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 { return {
"_variant": "atom", "_variant": "atom",
"atomKind": atomKind, "atomKind": atomKind,
@ -447,7 +455,7 @@ export namespace SimplePattern {
variant: _.Symbol.for("atom") 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 { return {
"_variant": "embedded", "_variant": "embedded",
"interface": $interface, "interface": $interface,
@ -464,7 +472,7 @@ export namespace SimplePattern {
variant: _.Symbol.for("embedded") 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 { return {
"_variant": "lit", "_variant": "lit",
"value": value, "value": value,
@ -481,7 +489,7 @@ export namespace SimplePattern {
variant: _.Symbol.for("lit") 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 { return {
"_variant": "seqof", "_variant": "seqof",
"pattern": pattern, "pattern": pattern,
@ -498,7 +506,7 @@ export namespace SimplePattern {
variant: _.Symbol.for("seqof") 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 { return {
"_variant": "setof", "_variant": "setof",
"pattern": pattern, "pattern": pattern,
@ -515,7 +523,7 @@ export namespace SimplePattern {
variant: _.Symbol.for("setof") 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 { return {
"_variant": "dictof", "_variant": "dictof",
"key": key, "key": key,
@ -533,7 +541,7 @@ export namespace SimplePattern {
variant: _.Symbol.for("dictof") 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 { return {
"_variant": "Ref", "_variant": "Ref",
"value": value, "value": value,
@ -553,7 +561,7 @@ export namespace SimplePattern {
} }
export namespace CompoundPattern { export namespace CompoundPattern {
export function rec<_embedded = _.GenericEmbedded>( export function rec<_embedded extends _.Embeddable = _.GenericEmbedded>(
{label, fields}: {label: NamedPattern<_embedded>, fields: NamedPattern<_embedded>} {label, fields}: {label: NamedPattern<_embedded>, fields: NamedPattern<_embedded>}
): CompoundPattern<_embedded> { ): CompoundPattern<_embedded> {
return { return {
@ -573,7 +581,7 @@ export namespace CompoundPattern {
variant: _.Symbol.for("rec") 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 { return {
"_variant": "tuple", "_variant": "tuple",
"patterns": patterns, "patterns": patterns,
@ -590,7 +598,7 @@ export namespace CompoundPattern {
variant: _.Symbol.for("tuple") 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>} {fixed, variable}: {fixed: Array<NamedPattern<_embedded>>, variable: NamedSimplePattern<_embedded>}
): CompoundPattern<_embedded> { ): CompoundPattern<_embedded> {
return { return {
@ -610,7 +618,7 @@ export namespace CompoundPattern {
variant: _.Symbol.for("tuplePrefix") 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 { return {
"_variant": "dict", "_variant": "dict",
"entries": entries, "entries": entries,
@ -629,8 +637,8 @@ export namespace CompoundPattern {
}; };
} }
export function DictionaryEntries<_embedded = _.GenericEmbedded>( export function DictionaryEntries<_embedded extends _.Embeddable = _.GenericEmbedded>(
value: _.EncodableDictionary<_.Value<_embedded>, NamedSimplePattern<_embedded>, _embedded> value: _.EncodableDictionary<_embedded, _.Value<_embedded>, NamedSimplePattern<_embedded>>
): DictionaryEntries<_embedded> {return value;} ): DictionaryEntries<_embedded> {return value;}
DictionaryEntries.schema = function () { 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 { return {
"variantLabel": variantLabel, "variantLabel": variantLabel,
"pattern": pattern, "pattern": pattern,
@ -759,7 +767,7 @@ NamedAlternative.schema = function () {
} }
export namespace NamedSimplePattern { 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 { return {
"_variant": "named", "_variant": "named",
"value": value, "value": value,
@ -776,7 +784,7 @@ export namespace NamedSimplePattern {
variant: _.Symbol.for("named") 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 { return {
"_variant": "anonymous", "_variant": "anonymous",
"value": value, "value": value,
@ -796,7 +804,7 @@ export namespace NamedSimplePattern {
} }
export namespace NamedPattern { 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 { return {
"_variant": "named", "_variant": "named",
"value": value, "value": value,
@ -813,7 +821,7 @@ export namespace NamedPattern {
variant: _.Symbol.for("named") 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 { return {
"_variant": "anonymous", "_variant": "anonymous",
"value": value, "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 { return {
"name": name, "name": name,
"pattern": pattern, "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); let result = toBundle(v);
if (result === void 0) throw new TypeError(`Invalid Bundle: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid Bundle: ${_.stringify(v)}`);
return result; 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>; let result: undefined | Bundle<_embedded>;
if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) { if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) {
let _tmp0: ({}) | undefined; let _tmp0: ({}) | undefined;
@ -899,27 +907,28 @@ export function toBundle<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>):
Bundle.__from_preserve__ = toBundle; 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); let result = toModules(v);
if (result === void 0) throw new TypeError(`Invalid Modules: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid Modules: ${_.stringify(v)}`);
return result; return result;
} }
export function toModules<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Modules<_embedded> { export function toModules<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Modules<_embedded> {
let _tmp0: (_.EncodableDictionary<ModulePath, Schema<_embedded>, _embedded>) | undefined; let _tmp0: (_.EncodableDictionary<_embedded, ModulePath, Schema<_embedded>>) | undefined;
let result: undefined | Modules<_embedded>; let result: undefined | Modules<_embedded>;
_tmp0 = void 0; _tmp0 = void 0;
if (_.Dictionary.isDictionary<_embedded>(v)) { if (_.Dictionary.isDictionary<_embedded>(v)) {
_tmp0 = new _.EncodableDictionary<ModulePath, Schema<_embedded>, _embedded>(fromModulePath, fromSchema<_embedded>); const _tmp1 = new _.DictionaryMap(v);
for (const [_tmp1, _tmp2] of v) { _tmp0 = new _.EncodableDictionary<_embedded, ModulePath, Schema<_embedded>>(fromModulePath, fromSchema<_embedded>);
let _tmp3: (ModulePath) | undefined; for (const [_tmp2, _tmp3] of _tmp1) {
_tmp3 = toModulePath(_tmp1); let _tmp4: (ModulePath) | undefined;
if (_tmp3 !== void 0) { _tmp4 = toModulePath(_tmp2);
let _tmp4: (Schema<_embedded>) | undefined; if (_tmp4 !== void 0) {
_tmp4 = toSchema(_tmp2); let _tmp5: (Schema<_embedded>) | undefined;
if (_tmp4 !== void 0) {_tmp0.set(_tmp3, _tmp4); continue;}; _tmp5 = toSchema(_tmp3);
if (_tmp5 !== void 0) {_tmp0.set(_tmp4, _tmp5); continue;};
}; };
_tmp0 = void 0; _tmp0 = void 0;
break; break;
@ -931,44 +940,45 @@ export function toModules<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>):
Modules.__from_preserve__ = toModules; Modules.__from_preserve__ = toModules;
export function fromModules<_embedded = _.GenericEmbedded>(_v: Modules<_embedded>): _.Value<_embedded> { export function fromModules<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: Modules<_embedded>): _.Value<_embedded> {
return new _.Dictionary<_embedded>( return _.Dictionary.from<_embedded>(
_.Array.from(_v.entries()).map(([k, v]) => [fromModulePath<_embedded>(k), fromSchema<_embedded>(v)]) _.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); let result = toSchema(v);
if (result === void 0) throw new TypeError(`Invalid Schema: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid Schema: ${_.stringify(v)}`);
return result; 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>; let result: undefined | Schema<_embedded>;
if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) { if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) {
let _tmp0: ({}) | undefined; let _tmp0: ({}) | undefined;
_tmp0 = _.is(v.label, $schema) ? {} : void 0; _tmp0 = _.is(v.label, $schema) ? {} : void 0;
if (_tmp0 !== void 0) { if (_tmp0 !== void 0) {
if (_.Dictionary.isDictionary<_embedded>(v[0])) { if (_.Dictionary.isDictionary<_embedded>(v[0])) {
let _tmp1: (_.Value<_embedded>) | undefined; let _tmp2: (_.Value<_embedded>) | undefined;
if ((_tmp1 = v[0].get($version)) !== void 0) { const _tmp1 = new _.DictionaryMap(v[0]);
let _tmp2: (Version) | undefined; if ((_tmp2 = _tmp1.get($version)) !== void 0) {
_tmp2 = toVersion(_tmp1); let _tmp3: (Version) | undefined;
if (_tmp2 !== void 0) { _tmp3 = toVersion(_tmp2);
let _tmp3: (_.Value<_embedded>) | undefined; if (_tmp3 !== void 0) {
if ((_tmp3 = v[0].get($embeddedType)) !== void 0) { let _tmp4: (_.Value<_embedded>) | undefined;
let _tmp4: (EmbeddedTypeName) | undefined; if ((_tmp4 = _tmp1.get($embeddedType)) !== void 0) {
_tmp4 = toEmbeddedTypeName(_tmp3); let _tmp5: (EmbeddedTypeName) | undefined;
if (_tmp4 !== void 0) { _tmp5 = toEmbeddedTypeName(_tmp4);
let _tmp5: (_.Value<_embedded>) | undefined; if (_tmp5 !== void 0) {
if ((_tmp5 = v[0].get($definitions)) !== void 0) { let _tmp6: (_.Value<_embedded>) | undefined;
let _tmp6: (Definitions<_embedded>) | undefined; if ((_tmp6 = _tmp1.get($definitions)) !== void 0) {
_tmp6 = toDefinitions(_tmp5); let _tmp7: (Definitions<_embedded>) | undefined;
if (_tmp6 !== void 0) { _tmp7 = toDefinitions(_tmp6);
if (_tmp7 !== void 0) {
result = { result = {
"version": _tmp2, "version": _tmp3,
"embeddedType": _tmp4, "embeddedType": _tmp5,
"definitions": _tmp6, "definitions": _tmp7,
__as_preserve__() {return fromSchema(this);}, __as_preserve__() {return fromSchema(this);},
__preserve_on__(e) { e.push(fromSchema(this)); }, __preserve_on__(e) { e.push(fromSchema(this)); },
__preserve_text_on__(w) { w.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; 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( return _.Record(
$schema, $schema,
[ [
new _.Dictionary<_embedded>( _.Dictionary.from<_embedded>(
[ [
[$version, fromVersion<_embedded>(_v["version"])], [$version, fromVersion<_embedded>(_v["version"])],
[$embeddedType, fromEmbeddedTypeName<_embedded>(_v["embeddedType"])], [$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); let result = toVersion(v);
if (result === void 0) throw new TypeError(`Invalid Version: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid Version: ${_.stringify(v)}`);
return result; 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 _tmp0: ({}) | undefined;
let result: undefined | Version; let result: undefined | Version;
_tmp0 = _.is(v, $1) ? {} : void 0; _tmp0 = _.is(v, $1) ? {} : void 0;
@ -1024,15 +1034,15 @@ export function toVersion<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>):
Version.__from_preserve__ = toVersion; 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); let result = toEmbeddedTypeName(v);
if (result === void 0) throw new TypeError(`Invalid EmbeddedTypeName: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid EmbeddedTypeName: ${_.stringify(v)}`);
return result; 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 _tmp0: ({}) | undefined;
let result: undefined | EmbeddedTypeName; let result: undefined | EmbeddedTypeName;
_tmp0 = _.is(v, __lit6) ? {} : void 0; _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 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) { switch (_v._variant) {
case "false": {return __lit6;}; case "false": {return __lit6;};
case "Ref": {return fromRef<_embedded>(_v.value);}; 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); let result = toDefinitions(v);
if (result === void 0) throw new TypeError(`Invalid Definitions: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid Definitions: ${_.stringify(v)}`);
return result; return result;
} }
export function toDefinitions<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Definitions<_embedded> { export function toDefinitions<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | Definitions<_embedded> {
let _tmp0: (_.EncodableDictionary<symbol, Definition<_embedded>, _embedded>) | undefined; let _tmp0: (_.JsDictionary<Definition<_embedded>>) | undefined;
let result: undefined | Definitions<_embedded>; let result: undefined | Definitions<_embedded>;
_tmp0 = void 0; _tmp0 = void 0;
if (_.Dictionary.isDictionary<_embedded>(v)) { if (_.Dictionary.isDictionary<_embedded>(v)) {
_tmp0 = new _.EncodableDictionary<symbol, Definition<_embedded>, _embedded>(k => k, fromDefinition<_embedded>); const _tmp1 = new _.DictionaryMap(v);
for (const [_tmp1, _tmp2] of v) { _tmp0 = {};
let _tmp3: (symbol) | undefined; for (const [_tmp2, _tmp3] of _tmp1) {
_tmp3 = typeof _tmp1 === 'symbol' ? _tmp1 : void 0; let _tmp4: (symbol) | undefined;
if (_tmp3 !== void 0) { _tmp4 = typeof _tmp2 === 'symbol' ? _tmp2 : void 0;
let _tmp4: (Definition<_embedded>) | undefined; if (_tmp4 !== void 0) {
_tmp4 = toDefinition(_tmp2); let _tmp5: (Definition<_embedded>) | undefined;
if (_tmp4 !== void 0) {_tmp0.set(_tmp3, _tmp4); continue;}; _tmp5 = toDefinition(_tmp3);
if (_tmp5 !== void 0) {_tmp0[_tmp4.description!] = _tmp5; continue;};
}; };
_tmp0 = void 0; _tmp0 = void 0;
break; break;
@ -1099,17 +1110,19 @@ export function toDefinitions<_embedded = _.GenericEmbedded>(v: _.Value<_embedde
Definitions.__from_preserve__ = toDefinitions; Definitions.__from_preserve__ = toDefinitions;
export function fromDefinitions<_embedded = _.GenericEmbedded>(_v: Definitions<_embedded>): _.Value<_embedded> { export function fromDefinitions<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: Definitions<_embedded>): _.Value<_embedded> {
return new _.Dictionary<_embedded>(_.Array.from(_v.entries()).map(([k, v]) => [k, fromDefinition<_embedded>(v)])); 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); let result = toDefinition(v);
if (result === void 0) throw new TypeError(`Invalid Definition: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid Definition: ${_.stringify(v)}`);
return result; 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>; let result: undefined | Definition<_embedded>;
if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) { if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) {
let _tmp0: ({}) | undefined; let _tmp0: ({}) | undefined;
@ -1207,7 +1220,7 @@ export function toDefinition<_embedded = _.GenericEmbedded>(v: _.Value<_embedded
export namespace Definition {export const __from_preserve__ = toDefinition;} 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) { switch (_v._variant) {
case "or": { case "or": {
return _.Record( 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); let result = toPattern(v);
if (result === void 0) throw new TypeError(`Invalid Pattern: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid Pattern: ${_.stringify(v)}`);
return result; 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 _tmp0: (SimplePattern<_embedded>) | undefined;
let result: undefined | Pattern<_embedded>; let result: undefined | Pattern<_embedded>;
_tmp0 = toSimplePattern(v); _tmp0 = toSimplePattern(v);
@ -1274,20 +1287,20 @@ export function toPattern<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>):
export namespace Pattern {export const __from_preserve__ = toPattern;} 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) { switch (_v._variant) {
case "SimplePattern": {return fromSimplePattern<_embedded>(_v.value);}; case "SimplePattern": {return fromSimplePattern<_embedded>(_v.value);};
case "CompoundPattern": {return fromCompoundPattern<_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); let result = toSimplePattern(v);
if (result === void 0) throw new TypeError(`Invalid SimplePattern: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid SimplePattern: ${_.stringify(v)}`);
return result; 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 _tmp0: ({}) | undefined;
let result: undefined | SimplePattern<_embedded>; let result: undefined | SimplePattern<_embedded>;
_tmp0 = _.is(v, $any) ? {} : void 0; _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 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) { switch (_v._variant) {
case "any": {return $any;}; case "any": {return $any;};
case "atom": {return _.Record($atom, [fromAtomKind<_embedded>(_v["atomKind"])]);}; 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); let result = toCompoundPattern(v);
if (result === void 0) throw new TypeError(`Invalid CompoundPattern: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid CompoundPattern: ${_.stringify(v)}`);
return result; 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>; let result: undefined | CompoundPattern<_embedded>;
if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) { if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) {
let _tmp0: ({}) | undefined; let _tmp0: ({}) | undefined;
@ -1574,7 +1587,7 @@ export function toCompoundPattern<_embedded = _.GenericEmbedded>(v: _.Value<_emb
export namespace CompoundPattern {export const __from_preserve__ = toCompoundPattern;} 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) { switch (_v._variant) {
case "rec": { case "rec": {
return _.Record( 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); let result = toDictionaryEntries(v);
if (result === void 0) throw new TypeError(`Invalid DictionaryEntries: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid DictionaryEntries: ${_.stringify(v)}`);
return result; return result;
} }
export function toDictionaryEntries<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | DictionaryEntries<_embedded> { export function toDictionaryEntries<_embedded extends _.Embeddable = _.GenericEmbedded>(v: _.Value<_embedded>): undefined | DictionaryEntries<_embedded> {
let _tmp0: (_.EncodableDictionary<_.Value<_embedded>, NamedSimplePattern<_embedded>, _embedded>) | undefined; let _tmp0: (_.EncodableDictionary<_embedded, _.Value<_embedded>, NamedSimplePattern<_embedded>>) | undefined;
let result: undefined | DictionaryEntries<_embedded>; let result: undefined | DictionaryEntries<_embedded>;
_tmp0 = void 0; _tmp0 = void 0;
if (_.Dictionary.isDictionary<_embedded>(v)) { if (_.Dictionary.isDictionary<_embedded>(v)) {
_tmp0 = new _.EncodableDictionary<_.Value<_embedded>, NamedSimplePattern<_embedded>, _embedded>(k => k, fromNamedSimplePattern<_embedded>); const _tmp1 = new _.DictionaryMap(v);
for (const [_tmp1, _tmp2] of v) { _tmp0 = new _.EncodableDictionary<_embedded, _.Value<_embedded>, NamedSimplePattern<_embedded>>(k => k, fromNamedSimplePattern<_embedded>);
let _tmp3: (_.Value<_embedded>) | undefined; for (const [_tmp2, _tmp3] of _tmp1) {
_tmp3 = _tmp1; let _tmp4: (_.Value<_embedded>) | undefined;
if (_tmp3 !== void 0) { _tmp4 = _tmp2;
let _tmp4: (NamedSimplePattern<_embedded>) | undefined; if (_tmp4 !== void 0) {
_tmp4 = toNamedSimplePattern(_tmp2); let _tmp5: (NamedSimplePattern<_embedded>) | undefined;
if (_tmp4 !== void 0) {_tmp0.set(_tmp3, _tmp4); continue;}; _tmp5 = toNamedSimplePattern(_tmp3);
if (_tmp5 !== void 0) {_tmp0.set(_tmp4, _tmp5); continue;};
}; };
_tmp0 = void 0; _tmp0 = void 0;
break; break;
@ -1631,19 +1645,19 @@ export function toDictionaryEntries<_embedded = _.GenericEmbedded>(v: _.Value<_e
DictionaryEntries.__from_preserve__ = toDictionaryEntries; DictionaryEntries.__from_preserve__ = toDictionaryEntries;
export function fromDictionaryEntries<_embedded = _.GenericEmbedded>(_v: DictionaryEntries<_embedded>): _.Value<_embedded> { export function fromDictionaryEntries<_embedded extends _.Embeddable = _.GenericEmbedded>(_v: DictionaryEntries<_embedded>): _.Value<_embedded> {
return new _.Dictionary<_embedded>( return _.Dictionary.from<_embedded>(
_.Array.from(_v.entries()).map(([k, v]) => [k, fromNamedSimplePattern<_embedded>(v)]) _.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); let result = toAtomKind(v);
if (result === void 0) throw new TypeError(`Invalid AtomKind: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid AtomKind: ${_.stringify(v)}`);
return result; 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 _tmp0: ({}) | undefined;
let result: undefined | AtomKind; let result: undefined | AtomKind;
_tmp0 = _.is(v, $Boolean) ? {} : void 0; _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 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) { switch (_v._variant) {
case "Boolean": {return $Boolean;}; case "Boolean": {return $Boolean;};
case "Double": {return $Double;}; 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); let result = toNamedAlternative(v);
if (result === void 0) throw new TypeError(`Invalid NamedAlternative: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid NamedAlternative: ${_.stringify(v)}`);
return result; 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>; let result: undefined | NamedAlternative<_embedded>;
if (_.isSequence(v) && v.length === 2) { if (_.isSequence(v) && v.length >= 2) {
let _tmp0: (string) | undefined; let _tmp0: (string) | undefined;
_tmp0 = typeof v[0] === 'string' ? v[0] : void 0; _tmp0 = typeof v[0] === 'string' ? v[0] : void 0;
if (_tmp0 !== void 0) { if (_tmp0 !== void 0) {
@ -1761,15 +1775,15 @@ export function toNamedAlternative<_embedded = _.GenericEmbedded>(v: _.Value<_em
NamedAlternative.__from_preserve__ = toNamedAlternative; 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); let result = toNamedSimplePattern(v);
if (result === void 0) throw new TypeError(`Invalid NamedSimplePattern: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid NamedSimplePattern: ${_.stringify(v)}`);
return result; 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 _tmp0: (Binding<_embedded>) | undefined;
let result: undefined | NamedSimplePattern<_embedded>; let result: undefined | NamedSimplePattern<_embedded>;
_tmp0 = toBinding(v); _tmp0 = toBinding(v);
@ -1800,20 +1814,20 @@ export function toNamedSimplePattern<_embedded = _.GenericEmbedded>(v: _.Value<_
export namespace NamedSimplePattern {export const __from_preserve__ = toNamedSimplePattern;} 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) { switch (_v._variant) {
case "named": {return fromBinding<_embedded>(_v.value);}; case "named": {return fromBinding<_embedded>(_v.value);};
case "anonymous": {return fromSimplePattern<_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); let result = toNamedPattern(v);
if (result === void 0) throw new TypeError(`Invalid NamedPattern: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid NamedPattern: ${_.stringify(v)}`);
return result; 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 _tmp0: (Binding<_embedded>) | undefined;
let result: undefined | NamedPattern<_embedded>; let result: undefined | NamedPattern<_embedded>;
_tmp0 = toBinding(v); _tmp0 = toBinding(v);
@ -1844,20 +1858,20 @@ export function toNamedPattern<_embedded = _.GenericEmbedded>(v: _.Value<_embedd
export namespace NamedPattern {export const __from_preserve__ = toNamedPattern;} 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) { switch (_v._variant) {
case "named": {return fromBinding<_embedded>(_v.value);}; case "named": {return fromBinding<_embedded>(_v.value);};
case "anonymous": {return fromPattern<_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); let result = toBinding(v);
if (result === void 0) throw new TypeError(`Invalid Binding: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid Binding: ${_.stringify(v)}`);
return result; 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>; let result: undefined | Binding<_embedded>;
if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) { if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) {
let _tmp0: ({}) | undefined; let _tmp0: ({}) | undefined;
@ -1885,17 +1899,17 @@ export function toBinding<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>):
Binding.__from_preserve__ = toBinding; 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"])]); 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); let result = toRef(v);
if (result === void 0) throw new TypeError(`Invalid Ref: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid Ref: ${_.stringify(v)}`);
return result; 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; let result: undefined | Ref;
if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) { if (_.Record.isRecord<_.Value<_embedded>, _.Tuple<_.Value<_embedded>>, _embedded>(v)) {
let _tmp0: ({}) | undefined; let _tmp0: ({}) | undefined;
@ -1923,15 +1937,15 @@ export function toRef<_embedded = _.GenericEmbedded>(v: _.Value<_embedded>): und
Ref.__from_preserve__ = toRef; 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); let result = toModulePath(v);
if (result === void 0) throw new TypeError(`Invalid ModulePath: ${_.stringify(v)}`); if (result === void 0) throw new TypeError(`Invalid ModulePath: ${_.stringify(v)}`);
return result; 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 _tmp0: (Array<symbol>) | undefined;
let result: undefined | ModulePath; let result: undefined | ModulePath;
_tmp0 = void 0; _tmp0 = void 0;
@ -1951,5 +1965,5 @@ export function toModulePath<_embedded = _.GenericEmbedded>(v: _.Value<_embedded
ModulePath.__from_preserve__ = toModulePath; 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);}

View File

@ -1,11 +1,11 @@
import { compare } from '@preserves/core'; import { compare, Embeddable } from '@preserves/core';
import * as M from './meta'; import * as M from './meta';
import * as H from './gen/host'; import * as H from './gen/host';
export * 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) { switch (p._variant) {
case 'or': return H.Definition.union([p.pattern0, p.pattern1, ... p.patternN].map(p => 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) }))); 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) { switch (p._variant) {
case 'SimplePattern': case 'SimplePattern':
return H.Simple.Field(fieldType(p.value)); 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) { switch (p._variant) {
case 'any': return H.Field.any(); case 'any': return H.Field.any();
case 'atom': return H.Field.AtomKind(p.atomKind); 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[] = []; const gathered: H.NamedField[] = [];
ps.forEach(p => gather(p, gathered)); ps.forEach(p => gather(p, gathered));
if (gathered.length === 0) return H.Simple.Field(H.Field.unit()); if (gathered.length === 0) return H.Simple.Field(H.Field.unit());
return H.Simple.Record(H.Record(gathered)); 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; if (p._variant === 'named') return p;
return M.NamedPattern.anonymous(M.Pattern.SimplePattern(p.value)); 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) { switch (p._variant) {
case 'named': { case 'named': {
const t = fieldType(p.value.pattern); const t = fieldType(p.value.pattern);

View File

@ -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 { SchemaDefinition } from './reflection';
import * as M from './meta'; import * as M from './meta';
import * as H from './host'; import * as H from './host';
export const UNIT: true = true; export const UNIT: true = true;
export type Parsed<V> = Atom | V | Parsed<V>[] | DictOf<V> | Bindings<V>; export type Parsed<V extends Embeddable> = Atom | V | Parsed<V>[] | DictOf<V> | Bindings<V>;
export type TopParsed<V> = Atom | V | Parsed<V>[] | DictOf<V> | TopBindings<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 BindingName = string;
export type Bindings<V> = { [key: BindingName]: Parsed<V> }; export type Bindings<V extends Embeddable> = { [key: BindingName]: Parsed<V> };
export type TopBindings<V> = Bindings<V> & Top<V>; export type TopBindings<V extends Embeddable> = Bindings<V> & Top<V>;
export type SingleConstructor<V> = ((input: any) => Parsed<V>) & { schema(): SchemaDefinition }; export type SingleConstructor<V extends Embeddable> = ((input: any) => Parsed<V>) & { schema(): SchemaDefinition };
export type MultipleConstructors<V> = { [key: string]: SingleConstructor<V> }; export type MultipleConstructors<V extends Embeddable> = { [key: string]: SingleConstructor<V> };
export type DefinitionConstructors<V> = SingleConstructor<V> | MultipleConstructors<V>; export type DefinitionConstructors<V extends Embeddable> = SingleConstructor<V> | MultipleConstructors<V>;
export namespace Bindings { export namespace Bindings {
export function empty<V>(): Bindings<V> { export function empty<V extends Embeddable>(): Bindings<V> {
return {}; 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>(); const bs = empty<V>();
bs[k] = v; bs[k] = v;
return bs; 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>(); const acc = empty<V>();
for (const v of vs) { for (const v of vs) {
Object.entries(v).forEach(([kw, vw]) => acc[kw] = vw); 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: 'simple', value: Parsed<V> }
| { type: 'compound', values: Bindings<V> } | { type: 'compound', values: Bindings<V> }
; ;
export namespace DynField { 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; if (f.type === 'simple') return f.value;
return f.values; 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"); if (f.type === 'simple') throw new Error("Cannot unwrap DynField.simple to compound fields");
return f.values; 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 }; 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); 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 }; 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; if (f.type === 'compound') return f.values;
return key ? Bindings.single(M.jsId(key.description!), f.value) : Bindings.empty(); 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); return f(a);
} }
export type Unparseable<V> = TopParsed<V>; export type Unparseable<V extends Embeddable> = TopParsed<V>;
export type Unparser<V> = (v: Parsed<V>) => Value<V>; export type Unparser<V extends Embeddable> = (v: Parsed<V>) => Value<V>;
export type UnparserCompound<V> = (v: Bindings<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 = []; activeModule: M.ModulePath = [];
unparserCache: { [key: string]: [Unparser<V>] } = {}; unparserCache: { [key: string]: [Unparser<V>] } = {};
@ -116,7 +135,7 @@ export class SchemaInterpreter<V> {
): R { ): R {
const { resolved, schema } = this._findModule(modulePath); const { resolved, schema } = this._findModule(modulePath);
return this._withModule(resolved, () => { return this._withModule(resolved, () => {
const definition = schema.definitions.get(name); const definition = JsDictionary.get(schema.definitions, name);
if (definition === void 0) { if (definition === void 0) {
throw new Error(`No such preserves-schema definition: ${[... modulePath, name].map(s => s.description!).join('.')}`); 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; 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( definitionConstructor(
modulePath: M.ModulePath, modulePath: M.ModulePath,
name: symbol, name: symbol,
): DefinitionConstructors<V> { ): DefinitionConstructors<V> {
return this._lookup(modulePath, name, (definition, schema): 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); const ty = H.definitionType(definition);
if (ty._variant === 'union') { if (ty._variant === 'union') {
const multiple: MultipleConstructors<V> = {}; const multiple: MultipleConstructors<V> = {};
ty.variants.forEach(v => { ty.variants.forEach(v => {
const _variant = v.label.description!; multiple[M.jsId(v.label.description!)] = this.buildConstructor(
switch (v.type._variant) { modulePath, name, schema, v.type, v.label);
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;
}
}); });
return multiple; return multiple;
} else { } else {
const flatName = M.formatModulePath([... modulePath, name]); return this.buildConstructor(modulePath, name, schema, ty.value);
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]);
}
}
}
} }
}); });
} }
@ -219,7 +235,11 @@ export class SchemaInterpreter<V> {
if (ty._variant === 'union' || ty.value._variant === 'Record') { if (ty._variant === 'union' || ty.value._variant === 'Record') {
return this.makeTop(modulePath, name, result0 as Bindings<V>); return this.makeTop(modulePath, name, result0 as Bindings<V>);
} else { } 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 'ByteString': return inputIf(Bytes.isBytes(input));
case 'Symbol': return inputIf(typeof input === 'symbol'); 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 'lit': return is(input, p.value) ? null : void 0;
case 'seqof': { case 'seqof': {
if (!isSequence(input)) return void 0; if (!isSequence(input)) return void 0;
@ -315,17 +335,29 @@ export class SchemaInterpreter<V> {
} }
case 'dictof': { case 'dictof': {
if (!Dictionary.isDictionary<V>(input)) return void 0; if (!Dictionary.isDictionary<V>(input)) return void 0;
const result: DictOf<V> = new EncodableDictionary( if (M.isSymbolPattern(p.key)) {
this.unparserSimplePattern(p.key), const result: Bindings<V> = {};
this.unparserSimplePattern(p.value)); for (const [k, v] of Dictionary.asMap<V>(input)) {
for (const [k, v] of input) { const kw = this.parseSimplePattern(p.key, k);
const kw = this.parseSimplePattern(p.key, k); if (kw === void 0 || typeof kw !== 'symbol') return void 0;
if (kw === void 0) return void 0; const vw = this.parseSimplePattern(p.value, v);
const vw = this.parseSimplePattern(p.value, v); if (vw === void 0) return void 0;
if (vw === void 0) return void 0; result[kw.description!] = vw === null ? UNIT : vw;
result.set(kw === null ? UNIT : kw, 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); 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))); fsw => Bindings.merge(lw, fsw)));
case 'tuple': { case 'tuple': {
if (!isSequence(input)) return void 0; 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>[] = []; let results: Bindings<V>[] = [];
for (let i = 0; i < p.patterns.length; i++) { for (let i = 0; i < p.patterns.length; i++) {
const w = this.parseNamedPattern(p.patterns[i], input[i]); const w = this.parseNamedPattern(p.patterns[i], input[i]);
@ -365,10 +397,11 @@ export class SchemaInterpreter<V> {
}); });
} }
case 'dict': { 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>[] = []; const results: Bindings<V>[] = [];
for (const [key, vp] of p.entries) { for (const [key, vp] of p.entries) {
const v = input.get(key); const v = inputMap.get(key);
if (v === void 0) return void 0; if (v === void 0) return void 0;
const vw = this.parseNamedSimplePattern(vp, v); const vw = this.parseNamedSimplePattern(vp, v);
if (vw === void 0) return void 0; if (vw === void 0) return void 0;
@ -467,7 +500,7 @@ export class SchemaInterpreter<V> {
switch (p._variant) { switch (p._variant) {
case 'any': return v => v as Value<V>; // ?! case 'any': return v => v as Value<V>; // ?!
case 'atom': return v => v as Atom; 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 'lit': return _v => p.value;
case 'seqof': { case 'seqof': {
const up = this.unparserSimplePattern(p.pattern); const up = this.unparserSimplePattern(p.pattern);
@ -480,8 +513,17 @@ export class SchemaInterpreter<V> {
case 'dictof': { case 'dictof': {
const kp = this.unparserSimplePattern(p.key); const kp = this.unparserSimplePattern(p.key);
const vp = this.unparserSimplePattern(p.value); const vp = this.unparserSimplePattern(p.value);
return vs => new Dictionary<V>(_iterMap( return vs => {
(vs as DictOf<V>).entries(), ([k, v]) => [kp(k), vp(v)])); 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': { case 'Ref': {
const up = this._unparser(p.value.module, p.value.name); 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( const ups: [Value<V>, Unparser<V>][] = Array.from(p.entries.entries()).map(
([key, vp]) => [key, this.unparserNamedSimplePattern(vp)]); ([key, vp]) => [key, this.unparserNamedSimplePattern(vp)]);
return bs => { return bs => {
const result = new Dictionary<V>(); const result = new DictionaryMap<V>();
for (const [key, up] of ups) { for (const [key, up] of ups) {
result.set(key, up(bs)); result.set(key, up(bs));
} }
return result; return result.simplifiedValue();
}; };
} }
} }
@ -531,4 +573,32 @@ export class SchemaInterpreter<V> {
return this.unparserSimplePattern(p.value); 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;
}
} }

View File

@ -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 * as M from './gen/schema';
import { isJsKeyword } from './compiler/jskw'; import { isJsKeyword } from './compiler/jskw';
@ -98,3 +98,8 @@ export function namelike(x: Input): string | undefined {
if (typeof x === 'boolean') return x ? 'true' : 'false'; if (typeof x === 'boolean') return x ? 'true' : 'false';
return void 0; return void 0;
} }
export function isSymbolPattern<T extends Embeddable>(p: M.SimplePattern<T>): boolean {
return p._variant === 'atom'
&& p.atomKind._variant === 'Symbol';
}

View File

@ -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 { Input, Pattern, Schema, Definition, CompoundPattern, SimplePattern } from './meta';
import * as M from './meta'; import * as M from './meta';
import { SchemaSyntaxError } from './error'; import { SchemaSyntaxError } from './error';
@ -70,7 +70,7 @@ export function parseSchema(toplevelTokens: Array<Input>, options: SchemaReaderO
{ {
let version: M.Version | undefined = void 0; let version: M.Version | undefined = void 0;
let embeddedType: M.EmbeddedTypeName = M.EmbeddedTypeName.$false(); 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 { function process(toplevelTokens: Array<Input>): void {
const toplevelClauses = splitBy(peel(toplevelTokens) as Array<Input>, M.DOT); const toplevelClauses = splitBy(peel(toplevelTokens) as Array<Input>, M.DOT);
@ -82,10 +82,10 @@ export function parseSchema(toplevelTokens: Array<Input>, options: SchemaReaderO
if (!M.isValidToken(name.description!)) { if (!M.isValidToken(name.description!)) {
throw new SchemaSyntaxError(preserves`Invalid definition name: ${name}`, pos); 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); 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)) { } else if (clause.length === 2 && is(clause[0], M.$version)) {
version = M.asVersion(peel(clause[1])); version = M.asVersion(peel(clause[1]));
} else if (clause.length === 2 && is(clause[0], M.$embeddedType)) { } 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())); case 'symbol': return ks(M.SimplePattern.atom(M.AtomKind.Symbol()));
default: { default: {
if (str[0] === '=') { 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)) { } else if (M.isValidQid(str)) {
return ks(M.SimplePattern.Ref(parseRef(str, pos))); return ks(M.SimplePattern.Ref(parseRef(str, pos)));
} else { } else {
@ -260,20 +260,20 @@ function parsePattern(name: symbol, body0: Array<Input>): Pattern {
if (item.size !== 1) complain(); if (item.size !== 1) complain();
const [vp] = item.values(); const [vp] = item.values();
return ks(M.SimplePattern.setof(walkSimple(vp))); 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 { } 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)) { } else if (Array.isArray(item)) {
return M.CompoundPattern.tuple(item.map(maybeNamed)); 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 { } 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();
}
} }
} }

View File

@ -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);
});
});

View File

@ -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>}'));
});
});

View File

@ -1,3 +1,4 @@
import { JsDictionary } from '@preserves/core';
import { readSchema, Meta } from '../src/index'; import { readSchema, Meta } from '../src/index';
describe('reader schema', () => { describe('reader schema', () => {
@ -14,12 +15,12 @@ describe('reader schema', () => {
'__preserve_on__', '__preserve_on__',
'__preserve_text_on__', '__preserve_text_on__',
]); ]);
expect(s.definitions.size).toBe(0); expect(JsDictionary.size(s.definitions)).toBe(0);
expect(s.embeddedType._variant).toBe('false'); expect(s.embeddedType._variant).toBe('false');
}); });
it('understands patterns under embed', () => { it('understands patterns under embed', () => {
const s = readSchema('version 1 . X = #:0 .'); 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._variant !== 'Pattern') fail('bad definition 1');
if (def.value._variant !== 'SimplePattern') fail ('bad definition 2'); if (def.value._variant !== 'SimplePattern') fail ('bad definition 2');
if (def.value.value._variant !== 'embedded') fail('bad definition 3'); if (def.value.value._variant !== 'embedded') fail('bad definition 3');

View File

@ -1,9 +1,9 @@
import { Value, is, preserves } from '@preserves/core'; import { Value, is, preserves, Embeddable } from '@preserves/core';
declare global { declare global {
namespace jest { namespace jest {
interface Matchers<R> { interface Matchers<R> {
is<T>(expected: Value<T>): R; is<T extends Embeddable>(expected: Value<T>): R;
toThrowFilter(f: (e: Error) => boolean): R; toThrowFilter(f: (e: Error) => boolean): R;
} }
} }

View File

@ -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 rollup:watch"
open "cd packages/schema; yarn run test: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 compile:watch"
open "cd packages/schema-cli; yarn run rollup:watch"
tmux select-layout even-vertical tmux select-layout even-vertical

View File

@ -308,6 +308,18 @@
resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340"
integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q== 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": "@istanbuljs/load-nyc-config@^1.0.0":
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
@ -1417,6 +1429,16 @@
dependencies: dependencies:
"@octokit/openapi-types" "^12.11.0" "@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": "@rollup/plugin-terser@^0.4":
version "0.4.0" version "0.4.0"
resolved "https://registry.yarnpkg.com/@rollup/plugin-terser/-/plugin-terser-0.4.0.tgz#4c76249ad337f3eb04ab409332f23717af2c1fbf" 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" jest-matcher-utils "^27.0.0"
pretty-format "^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@*": "@types/minimatch@*":
version "5.1.2" version "5.1.2"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" 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" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== 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: acorn-globals@^6.0.0:
version "6.0.0" version "6.0.0"
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" 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" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== 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: ansi-styles@^3.2.1:
version "3.2.1" version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 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" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b"
integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== 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: anymatch@^3.0.3, anymatch@~3.1.2:
version "3.1.3" version "3.1.3"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" 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" balanced-match "^1.0.0"
concat-map "0.0.1" 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: braces@^3.0.2, braces@~3.0.2:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" 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: dependencies:
delayed-stream "~1.0.0" 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: commander@^2.20.0:
version "2.20.3" version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" 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" readable-stream "^3.0.2"
typedarray "^0.0.6" typedarray "^0.0.6"
config-chain@^1.1.12: config-chain@^1.1.12, config-chain@^1.1.13:
version "1.1.13" version "1.1.13"
resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4"
integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== 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" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== 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" version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
@ -2601,6 +2655,11 @@ dynamic-dedupe@^0.3.0:
dependencies: dependencies:
xtend "^4.0.0" 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: ecc-jsbn@~0.1.1:
version "0.1.2" version "0.1.2"
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" 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" jsbn "~0.1.0"
safer-buffer "^2.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: electron-to-chromium@^1.4.284:
version "1.4.286" version "1.4.286"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.286.tgz#0e039de59135f44ab9a8ec9025e53a9135eba11f" 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" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== 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: encoding@^0.1.12:
version "0.1.13" version "0.1.13"
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
@ -2897,6 +2971,14 @@ for-each@^0.3.3:
dependencies: dependencies:
is-callable "^1.1.3" 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: forever-agent@~0.6.1:
version "0.6.1" version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" 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: dependencies:
is-glob "^4.0.1" 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: 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" version "7.2.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" 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" html-escaper "^2.0.0"
istanbul-lib-report "^3.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: jest-changed-files@^27.5.1:
version "27.5.1" version "27.5.1"
resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.5.1.tgz#a348aed00ec9bf671cc58a66fcbe7c3dfd6a68f5" 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" import-local "^3.0.2"
jest-cli "^27.5.1" 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: js-tokens@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@ -4370,6 +4488,11 @@ lru-cache@^6.0.0:
dependencies: dependencies:
yallist "^4.0.0" 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: make-dir@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" 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" resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== 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: minimatch@^3.0, minimatch@^3.0.4, minimatch@^3.1.1:
version "3.1.2" version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" 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: dependencies:
brace-expansion "^1.1.7" 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: minimist-options@4.1.0:
version "4.1.0" version "4.1.0"
resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" 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" resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.0.1.tgz#2b9408c6e81bb8b338d600fb3685e375a370a057"
integrity sha512-V9esFpNbK0arbN3fm2sxDKqMYgIp7XtVdE4Esj+PE4Qaaxdg1wIw48ITQIOn1sc8xXSmUviVL3cyjMqPlrVkiA== 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: minizlib@^1.3.3:
version "1.3.3" version "1.3.3"
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d"
@ -4742,6 +4884,13 @@ nopt@^5.0.0:
dependencies: dependencies:
abbrev "1" 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: normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.5.0:
version "2.5.0" version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" 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" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== 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: path-type@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" 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" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== 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: serialize-javascript@^6.0.0:
version "6.0.1" version "6.0.1"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c" 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" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== 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: sisteransi@^1.0.5:
version "1.0.5" version "1.0.5"
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" 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" char-regex "^1.0.2"
strip-ansi "^6.0.0" 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: string-width@^1.0.1:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 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" is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1" 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: string.prototype.trimend@^1.0.6:
version "1.0.6" version "1.0.6"
resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" 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: dependencies:
safe-buffer "~5.1.0" 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: strip-ansi@^3.0.0, strip-ansi@^3.0.1:
version "3.0.1" version "3.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 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: dependencies:
ansi-regex "^5.0.1" 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: strip-bom@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" 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" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== 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: wrap-ansi@^7.0.0:
version "7.0.0" version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" 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" string-width "^4.1.0"
strip-ansi "^6.0.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: wrappy@1:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"

View File

@ -1,6 +1,6 @@
if ! [ -d .venv ] if ! [ -d .venv ]
then then
python -m venv .venv python3 -m venv .venv
. .venv/bin/activate . .venv/bin/activate
pip install -e '.[dev]' pip install -e '.[dev]'
else else

View File

@ -1,6 +1,6 @@
# This used to just be # This used to just be
# PACKAGEVERSION := "`python3 setup.py --version`" # 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 all: test build-docs

View File

@ -217,7 +217,11 @@ class Decoder(BinaryCodec):
if not vs: raise DecodeError('Too few elements in encoded record') if not vs: raise DecodeError('Too few elements in encoded record')
return self.wrap(Record(vs[0], vs[1:])) return self.wrap(Record(vs[0], vs[1:]))
if tag == 0xb5: return self.wrap(tuple(self.nextvalues())) 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())) if tag == 0xb7: return self.wrap(ImmutableDict.from_kvs(self.nextvalues()))
raise DecodeError('Invalid tag: ' + hex(tag)) raise DecodeError('Invalid tag: ' + hex(tag))

View File

@ -59,13 +59,16 @@ The result of evaluating it on `testdata` is as follows:
"In each test, let stripped = strip(annotatedValue)," "In each test, let stripped = strip(annotatedValue),"
" encodeBinary(·) produce canonical ordering and no annotations," " encodeBinary(·) produce canonical ordering and no annotations,"
" looseEncodeBinary(·) produce any ordering, but with 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," " decodeBinary(·) include annotations,"
" encodeText(·) include annotations," " encodeText(·) include annotations,"
" decodeText(·) include annotations," " decodeText(·) include annotations,"
"and check the following numbered expectations according to the table above:" "and check the following numbered expectations according to the table above:"
"Implementations may vary in their treatment of the difference between expectations" "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." "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."
``` ```

View File

@ -505,7 +505,7 @@ class SchemaObject:
return () return ()
if p.key == TUPLE: if p.key == TUPLE:
if not sequenceish(v): raise SchemaDecodeFailed(cls, p, v) 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 i = 0
for pp in p[0]: for pp in p[0]:
cls.parse(pp, v[i], args) cls.parse(pp, v[i], args)

View File

@ -346,6 +346,10 @@ class Parser(TextCodec):
c = self.nextchar() c = self.nextchar()
if c in ' \t': return self.unshift_annotation(self.comment_line(), self.next()) 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 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 == 'f': self.require_delimiter('#f'); return self.wrap(False)
if c == 't': self.require_delimiter('#t'); return self.wrap(True) if c == 't': self.require_delimiter('#t'); return self.wrap(True)
if c == '{': return self.wrap(self.read_set()) if c == '{': return self.wrap(self.read_set())

View File

@ -0,0 +1,5 @@
#!/bin/sh
cd "$(dirname "$0")"
. ./.envrc
exec python -c \
'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])'

View File

@ -1,6 +1,6 @@
[project] [project]
name = "preserves" name = "preserves"
version = "0.994.0" version = "0.995.1"
description = "Data serialization format" description = "Data serialization format"
readme = "README.md" readme = "README.md"
requires-python = ">=3.6, <4" requires-python = ">=3.6, <4"

View File

@ -14,7 +14,7 @@
"In each test, let stripped = strip(annotatedValue)," "In each test, let stripped = strip(annotatedValue),"
" encodeBinary(·) produce canonical ordering and no annotations," " encodeBinary(·) produce canonical ordering and no annotations,"
" looseEncodeBinary(·) produce any ordering, but with 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," " decodeBinary(·) include annotations,"
" encodeText(·) include annotations," " encodeText(·) include annotations,"
" decodeText(·) include annotations," " decodeText(·) include annotations,"
@ -39,6 +39,10 @@
}> }>
"Implementations may vary in their treatment of the difference between expectations" "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." "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 { <TestCases {
annotation1: <Test #x"85 B103616263 B00109" @"abc" 9> annotation1: <Test #x"85 B103616263 B00109" @"abc" 9>
@ -62,6 +66,10 @@
<Test #x"85 B100 85 B1066e6f726d616c B000" # <Test #x"85 B100 85 B1066e6f726d616c B000" #
# normal # normal
0> 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"> bytes2: <Test #x"B20568656c6c6f" #"hello">
bytes2a: <Test @"Internal whitespace is allowed, not including commas" #x"B2 05 68 65 6c 6c 6f" #"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\""> 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 "> dict2: @"Missing close brace" <ParseShort "{ a: b, c: d ">
dict2a: @"Missing close brace" <ParseShort "{"> dict2a: @"Missing close brace" <ParseShort "{">
dict3: @"Duplicate key" <ParseError "{ a: 1, a: 2 }"> dict3: @"Duplicate key" <ParseError "{ a: 1, a: 2 }">
dict3a: @"Duplicate key" <DecodeError #x"b7 b00101 b00102 b00101 b00103 84">
dict4: @"Unexpected close brace" <ParseError "}"> dict4: @"Unexpected close brace" <ParseError "}">
dict5: @"Missing value" <DecodeError #x"b7 b00101 b00102 b00103 84"> dict5: @"Missing value" <DecodeError #x"b7 b00101 b00102 b00103 84">
dict6: @"Comma not allowed between key and colon" <ParseError "{ a,: 1, b: 2 }"> 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 "> set2: @"Missing close brace" <ParseShort "#{ 1 2 3 ">
set2a: @"Missing close brace" <ParseShort "#{"> set2a: @"Missing close brace" <ParseShort "#{">
set3: @"Duplicate value" <ParseError "#{a a}"> set3: @"Duplicate value" <ParseError "#{a a}">
set3a: @"Duplicate value" <DecodeError #x"b6 b00101 b00101 84">
string0: <Test #x"b100" ""> string0: <Test #x"b100" "">
string3: <Test #x"b10568656c6c6f" "hello"> string3: <Test #x"b10568656c6c6f" "hello">
string4: <Test #x"b1 14 616263e6b0b4e6b0b45c2f22080c0a0d0978797a" "abc\u6c34\u6C34\\/\"\b\f\n\r\txyz"> string4: <Test #x"b1 14 616263e6b0b4e6b0b45c2f22080c0a0d0978797a" "abc\u6c34\u6C34\\/\"\b\f\n\r\txyz">
@ -221,6 +231,14 @@
symbol12: <Test #x"b3042d2d2d31" ---1> symbol12: <Test #x"b3042d2d2d31" ---1>
symbol13: <Test #x"b3042b312e78" +1.x> symbol13: <Test #x"b3042b312e78" +1.x>
symbol14: <Test #x"b304f09d849e" |\uD834\uDD1E|> 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"> tag0: @"Unexpected end tag" <DecodeError #x"84">
tag1: @"Invalid tag" <DecodeError #x"10"> tag1: @"Invalid tag" <DecodeError #x"10">
tag2: @"Invalid tag" <DecodeError #x"61b10110"> tag2: @"Invalid tag" <DecodeError #x"61b10110">

View File

@ -105,7 +105,9 @@
'named 'named
(list (list
(and ?name (? symbol?)) (and ?name (? symbol?))
(app parse-SimplePattern (and ?pattern (not (== eof))))))) (app parse-SimplePattern (and ?pattern (not (== eof))))
_
...)))
(Binding ?name ?pattern)) (Binding ?name ?pattern))
(_ eof))) (_ eof)))
(define parse-Binding! (parse-success-or-error 'parse-Binding parse-Binding)) (define parse-Binding! (parse-success-or-error 'parse-Binding parse-Binding))
@ -126,7 +128,7 @@
((and dest ((and dest
(record (record
'bundle 'bundle
(list (app parse-Modules (and ?modules (not (== eof))))))) (list (app parse-Modules (and ?modules (not (== eof)))) _ ...)))
(Bundle ?modules)) (Bundle ?modules))
(_ eof))) (_ eof)))
(define parse-Bundle! (parse-success-or-error 'parse-Bundle parse-Bundle)) (define parse-Bundle! (parse-success-or-error 'parse-Bundle parse-Bundle))
@ -198,28 +200,34 @@
'rec 'rec
(list (list
(app parse-NamedPattern (and ?label (not (== eof)))) (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)) (CompoundPattern-rec ?label ?fields))
((and dest ((and dest
(record (record
'tuple 'tuple
(list (list
(list (list (app parse-NamedPattern (and ?patterns (not (== eof)))) ...)
(app parse-NamedPattern (and ?patterns (not (== eof)))) _
...)))) ...)))
(CompoundPattern-tuple ?patterns)) (CompoundPattern-tuple ?patterns))
((and dest ((and dest
(record (record
'tuplePrefix 'tuplePrefix
(list (list
(list (app parse-NamedPattern (and ?fixed (not (== eof)))) ...) (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)) (CompoundPattern-tuplePrefix ?fixed ?variable))
((and dest ((and dest
(record (record
'dict 'dict
(list (list
(app parse-DictionaryEntries (and ?entries (not (== eof))))))) (app parse-DictionaryEntries (and ?entries (not (== eof))))
_
...)))
(CompoundPattern-dict ?entries)) (CompoundPattern-dict ?entries))
(_ eof))) (_ eof)))
(define parse-CompoundPattern! (define parse-CompoundPattern!
@ -283,7 +291,9 @@
(app parse-NamedAlternative (and ?pattern1 (not (== eof)))) (app parse-NamedAlternative (and ?pattern1 (not (== eof))))
(list (list
(app parse-NamedAlternative (and ?patternN (not (== eof)))) (app parse-NamedAlternative (and ?patternN (not (== eof))))
...))))) ...))
_
...)))
(Definition-or ?pattern0 ?pattern1 ?patternN)) (Definition-or ?pattern0 ?pattern1 ?patternN))
((and dest ((and dest
(record (record
@ -294,7 +304,9 @@
(app parse-NamedPattern (and ?pattern1 (not (== eof)))) (app parse-NamedPattern (and ?pattern1 (not (== eof))))
(list (list
(app parse-NamedPattern (and ?patternN (not (== eof)))) (app parse-NamedPattern (and ?patternN (not (== eof))))
...))))) ...))
_
...)))
(Definition-and ?pattern0 ?pattern1 ?patternN)) (Definition-and ?pattern0 ?pattern1 ?patternN))
((app parse-Pattern (and dest (not (== eof)))) (Definition-Pattern dest)) ((app parse-Pattern (and dest (not (== eof)))) (Definition-Pattern dest))
(_ eof))) (_ eof)))
@ -452,7 +464,9 @@
((and dest ((and dest
(list (list
(and ?variantLabel (? string?)) (and ?variantLabel (? string?))
(app parse-Pattern (and ?pattern (not (== eof)))))) (app parse-Pattern (and ?pattern (not (== eof))))
_
...))
(NamedAlternative ?variantLabel ?pattern)) (NamedAlternative ?variantLabel ?pattern))
(_ eof))) (_ eof)))
(define parse-NamedAlternative! (define parse-NamedAlternative!
@ -569,7 +583,9 @@
'ref 'ref
(list (list
(app parse-ModulePath (and ?module (not (== eof)))) (app parse-ModulePath (and ?module (not (== eof))))
(and ?name (? symbol?))))) (and ?name (? symbol?))
_
...)))
(Ref ?module ?name)) (Ref ?module ?name))
(_ eof))) (_ eof)))
(define parse-Ref! (parse-success-or-error 'parse-Ref parse-Ref)) (define parse-Ref! (parse-success-or-error 'parse-Ref parse-Ref))
@ -608,7 +624,9 @@
(app parse-EmbeddedTypeName (and ?embeddedType (not (== eof))))) (app parse-EmbeddedTypeName (and ?embeddedType (not (== eof)))))
('version (app parse-Version (and ?version (not (== eof))))) ('version (app parse-Version (and ?version (not (== eof)))))
(_ _) (_ _)
...)))) ...)
_
...)))
(Schema ?definitions ?embeddedType ?version)) (Schema ?definitions ?embeddedType ?version))
(_ eof))) (_ eof)))
(define parse-Schema! (parse-success-or-error 'parse-Schema parse-Schema)) (define parse-Schema! (parse-success-or-error 'parse-Schema parse-Schema))
@ -718,30 +736,41 @@
((and dest ((and dest
(record (record
'atom 'atom
(list (app parse-AtomKind (and ?atomKind (not (== eof))))))) (list (app parse-AtomKind (and ?atomKind (not (== eof)))) _ ...)))
(SimplePattern-atom ?atomKind)) (SimplePattern-atom ?atomKind))
((and dest ((and dest
(record (record
'embedded 'embedded
(list (app parse-SimplePattern (and ?interface (not (== eof))))))) (list
(app parse-SimplePattern (and ?interface (not (== eof))))
_
...)))
(SimplePattern-embedded ?interface)) (SimplePattern-embedded ?interface))
((and dest (record 'lit (list ?value))) (SimplePattern-lit ?value)) ((and dest (record 'lit (list ?value _ ...))) (SimplePattern-lit ?value))
((and dest ((and dest
(record (record
'seqof 'seqof
(list (app parse-SimplePattern (and ?pattern (not (== eof))))))) (list
(app parse-SimplePattern (and ?pattern (not (== eof))))
_
...)))
(SimplePattern-seqof ?pattern)) (SimplePattern-seqof ?pattern))
((and dest ((and dest
(record (record
'setof 'setof
(list (app parse-SimplePattern (and ?pattern (not (== eof))))))) (list
(app parse-SimplePattern (and ?pattern (not (== eof))))
_
...)))
(SimplePattern-setof ?pattern)) (SimplePattern-setof ?pattern))
((and dest ((and dest
(record (record
'dictof 'dictof
(list (list
(app parse-SimplePattern (and ?key (not (== eof)))) (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)) (SimplePattern-dictof ?key ?value))
((app parse-Ref (and dest (not (== eof)))) (SimplePattern-Ref dest)) ((app parse-Ref (and dest (not (== eof)))) (SimplePattern-Ref dest))
(_ eof))) (_ eof)))

View File

@ -58,7 +58,8 @@
,(pattern->match-pattern fields-pat '_)))] ,(pattern->match-pattern fields-pat '_)))]
[(CompoundPattern-tuple named-pats) [(CompoundPattern-tuple named-pats)
(maybe-dest dest-pat-stx (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) [(CompoundPattern-tuplePrefix fixed-named-pats variable-named-pat)
(maybe-dest dest-pat-stx (maybe-dest dest-pat-stx
(if (null? fixed-named-pats) (if (null? fixed-named-pats)

View File

@ -117,6 +117,7 @@
(match (peek-char in-port) (match (peek-char in-port)
[(or (? eof-object?) #\] #\> #\} #\)) *TRAILER-ANCHOR*] [(or (? eof-object?) #\] #\> #\} #\)) *TRAILER-ANCHOR*]
[_ (next)]))) [_ (next)])))
#:interpreter-annotation (lambda (line) (record 'r (list 'interpreter line)))
#:on-hash (lambda (in-port source next parse-error* default) #:on-hash (lambda (in-port source next parse-error* default)
(match-lambda (match-lambda
[#\{ (read-sequence 's in-port source next #\})] [#\{ (read-sequence 's in-port source next #\})]

View File

@ -83,7 +83,7 @@
[#xB3 (string->symbol (bytes->string/utf-8 (next-bytes (next-varint))))] [#xB3 (string->symbol (bytes->string/utf-8 (next-bytes (next-varint))))]
[#xB4 (apply (lambda (label . fields) (record label fields)) (next-items))] [#xB4 (apply (lambda (label . fields) (record label fields)) (next-items))]
[#xB5 (next-items)] [#xB5 (next-items)]
[#xB6 (list->set (next-items))] [#xB6 (build-set (next-items))]
[#xB7 (build-dictionary (next-items))] [#xB7 (build-dictionary (next-items))]
[_ (return (on-fail "Invalid Preserves binary tag: ~v" lead-byte))])) [_ (return (on-fail "Invalid Preserves binary tag: ~v" lead-byte))]))
@ -112,9 +112,17 @@
['#:end '()] ['#:end '()]
[v (cons (wrap pos0 v) (next-items))])) [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) (define (build-dictionary items)
(when (not (even? (length items))) (return (on-fail "Odd number of items in dictionary"))) (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))) (let ((pos0 (pos)))
(match (read-byte in-port) (match (read-byte in-port)

View File

@ -70,9 +70,10 @@
[(_ re pat) (app (lambda (v) (regexp-try-match re v)) pat)])) [(_ re pat) (app (lambda (v) (regexp-try-match re v)) pat)]))
(define ((make-preserve-text-reader #:reader-name reader-name (define ((make-preserve-text-reader #:reader-name reader-name
#:interpreter-annotation interpreter-annotation
#:read-annotated-value read-annotated-value0
#:on-char on-char0 #:on-char on-char0
#:on-hash on-hash0 #:on-hash on-hash0)
#:read-annotated-value read-annotated-value0)
in-port source read-syntax? decode-embedded0) in-port source read-syntax? decode-embedded0)
(define read-annotations? read-syntax?) (define read-annotations? read-syntax?)
(define decode-embedded (or decode-embedded0 (define decode-embedded (or decode-embedded0
@ -106,6 +107,7 @@
[#\# (match (next-char*) [#\# (match (next-char*)
[(or #\space #\tab) (annotate-next-with (read-comment-line))] [(or #\space #\tab) (annotate-next-with (read-comment-line))]
[(or #\newline #\return) (annotate-next-with "")] [(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] [#\f (unless (delimiter-follows?) (parse-error* "Delimiter must follow #f")) #f]
[#\t (unless (delimiter-follows?) (parse-error* "Delimiter must follow #t")) #t] [#\t (unless (delimiter-follows?) (parse-error* "Delimiter must follow #t")) #t]
[#\" (read-literal-binary)] [#\" (read-literal-binary)]

View File

@ -15,6 +15,7 @@
(make-preserve-text-reader (make-preserve-text-reader
#:reader-name *reader-name* #:reader-name *reader-name*
#:read-annotated-value (lambda (in-port source next parse-error*) next) #: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) #:on-hash (lambda (in-port source next parse-error* default)
(match-lambda (match-lambda
[#\{ (sequence-fold in-port [#\{ (sequence-fold in-port

View File

@ -14,7 +14,7 @@
"In each test, let stripped = strip(annotatedValue)," "In each test, let stripped = strip(annotatedValue),"
" encodeBinary(·) produce canonical ordering and no annotations," " encodeBinary(·) produce canonical ordering and no annotations,"
" looseEncodeBinary(·) produce any ordering, but with 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," " decodeBinary(·) include annotations,"
" encodeText(·) include annotations," " encodeText(·) include annotations,"
" decodeText(·) include annotations," " decodeText(·) include annotations,"
@ -39,6 +39,10 @@
}> }>
"Implementations may vary in their treatment of the difference between expectations" "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." "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 { <TestCases {
annotation1: <Test #x"85 B103616263 B00109" @"abc" 9> annotation1: <Test #x"85 B103616263 B00109" @"abc" 9>
@ -62,6 +66,10 @@
<Test #x"85 B100 85 B1066e6f726d616c B000" # <Test #x"85 B100 85 B1066e6f726d616c B000" #
# normal # normal
0> 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"> bytes2: <Test #x"B20568656c6c6f" #"hello">
bytes2a: <Test @"Internal whitespace is allowed, not including commas" #x"B2 05 68 65 6c 6c 6f" #"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\""> 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 "> dict2: @"Missing close brace" <ParseShort "{ a: b, c: d ">
dict2a: @"Missing close brace" <ParseShort "{"> dict2a: @"Missing close brace" <ParseShort "{">
dict3: @"Duplicate key" <ParseError "{ a: 1, a: 2 }"> dict3: @"Duplicate key" <ParseError "{ a: 1, a: 2 }">
dict3a: @"Duplicate key" <DecodeError #x"b7 b00101 b00102 b00101 b00103 84">
dict4: @"Unexpected close brace" <ParseError "}"> dict4: @"Unexpected close brace" <ParseError "}">
dict5: @"Missing value" <DecodeError #x"b7 b00101 b00102 b00103 84"> dict5: @"Missing value" <DecodeError #x"b7 b00101 b00102 b00103 84">
dict6: @"Comma not allowed between key and colon" <ParseError "{ a,: 1, b: 2 }"> 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 "> set2: @"Missing close brace" <ParseShort "#{ 1 2 3 ">
set2a: @"Missing close brace" <ParseShort "#{"> set2a: @"Missing close brace" <ParseShort "#{">
set3: @"Duplicate value" <ParseError "#{a a}"> set3: @"Duplicate value" <ParseError "#{a a}">
set3a: @"Duplicate value" <DecodeError #x"b6 b00101 b00101 84">
string0: <Test #x"b100" ""> string0: <Test #x"b100" "">
string3: <Test #x"b10568656c6c6f" "hello"> string3: <Test #x"b10568656c6c6f" "hello">
string4: <Test #x"b1 14 616263e6b0b4e6b0b45c2f22080c0a0d0978797a" "abc\u6c34\u6C34\\/\"\b\f\n\r\txyz"> string4: <Test #x"b1 14 616263e6b0b4e6b0b45c2f22080c0a0d0978797a" "abc\u6c34\u6C34\\/\"\b\f\n\r\txyz">
@ -221,6 +231,14 @@
symbol12: <Test #x"b3042d2d2d31" ---1> symbol12: <Test #x"b3042d2d2d31" ---1>
symbol13: <Test #x"b3042b312e78" +1.x> symbol13: <Test #x"b3042b312e78" +1.x>
symbol14: <Test #x"b304f09d849e" |\uD834\uDD1E|> 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"> tag0: @"Unexpected end tag" <DecodeError #x"84">
tag1: @"Invalid tag" <DecodeError #x"10"> tag1: @"Invalid tag" <DecodeError #x"10">
tag2: @"Invalid tag" <DecodeError #x"61b10110"> tag2: @"Invalid tag" <DecodeError #x"61b10110">

View File

@ -138,6 +138,16 @@ PrecType = "PREC" / "PREC_LEFT" / "PREC_RIGHT" / "PREC_DYNAMIC";
ENDDOC 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 80)) (write-pexprs (string->pexprs P #:read-syntax? #t)) (newline))
(parameterize ((pretty-print-columns 10)) (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 S #:read-syntax? #t)) (newline))
(parameterize ((pretty-print-columns 40)) (write-pexprs (string->pexprs T #: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))

View File

@ -197,7 +197,7 @@ a binary-syntax document; otherwise, it should be interpreted as text.
86 - Embedded 86 - Embedded
87 - Double 87 - Double
B0 - Integer B0 - SignedInteger
B1 - String B1 - String
B2 - ByteString B2 - ByteString
B3 - Symbol B3 - Symbol

View File

@ -3,7 +3,7 @@ title: "P-expressions"
--- ---
Tony Garnock-Jones <tonyg@leastfixedpoint.com> Tony Garnock-Jones <tonyg@leastfixedpoint.com>
February 2024. Version 0.3.1. May 2024. Version 0.3.2.
[text syntax]: preserves-text.html [text syntax]: preserves-text.html
@ -58,7 +58,7 @@ in that uses of `Value` are replaced with `SimpleExpr`.
Embedded = "#:" SimpleExpr Embedded = "#:" SimpleExpr
Annotated = Annotation 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> linecomment = *<any unicode scalar value except CR or LF>
P-expression special punctuation marks are comma, semicolon, and P-expression special punctuation marks are comma, semicolon, and
@ -223,12 +223,14 @@ text-syntax encodings.
### Whole `Document`s ### Whole `Document`s
```preserves ```preserves
⌜{ ⌜#!/example/of/a/shebang
{
key: value key: value
# example of a comment at the end of a dictionary # example of a comment at the end of a dictionary
} }
# example of a comment at the end of the input file⌝ # example of a comment at the end of the input file⌝
= [ <b = @<r interpreter "/example/of/a/shebang">
[ <b
key <p |:|> value key <p |:|> value
@"example of a comment at the end of a dictionary" <a> @"example of a comment at the end of a dictionary" <a>
> >

View File

@ -4,7 +4,7 @@ title: "Preserves Schema"
--- ---
Tony Garnock-Jones <tonyg@leastfixedpoint.com> Tony Garnock-Jones <tonyg@leastfixedpoint.com>
December 2023. Version 0.3.5. April 2024. Version 0.4.
[abnf]: https://tools.ietf.org/html/rfc7405 [abnf]: https://tools.ietf.org/html/rfc7405
[identifierlike]: #sufficiently-identifierlike-values [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 Alternatives are separated by any number of slashes `/`, and leading or
trailing slashes are ignored. When parsing, the alternatives are tried in trailing slashes are ignored. When parsing, the alternatives are tried in
order; the result of the first successful alternative is the result of the 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 **Host-language types.** The type corresponding to an `OrPattern` is an
algebraic sum type, a union type, a variant type, or a concrete subclass algebraic sum type, a union type, a variant type, or a concrete subclass
@ -415,6 +423,18 @@ entry.
DictionaryPattern = "{" *(value ":" NamedSimplePattern) "}" 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 ### Identifiers and Bindings: NamedPattern and NamedSimplePattern
Compound patterns specifications contain `NamedPattern`s or Compound patterns specifications contain `NamedPattern`s or

View File

@ -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 Comments that are just hash `#` followed immediately by newline yield an
empty-string annotation. 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`; **Equivalence.** Annotations appear within syntax denoting a `Value`;
however, the annotations are not part of the denoted value. They are however, the annotations are not part of the denoted value. They are
only part of the syntax. Annotations do not play a part in only part of the syntax. Annotations do not play a part in

View File

@ -2,6 +2,7 @@
;; Add code like the following to your .emacs to install: ;; Add code like the following to your .emacs to install:
;; (autoload 'preserves-mode "~/src/preserves/preserves.el" nil t) ;; (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 '("\\.pr\\'" . preserves-mode))
;; (add-to-list 'auto-mode-alist '("\\.prs\\'" . preserves-mode)) ;; (add-to-list 'auto-mode-alist '("\\.prs\\'" . preserves-mode))

View File

@ -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: The total ordering specified [above](#total-order) means that the following statements are true:
- `"bzz"` &lt; `"c"` &lt; `"caa"` &lt; `#:"a"` - `"bzz"` &lt; `"c"` &lt; `"caa"` &lt; `#:"a"`
- `#t` &lt; `3.0f` &lt; `3.0` &lt; `3` &lt; `"3"` &lt; `|3|` &lt; `[]` &lt; `#:#t` - `#t` &lt; `3.0` &lt; `3` &lt; `"3"` &lt; `|3|` &lt; `[]` &lt; `#:#t`
- `[#f]` &lt; `[foo]`, because `Boolean` appears before `Symbol` in the kind ordering - `[#f]` &lt; `[foo]`, because `Boolean` appears before `Symbol` in the kind ordering
- `[x]` &lt; `[x y]`, because there is no element remaining to compare against `y` - `[x]` &lt; `[x y]`, because there is no element remaining to compare against `y`
- `[a b]` &lt; `[x]`, because `a` is smaller than `x` - `[a b]` &lt; `[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 | | `0` | B0 00 |
| `1` | B0 01 01 | | `1` | B0 01 01 |
| `255` | B0 02 00 FF | | `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.0` | 87 08 3F F0 00 00 00 00 00 00 |
| `-1.202e300` | 87 08 FE 3C B7 B7 59 BF 04 26 | | `-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 | | `#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.** **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 [1, 2, 3] [1, 5, 3] = ⊥`
- `merge #{a, b, c} #{a, b, c} = ⊥` - `merge #{a, b, c} #{a, b, c} = ⊥`
- `merge {a: 1, b: [2]} {b: [2, 99] c: 3} = {a: 1, b: [2, 99], c: 3}` - `merge {a: 1, b: [2]} {b: [2, 99] c: 3} = {a: 1, b: [2, 99], c: 3}`

498
python/0.994.0/404.html Normal file
View File

@ -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>

View File

@ -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">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">preserves</span> <span class="kn">import</span> <span class="o">*</span>
<span class="o">&gt;&gt;&gt;</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>

View File

@ -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