From b14a2d51150fd4c02d7c1ab03cef506eefa643f1 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Mon, 4 Dec 2023 20:43:27 -0500 Subject: [PATCH 1/7] data-model: Align message.json with the documented interfaces --- spec/data-model/message.json | 57 +++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/spec/data-model/message.json b/spec/data-model/message.json index 4b6c154ffd..b32ab9827a 100644 --- a/spec/data-model/message.json +++ b/spec/data-model/message.json @@ -22,8 +22,15 @@ }, "required": ["type", "name"] }, - "value": { - "oneOf": [{ "$ref": "#/$defs/literal" }, { "$ref": "#/$defs/variable" }] + "option": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "value": { + "oneOf": [{ "$ref": "#/$defs/literal" }, { "$ref": "#/$defs/variable" }] + } + }, + "required": ["name", "value"] }, "function": { @@ -32,16 +39,12 @@ "type": { "const": "function" }, "kind": { "enum": ["open", "close", "value"] }, "name": { "type": "string" }, + "operand": { + "oneOf": [{ "$ref": "#/$defs/literal" }, { "$ref": "#/$defs/variable" }] + }, "options": { "type": "array", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "value": { "$ref": "#/$defs/value" } - }, - "required": ["name", "value"] - } + "items": { "$ref": "#/$defs/option" } } }, "required": ["type", "kind", "name"] @@ -51,24 +54,26 @@ "properties": { "type": { "const": "unsupported-expression" }, "sigil": { - "enum": ["!", "@", "#", "%", "^", "&", "*", "<", ">", "?", "~"] + "enum": ["!", "@", "#", "%", "^", "&", "*", "<", ">", "/", "?", "~"] }, - "source": { "type": "string" } + "source": { "type": "string" }, + "operand": { + "oneOf": [{ "$ref": "#/$defs/literal" }, { "$ref": "#/$defs/variable" }] + } }, "required": ["type", "sigil", "source"] }, - "annotation": { - "oneOf": [ - { "$ref": "#/$defs/function" }, - { "$ref": "#/$defs/unsupported-expression" } - ] - }, "literal-expression": { "type": "object", "properties": { "arg": { "$ref": "#/$defs/literal" }, - "func": { "$ref": "#/$defs/annotation" } + "func": { + "oneOf": [ + { "$ref": "#/$defs/function" }, + { "$ref": "#/$defs/unsupported-expression" } + ] + } }, "required": ["arg"] }, @@ -76,14 +81,24 @@ "type": "object", "properties": { "arg": { "$ref": "#/$defs/variable" }, - "func": { "$ref": "#/$defs/annotation" } + "func": { + "oneOf": [ + { "$ref": "#/$defs/function" }, + { "$ref": "#/$defs/unsupported-expression" } + ] + } }, "required": ["arg"] }, "function-expression": { "type": "object", "properties": { - "func": { "$ref": "#/$defs/annotation" } + "func": { + "oneOf": [ + { "$ref": "#/$defs/function" }, + { "$ref": "#/$defs/unsupported-expression" } + ] + } }, "required": ["func"] }, From 44bf49d5e57da9d6351079c90273dbe6bdbdfeb4 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Mon, 4 Dec 2023 22:36:20 -0500 Subject: [PATCH 2/7] data-model: Better represent annotations in the data model, particularly when unsupported Fixes #552 --- spec/data-model/README.md | 36 ++++++++++++++++----------- spec/data-model/message.dtd | 12 ++++----- spec/data-model/message.json | 47 +++++++++++++++++++++--------------- spec/message.abnf | 10 +++++--- spec/syntax.md | 18 +++++++++----- 5 files changed, 73 insertions(+), 50 deletions(-) diff --git a/spec/data-model/README.md b/spec/data-model/README.md index 3577f72dbf..6d16f4bd63 100644 --- a/spec/data-model/README.md +++ b/spec/data-model/README.md @@ -117,28 +117,37 @@ The `body` strings are the "cooked" _text_ values, i.e. escape sequences are pro Implementations MUST NOT rely on the set of `Expression` interfaces being exhaustive, as future versions of this specification MAY define additional expressions. -An `Expression` `func` with an unrecognized value SHOULD be treated as an `UnsupportedExpression` value. ```ts interface Pattern { body: Array; } -type Expression = LiteralExpression | VariableExpression | FunctionExpression; +type Expression = LiteralExpression | VariableExpression | FunctionExpression | + UnsupportedExpression; interface LiteralExpression { + type: "literal-expression"; arg: Literal; - func?: FunctionRef | UnsupportedExpression; + annotation?: FunctionAnnotation | UnsupportedAnnotation; } interface VariableExpression { + type: "variable-expression"; arg: VariableRef; - func?: FunctionRef | UnsupportedExpression; + annotation?: FunctionAnnotation | UnsupportedAnnotation; } interface FunctionExpression { + type: "function-expression"; arg?: never; - func: FunctionRef | UnsupportedExpression; + annotation: FunctionAnnotation; +} + +interface UnsupportedExpression { + type: "unsupported-expression"; + arg?: never; + annotation: UnsupportedAnnotation; } ``` @@ -166,8 +175,8 @@ interface VariableRef { } ``` -A `FunctionRef` represents an _expression_ with a _function_ _annotation_. -In a `FunctionRef`, +A `FunctionAnnotation` represents a _function_ _annotation_. +In a `FunctionAnnotation`, the `kind` corresponds to the starting sigil of a _function_: `'open'` for `+`, `'close'` for `-`, and `'value'` for `:`. The `name` does not include this starting sigil. @@ -177,8 +186,8 @@ before the _annotation_ in the _expression_, if present. Each _option_ is represented by an `Option`. ```ts -interface FunctionRef { - type: "function"; +interface FunctionAnnotation { + type: "function-annotation"; kind: "open" | "close" | "value"; name: string; operand?: Literal | VariableRef; @@ -191,9 +200,8 @@ interface Option { } ``` -An `UnsupportedExpression` represents an _expression_ with a -_reserved annotation_ or a _private-use annotation_ not supported -by the implementation. +An `UnsupportedAnnotation` represents a +_private-use annotation_ not supported by the implementation or a _reserved annotation_. The `sigil` corresponds to the starting sigil of the _annotation_. The `source` is the "raw" value (i.e. escape sequences are not processed) and does not include the starting `sigil`. @@ -214,8 +222,8 @@ using an interface appropriate for the semantics and meaning that the implementation attaches to that _annotation_. ```ts -interface UnsupportedExpression { - type: "unsupported-expression"; +interface UnsupportedAnnotation { + type: "unsupported-annotation"; sigil: "!" | "@" | "#" | "%" | "^" | "&" | "*" | "<" | ">" | "/" | "?" | "~"; source: string; operand?: Literal | VariableRef; diff --git a/spec/data-model/message.dtd b/spec/data-model/message.dtd index 5f1810f39b..2a6df759db 100644 --- a/spec/data-model/message.dtd +++ b/spec/data-model/message.dtd @@ -24,8 +24,8 @@ @@ -34,13 +34,13 @@ - - + - - + + diff --git a/spec/data-model/message.json b/spec/data-model/message.json index b32ab9827a..f5ceed518c 100644 --- a/spec/data-model/message.json +++ b/spec/data-model/message.json @@ -33,10 +33,10 @@ "required": ["name", "value"] }, - "function": { + "function-annotation": { "type": "object", "properties": { - "type": { "const": "function" }, + "type": { "const": "function-annotation" }, "kind": { "enum": ["open", "close", "value"] }, "name": { "type": "string" }, "operand": { @@ -49,10 +49,10 @@ }, "required": ["type", "kind", "name"] }, - "unsupported-expression": { + "unsupported-annotation": { "type": "object", "properties": { - "type": { "const": "unsupported-expression" }, + "type": { "const": "unsupported-annotation" }, "sigil": { "enum": ["!", "@", "#", "%", "^", "&", "*", "<", ">", "/", "?", "~"] }, @@ -67,46 +67,53 @@ "literal-expression": { "type": "object", "properties": { + "type": { "const": "literal-expression" }, "arg": { "$ref": "#/$defs/literal" }, - "func": { + "annotation": { "oneOf": [ - { "$ref": "#/$defs/function" }, - { "$ref": "#/$defs/unsupported-expression" } + { "$ref": "#/$defs/function-annotation" }, + { "$ref": "#/$defs/unsupported-annotation" } ] } }, - "required": ["arg"] + "required": ["type", "arg"] }, "variable-expression": { "type": "object", "properties": { + "type": { "const": "variable-expression" }, "arg": { "$ref": "#/$defs/variable" }, - "func": { + "annotation": { "oneOf": [ - { "$ref": "#/$defs/function" }, - { "$ref": "#/$defs/unsupported-expression" } + { "$ref": "#/$defs/function-annotation" }, + { "$ref": "#/$defs/unsupported-annotation" } ] } }, - "required": ["arg"] + "required": ["type", "arg"] }, "function-expression": { "type": "object", "properties": { - "func": { - "oneOf": [ - { "$ref": "#/$defs/function" }, - { "$ref": "#/$defs/unsupported-expression" } - ] - } + "type": { "const": "function-expression" }, + "annotation": { "$ref": "#/$defs/function-annotation" } + }, + "required": ["type", "annotation"] + }, + "unsupported-expression": { + "type": "object", + "properties": { + "type": { "const": "unsupported-expression" }, + "annotation": { "$ref": "#/$defs/unsupported-annotation" } }, - "required": ["func"] + "required": ["type", "annotation"] }, "expression": { "oneOf": [ { "$ref": "#/$defs/literal-expression" }, { "$ref": "#/$defs/variable-expression" }, - { "$ref": "#/$defs/function-expression" } + { "$ref": "#/$defs/function-expression" }, + { "$ref": "#/$defs/unsupported-expression" } ] }, diff --git a/spec/message.abnf b/spec/message.abnf index bd7dbeb8eb..7e0cc6c9c4 100644 --- a/spec/message.abnf +++ b/spec/message.abnf @@ -20,12 +20,14 @@ variant = key *(s key) [s] quoted-pattern key = literal / "*" expression = literal-expression / variable-expression / function-expression + / private-use-expression / reserved-expression literal-expression = "{" [s] literal [s annotation] [s] "}" variable-expression = "{" [s] variable [s annotation] [s] "}" -function-expression = "{" [s] annotation [s] "}" -annotation = (function *(s option)) - / reserved-annotation - / private-use-annotation +function-expression = "{" [s] function-annotation [s] "}" +private-use-expression = "{" [s] private-use-annotation [s] "}" +reserved-expression = "{" [s] reserved-annotation [s] "}" +annotation = function-annotation / private-use-annotation / reserved-annotation +function-annotation = function *(s option) literal = quoted / unquoted variable = "$" name diff --git a/spec/syntax.md b/spec/syntax.md index cf34de5570..d62701b6ce 100644 --- a/spec/syntax.md +++ b/spec/syntax.md @@ -431,13 +431,21 @@ optionally followed by an _annotation_. A **_variable-expression_** contains a _variable_, optionally followed by an _annotation_. -A **_function-expression_** contains only an _annotation_. +A **_function-expression_** contains only a _function_ _annotation_. + +A **_private-use-expression_** contains only a _private-use annotation_. + +A **_reserved-expression_** contains only a _reserved annotation_. ```abnf expression = literal-expression / variable-expression / function-expression + / private-use-expression / reserved-expression literal-expression = "{" [s] literal [s annotation] [s] "}" variable-expression = "{" [s] variable [s annotation] [s] "}" -function-expression = "{" [s] annotation [s] "}" +function-expression = "{" [s] function-annotation [s] "}" +private-use-expression = "{" [s] private-use-annotation [s] "}" +reserved-expression = "{" [s] reserved-annotation [s] "}" +function-annotation = function *(s option) ``` There are several types of _expression_ that can appear in a _message_. @@ -476,12 +484,10 @@ Additionally, an _input-declaration_ can contain a _variable-expression_. An **_annotation_** is part of an _expression_ containing either a _function_ together with its associated _options_, or -a _reserved annotation_ or a _private-use annotation_. +a _private-use annotation_ or a _reserved annotation_. ```abnf -annotation = (function *(s option)) - / reserved-annotation - / private-use-annotation +annotation = function-annotation / private-use-annotation / reserved-annotation ``` An **_operand_** is the _literal_ of a _literal-expression_ or From 34a283885d727561be108331990fff25565087b0 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Mon, 4 Dec 2023 22:37:52 -0500 Subject: [PATCH 3/7] data-model: Drop operand from annotation nodes Operands are captured one level up, as expression node `arg` fields. --- spec/data-model/README.md | 7 ------- spec/data-model/message.json | 8 +------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/spec/data-model/README.md b/spec/data-model/README.md index 6d16f4bd63..087f0b15d0 100644 --- a/spec/data-model/README.md +++ b/spec/data-model/README.md @@ -181,8 +181,6 @@ the `kind` corresponds to the starting sigil of a _function_: `'open'` for `+`, `'close'` for `-`, and `'value'` for `:`. The `name` does not include this starting sigil. -The optional `operand` is the _literal_ or _variable_ -before the _annotation_ in the _expression_, if present. Each _option_ is represented by an `Option`. ```ts @@ -190,7 +188,6 @@ interface FunctionAnnotation { type: "function-annotation"; kind: "open" | "close" | "value"; name: string; - operand?: Literal | VariableRef; options?: Option[]; } @@ -212,9 +209,6 @@ and does not include the starting `sigil`. > This would result in new interfaces being added to > this data model. -If the _expression_ includes a _literal_ or _variable_ before the _annotation_, -it is included as the `operand`. - When parsing the syntax of a _message_ that includes a _private-use annotation_ supported by the implementation, the implementation SHOULD represent it in the data model @@ -226,7 +220,6 @@ interface UnsupportedAnnotation { type: "unsupported-annotation"; sigil: "!" | "@" | "#" | "%" | "^" | "&" | "*" | "<" | ">" | "/" | "?" | "~"; source: string; - operand?: Literal | VariableRef; } ``` diff --git a/spec/data-model/message.json b/spec/data-model/message.json index f5ceed518c..ebe5b85cea 100644 --- a/spec/data-model/message.json +++ b/spec/data-model/message.json @@ -39,9 +39,6 @@ "type": { "const": "function-annotation" }, "kind": { "enum": ["open", "close", "value"] }, "name": { "type": "string" }, - "operand": { - "oneOf": [{ "$ref": "#/$defs/literal" }, { "$ref": "#/$defs/variable" }] - }, "options": { "type": "array", "items": { "$ref": "#/$defs/option" } @@ -56,10 +53,7 @@ "sigil": { "enum": ["!", "@", "#", "%", "^", "&", "*", "<", ">", "/", "?", "~"] }, - "source": { "type": "string" }, - "operand": { - "oneOf": [{ "$ref": "#/$defs/literal" }, { "$ref": "#/$defs/variable" }] - } + "source": { "type": "string" } }, "required": ["type", "sigil", "source"] }, From 917238fb9af294a6973a91b1d7358847fb8dadfb Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Fri, 8 Dec 2023 11:50:52 -0500 Subject: [PATCH 4/7] data-model: Remove inferrable `type` fields --- spec/data-model/README.md | 6 +----- spec/data-model/message.json | 14 +++++--------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/spec/data-model/README.md b/spec/data-model/README.md index 087f0b15d0..f65df5e4a7 100644 --- a/spec/data-model/README.md +++ b/spec/data-model/README.md @@ -127,25 +127,21 @@ type Expression = LiteralExpression | VariableExpression | FunctionExpression | UnsupportedExpression; interface LiteralExpression { - type: "literal-expression"; arg: Literal; annotation?: FunctionAnnotation | UnsupportedAnnotation; } interface VariableExpression { - type: "variable-expression"; arg: VariableRef; annotation?: FunctionAnnotation | UnsupportedAnnotation; } interface FunctionExpression { - type: "function-expression"; arg?: never; annotation: FunctionAnnotation; } interface UnsupportedExpression { - type: "unsupported-expression"; arg?: never; annotation: UnsupportedAnnotation; } @@ -185,7 +181,7 @@ Each _option_ is represented by an `Option`. ```ts interface FunctionAnnotation { - type: "function-annotation"; + type: "function"; kind: "open" | "close" | "value"; name: string; options?: Option[]; diff --git a/spec/data-model/message.json b/spec/data-model/message.json index ebe5b85cea..51e9e1b07a 100644 --- a/spec/data-model/message.json +++ b/spec/data-model/message.json @@ -36,7 +36,7 @@ "function-annotation": { "type": "object", "properties": { - "type": { "const": "function-annotation" }, + "type": { "const": "function" }, "kind": { "enum": ["open", "close", "value"] }, "name": { "type": "string" }, "options": { @@ -61,7 +61,6 @@ "literal-expression": { "type": "object", "properties": { - "type": { "const": "literal-expression" }, "arg": { "$ref": "#/$defs/literal" }, "annotation": { "oneOf": [ @@ -70,12 +69,11 @@ ] } }, - "required": ["type", "arg"] + "required": ["arg"] }, "variable-expression": { "type": "object", "properties": { - "type": { "const": "variable-expression" }, "arg": { "$ref": "#/$defs/variable" }, "annotation": { "oneOf": [ @@ -84,23 +82,21 @@ ] } }, - "required": ["type", "arg"] + "required": ["arg"] }, "function-expression": { "type": "object", "properties": { - "type": { "const": "function-expression" }, "annotation": { "$ref": "#/$defs/function-annotation" } }, - "required": ["type", "annotation"] + "required": ["annotation"] }, "unsupported-expression": { "type": "object", "properties": { - "type": { "const": "unsupported-expression" }, "annotation": { "$ref": "#/$defs/unsupported-annotation" } }, - "required": ["type", "annotation"] + "required": ["annotation"] }, "expression": { "oneOf": [ From 9c5965c8b23c18c1ef8536d0f946085e7e2990a0 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Fri, 8 Dec 2023 12:04:28 -0500 Subject: [PATCH 5/7] data-model: Restore `annotation` abstraction --- spec/data-model/message.json | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/spec/data-model/message.json b/spec/data-model/message.json index 51e9e1b07a..acce03ffcb 100644 --- a/spec/data-model/message.json +++ b/spec/data-model/message.json @@ -57,17 +57,18 @@ }, "required": ["type", "sigil", "source"] }, + "annotation": { + "oneOf": [ + { "$ref": "#/$defs/function-annotation" }, + { "$ref": "#/$defs/unsupported-annotation" } + ] + }, "literal-expression": { "type": "object", "properties": { "arg": { "$ref": "#/$defs/literal" }, - "annotation": { - "oneOf": [ - { "$ref": "#/$defs/function-annotation" }, - { "$ref": "#/$defs/unsupported-annotation" } - ] - } + "annotation": { "$ref": "#/$defs/annotation" } }, "required": ["arg"] }, @@ -75,12 +76,7 @@ "type": "object", "properties": { "arg": { "$ref": "#/$defs/variable" }, - "annotation": { - "oneOf": [ - { "$ref": "#/$defs/function-annotation" }, - { "$ref": "#/$defs/unsupported-annotation" } - ] - } + "annotation": { "$ref": "#/$defs/annotation" } }, "required": ["arg"] }, From a5553cef00df609afc925af9bf5939cc424e7693 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Fri, 8 Dec 2023 11:59:04 -0500 Subject: [PATCH 6/7] grammar: Reduce expression productions --- spec/message.abnf | 12 +++++------- spec/syntax.md | 18 ++++++------------ 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/spec/message.abnf b/spec/message.abnf index 7e0cc6c9c4..8e08bfeaba 100644 --- a/spec/message.abnf +++ b/spec/message.abnf @@ -19,15 +19,13 @@ selector = expression variant = key *(s key) [s] quoted-pattern key = literal / "*" -expression = literal-expression / variable-expression / function-expression - / private-use-expression / reserved-expression +expression = literal-expression / variable-expression / annotation-expression literal-expression = "{" [s] literal [s annotation] [s] "}" variable-expression = "{" [s] variable [s annotation] [s] "}" -function-expression = "{" [s] function-annotation [s] "}" -private-use-expression = "{" [s] private-use-annotation [s] "}" -reserved-expression = "{" [s] reserved-annotation [s] "}" -annotation = function-annotation / private-use-annotation / reserved-annotation -function-annotation = function *(s option) +annotation-expression = "{" [s] annotation [s] "}" +annotation = (function *(s option)) + / reserved-annotation + / private-use-annotation literal = quoted / unquoted variable = "$" name diff --git a/spec/syntax.md b/spec/syntax.md index d62701b6ce..b9f9e68825 100644 --- a/spec/syntax.md +++ b/spec/syntax.md @@ -431,21 +431,13 @@ optionally followed by an _annotation_. A **_variable-expression_** contains a _variable_, optionally followed by an _annotation_. -A **_function-expression_** contains only a _function_ _annotation_. - -A **_private-use-expression_** contains only a _private-use annotation_. - -A **_reserved-expression_** contains only a _reserved annotation_. +An **_annotation-expression_** contains an _annotation_ without an _operand_. ```abnf -expression = literal-expression / variable-expression / function-expression - / private-use-expression / reserved-expression +expression = literal-expression / variable-expression / annotation-expression literal-expression = "{" [s] literal [s annotation] [s] "}" variable-expression = "{" [s] variable [s annotation] [s] "}" -function-expression = "{" [s] function-annotation [s] "}" -private-use-expression = "{" [s] private-use-annotation [s] "}" -reserved-expression = "{" [s] reserved-annotation [s] "}" -function-annotation = function *(s option) +annotation-expression = "{" [s] annotation [s] "}" ``` There are several types of _expression_ that can appear in a _message_. @@ -487,7 +479,9 @@ a _function_ together with its associated _options_, or a _private-use annotation_ or a _reserved annotation_. ```abnf -annotation = function-annotation / private-use-annotation / reserved-annotation +annotation = (function *(s option)) + / reserved-annotation + / private-use-annotation ``` An **_operand_** is the _literal_ of a _literal-expression_ or From be381fd3db55e3f4d9e57f3564d1602bb903ced4 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Fri, 8 Dec 2023 12:23:45 -0500 Subject: [PATCH 7/7] Reference "private-use" before "reserved" --- spec/message.abnf | 2 +- spec/syntax.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/message.abnf b/spec/message.abnf index 8e08bfeaba..8d6950d2cc 100644 --- a/spec/message.abnf +++ b/spec/message.abnf @@ -24,8 +24,8 @@ literal-expression = "{" [s] literal [s annotation] [s] "}" variable-expression = "{" [s] variable [s annotation] [s] "}" annotation-expression = "{" [s] annotation [s] "}" annotation = (function *(s option)) - / reserved-annotation / private-use-annotation + / reserved-annotation literal = quoted / unquoted variable = "$" name diff --git a/spec/syntax.md b/spec/syntax.md index b9f9e68825..e4ce167bb7 100644 --- a/spec/syntax.md +++ b/spec/syntax.md @@ -480,8 +480,8 @@ a _private-use annotation_ or a _reserved annotation_. ```abnf annotation = (function *(s option)) - / reserved-annotation / private-use-annotation + / reserved-annotation ``` An **_operand_** is the _literal_ of a _literal-expression_ or