Skip to content

Commit 7dad8fc

Browse files
eemeliaphillips
andauthored
Match on variables instead of expressions (#877)
* Match on variables instead of expressions * Apply suggestions from code review Co-authored-by: Addison Phillips <[email protected]> * Apply suggestions from code review * Add missing test changes noticed during implementation * Empty commit to re-trigger CLA check --------- Co-authored-by: Addison Phillips <[email protected]>
1 parent 40db4e0 commit 7dad8fc

File tree

17 files changed

+157
-173
lines changed

17 files changed

+157
-173
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ Functions can optionally take _options_:
7676
Messages can use a _selector_ to choose between different _variants_,
7777
which correspond to the grammatical (or other) requirements of the language:
7878

79-
.match {$count :integer}
79+
.input {$count :integer}
80+
.match $count
8081
0 {{You have no notifications.}}
8182
one {{You have {$count} notification.}}
8283
* {{You have {$count} notifications.}}

exploration/registry-xml/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,8 @@ For the sake of brevity, only `locales="en"` is considered.
163163
Given the above description, the `:number` function is defined to work both in a selector and a placeholder:
164164

165165
```
166-
.match {$count :number}
166+
.input {$count :number}
167+
.match $count
167168
1 {{One new message}}
168169
* {{{$count :number} new messages}}
169170
```

exploration/selection-declaration.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Effect of Selectors on Subsequent Placeholders
22

3-
Status: **Proposed, Ballot Requested**
3+
Status: **Accepted**
44

55
<details>
66
<summary>Metadata</summary>
@@ -12,6 +12,12 @@ Status: **Proposed, Ballot Requested**
1212
<dt>Pull Requests</dt>
1313
<dd><a href="https://github.com/unicode-org/message-format-wg/pull/755">#755</a></dd>
1414
<dd><a href="https://github.com/unicode-org/message-format-wg/pull/824">#824</a></dd>
15+
<dd><a href="https://github.com/unicode-org/message-format-wg/pull/860">#860</a></dd>
16+
<dd><a href="https://github.com/unicode-org/message-format-wg/pull/867">#867</a></dd>
17+
<dd><a href="https://github.com/unicode-org/message-format-wg/pull/877">#877</a></dd>
18+
<dt>Ballot</dt>
19+
<dd><a href="https://github.com/unicode-org/message-format-wg/pull/872">#872</a> (discussion)</dd>
20+
<dd><a href="https://github.com/unicode-org/message-format-wg/pull/873">#873</a> (voting)</dd>
1521
</dl>
1622
</details>
1723

spec/data-model/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ interface PatternMessage {
8484
interface SelectMessage {
8585
type: "select";
8686
declarations: Declaration[];
87-
selectors: Expression[];
87+
selectors: VariableRef[];
8888
variants: Variant[];
8989
}
9090
```

spec/data-model/message.dtd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
name NMTOKEN #REQUIRED
1111
>
1212

13-
<!ELEMENT selectors (expression)+>
13+
<!ELEMENT selectors (variable)+>
1414
<!ELEMENT variant (key+,pattern)>
1515
<!ELEMENT key (#PCDATA)>
1616
<!ATTLIST key catchall (true | false) "false">

spec/data-model/message.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@
139139
"declarations": { "$ref": "#/$defs/declarations" },
140140
"selectors": {
141141
"type": "array",
142-
"items": { "$ref": "#/$defs/expression" }
142+
"items": { "$ref": "#/$defs/variable" }
143143
},
144144
"variants": {
145145
"type": "array",

spec/errors.md

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,10 @@ or contains some error which leads to further errors,
4646
an implementation which does not emit all of the errors
4747
SHOULD prioritise _Syntax Errors_ and _Data Model Errors_ over others.
4848

49-
When an error occurs within a _selector_,
49+
When an error occurs while resolving a _selector_
50+
or calling MatchSelectorKeys with its resolved value,
5051
the _selector_ MUST NOT match any _variant_ _key_ other than the catch-all `*`
51-
and a _Resolution Error_ or a _Message Function Error_ MUST be emitted.
52+
and a _Bad Selector_ error MUST be emitted.
5253

5354
## Syntax Errors
5455

@@ -85,13 +86,16 @@ does not equal the number of _selectors_.
8586
> Example invalid messages resulting in a _Variant Key Mismatch_ error:
8687
>
8788
> ```
88-
> .match {$one :func}
89+
> .input {$one :func}
90+
> .match $one
8991
> 1 2 {{Too many}}
9092
> * {{Otherwise}}
9193
> ```
9294
>
9395
> ```
94-
> .match {$one :func} {$two :func}
96+
> .input {$one :func}
97+
> .input {$two :func}
98+
> .match $one $two
9599
> 1 2 {{Two keys}}
96100
> * {{Missing a key}}
97101
> * * {{Otherwise}}
@@ -105,41 +109,44 @@ does not include a _variant_ with only catch-all keys.
105109
> Example invalid messages resulting in a _Missing Fallback Variant_ error:
106110
>
107111
> ```
108-
> .match {$one :func}
112+
> .input {$one :func}
113+
> .match $one
109114
> 1 {{Value is one}}
110115
> 2 {{Value is two}}
111116
> ```
112117
>
113118
> ```
114-
> .match {$one :func} {$two :func}
119+
> .input {$one :func}
120+
> .input {$two :func}
121+
> .match $one $two
115122
> 1 * {{First is one}}
116123
> * 1 {{Second is one}}
117124
> ```
118125
119126
### Missing Selector Annotation
120127
121128
A **_<dfn>Missing Selector Annotation</dfn>_** error occurs when the _message_
122-
contains a _selector_ that does not have an _annotation_,
123-
or contains a _variable_ that does not directly or indirectly reference a _declaration_ with an _annotation_.
129+
contains a _selector_ that does not
130+
directly or indirectly reference a _declaration_ with a _function_.
124131
125132
> Examples of invalid messages resulting in a _Missing Selector Annotation_ error:
126133
>
127134
> ```
128-
> .match {$one}
135+
> .match $one
129136
> 1 {{Value is one}}
130137
> * {{Value is not one}}
131138
> ```
132139
>
133140
> ```
134141
> .local $one = {|The one|}
135-
> .match {$one}
142+
> .match $one
136143
> 1 {{Value is one}}
137144
> * {{Value is not one}}
138145
> ```
139146
>
140147
> ```
141148
> .input {$one}
142-
> .match {$one}
149+
> .match $one
143150
> 1 {{Value is one}}
144151
> * {{Value is not one}}
145152
> ```
@@ -199,13 +206,16 @@ same list of _keys_ is used for more than one _variant_.
199206
> Examples of invalid messages resulting in a _Duplicate Variant_ error:
200207
>
201208
> ```
202-
> .match {$var :string}
209+
> .input {$var :string}
210+
> .match $var
203211
> * {{The first default}}
204212
> * {{The second default}}
205213
> ```
206214
>
207215
> ```
208-
> .match {$x :string} {$y :string}
216+
> .input {$x :string}
217+
> .input {$y :string}
218+
> .match $x $y
209219
> * foo {{The first "foo" variant}}
210220
> bar * {{The "bar" variant}}
211221
> * |foo| {{The second "foo" variant}}
@@ -230,7 +240,8 @@ An **_<dfn>Unresolved Variable</dfn>_** error occurs when a variable reference c
230240
> ```
231241
>
232242
> ```
233-
> .match {$var :func}
243+
> .input {$var :func}
244+
> .match $var
234245
> 1 {{The value is one.}}
235246
> * {{The value is not one.}}
236247
> ```
@@ -249,7 +260,8 @@ a reference to a function which cannot be resolved.
249260
> ```
250261
>
251262
> ```
252-
> .match {|horse| :func}
263+
> .local $horse = {|horse| :func}
264+
> .match $horse
253265
> 1 {{The value is one.}}
254266
> * {{The value is not one.}}
255267
> ```
@@ -264,7 +276,7 @@ with a resolved value which does not support selection.
264276
>
265277
> ```
266278
> .local $day = {|2024-05-01| :date}
267-
> .match {$day}
279+
> .match $day
268280
> * {{The due date is {$day}}}
269281
> ```
270282
@@ -326,7 +338,8 @@ for that specific _function_.
326338
> ```
327339
>
328340
> ```
329-
> .match {|horse| :number}
341+
> .local $horse = {|horse| :number}
342+
> .match $horse
330343
> 1 {{The value is one.}}
331344
> * {{The value is not one.}}
332345
> ```
@@ -363,7 +376,8 @@ does not match the expected implementation-defined format.
363376
> which is a requirement of the `:number` function:
364377
>
365378
> ```
366-
> .match {42 :number}
379+
> .local $answer = {42 :number}
380+
> .match $answer
367381
> 1 {{The value is one.}}
368382
> horse {{The value is a horse.}}
369383
> * {{The value is not one.}}

spec/formatting.md

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ nor be made available to function implementations.
5353
> value of a given _expression_ until it is actually used by a
5454
> selection or formatting process.
5555
> However, when an _expression_ is resolved, it MUST behave as if all preceding
56-
> _declarations_ and _selectors_ affecting _variables_ referenced by that _expression_
56+
> _declarations_ affecting _variables_ referenced by that _expression_
5757
> have already been evaluated in the order in which the relevant _declarations_
58-
> and _selectors_ appear in the _message_.
58+
> appear in the _message_.
5959
6060
## Formatting Context
6161

@@ -85,7 +85,7 @@ Implementations MAY include additional fields in their _formatting context_.
8585

8686
## Expression and Markup Resolution
8787

88-
_Expressions_ are used in _declarations_, _selectors_, and _patterns_.
88+
_Expressions_ are used in _declarations_ and _patterns_.
8989
_Markup_ is only used in _patterns_.
9090

9191
In a _declaration_, the resolved value of the _expression_ is bound to a _variable_,
@@ -97,8 +97,6 @@ In an _input-declaration_, the _variable_ operand of the _variable-expression_
9797
identifies not only the name of the external input value,
9898
but also the _variable_ to which the resolved value of the _variable-expression_ is bound.
9999

100-
In _selectors_, the resolved value of an _expression_ is used for _pattern selection_.
101-
102100
In a _pattern_, the resolved value of an _expression_ or _markup_ is used in its _formatting_.
103101

104102
The form that resolved values take is implementation-dependent,
@@ -429,7 +427,8 @@ according to their _key_ values and selecting the first one.
429427
> > For example, in the `pl` (Polish) locale, this _message_ cannot reach
430428
> > the `*` _variant_:
431429
> > ```
432-
> > .match {$num :integer}
430+
> > .input {$num :integer}
431+
> > .match $num
433432
> > 0 {{ }}
434433
> > one {{ }}
435434
> > few {{ }}
@@ -449,13 +448,16 @@ Each _key_ corresponds to a _selector_ by its position in the _variant_.
449448
> For example, in this message:
450449
>
451450
> ```
452-
> .match {:one} {:two} {:three}
451+
> .input {$one :number}
452+
> .input {$two :number}
453+
> .input {$three :number}
454+
> .match $one $two $three
453455
> 1 2 3 {{ ... }}
454456
> ```
455457
>
456-
> The first _key_ `1` corresponds to the first _selector_ (`{:one}`),
457-
> the second _key_ `2` to the second _selector_ (`{:two}`),
458-
> and the third _key_ `3` to the third _selector_ (`{:three}`).
458+
> The first _key_ `1` corresponds to the first _selector_ (`$one`),
459+
> the second _key_ `2` to the second _selector_ (`$two`),
460+
> and the third _key_ `3` to the third _selector_ (`$three`).
459461
460462
To determine which _variant_ best matches a given set of inputs,
461463
each _selector_ is used in turn to order and filter the list of _variants_.
@@ -468,15 +470,6 @@ Earlier _selectors_ in the _matcher_'s list of _selectors_ have a higher priorit
468470
When all of the _selectors_ have been processed,
469471
the earliest-sorted _variant_ in the remaining list of _variants_ is selected.
470472
471-
> [!NOTE]
472-
> A _selector_ is not a _declaration_.
473-
> Even when the same _function_ can be used for both formatting and selection
474-
> of a given _operand_
475-
> the _annotation_ that appears in a _selector_ has no effect on subsequent
476-
> _selectors_ nor on the formatting used in _placeholders_.
477-
> To use the same value for selection and formatting,
478-
> set its value with a `.input` or `.local` _declaration_.
479-
480473
This selection method is defined in more detail below.
481474
An implementation MAY use any pattern selection method,
482475
as long as its observable behavior matches the results of the method defined here.
@@ -600,7 +593,9 @@ the variable reference `$bar` resolves to the string `'bar'`,
600593
pattern selection proceeds as follows for this message:
601594
602595
```
603-
.match {$foo :string} {$bar :string}
596+
.input {$foo :string}
597+
.input {$bar :string}
598+
.match $foo $bar
604599
bar bar {{All bar}}
605600
foo foo {{All foo}}
606601
* * {{Otherwise}}
@@ -631,7 +626,9 @@ Alternatively, with the same implementation and formatting context as in Example
631626
pattern selection would proceed as follows for this message:
632627
633628
```
634-
.match {$foo :string} {$bar :string}
629+
.input {$foo :string}
630+
.input {$bar :string}
631+
.match $foo $bar
635632
* bar {{Any and bar}}
636633
foo * {{Foo and any}}
637634
foo bar {{Foo and bar}}
@@ -680,7 +677,7 @@ the pattern selection proceeds as follows for this message:
680677
681678
```
682679
.input {$count :number}
683-
.match {$count}
680+
.match $count
684681
one {{Category match for {$count}}}
685682
1 {{Exact match for {$count}}}
686683
* {{Other match for {$count}}}

spec/message.abnf

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ local-declaration = local s variable [s] "=" [s] expression
1414

1515
quoted-pattern = "{{" pattern "}}"
1616

17-
matcher = match-statement 1*([s] variant)
18-
match-statement = match 1*([s] selector)
19-
selector = expression
17+
matcher = match-statement s variant *([s] variant)
18+
match-statement = match 1*(s selector)
19+
selector = variable
2020
variant = key *(s key) [s] quoted-pattern
2121
key = literal / "*"
2222

0 commit comments

Comments
 (0)