Skip to content

Commit

Permalink
Add a :math function, for addition and subtraction (#932)
Browse files Browse the repository at this point in the history
* Add a :math function, for addition and subtraction

* Clarify utility note

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

* Add note on integer overflow

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

---------

Co-authored-by: Addison Phillips <addison@unicode.org>
  • Loading branch information
eemeli and aphillips authored Nov 15, 2024
1 parent 778d784 commit b6ba4bf
Show file tree
Hide file tree
Showing 2 changed files with 148 additions and 0 deletions.
71 changes: 71 additions & 0 deletions spec/registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,77 @@ together with the resolved options' values.
The _function_ `:integer` performs selection as described in [Number Selection](#number-selection) below.
### The `:math` function
The function `:math` is a selector and formatter for matching or formatting
numeric values to which a mathematical operation has been applied.
> This function is useful for selection and formatting of values that
> differ from the input value by a specified amount.
> For example, it can be used in a message such as this:
> ```
> .input {$like_count :integer}
> .local $others_count = {$like_count :math subtract=1}
> .match $like_count $others_count
> 0 * {{Your post has no likes.}}
> 1 * {{{$name} liked your post.}}
> * 1 {{{$name} and one other person liked your post.}}
> * * {{{$name} and {$others_count} other people liked your post.}}
> ```
#### Operands
The function `:math` requires a [Number Operand](#number-operands) as its _operand_.
#### Options
The options on `:math` are exclusive with each other,
and exactly one option is always required.
The options do not have default values.
The following options and their values are
required in the default registry to be available on the function `:math`:
- `add`
- ([digit size option](#digit-size-options))
- `subtract`
- ([digit size option](#digit-size-options))
If no options or more than one option is set,
or if an _option_ value is not a [digit size option](#digit-size-options),
a _Bad Option_ error is emitted
and a _fallback value_ used as the _resolved value_ of the _expression_.
#### Resolved Value
The _resolved value_ of an _expression_ with a `:math` _function_
contains the implementation-defined numeric value
of the _operand_ of the annotated _expression_.
If the `add` option is set,
the numeric value of the _resolved value_ is formed by incrementing
the numeric value of the _operand_ by the integer value of the digit size option value.
If the `subtract` option is set,
the numeric value of the _resolved value_ is formed by decrementing
the numeric value of the _operand_ by the integer value of the digit size option value.
If the _operand_ of the _expression_ is an implementation-defined numeric type,
such as the _resolved value_ of an _expression_ with a `:number` or `:integer` _annotation_,
it can include option values.
These are included in the resolved option values of the _expression_.
The `:math` _options_ are not included in the resolved option values.
> [!NOTE]
> Implementations can encounter practical limits with `:math` _expressions_,
> such as the result of adding two integers exceeding
> the storage or precision of some implementation-defined number type.
> In such cases, implementations can emit an _Unsupported Operation_ error
> or they might just silently overflow the underlying data value.
#### Selection
The _function_ `:math` performs selection as described in [Number Selection](#number-selection) below.
### The `:currency` function
The function `:currency` is a selector and formatter for currency values,
Expand Down
77 changes: 77 additions & 0 deletions test/tests/functions/math.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{
"$schema": "https://raw.githubusercontent.com/unicode-org/message-format-wg/main/test/schemas/v0/tests.schema.json",
"scenario": "Math function",
"description": "The built-in formatter and selector for addition and subtraction.",
"defaultTestProperties": {
"bidiIsolation": "none",
"locale": "en-US"
},
"tests": [
{
"src": "{:math add=13}",
"expErrors": [{ "type": "bad-operand" }]
},
{
"src": "{foo :math add=13}",
"expErrors": [{ "type": "bad-operand" }]
},
{
"src": "{42 :math}",
"expErrors": [{ "type": "bad-option" }]
},
{
"src": "{42 :math add=foo}",
"expErrors": [{ "type": "bad-option" }]
},
{
"src": "{42 :math subtract=foo}",
"expErrors": [{ "type": "bad-option" }]
},
{
"src": "{42 :math foo=13}",
"expErrors": [{ "type": "bad-option" }]
},
{
"src": "{42 :math add=13 subtract=13}",
"expErrors": [{ "type": "bad-option" }]
},
{
"src": "{41 :math add=1}",
"exp": "42"
},
{
"src": "{52 :math subtract=10}",
"exp": "42"
},
{
"src": "{41 :math add=1 foo=13}",
"exp": "42"
},
{
"src": ".local $x = {41 :integer signDisplay=always} {{{$x :math add=1}}}",
"exp": "+42"
},
{
"src": ".local $x = {52 :number signDisplay=always} {{{$x :math subtract=10}}}",
"exp": "+42"
},
{
"src": "{$x :math add=1}",
"params": [{ "name": "x", "value": 41 }],
"exp": "42"
},
{
"src": "{$x :math subtract=10}",
"params": [{ "name": "x", "value": 52 }],
"exp": "42"
},
{
"src": ".local $x = {1 :math add=1} .match $x 1 {{=1}} 2 {{=2}} * {{other}}",
"exp": "=2"
},
{
"src": ".local $x = {10 :integer} .local $y = {$x :math subtract=6} .match $y 10 {{=10}} 4 {{=4}} * {{other}}",
"exp": "=4"
}
]
}

0 comments on commit b6ba4bf

Please sign in to comment.