Skip to content

Commit

Permalink
Refactor errors, adding section for Message Function Errors (#774)
Browse files Browse the repository at this point in the history
* Refactor errors, adding section for Message Function Errors

* Apply suggestions from code review

Co-authored-by: Addison Phillips <addison@unicode.org>

* Apply suggestions from code review

* Drop exemplary text from Formatting Error description

* Drop "Bad Expression", add SHOULD for letting functions pick their error

* Use "appropriate" rather than "a" for Message Function Errors

Co-authored-by: Addison Phillips <addison@unicode.org>

* Apply suggestions from code review

Co-authored-by: Richard Gibson <richard.gibson@gmail.com>
Co-authored-by: Addison Phillips <addison@unicode.org>

* Apply suggestions from code review

Co-authored-by: Addison Phillips <addison@unicode.org>

* Drop Selection & Formatting erorrs, add Bad Selector & Bad Variant Key

* Apply suggestions from code review

Co-authored-by: Addison Phillips <addison@unicode.org>

---------

Co-authored-by: Addison Phillips <addison@unicode.org>
Co-authored-by: Richard Gibson <richard.gibson@gmail.com>
  • Loading branch information
3 people committed May 13, 2024
1 parent 7cdea8e commit f111102
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 75 deletions.
3 changes: 1 addition & 2 deletions spec/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
1. [Syntax Errors](errors.md#syntax-errors)
1. [Data Model Errors](errors.md#data-model-errors)
1. [Resolution Errors](errors.md#resolution-errors)
1. [Selection Errors](errors.md#selection-errors)
1. [Formatting Errors](errors.md#formatting-errors)
1. [Message Function Errors](errors.md#message-function-errors)
1. [Registry](registry.md)
1. [`registry.dtd`](registry.dtd)
1. [Formatting](formatting.md)
Expand Down
149 changes: 91 additions & 58 deletions spec/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ and MUST be emitted as soon as possible.
The other error categories are only emitted during formatting,
but it might be possible to detect them with validation tools.

During selection, an _expression_ handler MUST only emit _Resolution Errors_ and _Selection Errors_.
During formatting, an _expression_ handler MUST only emit _Resolution Errors_ and _Formatting Errors_.
During selection and formatting,
_expression_ handlers MUST only emit _Message Function Errors_.

_Resolution Errors_ and _Formatting Errors_ in _expressions_ that are not used
in _pattern selection_ or _formatting_ MAY be ignored,
as they do not affect the output of the formatter.
Implementations do not have to check for or emit _Resolution Errors_
or _Message Function Errors_ in _expressions_ that are not otherwise used by the _message_,
such as _placeholders_ in unselected _patterns_
or _declarations_ that are never referenced during _formatting_.

In all cases, when encountering a runtime error,
a message formatter MUST provide some representation of the message.
Expand All @@ -34,7 +35,7 @@ SHOULD prioritise _Syntax Errors_ and _Data Model Errors_ over others.

When an error occurs within a _selector_,
the _selector_ MUST NOT match any _variant_ _key_ other than the catch-all `*`
and a _Resolution Error_ or a _Selection Error_ MUST be emitted.
and a _Resolution Error_ or a _Message Function Error_ MUST be emitted.

## Syntax Errors

Expand Down Expand Up @@ -242,34 +243,6 @@ or for private implementation use that is not supported by the current implement
> * {{The value is not one.}}
> ```
### Invalid Expression

An **_<dfn>Invalid Expression</dfn>_** error occurs when a _message_ includes an _expression_
whose implementation-defined internal requirements produce an error during _function resolution_
or when a _function_ returns a value (such as `null`) that the implementation does not support.

An **_<dfn>Operand Mismatch Error</dfn>_** is an _Invalid Expression_ error that occurs when
an _operand_ provided to a _function_ during _function resolution_ does not match one of the
expected implementation-defined types for that function;
or in which a literal _operand_ value does not have the required format
and thus cannot be processed into one of the expected implementation-defined types
for that specific _function_.

> For example, the following _message_ produces an _Operand Mismatch Error_
> (a type of _Invalid Expression_ error)
> because the literal `|horse|` does not match the production `number-literal`,
> which is a requirement of the function `:number` for its operand:
> ```
> .local $horse = {horse :number}
> {{You have a {$horse}.}}
> ```
> The following _message_ might produce an _Invalid Expression_ error if the
> the function `:function` threw an exception or otherwise emitted an error
> rather than returning a valid value:
>```
> {{This has an invalid expression {$var :function} because it has a bug in it.}}
>```
### Unsupported Statement

An **_<dfn>Unsupported Statement</dfn>_** error occurs when a message includes a _reserved statement_.
Expand All @@ -282,42 +255,41 @@ An **_<dfn>Unsupported Statement</dfn>_** error occurs when a message includes a
> {{The message body}}
> ```
## Selection Errors
### Bad Selector

**_<dfn>Selection Errors</dfn>_** occur when message selection fails.
A **_<dfn>Bad Selector</dfn>_** error occurs when a message includes a _selector_
with a resolved value which does not support selection.

> For example, attempting to format either of the following messages
> might result in a _Selection Error_ if done within a context that
> uses a `:number` selector function which requires its input to be numeric:
>
> ```
> .match {|horse| :number}
> 1 {{The value is one.}}
> * {{The value is not one.}}
> ```
> For example, attempting to format this message
> would result in a _Bad Selector_ error:
>
> ```
> .local $sel = {|horse| :number}
> .match {$sel}
> 1 {{The value is one.}}
> * {{The value is not one.}}
> .local $day = {|2024-05-01| :date}
> .match {$day}
> * {{The due date is {$day}}}
> ```
## Formatting Errors
## Message Function Errors

A **_<dfn>Message Function Error</dfn>_** is any error that occurs
when calling a message function implementation
or which depends on validation associated with a specific function.

**_<dfn>Formatting Errors</dfn>_** occur during the formatting of a resolved value,
for example when encountering a value with an unsupported type
or an internally inconsistent set of options.
Implementations SHOULD provide a way for _functions_ to emit
(or cause to be emitted) any of the types of error defined in this section.
Implementations MAY also provide implementation-defined _Message Function Error_ types.

> For example, attempting to format any of the following messages
> might result in a _Formatting Error_ if done within a context that
> might result in a _Message Function Error_ if done within a context that
>
> 1. provides for the variable reference `$user` to resolve to
> 1. Provides for the variable reference `$user` to resolve to
> an object `{ name: 'Kat', id: 1234 }`,
> 2. provides for the variable reference `$field` to resolve to
> 2. Provides for the variable reference `$field` to resolve to
> a string `'address'`, and
> 3. uses a `:get` formatting function which requires its argument to be an object and
> an option `field` to be provided with a string value,
> 3. Uses a `:get` message function which requires its argument to be an object and
> an option `field` to be provided with a string value.
>
> The exact type of _Message Function Error_ is determined by the message function implementation.
>
> ```
> Hello, {horse :get field=name}!
Expand All @@ -336,3 +308,64 @@ or an internally inconsistent set of options.
> Your {$field} is {$id :get field=$field}
> ```
### Bad Operand

A **_<dfn>Bad Operand</dfn>_** error is any error that occurs due to the content or format of the _operand_,
such as when the _operand_ provided to a _function_ during _function resolution_ does not match one of the
expected implementation-defined types for that function;
or in which a literal _operand_ value does not have the required format
and thus cannot be processed into one of the expected implementation-defined types
for that specific _function_.

> For example, the following _messages_ each produce a _Bad Operand_ error
> because the literal `|horse|` does not match the `number-literal` production,
> which is a requirement of the function `:number` for its operand:
>
> ```
> .local $horse = {|horse| :number}
> {{You have a {$horse}.}}
> ```
>
> ```
> .match {|horse| :number}
> 1 {{The value is one.}}
> * {{The value is not one.}}
> ```
### Bad Option

A **_<dfn>Bad Option</dfn>_** error is an error that occurs when there is
an implementation-defined error with an _option_ or its value.
These might include:
- A required _option_ is missing.
- Mutually exclusive _options_ are supplied.
- An _option_ value provided to a _function_ during _function resolution_
does not match one of the implementation-defined types or values for that _function_;
or in which the literal _option_ value does not have the required format
and thus cannot be processed into one of the expected
implementation-defined types for that specific _function_.

> For example, the following _message_ might produce a _Bad Option_ error
> because the literal `foo` does not match the production `digit-size-option`,
> which is a requirement of the function `:number` for its `minimumFractionDigits` _option_:
>
> ```
> The answer is {42 :number minimumFractionDigits=foo}.
> ```
### Bad Variant Key

A **_<dfn>Bad Variant Key</dfn>_** error is an error that occurs when a _variant_ _key_
does not match the expected implementation-defined format.

> For example, the following _message_ produces a _Bad Variant Key_ error
> because `horse` is not a recognized plural category and
> does not match the `number-literal` production,
> which is a requirement of the `:number` function:
>
> ```
> .match {42 :number}
> 1 {{The value is one.}}
> horse {{The value is a horse.}}
> * {{The value is not one.}}
> ```
12 changes: 6 additions & 6 deletions spec/formatting.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,8 @@ the following steps are taken:
argument type `T` and return type `U`
for implementations of functions
such that `U` can be coerced to `T`.
Implementations of a _function_ SHOULD emit an
_Invalid Expression_ error for _operands_ whose resolved value
Implementations of a _function_ SHOULD emit a
_Bad Operand_ error for _operands_ whose resolved value
or type is not supported.

> [!NOTE]
Expand Down Expand Up @@ -307,13 +307,13 @@ the following steps are taken:
resolve the value of the _expression_ as the result of that function call.

If the call fails or does not return a valid value,
emit a _Invalid Expression_ error.
emit the appropriate _Message Function Error_ for the failure.

Implementations MAY provide a mechanism for the _function_ to provide
additional detail about internal failures.
Specifically, if the cause of the failure was that the datatype, value, or format of the
_operand_ did not match that expected by the _function_,
the _function_ might cause an _Operand Mismatch Error_ to be emitted.
the _function_ might cause a _Bad Operand_ error to be emitted.

In all failure cases, use the _fallback value_ for the _expression_ as the resolved value.

Expand Down Expand Up @@ -519,7 +519,7 @@ First, resolve the values of each _selector_:
1. Else:
1. Let `nomatch` be a resolved value for which selection always fails.
1. Append `nomatch` as the last element of the list `res`.
1. Emit a _Selection Error_.
1. Emit a _Bad Selector_ error.

The form of the resolved values is determined by each implementation,
along with the manner of determining their support for selection.
Expand Down Expand Up @@ -735,7 +735,7 @@ each _text_ and _placeholder_ part of the selected _pattern_ is resolved and for

Resolved values cannot always be formatted by a given implementation.
When such an error occurs during _formatting_,
an implementation SHOULD emit a _Formatting Error_ and produce a
an implementation SHOULD emit an appropriate _Message Function Error_ and produce a
_fallback value_ for the _placeholder_ that produced the error.
A formatting function MAY substitute a value to use instead of a _fallback value_.

Expand Down
18 changes: 9 additions & 9 deletions spec/registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ The function `:string` provides string selection and formatting.
The _operand_ of `:string` is either any implementation-defined type
that is a string or for which conversion to a string is supported,
or any _literal_ value.
All other values produce an _Invalid Expression_ error.
All other values produce a _Bad Operand_ error.

> For example, in Java, implementations of the `java.lang.CharSequence` interface
> (such as `java.lang.String` or `java.lang.StringBuilder`),
Expand Down Expand Up @@ -609,7 +609,7 @@ The _function_ `:integer` performs selection as described in [Number Selection](

The _operand_ of a number function is either an implementation-defined type or
a literal whose contents match the `number-literal` production in the [ABNF](/spec/message.abnf).
All other values produce an _Invalid Expression_ error.
All other values produce a _Bad Operand_ error.

> For example, in Java, any subclass of `java.lang.Number` plus the primitive
> types (`byte`, `short`, `int`, `long`, `float`, `double`, etc.)
Expand Down Expand Up @@ -684,7 +684,7 @@ numeric selectors perform as described below.
1. Else if `key` is one of the keywords `zero`, `one`, `two`, `few`, `many`, or `other`, then
1. If `key` and `keyword` consist of the same sequence of Unicode code points, then
1. Append `key` as the last element of the list `resultKeyword`.
1. Else, emit a _Selection Error_.
1. Else, emit a _Bad Variant Key_ error.
1. Return a new list whose elements are the concatenation of the elements (in order) of `resultExact` followed by the elements (in order) of `resultKeyword`.

> [!NOTE]
Expand Down Expand Up @@ -785,15 +785,15 @@ If no options are specified, this function defaults to the following:
The _operand_ of the `:datetime` function is either
an implementation-defined date/time type
or a _date/time literal value_, as defined in [Date and Time Operand](#date-and-time-operands).
All other _operand_ values produce an _Invalid Expression_ error.
All other _operand_ values produce a _Bad Operand_ error.

#### Options

The `:datetime` function can use either the appropriate _style options_
or can use a collection of _field options_ (but not both) to control the formatted
output.

If both are specified, an _Invalid Expression_ error MUST be emitted
If both are specified, a _Bad Option_ error MUST be emitted
and a _fallback value_ used as the resolved value of the _expression_.

> [!NOTE]
Expand Down Expand Up @@ -910,7 +910,7 @@ If no options are specified, this function defaults to the following:
The _operand_ of the `:date` function is either
an implementation-defined date/time type
or a _date/time literal value_, as defined in [Date and Time Operand](#date-and-time-operands).
All other _operand_ values produce an _Invalid Expression_ error.
All other _operand_ values produce a _Bad Operand_ error.

#### Options

Expand All @@ -933,7 +933,7 @@ If no options are specified, this function defaults to the following:
The _operand_ of the `:time` function is either
an implementation-defined date/time type
or a _date/time literal value_, as defined in [Date and Time Operand](#date-and-time-operands).
All other _operand_ values produce an _Invalid Expression_ error.
All other _operand_ values produce a _Bad Operand_ error.

#### Options

Expand All @@ -950,7 +950,7 @@ The function `:time` has these _options_:
The _operand_ of a date/time function is either
an implementation-defined date/time type
or a _date/time literal value_, as defined below.
All other _operand_ values produce an _Invalid Expression_ error.
All other _operand_ values produce a _Bad Operand_ error.

A **_<dfn>date/time literal value</dfn>_** is a non-empty string consisting of an ISO 8601 date,
or an ISO 8601 datetime optionally followed by a timezone offset.
Expand All @@ -972,7 +972,7 @@ For more information, see [Working with Timezones](https://w3c.github.io/timezon
> The [ABNF](/spec/message.abnf) and [syntax](/spec/syntax.md) of MF2
> do not formally define date/time literals.
> This means that a _message_ can be syntactically valid but produce
> an _Operand Mismatch Error_ at runtime.
> a _Bad Operand_ error at runtime.
> [!NOTE]
> String values passed as variables in the _formatting context_'s
Expand Down

0 comments on commit f111102

Please sign in to comment.