Compare commits
84 Commits
javascript
...
main
Author | SHA1 | Date |
---|---|---|
Tony Garnock-Jones | 685302f547 | |
Tony Garnock-Jones | f83e67899e | |
Tony Garnock-Jones | f2331c0e1e | |
Tony Garnock-Jones | f628e7d31f | |
Tony Garnock-Jones | b767fa4eb0 | |
Tony Garnock-Jones | 58110e7c0c | |
Tony Garnock-Jones | 58ebc93eb5 | |
Tony Garnock-Jones | f18ba9c9d4 | |
Tony Garnock-Jones | 87ecdb7efe | |
Tony Garnock-Jones | 0533840bc0 | |
Tony Garnock-Jones | 77c16df89b | |
Tony Garnock-Jones | 35e6ba2e82 | |
Tony Garnock-Jones | 536e32b0e8 | |
Tony Garnock-Jones | 9192bdea7e | |
Tony Garnock-Jones | 19ac8d16c8 | |
Tony Garnock-Jones | 7f284a9d52 | |
Tony Garnock-Jones | cadf54b927 | |
Tony Garnock-Jones | a8b300e57d | |
Tony Garnock-Jones | 4e5e64f0a6 | |
Tony Garnock-Jones | c8ce125192 | |
Tony Garnock-Jones | c9fa9c590b | |
Tony Garnock-Jones | d568fc56ce | |
Tony Garnock-Jones | 42f4672446 | |
Tony Garnock-Jones | 1c86d8b7c5 | |
Tony Garnock-Jones | 64c1090938 | |
Tony Garnock-Jones | dc61963e16 | |
Tony Garnock-Jones | a33786e469 | |
Tony Garnock-Jones | 23ba2e5a59 | |
Tony Garnock-Jones | 7b8e0ff4b6 | |
Tony Garnock-Jones | 3f7819fafa | |
Tony Garnock-Jones | f5d76a847b | |
Tony Garnock-Jones | 443406a7d7 | |
Tony Garnock-Jones | 05103e9825 | |
Tony Garnock-Jones | 4f75d6d5a3 | |
Tony Garnock-Jones | 07b7739d00 | |
Tony Garnock-Jones | 8f3d22adf1 | |
Tony Garnock-Jones | 8222675b6b | |
Tony Garnock-Jones | fca4b3a22e | |
Tony Garnock-Jones | c5dd2d749a | |
Tony Garnock-Jones | c986ca76cf | |
Tony Garnock-Jones | 3e67c75427 | |
Tony Garnock-Jones | 6bc159e3c6 | |
Tony Garnock-Jones | 99d1acdec7 | |
Tony Garnock-Jones | 3093b89f0d | |
Tony Garnock-Jones | 00c0de40ea | |
Tony Garnock-Jones | 7657952993 | |
Tony Garnock-Jones | 9ecbd0bdd1 | |
Tony Garnock-Jones | 297e1630a8 | |
Tony Garnock-Jones | 85ca0b6c0a | |
Tony Garnock-Jones | 7c9c410a9b | |
Tony Garnock-Jones | cbbc6c50c0 | |
Tony Garnock-Jones | eb4f456550 | |
Tony Garnock-Jones | 4f4ff6e108 | |
Tony Garnock-Jones | 055a7f90e9 | |
Tony Garnock-Jones | b2f6149042 | |
Tony Garnock-Jones | 1bd4a3cdb4 | |
Tony Garnock-Jones | dc0ddf95dd | |
Tony Garnock-Jones | eeace57670 | |
Tony Garnock-Jones | 0aa39da971 | |
Tony Garnock-Jones | f0815ce4eb | |
Tony Garnock-Jones | afba8a0bff | |
Tony Garnock-Jones | d9ec3bfb14 | |
Tony Garnock-Jones | 95ac4b13df | |
Tony Garnock-Jones | 3eeee5f090 | |
Tony Garnock-Jones | aeacce22fc | |
Tony Garnock-Jones | 0726684ab5 | |
Tony Garnock-Jones | f74c4ebaf0 | |
Tony Garnock-Jones | 48a063539a | |
Tony Garnock-Jones | db96fcc95a | |
Tony Garnock-Jones | cee4a25460 | |
Tony Garnock-Jones | 7948ad4260 | |
Tony Garnock-Jones | 3d3c79e617 | |
Tony Garnock-Jones | b925b53756 | |
Tony Garnock-Jones | c0289e0a05 | |
Tony Garnock-Jones | 41189f551d | |
Tony Garnock-Jones | cc8313cf25 | |
Tony Garnock-Jones | bfbff65bb6 | |
Tony Garnock-Jones | 442a987523 | |
Tony Garnock-Jones | f45b136ef5 | |
Tony Garnock-Jones | 73c6593f84 | |
Tony Garnock-Jones | a9e226f759 | |
Tony Garnock-Jones | 33db0b8718 | |
Tony Garnock-Jones | e923d87fa5 | |
Tony Garnock-Jones | 83697b0e56 |
2
NOTICE
2
NOTICE
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -13,5 +13,5 @@ defaults:
|
||||||
layout: page
|
layout: page
|
||||||
|
|
||||||
title: "Preserves"
|
title: "Preserves"
|
||||||
version_date: "January 2024"
|
version_date: "March 2024"
|
||||||
version: "0.993.0"
|
version: "0.995.0"
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
[
|
[
|
||||||
{"version":"0.992.2","title":"0.992.2","aliases":["latest"]},
|
{"version":"0.995.1","title":"0.995.1","aliases":["latest"]},
|
||||||
|
{"version":"0.995.0","title":"0.995.0","aliases":[]},
|
||||||
|
{"version":"0.994.0","title":"0.994.0","aliases":[]},
|
||||||
|
{"version":"0.993.0","title":"0.993.0","aliases":[]},
|
||||||
|
{"version":"0.992.2","title":"0.992.2","aliases":[]},
|
||||||
{"version":"0.992.1","title":"0.992.1","aliases":[]},
|
{"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":[]},
|
||||||
{"version":"0.991.0","title":"0.991.0","aliases":[]},
|
{"version":"0.991.0","title":"0.991.0","aliases":[]},
|
||||||
|
|
|
@ -5,7 +5,7 @@ For a value `V`, we write `«V»` for the binary encoding of `V`.
|
||||||
«#t» = [0x81]
|
«#t» = [0x81]
|
||||||
|
|
||||||
«@W V» = [0x85] ++ «W» ++ «V»
|
«@W V» = [0x85] ++ «W» ++ «V»
|
||||||
«#!V» = [0x86] ++ «V»
|
«#:V» = [0x86] ++ «V»
|
||||||
|
|
||||||
«V» if V ∈ Double = [0x87, 0x08] ++ binary64(V)
|
«V» if V ∈ Double = [0x87, 0x08] ++ binary64(V)
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ class="postcard-grammar binarysyntax">*V*</span>.
|
||||||
|
|
||||||
{:.postcard-grammar.binarysyntax}
|
{:.postcard-grammar.binarysyntax}
|
||||||
«`@`*W* *V*» | = | `85` «*W*» «*V*»
|
«`@`*W* *V*» | = | `85` «*W*» «*V*»
|
||||||
«`#!`*V*» | = | `86` «*V*»
|
«`#:`*V*» | = | `86` «*V*»
|
||||||
|
|
||||||
{:.postcard-grammar.binarysyntax}
|
{:.postcard-grammar.binarysyntax}
|
||||||
«*V*» | = | `87``08` **binary64**(*V*) | if *V* ∈ Double
|
«*V*» | = | `87``08` **binary64**(*V*) | if *V* ∈ Double
|
||||||
|
|
|
@ -15,7 +15,7 @@ Set := `#{` Expr* Trailer ws `}`
|
||||||
|
|
||||||
Trailer := (ws Annotation)*
|
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)
|
||||||
```
|
```
|
||||||
|
|
|
@ -18,6 +18,6 @@ The definitions of `Atom`, `ws`, and `linecomment` are as given in the Preserves
|
||||||
| *Trailer* | := | (**ws** *Annotation*)<sup>⋆</sup>
|
| *Trailer* | := | (**ws** *Annotation*)<sup>⋆</sup>
|
||||||
|
|
||||||
{:.postcard-grammar.textsyntax}
|
{:.postcard-grammar.textsyntax}
|
||||||
| *Embedded* | := | `#!` *SimpleExpr*
|
| *Embedded* | := | `#:` *SimpleExpr*
|
||||||
| *Annotated* | := | *Annotation* *SimpleExpr*
|
| *Annotated* | := | *Annotation* *SimpleExpr*
|
||||||
| *Annotation* | := | `@` *SimpleExpr* | `#` ((**space** | **tab**) *linecomment*) (**cr** | **lf**)
|
| *Annotation* | := | `@` *SimpleExpr* | `#` ((**space** | **tab** | `!`) *linecomment*) (**cr** | **lf**)
|
||||||
|
|
|
@ -9,9 +9,9 @@ Set := `#{` (commas Value)* commas `}`
|
||||||
Dictionary := `{` (commas Value ws `:` Value)* commas `}`
|
Dictionary := `{` (commas Value ws `:` Value)* commas `}`
|
||||||
commas := (ws `,`)* ws
|
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`
|
||||||
|
|
|
@ -11,9 +11,9 @@
|
||||||
| **commas** | := | (**ws** `,`)<sup>⋆</sup> **ws** |
|
| **commas** | := | (**ws** `,`)<sup>⋆</sup> **ws** |
|
||||||
|
|
||||||
{:.postcard-grammar.textsyntax}
|
{:.postcard-grammar.textsyntax}
|
||||||
| *Embedded* | := | `#!`*Value* |
|
| *Embedded* | := | `#:`*Value* |
|
||||||
| *Annotated* | := | *Annotation* *Value* |
|
| *Annotated* | := | *Annotation* *Value* |
|
||||||
| *Annotation* | := | `@`*Value* |`#` ((**space** | **tab**) *linecomment*) (**cr** | **lf**) |
|
| *Annotation* | := | `@`*Value* |`#` ((**space** | **tab** | `!`) *linecomment*) (**cr** | **lf**) |
|
||||||
|
|
||||||
{:.postcard-grammar.textsyntax}
|
{:.postcard-grammar.textsyntax}
|
||||||
| *Atom* | := | *Boolean* | *ByteString* | *String* | *QuotedSymbol* | *Symbol* | *Number* |
|
| *Atom* | := | *Boolean* | *ByteString* | *String* | *QuotedSymbol* | *Symbol* | *Number* |
|
||||||
|
|
|
@ -11,6 +11,6 @@ syntax](https://preserves.dev/preserves-text.html):
|
||||||
Sequence : [value1 value2 ...]
|
Sequence : [value1 value2 ...]
|
||||||
Set : #{value1 value2 ...}
|
Set : #{value1 value2 ...}
|
||||||
Dictionary : {key1: value1 key2: value2 ...: ...}
|
Dictionary : {key1: value1 key2: value2 ...: ...}
|
||||||
Embedded : #!value
|
Embedded : #:value
|
||||||
|
|
||||||
Commas are optional in sequences, sets, and dictionaries.
|
Commas are optional in sequences, sets, and dictionaries.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
/build.python/
|
||||||
|
/*.deb
|
|
@ -0,0 +1,10 @@
|
||||||
|
PYTHON_PACKAGEVERSION := $(shell ../implementations/python/print-package-version)
|
||||||
|
|
||||||
|
all: python3-preserves_$(PYTHON_PACKAGEVERSION)_all.deb
|
||||||
|
|
||||||
|
python3-preserves_%_all.deb:
|
||||||
|
./build-python-deb
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.deb
|
||||||
|
rm -rf build.*
|
|
@ -0,0 +1,37 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
PYTHON_PACKAGEVERSION=$(../implementations/python/print-package-version)
|
||||||
|
DIRTY=
|
||||||
|
if ! git diff-index --quiet HEAD --
|
||||||
|
then
|
||||||
|
DIRTY=+
|
||||||
|
fi
|
||||||
|
GITSUFFIX=$(git log --date=format:%Y%m%d%H%M%S --pretty=~git%cd.%h -1)
|
||||||
|
VERSION=${PYTHON_PACKAGEVERSION}${GITSUFFIX}${DIRTY}
|
||||||
|
|
||||||
|
echo "Building deb for ${VERSION}"
|
||||||
|
(cd ../implementations/python && . ./.envrc && make build-only)
|
||||||
|
|
||||||
|
rm -rf build.python
|
||||||
|
mkdir build.python
|
||||||
|
|
||||||
|
(
|
||||||
|
cd build.python
|
||||||
|
tar -zxvf ../../implementations/python/dist/preserves-${PYTHON_PACKAGEVERSION}.tar.gz
|
||||||
|
(
|
||||||
|
cd preserves-${PYTHON_PACKAGEVERSION}
|
||||||
|
cp -a ../../python ./debian
|
||||||
|
cat > ./debian/changelog <<EOF
|
||||||
|
preserves (${VERSION}) UNRELEASED; urgency=low
|
||||||
|
|
||||||
|
* Unofficial debian packaging of Python Preserves
|
||||||
|
|
||||||
|
-- Tony Garnock-Jones <tonyg@leastfixedpoint.com> $(date --rfc-email)
|
||||||
|
EOF
|
||||||
|
|
||||||
|
dpkg-buildpackage
|
||||||
|
)
|
||||||
|
cp *.deb ..
|
||||||
|
)
|
|
@ -0,0 +1,14 @@
|
||||||
|
Source: preserves
|
||||||
|
Section: python
|
||||||
|
Priority: optional
|
||||||
|
Maintainer: Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||||
|
Build-Depends: debhelper-compat (= 12), python3, dh-python, pybuild-plugin-pyproject
|
||||||
|
Standards-Version: 3.9.3
|
||||||
|
Homepage: https://preserves.dev/
|
||||||
|
Vcs-Git: https://gitlab.com/preserves/preserves.git
|
||||||
|
Vcs-Browser: https://gitlab.com/preserves/preserves
|
||||||
|
|
||||||
|
Package: python3-preserves
|
||||||
|
Architecture: all
|
||||||
|
Depends: ${python3:Depends}
|
||||||
|
Description: Python implementation of the Preserves data language
|
|
@ -0,0 +1,6 @@
|
||||||
|
#!/usr/bin/make -f
|
||||||
|
#export DH_VERBOSE=1
|
||||||
|
export PYBUILD_NAME=preserves
|
||||||
|
|
||||||
|
%:
|
||||||
|
dh $@ --with python3 --buildsystem=pybuild
|
|
@ -41,7 +41,7 @@ let render
|
||||||
)
|
)
|
||||||
m
|
m
|
||||||
++ " }"
|
++ " }"
|
||||||
, embedded = λ(value : Text) → "#!${value}"
|
, embedded = λ(value : Text) → "#:${value}"
|
||||||
}
|
}
|
||||||
|
|
||||||
let Preserves/boolean = ./boolean.dhall
|
let Preserves/boolean = ./boolean.dhall
|
||||||
|
@ -94,7 +94,7 @@ let example0 =
|
||||||
)}
|
)}
|
||||||
''
|
''
|
||||||
≡ ''
|
≡ ''
|
||||||
{ a: 1 b: [ 2 3 ] c: { d: 1.0 e: -1.0 } d: #!#t e: <capture <_>> }
|
{ a: 1 b: [ 2 3 ] c: { d: 1.0 e: -1.0 } d: #:#t e: <capture <_>> }
|
||||||
''
|
''
|
||||||
|
|
||||||
in render
|
in render
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@preserves/core",
|
"name": "@preserves/core",
|
||||||
"version": "0.993.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",
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 });
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
import { isEmbedded } from './embedded';
|
||||||
|
import { Equivalence, _iterMap } from './flex';
|
||||||
|
|
||||||
|
export interface JsDictionary<V> {
|
||||||
|
[key: string]: V;
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace JsDictionary {
|
||||||
|
export function isJsDictionary<V>(x: any): x is JsDictionary<V> {
|
||||||
|
// We accept only literal objects and objects created via `new Object` as dictionaries.
|
||||||
|
// Furthermore, we require no function-valued `__as_preserve__` property to exist.
|
||||||
|
return typeof x === 'object'
|
||||||
|
&& x !== null
|
||||||
|
&& Object.getPrototypeOf(Object.getPrototypeOf(x)) === null
|
||||||
|
&& typeof x.__as_preserve__ !== 'function'
|
||||||
|
&& !isEmbedded(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function from<V>(entries: Iterable<[symbol, V]>): JsDictionary<V> {
|
||||||
|
const r: JsDictionary<V> = {};
|
||||||
|
for (const [key, value] of entries) r[key.description!] = value;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clear<V>(j: JsDictionary<V>): void {
|
||||||
|
for (const key in j) delete j[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function remove<V>(j: JsDictionary<V>, key: symbol): boolean {
|
||||||
|
const result = has(j, key);
|
||||||
|
delete j[key.description!];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function forEach<V>(
|
||||||
|
j: JsDictionary<V>,
|
||||||
|
callbackfn: (value: V, key: symbol) => void,
|
||||||
|
): void {
|
||||||
|
Object.entries(j).forEach(([key, val]) => callbackfn(val, Symbol.for(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function get<V>(j: JsDictionary<V>, key: symbol): V | undefined {
|
||||||
|
return j[key.description!];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function has<V>(j: JsDictionary<V>, key: symbol): boolean {
|
||||||
|
return Object.hasOwnProperty.call(j, key.description!);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function set<V>(j: JsDictionary<V>, key: symbol, value: V): JsDictionary<V> {
|
||||||
|
j[key.description!] = value;
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function size<V>(j: JsDictionary<V>): number {
|
||||||
|
return Object.keys(j).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function entries<V>(j: JsDictionary<V>): IterableIterator<[symbol, V]> {
|
||||||
|
return _iterMap(Object.entries(j).values(), ([k, v]) => [Symbol.for(k), v]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function keys<V>(j: JsDictionary<V>): IterableIterator<symbol> {
|
||||||
|
return _iterMap(Object.keys(j).values(), k => Symbol.for(k));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function values<V>(j: JsDictionary<V>): IterableIterator<V> {
|
||||||
|
return Object.values(j).values();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clone<V>(j: JsDictionary<V>): JsDictionary<V> {
|
||||||
|
const r: JsDictionary<V> = {};
|
||||||
|
Object.keys(j).forEach(k => r[k] = j[k]);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function equals<V>(
|
||||||
|
j1: JsDictionary<V>,
|
||||||
|
j2: JsDictionary<V>,
|
||||||
|
eqv: Equivalence<V> = (v1, v2) => v1 === v2,
|
||||||
|
): boolean {
|
||||||
|
if (size(j1) !== size(j2)) return false;
|
||||||
|
for (let [k, v] of entries(j1)) {
|
||||||
|
if (!has(j2, k)) return false;
|
||||||
|
if (!eqv(v, get(j2, k)!)) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,13 +3,15 @@ import { Bytes } from "./bytes";
|
||||||
import { fold } from "./fold";
|
import { 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;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 });
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,353 @@
|
||||||
|
// Preserves-Expressions. https://preserves.dev/preserves-expressions.html
|
||||||
|
|
||||||
|
import { ReaderBase } from './reader';
|
||||||
|
import { Atom, Value } from './values';
|
||||||
|
import { Position, annotate, formatPosition } from './annotated';
|
||||||
|
import { Record as VRecord } from './record';
|
||||||
|
import { Embeddable, GenericEmbedded } from './embedded';
|
||||||
|
import { fromJS } from './fromjs';
|
||||||
|
import { DictionaryMap, Set as VSet } from './dictionary';
|
||||||
|
|
||||||
|
export type Expr = SimpleExpr | Punct;
|
||||||
|
export type SimpleExpr = Atom | Compound | Embedded;
|
||||||
|
|
||||||
|
export type Positioned<I> = { position: Position, item: I, annotations?: Annotations };
|
||||||
|
|
||||||
|
export class Punct {
|
||||||
|
constructor(public text: string) {}
|
||||||
|
__as_preserve__(): Value { return VRecord(Symbol.for('p'), [Symbol.for(this.text)]); }
|
||||||
|
|
||||||
|
isComma(): boolean { return this.text === ','; }
|
||||||
|
static isComma(v: Expr): boolean { return v instanceof Punct && v.isComma(); }
|
||||||
|
|
||||||
|
isColon(n = 1): boolean { return this.text === ':'.repeat(n); }
|
||||||
|
static isColon(v: Expr, n = 1): boolean { return v instanceof Punct && v.isColon(n); }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Embedded {
|
||||||
|
constructor(public expr: SimpleExpr, public annotations?: Annotations) {}
|
||||||
|
__as_preserve__(): Value {
|
||||||
|
const v = fromJS(this.expr);
|
||||||
|
return new GenericEmbedded(this.annotations?.wrap(v) ?? v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BaseCompound<I> {
|
||||||
|
positions: Position[] = [];
|
||||||
|
exprs: I[] = [];
|
||||||
|
annotations?: Annotations[] = void 0; // sparse array when non-void
|
||||||
|
|
||||||
|
get(i: number): Positioned<I> | undefined {
|
||||||
|
if (i >= this.exprs.length) return void 0;
|
||||||
|
return {
|
||||||
|
position: this.positions[i],
|
||||||
|
item: this.exprs[i],
|
||||||
|
annotations: this.annotations && this.annotations[i],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
push(p: Positioned<I>): true;
|
||||||
|
push(expr: I, position: Position, annotations?: Annotations): true;
|
||||||
|
push(v: Positioned<I> | I, position?: Position, annotations?: Annotations) {
|
||||||
|
if (position === void 0) {
|
||||||
|
const p = v as Positioned<I>;
|
||||||
|
if (p.annotations) this._ensureAnnotations()[this.exprs.length] = p.annotations;
|
||||||
|
this.positions.push(p.position);
|
||||||
|
this.exprs.push(p.item);
|
||||||
|
} else {
|
||||||
|
if (annotations) this._ensureAnnotations()[this.exprs.length] = annotations;
|
||||||
|
this.positions.push(position);
|
||||||
|
this.exprs.push(v as I);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ensureAnnotations(): Annotations[] {
|
||||||
|
if (this.annotations === void 0) this.annotations = [];
|
||||||
|
return this.annotations;
|
||||||
|
}
|
||||||
|
|
||||||
|
_annotationsAt(index: number): Annotations {
|
||||||
|
return this._ensureAnnotations()[index] ??= new Annotations();
|
||||||
|
}
|
||||||
|
|
||||||
|
preservesValues(): Value[] {
|
||||||
|
return this.exprs.map((p, i) => {
|
||||||
|
const v = fromJS(p);
|
||||||
|
if (this.annotations?.[i] !== void 0) {
|
||||||
|
return this.annotations[i].wrap(v);
|
||||||
|
} else {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
__as_preserve__(): Value {
|
||||||
|
return this.preservesValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
map<R>(f: (item: Positioned<I>, index: number) => R, offset = 0): R[] {
|
||||||
|
const result: R[] = [];
|
||||||
|
for (let i = offset; i < this.exprs.length; i++) {
|
||||||
|
result.push(f(this.get(i)!, i));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Symbol.iterator](): IterableIterator<Positioned<I>> {
|
||||||
|
let c = this;
|
||||||
|
let i = 0;
|
||||||
|
return {
|
||||||
|
next(): IteratorResult<Positioned<I>> {
|
||||||
|
if (i < c.exprs.length) {
|
||||||
|
return { done: false, value: c.get(i++)! };
|
||||||
|
} else {
|
||||||
|
return { done: true, value: void 0 };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[Symbol.iterator]() { return c[Symbol.iterator](); }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Document extends BaseCompound<Expr> {}
|
||||||
|
|
||||||
|
export class Annotations extends BaseCompound<SimpleExpr> {
|
||||||
|
wrap(v: Value): Value {
|
||||||
|
return annotate(v, ... this.preservesValues());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CompoundVariant = 'sequence' | 'record' | 'block' | 'group' | 'set';
|
||||||
|
|
||||||
|
export abstract class Compound extends BaseCompound<Expr> {
|
||||||
|
abstract get variant(): CompoundVariant;
|
||||||
|
__as_preserve__(): Value {
|
||||||
|
const vs = this.preservesValues();
|
||||||
|
switch (this.variant) {
|
||||||
|
case 'sequence': return vs;
|
||||||
|
case 'record': return VRecord(Symbol.for('r'), vs);
|
||||||
|
case 'block': return VRecord(Symbol.for('b'), vs);
|
||||||
|
case 'group': return VRecord(Symbol.for('g'), vs);
|
||||||
|
case 'set': return VRecord(Symbol.for('s'), vs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Sequence extends Compound {
|
||||||
|
get variant(): CompoundVariant { return 'sequence'; }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Record extends Compound {
|
||||||
|
get variant(): CompoundVariant { return 'record'; }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Block extends Compound {
|
||||||
|
get variant(): CompoundVariant { return 'block'; }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Group extends Compound {
|
||||||
|
get variant(): CompoundVariant { return 'group'; }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Set extends Compound {
|
||||||
|
get variant(): CompoundVariant { return 'set'; }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Reader extends ReaderBase<never> {
|
||||||
|
nextDocument(howMany: 'all' | 'one' = 'all'): Document {
|
||||||
|
const doc = new Document();
|
||||||
|
this.readExpr(doc);
|
||||||
|
if (howMany === 'all') {
|
||||||
|
while (this.readExpr(doc)) {}
|
||||||
|
}
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
readCompound(c: Compound, terminator: string): Compound {
|
||||||
|
while (this.readExpr(c, terminator)) {}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
readSimpleExpr(c: BaseCompound<SimpleExpr>): boolean {
|
||||||
|
return this._readInto(c, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
readExpr(c: BaseCompound<Expr>, terminator: string | null = null): boolean {
|
||||||
|
return this._readInto(c as BaseCompound<SimpleExpr> /* yuck */, true, terminator);
|
||||||
|
}
|
||||||
|
|
||||||
|
_checkTerminator(actual: string, expected: string | null, startPos: Position): false {
|
||||||
|
if (actual === expected) return false;
|
||||||
|
this.state.error('Unexpected ' + actual, startPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
_readInto(c: BaseCompound<SimpleExpr>, acceptPunct: boolean, terminator: string | null = null): boolean {
|
||||||
|
while (true) {
|
||||||
|
this.state.skipws();
|
||||||
|
if (this.state.atEnd() && terminator === null) return false;
|
||||||
|
const startPos = this.state.copyPos();
|
||||||
|
const ch = this.state.nextchar();
|
||||||
|
switch (ch) {
|
||||||
|
case '"':
|
||||||
|
return c.push(this.state.readString('"'), startPos);
|
||||||
|
case '|':
|
||||||
|
return c.push(Symbol.for(this.state.readString('|')), startPos);
|
||||||
|
case ';':
|
||||||
|
if (acceptPunct) {
|
||||||
|
return (c as BaseCompound<Expr>).push(new Punct(';'), startPos);
|
||||||
|
} else {
|
||||||
|
this.state.error('Semicolon is not permitted at this location', startPos);
|
||||||
|
}
|
||||||
|
case '@':
|
||||||
|
if (!this.readSimpleExpr(c._annotationsAt(c.exprs.length))) {
|
||||||
|
this.state.error('Missing annotation', startPos);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
case ':': {
|
||||||
|
let colons: string = ch;
|
||||||
|
while (!this.state.atEnd() && this.state.peek() === ':') {
|
||||||
|
colons = colons + ':';
|
||||||
|
this.state.advance();
|
||||||
|
}
|
||||||
|
if (acceptPunct) {
|
||||||
|
return (c as BaseCompound<Expr>).push(new Punct(colons), startPos);
|
||||||
|
} else {
|
||||||
|
this.state.error('Colons are not permitted at this location', startPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case '#': {
|
||||||
|
const ch = this.state.nextchar();
|
||||||
|
switch (ch) {
|
||||||
|
case ' ': case '\t': {
|
||||||
|
const here = this.state.copyPos();
|
||||||
|
c._annotationsAt(c.exprs.length).push(this.state.readCommentLine(), here);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case '\n': case '\r': {
|
||||||
|
const here = this.state.copyPos();
|
||||||
|
c._annotationsAt(c.exprs.length).push('', here);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case '!': {
|
||||||
|
const here = this.state.copyPos();
|
||||||
|
const r = new Record();
|
||||||
|
r.push(Symbol.for('interpreter'), here);
|
||||||
|
r.push(this.state.readCommentLine(), here);
|
||||||
|
c._annotationsAt(c.exprs.length).push(r, here);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case 'f': this.state.requireDelimiter('#f'); return c.push(false, startPos);
|
||||||
|
case 't': this.state.requireDelimiter('#t'); return c.push(true, startPos);
|
||||||
|
case '{': return c.push(this.readCompound(new Set(), '}'), startPos);
|
||||||
|
case '"': return c.push(this.state.readLiteralBinary(), startPos);
|
||||||
|
case 'x': switch (this.state.nextchar()) {
|
||||||
|
case '"': return c.push(this.state.readHexBinary(), startPos);
|
||||||
|
case 'd': return c.push(this.state.readHexFloat(), startPos);
|
||||||
|
default: this.state.error('Invalid #x syntax', startPos);
|
||||||
|
}
|
||||||
|
case '[': return c.push(this.state.readBase64Binary(), startPos);
|
||||||
|
case ':': {
|
||||||
|
const r = new BaseCompound<SimpleExpr>();
|
||||||
|
if (!this.readSimpleExpr(r)) return false;
|
||||||
|
const e = new Embedded(r.exprs[0], r.annotations && r.annotations[0]);
|
||||||
|
return c.push(e, startPos);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
this.state.error(`Invalid # syntax: ${ch}`, startPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case '(': return c.push(this.readCompound(new Group(), ')'), startPos);
|
||||||
|
case '<': return c.push(this.readCompound(new Record(), '>'), startPos);
|
||||||
|
case '[': return c.push(this.readCompound(new Sequence(), ']'), startPos);
|
||||||
|
case '{': return c.push(this.readCompound(new Block(), '}'), startPos);
|
||||||
|
case ')': return this._checkTerminator(ch, terminator, startPos);
|
||||||
|
case '>': return this._checkTerminator(ch, terminator, startPos);
|
||||||
|
case ']': return this._checkTerminator(ch, terminator, startPos);
|
||||||
|
case '}': return this._checkTerminator(ch, terminator, startPos);
|
||||||
|
case ',':
|
||||||
|
if (acceptPunct) {
|
||||||
|
return (c as BaseCompound<Expr>).push(new Punct(','), startPos);
|
||||||
|
} else {
|
||||||
|
this.state.error('Comma is not permitted at this location', startPos);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return c.push(this.state.readRawSymbolOrNumber(ch), startPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AsPreservesOptions<T extends Embeddable> {
|
||||||
|
onGroup?: (g: Positioned<Group>) => Value<T>;
|
||||||
|
onEmbedded?: (e: Positioned<Expr>, walk: (p: Positioned<Expr>) => Value<T>) => Value<T>;
|
||||||
|
error?: (tag: string, position: Position) => Value<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asPreserves<T extends Embeddable>(
|
||||||
|
p: Positioned<Expr>,
|
||||||
|
options: AsPreservesOptions<T> = {},
|
||||||
|
): Value<T> {
|
||||||
|
const error = options.error ?? ((tag, position) => {
|
||||||
|
throw new Error(formatPosition(position) + ": " + tag);
|
||||||
|
});
|
||||||
|
|
||||||
|
function nonCommas(p: Compound): Positioned<Expr>[] {
|
||||||
|
return Array.from(p).filter(p => !Punct.isComma(p.item));
|
||||||
|
}
|
||||||
|
|
||||||
|
function walk(p: Positioned<Expr>): Value<T> {
|
||||||
|
if (p.item instanceof Punct) {
|
||||||
|
return error('invalid-punctuation', p.position);
|
||||||
|
} else if (p.item instanceof Embedded) {
|
||||||
|
if (options.onEmbedded) {
|
||||||
|
return options.onEmbedded({ position: p.position, item: p.item.expr }, walk);
|
||||||
|
} else {
|
||||||
|
return error('unexpected-embedded', p.position);
|
||||||
|
}
|
||||||
|
} else if (p.item instanceof Compound) {
|
||||||
|
switch (p.item.variant) {
|
||||||
|
case 'sequence':
|
||||||
|
return nonCommas(p.item).map(walk);
|
||||||
|
case 'record': {
|
||||||
|
const vs = nonCommas(p.item).map(walk);
|
||||||
|
if (vs.length < 1) {
|
||||||
|
return error('invalid-record', p.position);
|
||||||
|
}
|
||||||
|
const r = vs.slice(1) as unknown as VRecord<Value<T>, Value<T>[], T>;
|
||||||
|
r.label = vs[0];
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
case 'block': {
|
||||||
|
const d = new DictionaryMap<T>();
|
||||||
|
const vs = nonCommas(p.item);
|
||||||
|
if ((vs.length % 3) !== 0) {
|
||||||
|
return error('invalid-dictionary', p.position);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < vs.length; i += 3) {
|
||||||
|
if (!Punct.isColon(vs[i + 1].item)) {
|
||||||
|
return error('missing-colon', vs[i + 1].position);
|
||||||
|
}
|
||||||
|
const k = walk(vs[i]);
|
||||||
|
const v = walk(vs[i + 2]);
|
||||||
|
d.set(k, v);
|
||||||
|
}
|
||||||
|
return d.simplifiedValue();
|
||||||
|
}
|
||||||
|
case 'group': {
|
||||||
|
if (options.onGroup) {
|
||||||
|
return options.onGroup(p as Positioned<Group>);
|
||||||
|
} else {
|
||||||
|
return error('unexpected-group', p.position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'set':
|
||||||
|
return new VSet(nonCommas(p.item).map(walk));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return p.item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return walk(p);
|
||||||
|
}
|
|
@ -2,15 +2,15 @@
|
||||||
|
|
||||||
import type { Value } from './values';
|
import 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> {
|
||||||
|
|
|
@ -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>)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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>;
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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'));
|
||||||
|
});
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { Pexpr, Value, fromJS, parse, stringify } from '../src/index';
|
||||||
|
import './test-utils';
|
||||||
|
|
||||||
|
function P(s: string): Value<any>[] {
|
||||||
|
return parse(s, { includeAnnotations: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('basics', () => {
|
||||||
|
it('simple example', () => {
|
||||||
|
const r = new Pexpr.Reader('#!foo\n<bar {zot ::quux}, [a; b; c;]>');
|
||||||
|
const d = r.nextDocument();
|
||||||
|
expect(fromJS(d)).is(P(`[\n#!foo\n
|
||||||
|
<r bar <b zot <p |::|> quux> <p |,|> [a <p |;|> b <p |;|> c <p |;|>]>]`));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('simple group', () => {
|
||||||
|
const r = new Pexpr.Reader('(+ 1 2)');
|
||||||
|
expect(fromJS(r.nextDocument())).is(P('[<g + 1 2>]'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('asPreserves', () => {
|
||||||
|
const s = '{a: b, c: d, e: [1, 2 <r 3 4>]}';
|
||||||
|
const d = new Pexpr.Reader(s).nextDocument();
|
||||||
|
const v = Pexpr.asPreserves(d.get(0)!);
|
||||||
|
expect(v).is(P(s));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('trailing comments', () => {
|
||||||
|
it('basics 1', () => {
|
||||||
|
const d = new Pexpr.Reader('# a comment with nothing after').nextDocument();
|
||||||
|
expect(d.annotations?.[d.exprs.length].get(0)?.item).toBe('a comment with nothing after');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('basics 2', () => {
|
||||||
|
const d = new Pexpr.Reader('# a comment with nothing after\n').nextDocument();
|
||||||
|
expect(d.annotations?.[d.exprs.length].get(0)?.item).toBe('a comment with nothing after');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('inside a sequence', () => {
|
||||||
|
const d = new Pexpr.Reader('[\n1\n# a comment with nothing after\n]\n').nextDocument();
|
||||||
|
const seq = d.get(0)?.item as Pexpr.Compound;
|
||||||
|
expect(seq.annotations?.[seq.exprs.length].get(0)?.item).toBe('a comment with nothing after');
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,4 +1,4 @@
|
||||||
import { Bytes, Decoder, genericEmbeddedType, encode, Reader, Double } from '../src/index';
|
import { Bytes, Decoder, genericEmbeddedType, encode, Reader, Double, KeyedDictionary, Value } from '../src/index';
|
||||||
import './test-utils';
|
import './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][]));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}<');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@preserves/schema-cli",
|
"name": "@preserves/schema-cli",
|
||||||
"version": "0.993.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.993.0",
|
"@preserves/core": "^0.995.206",
|
||||||
"@preserves/schema": "^0.993.0",
|
"@preserves/schema": "^0.995.206",
|
||||||
"chalk": "^4.1",
|
"chalk": "^4.1",
|
||||||
"chokidar": "^3.5",
|
"chokidar": "^3.5",
|
||||||
"commander": "^7.2",
|
"commander": "^7.2",
|
||||||
|
|
|
@ -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))));
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@preserves/schema",
|
"name": "@preserves/schema",
|
||||||
"version": "0.993.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.993.0"
|
"@preserves/core": "^0.995.206"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/js-beautify": "1.14",
|
||||||
|
"js-beautify": "1.15"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,33 +68,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// I.env.forEach((_schema, path) => console.log(PreservesSchema.Meta.formatModulePath(path)));
|
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);
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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!;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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)}`);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -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;};
|
||||||
|
|
|
@ -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);}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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';
|
||||||
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { } from '@preserves/core';
|
||||||
|
import { compile, Meta as M, readSchema } from '../src/index';
|
||||||
|
import './test-utils';
|
||||||
|
import { js as format } from 'js-beautify';
|
||||||
|
|
||||||
|
function compileSingleSchema(source: string): string {
|
||||||
|
return format(compile([], [Symbol.for('test')], readSchema(`version 1 . ${source}`), {}));
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('compiler', () => {
|
||||||
|
it('basics', () => {
|
||||||
|
expect(compileSingleSchema(`X = int .`)).toContain(`\nexport type X = number;\n`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('symbol-keyed dictionary', () => {
|
||||||
|
const s = compileSingleSchema(`D = { symbol:any ...:... } .`);
|
||||||
|
expect(s).toMatch(/^export type D.*= _.JsDictionary < _.Value < _embedded >> ;$/m);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('string-keyed dictionary', () => {
|
||||||
|
const s = compileSingleSchema(`D = { string:any ...:... } .`);
|
||||||
|
expect(s).toMatch(/^export type D.*= _.EncodableDictionary < _embedded, string, _.Value < _embedded >> ;$/m);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('any-keyed dictionary', () => {
|
||||||
|
const s = compileSingleSchema(`D = { any:any ...:... } .`);
|
||||||
|
expect(s).toMatch(/^export type D.*= _.EncodableDictionary < _embedded, _.Value < _embedded > , _.Value < _embedded >> ;$/m);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,111 @@
|
||||||
|
import { GenericEmbedded, stringify, fromJS, parse, EncodableDictionary, KeyedDictionary } from '@preserves/core';
|
||||||
|
import { SchemaInterpreter, readSchema } from '../src/index';
|
||||||
|
import './test-utils';
|
||||||
|
|
||||||
|
describe('interpreter', () => {
|
||||||
|
const I = new SchemaInterpreter<GenericEmbedded>();
|
||||||
|
|
||||||
|
const X_schema = readSchema(`
|
||||||
|
version 1 .
|
||||||
|
A = <foo> .
|
||||||
|
B = <bar @v int> .
|
||||||
|
C = <zot @v int @w int> .
|
||||||
|
N = int .
|
||||||
|
|
||||||
|
U = <class @a int @b int> / <true @c int @d int> .
|
||||||
|
V = <public @n int> / <private @n int> .
|
||||||
|
W = <const> / <let> .
|
||||||
|
|
||||||
|
D1 = { symbol:A ...:... } .
|
||||||
|
D2 = { any:A ...:... } .
|
||||||
|
D3 = { string:A ...:... } .
|
||||||
|
`);
|
||||||
|
const X = Symbol.for('X');
|
||||||
|
I.env.set([X], X_schema);
|
||||||
|
|
||||||
|
const E = I.moduleTree();
|
||||||
|
|
||||||
|
it('basically works', () => {
|
||||||
|
const a = E.X.A();
|
||||||
|
const b = E.X.B(22);
|
||||||
|
const c = E.X.C({v: 33, w: 44});
|
||||||
|
const n = E.X.N(22);
|
||||||
|
expect(stringify(a)).toBe('<foo>');
|
||||||
|
expect(stringify(b)).toBe('<bar 22>');
|
||||||
|
expect(stringify(c)).toBe('<zot 33 44>');
|
||||||
|
expect(stringify(n)).toBe('22');
|
||||||
|
expect(parse('<foo>')).is(fromJS(a));
|
||||||
|
expect(parse('<bar 22>')).is(fromJS(b));
|
||||||
|
expect(parse('<zot 33 44>')).is(fromJS(c));
|
||||||
|
expect(parse('22')).is(fromJS(n));
|
||||||
|
expect(stringify(E.X.asA(fromJS(a)))).toBe('<foo>');
|
||||||
|
expect(stringify(E.X.asB(fromJS(b)))).toBe('<bar 22>');
|
||||||
|
expect(stringify(E.X.asC(fromJS(c)))).toBe('<zot 33 44>');
|
||||||
|
expect(stringify(E.X.asN(fromJS(n)))).toBe('22');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('escapes JS keywords', () => {
|
||||||
|
expect(Object.keys(E.X.U)).toEqual(['$class', '$true']);
|
||||||
|
expect(Object.keys(E.X.V)).toEqual(['$public', '$private']);
|
||||||
|
expect(Object.keys(E.X.W)).toEqual(['$const', '$let']);
|
||||||
|
});
|
||||||
|
|
||||||
|
const STANDARD_METHODS = ['__as_preserve__', '__preserve_on__', '__preserve_text_on__'];
|
||||||
|
|
||||||
|
it('accepts correct arguments to n-ary variant ctors', () => {
|
||||||
|
expect(stringify(E.X.U.$class({ a: 123, b: 234 }))).toBe('<class 123 234>');
|
||||||
|
expect(stringify(E.X.U.$true({ c: 123, d: 234 }))).toBe('<true 123 234>');
|
||||||
|
expect(Object.keys(E.X.U.$class({ a: 123, b: 234 }))).toEqual([
|
||||||
|
'_variant', 'a', 'b', ... STANDARD_METHODS]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts correct arguments to unary variant ctors', () => {
|
||||||
|
expect(stringify(E.X.V.$public(123))).toBe('<public 123>');
|
||||||
|
expect(stringify(E.X.V.$private(123))).toBe('<private 123>');
|
||||||
|
expect(Object.keys(E.X.V.$public(123))).toEqual([
|
||||||
|
'_variant', 'n', ... STANDARD_METHODS]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts correct arguments to nullary variant ctors', () => {
|
||||||
|
expect(stringify(E.X.W.$const())).toBe('<const>');
|
||||||
|
expect(stringify(E.X.W.$let())).toBe('<let>');
|
||||||
|
expect(Object.keys(E.X.W.$const())).toEqual([
|
||||||
|
'_variant', ... STANDARD_METHODS]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('produces JsDictionary for symbol-keyed dicts', () => {
|
||||||
|
const v = E.X.asD1(parse('{ a: <foo>, b: <foo>}'));
|
||||||
|
expect(Object.keys(v)).toEqual(['a', 'b']);
|
||||||
|
expect(stringify(E.X.fromA(v.a))).toBe('<foo>');
|
||||||
|
expect(stringify(E.X.fromA(v.b))).toBe('<foo>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('produces EncodableDictionary for any-keyed dicts', () => {
|
||||||
|
const d2 = E.X.asD2(parse('{ a: <foo>, b: <foo>}'));
|
||||||
|
expect(d2 instanceof EncodableDictionary).toBe(true);
|
||||||
|
expect(Array.from(d2.keys())).toEqual([Symbol.for('a'), Symbol.for('b')]);
|
||||||
|
expect(fromJS(d2.get(Symbol.for('a')))).is(fromJS(E.X.A()));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts either kind of dictionary for symbol-keyed dicts', () => {
|
||||||
|
const v = { a: E.X.A(), b: E.X.A() };
|
||||||
|
expect(stringify(v)).toBe('{a: <foo> b: <foo>}');
|
||||||
|
expect(E.X.fromD1(v)).is(parse('{a: <foo> b: <foo>}'));
|
||||||
|
expect(E.X.fromD1(E.X.D1(v))).is(parse('{a: <foo> b: <foo>}'));
|
||||||
|
expect(E.X.fromD1(E.X.D1(new KeyedDictionary([
|
||||||
|
[parse('a'), parse('<foo>')],
|
||||||
|
[parse('b'), parse('<foo>')],
|
||||||
|
])))).is(parse('{a: <foo> b: <foo>}'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts either kind of dictionary for any-keyed dicts', () => {
|
||||||
|
const v = { a: E.X.A(), b: E.X.A() };
|
||||||
|
expect(stringify(v)).toBe('{a: <foo> b: <foo>}');
|
||||||
|
expect(E.X.fromD2(v)).is(parse('{a: <foo> b: <foo>}'));
|
||||||
|
expect(E.X.fromD2(E.X.D2(v))).is(parse('{a: <foo> b: <foo>}'));
|
||||||
|
expect(E.X.fromD2(E.X.D2(new KeyedDictionary([
|
||||||
|
[parse('a'), parse('<foo>')],
|
||||||
|
[parse('b'), parse('<foo>')],
|
||||||
|
])))).is(parse('{a: <foo> b: <foo>}'));
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { JsDictionary } from '@preserves/core';
|
||||||
import { readSchema, Meta } from '../src/index';
|
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');
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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))
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ def map_embeddeds(f, v):
|
||||||
|
|
||||||
```python
|
```python
|
||||||
>>> map_embeddeds(lambda w: Embedded(f'w={w}'), ['a', Embedded(123), {'z': 6.0}])
|
>>> map_embeddeds(lambda w: Embedded(f'w={w}'), ['a', Embedded(123), {'z': 6.0}])
|
||||||
('a', #!'w=123', {'z': 6.0})
|
('a', #:'w=123', {'z': 6.0})
|
||||||
|
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -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."
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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())
|
||||||
|
@ -356,7 +360,7 @@ class Parser(TextCodec):
|
||||||
if c == 'd': return self.wrap(self.read_hex_float())
|
if c == 'd': return self.wrap(self.read_hex_float())
|
||||||
raise DecodeError('Invalid #x syntax')
|
raise DecodeError('Invalid #x syntax')
|
||||||
if c == '[': return self.wrap(self.read_base64_binary())
|
if c == '[': return self.wrap(self.read_base64_binary())
|
||||||
if c == '!':
|
if c == ':':
|
||||||
if self.parse_embedded is None:
|
if self.parse_embedded is None:
|
||||||
raise DecodeError('No parse_embedded function supplied')
|
raise DecodeError('No parse_embedded function supplied')
|
||||||
return self.wrap(Embedded(self.parse_embedded(self.next())))
|
return self.wrap(Embedded(self.parse_embedded(self.next())))
|
||||||
|
|
|
@ -575,7 +575,7 @@ class Embedded:
|
||||||
>>> import io
|
>>> import io
|
||||||
>>> e = Embedded(io.StringIO('some text'))
|
>>> e = Embedded(io.StringIO('some text'))
|
||||||
>>> e # doctest: +ELLIPSIS
|
>>> e # doctest: +ELLIPSIS
|
||||||
#!<_io.StringIO object at ...>
|
#:<_io.StringIO object at ...>
|
||||||
>>> e.embeddedValue # doctest: +ELLIPSIS
|
>>> e.embeddedValue # doctest: +ELLIPSIS
|
||||||
<_io.StringIO object at ...>
|
<_io.StringIO object at ...>
|
||||||
|
|
||||||
|
@ -588,7 +588,7 @@ class Embedded:
|
||||||
...
|
...
|
||||||
TypeError: Cannot preserves-format: None
|
TypeError: Cannot preserves-format: None
|
||||||
>>> print(preserves.stringify(Embedded(None), format_embedded=lambda x: 'abcdef'))
|
>>> print(preserves.stringify(Embedded(None), format_embedded=lambda x: 'abcdef'))
|
||||||
#!"abcdef"
|
#:"abcdef"
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -610,12 +610,12 @@ class Embedded:
|
||||||
return hash(self.embeddedValue)
|
return hash(self.embeddedValue)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '#!%r' % (self.embeddedValue,)
|
return '#:%r' % (self.embeddedValue,)
|
||||||
|
|
||||||
def __preserve_write_binary__(self, encoder):
|
def __preserve_write_binary__(self, encoder):
|
||||||
encoder.buffer.append(0x86)
|
encoder.buffer.append(0x86)
|
||||||
encoder.append(encoder.encode_embedded(self.embeddedValue))
|
encoder.append(encoder.encode_embedded(self.embeddedValue))
|
||||||
|
|
||||||
def __preserve_write_text__(self, formatter):
|
def __preserve_write_text__(self, formatter):
|
||||||
formatter.chunks.append('#!')
|
formatter.chunks.append('#:')
|
||||||
formatter.append(formatter.format_embedded(self.embeddedValue))
|
formatter.append(formatter.format_embedded(self.embeddedValue))
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/sh
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
. ./.envrc
|
||||||
|
exec python -c \
|
||||||
|
'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])'
|
|
@ -1,6 +1,6 @@
|
||||||
[project]
|
[project]
|
||||||
name = "preserves"
|
name = "preserves"
|
||||||
version = "0.993.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"
|
||||||
|
|
Binary file not shown.
|
@ -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 }">
|
||||||
|
@ -167,9 +176,9 @@
|
||||||
list11: <Test #x"b5b0010184" [01]>
|
list11: <Test #x"b5b0010184" [01]>
|
||||||
list12: <Test #x"b5b0010c84" [12]>
|
list12: <Test #x"b5b0010c84" [12]>
|
||||||
noinput0: @"No input at all" <DecodeEOF #x"">
|
noinput0: @"No input at all" <DecodeEOF #x"">
|
||||||
embed0: <Test #x"86b000" #!0>
|
embed0: <Test #x"86b000" #:0>
|
||||||
embed1: <Test #x"8686b000" #!#!0>
|
embed1: <Test #x"8686b000" #:#:0>
|
||||||
embed2: <Test #x"b586b00086b10568656c6c6f84" [#!0 #!"hello"]>
|
embed2: <Test #x"b586b00086b10568656c6c6f84" [#:0 #:"hello"]>
|
||||||
record1: <Test #x"b4 b30763617074757265 b4 b30764697363617264 84 84" <capture <discard>>>
|
record1: <Test #x"b4 b30763617074757265 b4 b30764697363617264 84 84" <capture <discard>>>
|
||||||
record2: <Test #x"b4 b3076f627365727665 b4 b305737065616b b4 b30764697363617264 84 b4 b30763617074757265 b4 b30764697363617264 84 84 84 84" <observe <speak <discard> <capture <discard>>>>>
|
record2: <Test #x"b4 b3076f627365727665 b4 b305737065616b b4 b30764697363617264 84 b4 b30763617074757265 b4 b30764697363617264 84 84 84 84" <observe <speak <discard> <capture <discard>>>>>
|
||||||
record2a: @"Commas not allowed in records" <ParseError "<observe <speak <discard>, <capture <discard>>>>">
|
record2a: @"Commas not allowed in records" <ParseError "<observe <speak <discard>, <capture <discard>>>>">
|
||||||
|
@ -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">
|
||||||
|
|
|
@ -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)))
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -41,7 +41,7 @@ SimplePattern =
|
||||||
# special builtins: bool, double, int, string, bytes, symbol
|
# special builtins: bool, double, int, string, bytes, symbol
|
||||||
/ <atom @atomKind AtomKind>
|
/ <atom @atomKind AtomKind>
|
||||||
|
|
||||||
# matches an embedded value in the input: #!p
|
# matches an embedded value in the input: #:p
|
||||||
/ <embedded @interface SimplePattern>
|
/ <embedded @interface SimplePattern>
|
||||||
|
|
||||||
# =symbol, <<lit> any>, or plain non-symbol atom
|
# =symbol, <<lit> any>, or plain non-symbol atom
|
||||||
|
|
|
@ -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 #\})]
|
||||||
|
@ -279,7 +280,7 @@
|
||||||
[(BLOCK ps ...) (grouped (convert-inner ps) " " "" "{ " " }")]
|
[(BLOCK ps ...) (grouped (convert-inner ps) " " "" "{ " " }")]
|
||||||
[(SET ps ...) (grouped (convert-inner ps) " " "" "#{ " " }")]
|
[(SET ps ...) (grouped (convert-inner ps) " " "" "#{ " " }")]
|
||||||
[(TRAILER-ANCHOR) ""]
|
[(TRAILER-ANCHOR) ""]
|
||||||
[(embedded v) (list "#!" (convert (encode-embedded v)))]
|
[(embedded v) (list "#:" (convert (encode-embedded v)))]
|
||||||
[(strip-annotations (record 'p (list s))) (symbol->string s)]
|
[(strip-annotations (record 'p (list s))) (symbol->string s)]
|
||||||
[v (preserve->string v)]))
|
[v (preserve->string v)]))
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)]
|
||||||
|
@ -114,7 +116,7 @@
|
||||||
[#\d (read-hex-float)]
|
[#\d (read-hex-float)]
|
||||||
[c (parse-error* "Invalid #x syntax: ~v" c)])]
|
[c (parse-error* "Invalid #x syntax: ~v" c)])]
|
||||||
[#\[ (read-base64-binary '())]
|
[#\[ (read-base64-binary '())]
|
||||||
[#\! (embedded (decode-embedded (next)))]
|
[#\: (embedded (decode-embedded (next)))]
|
||||||
[c (on-hash c)])]
|
[c (on-hash c)])]
|
||||||
|
|
||||||
[c (on-char c)]))
|
[c (on-char c)]))
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 }">
|
||||||
|
@ -167,9 +176,9 @@
|
||||||
list11: <Test #x"b5b0010184" [01]>
|
list11: <Test #x"b5b0010184" [01]>
|
||||||
list12: <Test #x"b5b0010c84" [12]>
|
list12: <Test #x"b5b0010c84" [12]>
|
||||||
noinput0: @"No input at all" <DecodeEOF #x"">
|
noinput0: @"No input at all" <DecodeEOF #x"">
|
||||||
embed0: <Test #x"86b000" #!0>
|
embed0: <Test #x"86b000" #:0>
|
||||||
embed1: <Test #x"8686b000" #!#!0>
|
embed1: <Test #x"8686b000" #:#:0>
|
||||||
embed2: <Test #x"b586b00086b10568656c6c6f84" [#!0 #!"hello"]>
|
embed2: <Test #x"b586b00086b10568656c6c6f84" [#:0 #:"hello"]>
|
||||||
record1: <Test #x"b4 b30763617074757265 b4 b30764697363617264 84 84" <capture <discard>>>
|
record1: <Test #x"b4 b30763617074757265 b4 b30764697363617264 84 84" <capture <discard>>>
|
||||||
record2: <Test #x"b4 b3076f627365727665 b4 b305737065616b b4 b30764697363617264 84 b4 b30763617074757265 b4 b30764697363617264 84 84 84 84" <observe <speak <discard> <capture <discard>>>>>
|
record2: <Test #x"b4 b3076f627365727665 b4 b305737065616b b4 b30764697363617264 84 b4 b30763617074757265 b4 b30764697363617264 84 84 84 84" <observe <speak <discard> <capture <discard>>>>>
|
||||||
record2a: @"Commas not allowed in records" <ParseError "<observe <speak <discard>, <capture <discard>>>>">
|
record2a: @"Commas not allowed in records" <ParseError "<observe <speak <discard>, <capture <discard>>>>">
|
||||||
|
@ -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">
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -176,7 +176,7 @@
|
||||||
[(? set?) (write-sequence distance "#{" (if commas? "," "") "}" write-value (set->list v))]
|
[(? set?) (write-sequence distance "#{" (if commas? "," "") "}" write-value (set->list v))]
|
||||||
[(? dict?) (write-sequence distance "{" (if commas? "," "") "}" write-key-value (dict->list v))]
|
[(? dict?) (write-sequence distance "{" (if commas? "," "") "}" write-key-value (dict->list v))]
|
||||||
[(embedded value)
|
[(embedded value)
|
||||||
(! "#!")
|
(! "#:")
|
||||||
(write-value distance (encode-embedded value))]
|
(write-value distance (encode-embedded value))]
|
||||||
[other (error 'write-preserve/text "Attempt to serialize non-preserve: ~v" other)]))
|
[other (error 'write-preserve/text "Attempt to serialize non-preserve: ~v" other)]))
|
||||||
|
|
||||||
|
|
|
@ -130,7 +130,7 @@ representation of `D`.
|
||||||
|
|
||||||
### Embeddeds.
|
### Embeddeds.
|
||||||
|
|
||||||
«#!V» = [0x86] ++ «V»
|
«#:V» = [0x86] ++ «V»
|
||||||
|
|
||||||
The `Repr` of an `Embedded` is the `Repr` of a `Value` chosen to
|
The `Repr` of an `Embedded` is the `Repr` of a `Value` chosen to
|
||||||
represent the denoted object, prefixed with `[0x86]`.
|
represent the denoted object, prefixed with `[0x86]`.
|
||||||
|
@ -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
|
||||||
|
|
|
@ -3,7 +3,7 @@ title: "P-expressions"
|
||||||
---
|
---
|
||||||
|
|
||||||
Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||||
October 2023. Version 0.3.0.
|
May 2024. Version 0.3.2.
|
||||||
|
|
||||||
[text syntax]: preserves-text.html
|
[text syntax]: preserves-text.html
|
||||||
|
|
||||||
|
@ -56,9 +56,9 @@ except special punctuation.
|
||||||
Embedded and annotated values are as in the text syntax, differing only
|
Embedded and annotated values are as in the text syntax, differing only
|
||||||
in that uses of `Value` are replaced with `SimpleExpr`.
|
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
|
||||||
|
@ -100,7 +100,7 @@ We write ⌜*p*⌝ for the encoding into Preserves of a P-expression *p*.
|
||||||
| ⌜`{`*p* ...`}`⌝ | = | `<b` ⌜*p*⌝ ...`>` |
|
| ⌜`{`*p* ...`}`⌝ | = | `<b` ⌜*p*⌝ ...`>` |
|
||||||
| ⌜`(`*p* ...`)`⌝ | = | `<g` ⌜*p*⌝ ...`>` |
|
| ⌜`(`*p* ...`)`⌝ | = | `<g` ⌜*p*⌝ ...`>` |
|
||||||
| ⌜`#{`*p* ...`}`⌝ | = | `<s `⌜*p*⌝ ...`>` |
|
| ⌜`#{`*p* ...`}`⌝ | = | `<s `⌜*p*⌝ ...`>` |
|
||||||
| ⌜`#!`*p*⌝ | = | `#!`⌜*p*⌝ |
|
| ⌜`#:`*p*⌝ | = | `#:`⌜*p*⌝ |
|
||||||
| ⌜`@`*p* *q*⌝ | = | `@`⌜*p*⌝ ⌜*q*⌝ |
|
| ⌜`@`*p* *q*⌝ | = | `@`⌜*p*⌝ ⌜*q*⌝ |
|
||||||
| ⌜*p*⌝ | = | *p* | when *p* ∈ **Atom** |
|
| ⌜*p*⌝ | = | *p* | when *p* ∈ **Atom** |
|
||||||
| ⌜`,`⌝ | = | `<p |,|>` |
|
| ⌜`,`⌝ | = | `<p |,|>` |
|
||||||
|
@ -196,9 +196,9 @@ text-syntax encodings.
|
||||||
```
|
```
|
||||||
|
|
||||||
```preserves
|
```preserves
|
||||||
⌜[1 + 2.0, print "Hello", predicate: #t, foo, #!remote, bar]⌝
|
⌜[1 + 2.0, print "Hello", predicate: #t, foo, #:remote, bar]⌝
|
||||||
= [1 + 2.0 <p |,|> print "Hello" <p |,|> predicate <p |:|> #t <p |,|>
|
= [1 + 2.0 <p |,|> print "Hello" <p |,|> predicate <p |:|> #t <p |,|>
|
||||||
foo <p |,|> #!remote <p |,|> bar]
|
foo <p |,|> #:remote <p |,|> bar]
|
||||||
```
|
```
|
||||||
|
|
||||||
```preserves
|
```preserves
|
||||||
|
@ -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>
|
||||||
>
|
>
|
||||||
|
@ -295,7 +297,7 @@ P-expression *p* ∈ `Expr` − {`,`}.
|
||||||
| **uncomma**(`{`*p* ...`}`) | = | `{`**uncomma**(*p*) ...`}` | omitting any *p* = `,` |
|
| **uncomma**(`{`*p* ...`}`) | = | `{`**uncomma**(*p*) ...`}` | omitting any *p* = `,` |
|
||||||
| **uncomma**(`(`*p* ...`)`) | = | `(`**uncomma**(*p*) ...`)` | omitting any *p* = `,` |
|
| **uncomma**(`(`*p* ...`)`) | = | `(`**uncomma**(*p*) ...`)` | omitting any *p* = `,` |
|
||||||
| **uncomma**(`#{`*p* ...`}`) | = | `#{`**uncomma**(*p*) ...`}` | omitting any *p* = `,` |
|
| **uncomma**(`#{`*p* ...`}`) | = | `#{`**uncomma**(*p*) ...`}` | omitting any *p* = `,` |
|
||||||
| **uncomma**(`#!`*p*) | = | `#!`**uncomma**(*p*) | |
|
| **uncomma**(`#:`*p*) | = | `#:`**uncomma**(*p*) | |
|
||||||
| **uncomma**(`@`*p* *q*) | = | `@`**uncomma**(*p*) **uncomma**(*q*) | |
|
| **uncomma**(`@`*p* *q*) | = | `@`**uncomma**(*p*) **uncomma**(*q*) | |
|
||||||
| **uncomma**(*p*) | = | *p* | if *p* ∈ **Atom** ∪ **Punct** − {`,`} |
|
| **uncomma**(*p*) | = | *p* | if *p* ∈ **Atom** ∪ **Punct** − {`,`} |
|
||||||
|
|
||||||
|
@ -308,7 +310,7 @@ P-expression *p* ∈ `Expr` − {`,`} to a corresponding Preserves `Value`.
|
||||||
| ⌞`<`ℓ *p* ...`>`⌟ | = | `<`⌞ℓ⌟ ⌞*p*⌟ ...`>` | |
|
| ⌞`<`ℓ *p* ...`>`⌟ | = | `<`⌞ℓ⌟ ⌞*p*⌟ ...`>` | |
|
||||||
| ⌞`{`*k*`:`*v* ...`}`⌟ | = | `{`⌞*k*⌟`:`⌞*v*⌟ ...`}` | if all ⌞*k*⌟ ... are distinct |
|
| ⌞`{`*k*`:`*v* ...`}`⌟ | = | `{`⌞*k*⌟`:`⌞*v*⌟ ...`}` | if all ⌞*k*⌟ ... are distinct |
|
||||||
| ⌞`#{`*p* ...`}`⌟ | = | `#{`⌞*p*⌟ ...`}` | if all ⌞*p*⌟ ... are distinct |
|
| ⌞`#{`*p* ...`}`⌟ | = | `#{`⌞*p*⌟ ...`}` | if all ⌞*p*⌟ ... are distinct |
|
||||||
| ⌞`#!`*p*⌟ | = | `#!`⌞*p*⌟ | |
|
| ⌞`#:`*p*⌟ | = | `#:`⌞*p*⌟ | |
|
||||||
| ⌞`@`*p* *q*⌟ | = | `@`⌞*p*⌟ ⌞*q*⌟ | |
|
| ⌞`@`*p* *q*⌟ | = | `@`⌞*p*⌟ ⌞*q*⌟ | |
|
||||||
| ⌞*p*⌟ | = | *p* | when *p* ∈ **Atom** |
|
| ⌞*p*⌟ | = | *p* | when *p* ∈ **Atom** |
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
@ -327,11 +335,11 @@ Specifying the name of a kind of `Atom` matches that kind of atom:
|
||||||
AtomKindPattern = "bool" / "double" / "int" / "string" / "bytes" / "symbol"
|
AtomKindPattern = "bool" / "double" / "int" / "string" / "bytes" / "symbol"
|
||||||
|
|
||||||
Embedded input `Value`s are matched with embedded patterns. The
|
Embedded input `Value`s are matched with embedded patterns. The
|
||||||
portion under the `#!` prefix is the *interface* schema for the
|
portion under the `#:` prefix is the *interface* schema for the
|
||||||
embedded value.[^interface-schema] The result of a match is an
|
embedded value.[^interface-schema] The result of a match is an
|
||||||
instance of the schema-wide `embeddedType`, if one is supplied.
|
instance of the schema-wide `embeddedType`, if one is supplied.
|
||||||
|
|
||||||
EmbeddedPattern = "#!" SimplePattern
|
EmbeddedPattern = "#:" SimplePattern
|
||||||
|
|
||||||
A literal pattern may be expressed in any of three ways: non-symbol
|
A literal pattern may be expressed in any of three ways: non-symbol
|
||||||
atoms stand for themselves directly; symbols, prefixed with an equal
|
atoms stand for themselves directly; symbols, prefixed with an equal
|
||||||
|
@ -368,9 +376,9 @@ identifier.
|
||||||
the interface schema associated with an embedded value describes
|
the interface schema associated with an embedded value describes
|
||||||
the messages that may be sent to that actor.
|
the messages that may be sent to that actor.
|
||||||
|
|
||||||
**Examples.** `#!any` may denote a reference to an Actor able to
|
**Examples.** `#:any` may denote a reference to an Actor able to
|
||||||
receive any value as a message; `#!#t`, a reference to an Actor
|
receive any value as a message; `#:#t`, a reference to an Actor
|
||||||
expecting *only* the "true" message; `#!Session`, a reference to
|
expecting *only* the "true" message; `#:Session`, a reference to
|
||||||
an Actor expecting any message matching a schema defined as
|
an Actor expecting any message matching a schema defined as
|
||||||
`Session` in this file.
|
`Session` in this file.
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -628,7 +648,7 @@ Simple patterns are as described above:
|
||||||
# special builtins: bool, double, int, string, bytes, symbol
|
# special builtins: bool, double, int, string, bytes, symbol
|
||||||
/ <atom @atomKind AtomKind>
|
/ <atom @atomKind AtomKind>
|
||||||
|
|
||||||
# matches an embedded value in the input: #!p
|
# matches an embedded value in the input: #:p
|
||||||
/ <embedded @interface SimplePattern>
|
/ <embedded @interface SimplePattern>
|
||||||
|
|
||||||
# =symbol, <<lit> any>, or plain non-symbol atom
|
# =symbol, <<lit> any>, or plain non-symbol atom
|
||||||
|
@ -973,16 +993,16 @@ definitions for the metaschema.
|
||||||
further; also, consideration of *dependent* schemas (analogous to
|
further; also, consideration of *dependent* schemas (analogous to
|
||||||
dependent contracts) could be of interest.
|
dependent contracts) could be of interest.
|
||||||
|
|
||||||
**Example.** In the following fragment, `#!Session` is the handle a
|
**Example.** In the following fragment, `#:Session` is the handle a
|
||||||
connected user uses to interact with a chatroom. In the
|
connected user uses to interact with a chatroom. In the
|
||||||
implementation, `Says` messages are dropped if their `who` doesn't
|
implementation, `Says` messages are dropped if their `who` doesn't
|
||||||
match the `uid` supplied in the `Join` assertion. It'd be nice to
|
match the `uid` supplied in the `Join` assertion. It'd be nice to
|
||||||
capture that using a dependent schema, passing in the specific
|
capture that using a dependent schema, passing in the specific
|
||||||
`uid` value to the `Session` constructor, something like
|
`uid` value to the `Session` constructor, something like
|
||||||
`#!(Session uid)`.
|
`#:(Session uid)`.
|
||||||
|
|
||||||
Join = <joinedUser @uid UserId @handle #!Session>.
|
Join = <joinedUser @uid UserId @handle #:Session>.
|
||||||
Session = @observeSpeech <Observe =says @observer #!Says> / Says .
|
Session = @observeSpeech <Observe =says @observer #:Says> / Says .
|
||||||
Says = <says @who UserId @what string>.
|
Says = <says @who UserId @what string>.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -263,9 +263,9 @@ grammar above.[^rationale-no-general-machine-syntax]
|
||||||
annotations potentially contained within machine-encoded values.
|
annotations potentially contained within machine-encoded values.
|
||||||
|
|
||||||
Finally, an `Embedded` is written as a `Value` chosen to represent the
|
Finally, an `Embedded` is written as a `Value` chosen to represent the
|
||||||
denoted object, prefixed with `#!`.
|
denoted object, prefixed with `#:`.
|
||||||
|
|
||||||
Embedded = "#!" Value
|
Embedded = "#:" Value
|
||||||
|
|
||||||
## <a id="annotations"></a>Annotations and Comments
|
## <a id="annotations"></a>Annotations and Comments
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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))
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue