Switch from `#!` to `#:` for embedded values

This commit is contained in:
Tony Garnock-Jones 2024-02-05 22:38:49 +01:00
parent 83697b0e56
commit e923d87fa5
29 changed files with 57 additions and 57 deletions

View File

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

View File

@ -5,7 +5,7 @@ For a value `V`, we write `«V»` for the binary encoding of `V`.
«#t» = [0x81]
«@W V» = [0x85] ++ «W» ++ «V»
«#!V» = [0x86] ++ «V»
«#:V» = [0x86] ++ «V»
«V» if V ∈ Double = [0x87, 0x08] ++ binary64(V)

View File

@ -8,7 +8,7 @@ class="postcard-grammar binarysyntax">*V*</span>.
{:.postcard-grammar.binarysyntax}
«`@`*W* *V*» | = | `85` «*W*» «*V*»
«`#!`*V*» | = | `86` «*V*»
«`#:`*V*» | = | `86` «*V*»
{:.postcard-grammar.binarysyntax}
«*V*» | = | `87``08` **binary64**(*V*) | if *V* ∈ Double

View File

@ -15,7 +15,7 @@ Set := `#{` Expr* Trailer ws `}`
Trailer := (ws Annotation)*
Embedded := `#!` SimpleExpr
Embedded := `#:` SimpleExpr
Annotated := Annotation SimpleExpr
Annotation := `@` SimpleExpr | `#` ((space | tab) linecomment) (cr | lf)
```

View File

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

View File

@ -9,7 +9,7 @@ Set := `#{` (commas Value)* commas `}`
Dictionary := `{` (commas Value ws `:` Value)* commas `}`
commas := (ws `,`)* ws
Embedded := `#!` Value
Embedded := `#:` Value
Annotated := Annotation Value
Annotation := `@` Value | `#` ((space | tab) linecomment) (cr | lf)

View File

@ -11,7 +11,7 @@
| **commas** | := | (**ws** `,`)<sup></sup> **ws** |
{:.postcard-grammar.textsyntax}
| *Embedded* | := | `#!`*Value* |
| *Embedded* | := | `#:`*Value* |
| *Annotated* | := | *Annotation* *Value* |
| *Annotation* | := | `@`*Value* &#124;`#` ((**space** &#124; **tab**) *linecomment*) (**cr** &#124; **lf**) |

View File

@ -11,6 +11,6 @@ syntax](https://preserves.dev/preserves-text.html):
Sequence : [value1 value2 ...]
Set : #{value1 value2 ...}
Dictionary : {key1: value1 key2: value2 ...: ...}
Embedded : #!value
Embedded : #:value
Commas are optional in sequences, sets, and dictionaries.

View File

@ -41,7 +41,7 @@ let render
)
m
++ " }"
, embedded = λ(value : Text) → "#!${value}"
, embedded = λ(value : Text) → "#:${value}"
}
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

View File

@ -26,7 +26,7 @@ export class Embedded<T> {
}
toString(): string {
return '#!' + (this.embeddedValue as any).toString();
return '#:' + (this.embeddedValue as any).toString();
}
__as_preserve__<R>(): T extends R ? Value<R> : never {

View File

@ -354,7 +354,7 @@ export class Reader<T> {
default: this.state.error('Invalid #x syntax', startPos);
}
case '[': return this.state.readBase64Binary();
case '!': return embed(this.embeddedType.fromValue(
case ':': return embed(this.embeddedType.fromValue(
new Reader<GenericEmbedded>(this.state, genericEmbeddedTypeDecode).next(),
this.state.options));
default:

View File

@ -297,7 +297,7 @@ export class Writer<T> {
}
else {
((v: Embedded<T>) => {
this.state.pieces.push('#!');
this.state.pieces.push('#:');
if ('write' in this.embeddedWrite) {
this.embeddedWrite.write(this.state, v.embeddedValue);
} else {

View File

@ -18,7 +18,7 @@ describe('reader schema', () => {
expect(s.embeddedType._variant).toBe('false');
});
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'))!;
if (def._variant !== 'Pattern') fail('bad definition 1');
if (def.value._variant !== 'SimplePattern') fail ('bad definition 2');

View File

@ -9,7 +9,7 @@ def map_embeddeds(f, v):
```python
>>> 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})
```
"""

View File

@ -356,7 +356,7 @@ class Parser(TextCodec):
if c == 'd': return self.wrap(self.read_hex_float())
raise DecodeError('Invalid #x syntax')
if c == '[': return self.wrap(self.read_base64_binary())
if c == '!':
if c == ':':
if self.parse_embedded is None:
raise DecodeError('No parse_embedded function supplied')
return self.wrap(Embedded(self.parse_embedded(self.next())))

View File

@ -575,7 +575,7 @@ class Embedded:
>>> import io
>>> e = Embedded(io.StringIO('some text'))
>>> e # doctest: +ELLIPSIS
#!<_io.StringIO object at ...>
#:<_io.StringIO object at ...>
>>> e.embeddedValue # doctest: +ELLIPSIS
<_io.StringIO object at ...>
@ -588,7 +588,7 @@ class Embedded:
...
TypeError: Cannot preserves-format: None
>>> print(preserves.stringify(Embedded(None), format_embedded=lambda x: 'abcdef'))
#!"abcdef"
#:"abcdef"
```
@ -610,12 +610,12 @@ class Embedded:
return hash(self.embeddedValue)
def __repr__(self):
return '#!%r' % (self.embeddedValue,)
return '#:%r' % (self.embeddedValue,)
def __preserve_write_binary__(self, encoder):
encoder.buffer.append(0x86)
encoder.append(encoder.encode_embedded(self.embeddedValue))
def __preserve_write_text__(self, formatter):
formatter.chunks.append('#!')
formatter.chunks.append('#:')
formatter.append(formatter.format_embedded(self.embeddedValue))

View File

@ -167,9 +167,9 @@
list11: <Test #x"b5b0010184" [01]>
list12: <Test #x"b5b0010c84" [12]>
noinput0: @"No input at all" <DecodeEOF #x"">
embed0: <Test #x"86b000" #!0>
embed1: <Test #x"8686b000" #!#!0>
embed2: <Test #x"b586b00086b10568656c6c6f84" [#!0 #!"hello"]>
embed0: <Test #x"86b000" #:0>
embed1: <Test #x"8686b000" #:#:0>
embed2: <Test #x"b586b00086b10568656c6c6f84" [#:0 #:"hello"]>
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>>>>>
record2a: @"Commas not allowed in records" <ParseError "<observe <speak <discard>, <capture <discard>>>>">

View File

@ -41,7 +41,7 @@ SimplePattern =
# special builtins: bool, double, int, string, bytes, symbol
/ <atom @atomKind AtomKind>
# matches an embedded value in the input: #!p
# matches an embedded value in the input: #:p
/ <embedded @interface SimplePattern>
# =symbol, <<lit> any>, or plain non-symbol atom

View File

@ -279,7 +279,7 @@
[(BLOCK ps ...) (grouped (convert-inner ps) " " "" "{ " " }")]
[(SET ps ...) (grouped (convert-inner ps) " " "" "#{ " " }")]
[(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)]
[v (preserve->string v)]))

View File

@ -114,7 +114,7 @@
[#\d (read-hex-float)]
[c (parse-error* "Invalid #x syntax: ~v" c)])]
[#\[ (read-base64-binary '())]
[#\! (embedded (decode-embedded (next)))]
[#\: (embedded (decode-embedded (next)))]
[c (on-hash c)])]
[c (on-char c)]))

View File

@ -167,9 +167,9 @@
list11: <Test #x"b5b0010184" [01]>
list12: <Test #x"b5b0010c84" [12]>
noinput0: @"No input at all" <DecodeEOF #x"">
embed0: <Test #x"86b000" #!0>
embed1: <Test #x"8686b000" #!#!0>
embed2: <Test #x"b586b00086b10568656c6c6f84" [#!0 #!"hello"]>
embed0: <Test #x"86b000" #:0>
embed1: <Test #x"8686b000" #:#:0>
embed2: <Test #x"b586b00086b10568656c6c6f84" [#:0 #:"hello"]>
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>>>>>
record2a: @"Commas not allowed in records" <ParseError "<observe <speak <discard>, <capture <discard>>>>">

View File

@ -176,7 +176,7 @@
[(? set?) (write-sequence distance "#{" (if commas? "," "") "}" write-value (set->list v))]
[(? dict?) (write-sequence distance "{" (if commas? "," "") "}" write-key-value (dict->list v))]
[(embedded value)
(! "#!")
(! "#:")
(write-value distance (encode-embedded value))]
[other (error 'write-preserve/text "Attempt to serialize non-preserve: ~v" other)]))

View File

@ -130,7 +130,7 @@ representation of `D`.
### Embeddeds.
«#!V» = [0x86] ++ «V»
«#:V» = [0x86] ++ «V»
The `Repr` of an `Embedded` is the `Repr` of a `Value` chosen to
represent the denoted object, prefixed with `[0x86]`.

View File

@ -3,7 +3,7 @@ title: "P-expressions"
---
Tony Garnock-Jones <tonyg@leastfixedpoint.com>
October 2023. Version 0.3.0.
February 2024. Version 0.3.1.
[text syntax]: preserves-text.html
@ -56,7 +56,7 @@ except special punctuation.
Embedded and annotated values are as in the text syntax, differing only
in that uses of `Value` are replaced with `SimpleExpr`.
Embedded = "#!" SimpleExpr
Embedded = "#:" SimpleExpr
Annotated = Annotation SimpleExpr
Annotation = "@" SimpleExpr / "#" [(%x20 / %x09) linecomment] (CR / LF)
linecomment = *<any unicode scalar value except CR or LF>
@ -100,7 +100,7 @@ We write ⌜*p*⌝ for the encoding into Preserves of a P-expression *p*.
| ⌜`{`*p* ...`}`⌝ | = | `<b` ⌜*p*⌝ ...`>` |
| ⌜`(`*p* ...`)`⌝ | = | `<g` ⌜*p*⌝ ...`>` |
| ⌜`#{`*p* ...`}`⌝ | = | `<s `⌜*p*⌝ ...`>` |
| ⌜`#!`*p*⌝ | = | `#!`⌜*p*⌝ |
| ⌜`#:`*p*⌝ | = | `#:`⌜*p*⌝ |
| ⌜`@`*p* *q*⌝ | = | `@`⌜*p*⌝ ⌜*q*⌝ |
| ⌜*p*⌝ | = | *p* | when *p***Atom** |
| ⌜`,`⌝ | = | `<p |,|>` |
@ -196,9 +196,9 @@ text-syntax encodings.
```
```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 |,|>
foo <p |,|> #!remote <p |,|> bar]
foo <p |,|> #:remote <p |,|> bar]
```
```preserves
@ -295,7 +295,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*) | |
| **uncomma**(`#:`*p*) | = | `#:`**uncomma**(*p*) | |
| **uncomma**(`@`*p* *q*) | = | `@`**uncomma**(*p*) **uncomma**(*q*) | |
| **uncomma**(*p*) | = | *p* | if *p***Atom** **Punct** {`,`} |
@ -308,7 +308,7 @@ P-expression *p* ∈ `Expr` {`,`} to a corresponding Preserves `Value`.
| ⌞`<` *p* ...`>`⌟ | = | `<`⌞ℓ⌟ ⌞*p*⌟ ...`>` | |
| ⌞`{`*k*`:`*v* ...`}`⌟ | = | `{`⌞*k*⌟`:`⌞*v*⌟ ...`}` | if all ⌞*k*⌟ ... are distinct |
| ⌞`#{`*p* ...`}`⌟ | = | `#{`⌞*p*⌟ ...`}` | if all ⌞*p*⌟ ... are distinct |
| ⌞`#!`*p*⌟ | = | `#!`⌞*p*⌟ | |
| ⌞`#:`*p*⌟ | = | `#:`⌞*p*⌟ | |
| ⌞`@`*p* *q*⌟ | = | `@`⌞*p*⌟ ⌞*q*⌟ | |
| ⌞*p*⌟ | = | *p* | when *p***Atom** |

View File

@ -327,11 +327,11 @@ Specifying the name of a kind of `Atom` matches that kind of atom:
AtomKindPattern = "bool" / "double" / "int" / "string" / "bytes" / "symbol"
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
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
atoms stand for themselves directly; symbols, prefixed with an equal
@ -368,9 +368,9 @@ identifier.
the interface schema associated with an embedded value describes
the messages that may be sent to that actor.
**Examples.** `#!any` may denote a reference to an Actor able to
receive any value as a message; `#!#t`, a reference to an Actor
expecting *only* the "true" message; `#!Session`, a reference to
**Examples.** `#:any` may denote a reference to an Actor able to
receive any value as a message; `#:#t`, a reference to an Actor
expecting *only* the "true" message; `#:Session`, a reference to
an Actor expecting any message matching a schema defined as
`Session` in this file.
@ -628,7 +628,7 @@ Simple patterns are as described above:
# special builtins: bool, double, int, string, bytes, symbol
/ <atom @atomKind AtomKind>
# matches an embedded value in the input: #!p
# matches an embedded value in the input: #:p
/ <embedded @interface SimplePattern>
# =symbol, <<lit> any>, or plain non-symbol atom
@ -973,16 +973,16 @@ definitions for the metaschema.
further; also, consideration of *dependent* schemas (analogous to
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
implementation, `Says` messages are dropped if their `who` doesn't
match the `uid` supplied in the `Join` assertion. It'd be nice to
capture that using a dependent schema, passing in the specific
`uid` value to the `Session` constructor, something like
`#!(Session uid)`.
`#:(Session uid)`.
Join = <joinedUser @uid UserId @handle #!Session>.
Session = @observeSpeech <Observe =says @observer #!Says> / Says .
Join = <joinedUser @uid UserId @handle #:Session>.
Session = @observeSpeech <Observe =says @observer #:Says> / Says .
Says = <says @who UserId @what string>.

View File

@ -263,9 +263,9 @@ grammar above.[^rationale-no-general-machine-syntax]
annotations potentially contained within machine-encoded values.
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

View File

@ -214,8 +214,8 @@ sequences use [the Preserves binary encoding](preserves-binary.html).
The total ordering specified [above](#total-order) means that the following statements are true:
- `"bzz"` &lt; `"c"` &lt; `"caa"` &lt; `#!"a"`
- `#t` &lt; `3.0f` &lt; `3.0` &lt; `3` &lt; `"3"` &lt; `|3|` &lt; `[]` &lt; `#!#t`
- `"bzz"` &lt; `"c"` &lt; `"caa"` &lt; `#:"a"`
- `#t` &lt; `3.0f` &lt; `3.0` &lt; `3` &lt; `"3"` &lt; `|3|` &lt; `[]` &lt; `#:#t`
- `[#f]` &lt; `[foo]`, because `Boolean` appears before `Symbol` in the kind ordering
- `[x]` &lt; `[x y]`, because there is no element remaining to compare against `y`
- `[a b]` &lt; `[x]`, because `a` is smaller than `x`

View File

@ -41,7 +41,7 @@ SimplePattern =
# special builtins: bool, double, int, string, bytes, symbol
/ <atom @atomKind AtomKind>
# matches an embedded value in the input: #!p
# matches an embedded value in the input: #:p
/ <embedded @interface SimplePattern>
# =symbol, <<lit> any>, or plain non-symbol atom

View File

@ -167,9 +167,9 @@
list11: <Test #x"b5b0010184" [01]>
list12: <Test #x"b5b0010c84" [12]>
noinput0: @"No input at all" <DecodeEOF #x"">
embed0: <Test #x"86b000" #!0>
embed1: <Test #x"8686b000" #!#!0>
embed2: <Test #x"b586b00086b10568656c6c6f84" [#!0 #!"hello"]>
embed0: <Test #x"86b000" #:0>
embed1: <Test #x"8686b000" #:#:0>
embed2: <Test #x"b586b00086b10568656c6c6f84" [#:0 #:"hello"]>
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>>>>>
record2a: @"Commas not allowed in records" <ParseError "<observe <speak <discard>, <capture <discard>>>>">