Skip to content

Implement private-use separately from reserved #421

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Jul 24, 2023
12 changes: 7 additions & 5 deletions spec/formatting.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,18 +92,18 @@ and different implementations MAY choose to perform different levels of resoluti
> or some other locally appropriate value.

Depending on the presence or absence of an _operand_
and a _function_ or _reserved_ _annotation_,
and a _function_, _private-use_, or _reserved_ _annotation_,
one of the following is used to resolve the value of the _expression_:

- If the _expression_ contains no _annotation_,
its resolved value is determined by _literal resolution_ or _variable resolution_,
depending on the shape of the _operand_.
- Else, if the _expression_ has a _function_ _annotation_,
its resolved value is defined by _function resolution_.
- Else, the _expression_ has a _reserved_ _annotation_.
If the _annotation_ uses a `private-start` character that the implementation supports,
its value is resolved according to the implementation's specification.
Else, an Unsupported Expression error is emitted and a fallback value is used as its value.
- Else, if the _expression_ has a _private-use_ _annotation_,
its resolved value is defined according to the implementations's specification.
- Else, the _expression_ has a _reserved_ _annotation_,
an Unsupported Expression error is emitted and a fallback value is used as its value.
Comment on lines +105 to +106
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a run-on sentence, and the "it" could be specified a bit more explicitly. Yes, I realise that I'm in part correcting my own suggestion here.

Suggested change
- Else, the _expression_ has a _reserved_ _annotation_,
an Unsupported Expression error is emitted and a fallback value is used as its value.
- Else, the _expression_ has a _reserved_ _annotation_.
An Unsupported Expression error is emitted and
the expression resolves to a fallback value.


### Literal Resolution

Expand Down Expand Up @@ -183,6 +183,8 @@ An _expression_ fails to resolve when:

- A _variable_ _operand_ fails to resolve.
- A _function_ _annotation_ fails to resolve.
- A _private-use_ _annotation_ is unsupported by the implementation or if
a _private-use_ _annotation_ fails to resolve.
- The _expression_ has a _reserved_ _annotation_.

The _fallback value_ depends on the contents of the _expression_:
Expand Down
16 changes: 10 additions & 6 deletions spec/message.abnf
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ variant = when 1*(s key) [s] pattern
key = literal / "*"

expression = "{" [s] ((operand [s annotation]) / annotation) [s] "}"
operand = literal / variable
annotation = (function *(s option)) / reserved
operand = literal / variable
annotation = (function *(s option)) / reserved / private-use

literal = quoted / unquoted
variable = "$" name
Expand Down Expand Up @@ -42,11 +42,15 @@ unquoted = unquoted-start *name-char
unquoted-start = name-start / DIGIT / "."
/ %xB7 / %x300-36F / %x203F-2040

; reserve additional sigils for use by future versions of this
; specification or for private use by implementations
reserved = ( reserved-start / private-start ) reserved-body
reserved-start = "!" / "@" / "#" / "%" / "*" / "<" / ">" / "/" / "?" / "~"

; reserve sigils for private-use by implementations
private-use = private-start reserved-body
private-start = "^" / "&"

; reserve additional sigils for use by
; future versions of this specification
reserved = reserved-start reserved-body
reserved-start = "!" / "@" / "#" / "%" / "*" / "<" / ">" / "/" / "?" / "~"
reserved-body = *( [s] 1*(reserved-char / reserved-escape / literal))
reserved-char = %x00-08 ; omit HTAB and LF
/ %x0B-0C ; omit CR
Expand Down
54 changes: 45 additions & 9 deletions spec/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
1. [Variants](#variants)
1. [Patterns](#patterns)
1. [Expressions](#expressions)
1. [Reserved Sequences](#reserved)
1. [Private-Use Sequences](#private-use)
2. [Reserved Sequences](#reserved)
Comment on lines +22 to +23
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to start using explicit <a name="foo"></a> anchors at some point, rather than having two different names for spec sections.

1. [Tokens](#tokens)
1. [Keywords](#keywords)
1. [Text](#text)
Expand Down Expand Up @@ -410,20 +411,56 @@ option = name [s] "=" [s] (literal / variable)
> {{+h1 name=above-and-beyond}Above And Beyond{-h1}}
> ```

#### Private-Use

A **_private-use_** _annotation_ is an _annotation_ whose syntax is reserved
for use by a specific implementation or by private agreement between multiple implementations.
Implementations MAY define their own meaning and semantics for _private-use_ annotations.

A _private-use_ annotation starts with either U+0026 AMPERSAND `&` or U+005E CIRCUMFLEX ACCENT `^`.

Characters, including whitespace, are assigned meaning by the implementation.
The definition of escapes in the `reserved-body` production, used for the body of
a _private-use_ annotation is an affordance to implementations that
wish to use a syntax exactly like other functions. Specifically:
* The characters `\`, `{`, and `}` MUST be escaped as `\\`, `\{`, and `\}` respectively
when they appear in the body of a _private-use_ annotation.
* The character `|` is special: it SHOULD be escaped as `\|` in a _private-use_ annotation,
but can appear unescaped as long as it is paired with another `|`. This is an affordance to
allow _literals_ to appear in the private use syntax.

A _private-use_ _annotation_ MAY be empty after its introducing sigil.

**NOTE:** Users are cautioned that _private-use_ sequences cannot be reliably exchanged
and can result in errors during formatting.
It is generally a better idea to use the function registry
to define additional formatting or annotation options.

```abnf
private-use = private-start reserved-body
private-start = "&" / "^"
```

> Here are some examples of what _private-use_ sequences might look like:
> ```
> {Here's private use with an operand: {$foo &bar}}
> {Here's a placeholder that is entirely private-use: {&anything here}}
> {Here's a private-use function that uses normal function syntax: {$operand ^foo option=|literal|}}
> {The character \| has to be paired or escaped: {&private || |something between| or isolated: \| }}
> {Stop {& "translate 'stop' as a verb" might be a translator instruction or comment }}
> {Protect stuff in {^ph}<a>{^/ph}private use{^ph}</a>{^/ph}}
>```

#### Reserved

**_Reserved_** annotations start with a reserved character
and are intended for future standardization
as well as private implementation use.
and are intended for future standardization.
A _reserved_ _annotation_ MAY be empty or contain arbitrary text.
This allows maximum flexibility in future standardization,
as future definitions are expected to define additional semantics and constraints
as future definitions MAY define additional semantics and constraints
on the contents of these _annotations_.
A _reserved_ _annotation_ does not include trailing whitespace.

Implementations MAY define their own meaning and semantics for
_reserved_ annotations that start with
the U+0026 AMPERSAND `&` or U+005E CIRCUMFLEX ACCENT `^` characters.
Implementations MUST NOT assign meaning or semantics to
an _annotation_ starting with `reserved-start`:
these are reserved for future standardization.
Expand All @@ -433,9 +470,8 @@ While a reserved sequence is technically "well-formed",
unrecognized reserved sequences have no meaning and MAY result in errors during formatting.

```abnf
reserved = ( reserved-start / private-start ) reserved-body
reserved = reserved-start reserved-body
reserved-start = "!" / "@" / "#" / "%" / "*" / "<" / ">" / "/" / "?" / "~"
private-start = "^" / "&"
reserved-body = *( [s] 1*(reserved-char / reserved-escape / literal))
reserved-char = %x00-08 ; omit HTAB and LF
/ %x0B-0C ; omit CR
Expand Down