Skip to content

Commit 73fc2cf

Browse files
catamorphismeemeli
andauthored
Implement the simplified pattern selection algorithm in the spec (#898) (#1080)
* Implement the simplified pattern selection algorithm in the spec (#898) Implement Mark Davis's suggested pattern selection algorithm in the spec. Update the "resolved values" example to use the `match()` and `compare()` methods instead of `selectKeys()`. Rewrite the numeric and `:string` selector specs accordingly. * Use sentence case for SelectorsMatch and SelectorsCompare * Make notation for match/compare consistent * Add missing `let`s * Rephrase to use early return * Move pattern selection examples to an appendix * Fix internal link * Fix method names in examples * Fix assertions; fix method names in function specs * Replace references to selectKeys with match/compare * Update spec/formatting.md Co-authored-by: Eemeli Aro <[email protected]> * Replace assertions with prose * Update spec/formatting.md Co-authored-by: Eemeli Aro <[email protected]> * Rewrite 'Operations on Resolved Values' section * Fix markup * Move examples to appendices.md * Add NormalizeKey operation; clean up markup errors that I missed earlier * Update spec for :test:select function * Rename Compare to BetterThan and make it and SelectorsCompare return a boolean * Update spec/formatting.md Co-authored-by: Eemeli Aro <[email protected]> * Update spec/formatting.md Co-authored-by: Eemeli Aro <[email protected]> * Update spec/formatting.md Co-authored-by: Eemeli Aro <[email protected]> * Update spec/formatting.md Co-authored-by: Eemeli Aro <[email protected]> * Update spec/formatting.md Co-authored-by: Eemeli Aro <[email protected]> * Update spec/formatting.md Co-authored-by: Eemeli Aro <[email protected]> * Update spec/formatting.md Co-authored-by: Eemeli Aro <[email protected]> * Update examples for spec changes * Fix typo * Update spec/formatting.md Co-authored-by: Eemeli Aro <[email protected]> * Update spec/formatting.md Co-authored-by: Eemeli Aro <[email protected]> * Update spec/formatting.md Co-authored-by: Eemeli Aro <[email protected]> --------- Co-authored-by: Eemeli Aro <[email protected]>
1 parent 0028d17 commit 73fc2cf

File tree

5 files changed

+346
-258
lines changed

5 files changed

+346
-258
lines changed

spec/appendices.md

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,202 @@ fingerprinting, and other types of bad behavior.
4343
Any installed code needs to be appropriately sandboxed.
4444
In addition, end-users need to be aware of the risks involved.
4545

46+
### Non-normative Examples
47+
48+
#### Pattern Selection Examples
49+
50+
##### Selection Example 1
51+
52+
Presuming a minimal implementation which only supports `:string` _function_
53+
which matches keys by using string comparison,
54+
and a formatting context in which
55+
the variable reference `$foo` resolves to the string `'foo'` and
56+
the variable reference `$bar` resolves to the string `'bar'`,
57+
pattern selection proceeds as follows for this message:
58+
59+
```
60+
.input {$foo :string}
61+
.input {$bar :string}
62+
.match $foo $bar
63+
bar bar {{All bar}}
64+
foo foo {{All foo}}
65+
* * {{Otherwise}}
66+
```
67+
68+
1. Each selector is resolved, yielding the list `res` = `{foo, bar}`.
69+
2. `bestVariant` is set to `UNSET`.
70+
3. `keys` is set to `{bar, bar}`.
71+
4. `match` is set to SelectorsMatch(`{foo, bar}`, `{bar, bar}`).
72+
The result of SelectorsMatch(`{foo, bar}`, `{bar, bar}`) is
73+
determined as follows:
74+
1. `result` is set to true.
75+
1. `i` is set to 0.
76+
1. `k` is set to the string `bar`.
77+
1. `sel` is set to a resolved value corresponding to the string `foo`.
78+
1. Match(`sel`, `'bar'`) is false.
79+
1. The result of SelectorsMatch(`{foo, bar}`, `{bar, bar}`) is false.
80+
Thus, `match` is set to false.
81+
5. `keys` is set to `{foo, foo}`.
82+
6. `match` is set to SelectorsMatch(`{foo, bar}`, `{foo, foo}`).
83+
The result of SelectorsMatch(`{foo, bar}`, `{foo, foo}`) is
84+
determined as follows:
85+
1. `result` is set to true.
86+
1. `i` is set to 0.
87+
1. `k` is set to the string `foo`.
88+
1. `sel` is set to a resolved value corresponding to the string `foo`.
89+
1. Match(`sel`, `'foo'`) is true.
90+
1. `i` is set to 1.
91+
1. `k` is set to the string `foo`.
92+
1. `sel` is set to a resolved value corresponding to the string `bar`.
93+
1. Match(`sel`, `'bar'`) is false.
94+
1. The result of SelectorsMatch(`{foo, bar}`, `{foo, foo}`) is false.
95+
7. `keys` is set to `* *`.
96+
8. The result of SelectorsMatch(`{foo, bar}`, `{*, *}`) is
97+
determined as follows:
98+
1. `result` is set to true.
99+
1. `i` is set to 0.
100+
1. `i` is set to 1.
101+
1. `i` is set to 2.
102+
1. The result of SelectorsMatch(`{foo, bar}`, `{*, *}`) is true.
103+
9. `bestVariant` is set to the variant `* * {{Otherwise}}`
104+
10. The pattern `Otherwise` is selected.
105+
106+
##### Selection Example 2
107+
108+
Alternatively, with the same implementation and formatting context as in Example 1,
109+
pattern selection would proceed as follows for this message:
110+
111+
```
112+
.input {$foo :string}
113+
.input {$bar :string}
114+
.match $foo $bar
115+
* bar {{Any and bar}}
116+
foo * {{Foo and any}}
117+
foo bar {{Foo and bar}}
118+
* * {{Otherwise}}
119+
```
120+
121+
1. Each selector is resolved, yielding the list `res` = `{foo, bar}`.
122+
2. `bestVariant` is set to `UNSET`.
123+
3. `keys` is set to `{*, bar}`.
124+
4. `match` is set to SelectorsMatch(`{foo, bar}`, `{*, bar}`)
125+
The result of SelectorsMatch(`{foo, bar}`, `{*, bar}`) is
126+
determined as follows:
127+
1. `result` is set to true.
128+
2. `i` is set to 0.
129+
3. `i` is set to 1.
130+
4. `k` is set to the string `bar`.
131+
5. `sel` is set to a resolved value corresponding to the string `bar`.
132+
6. Match(`sel`, `'bar'`) is true.
133+
7. `i` is set to 2.
134+
1. The result of SelectorsMatch(`{foo, bar}`, `{*, bar}`) is true.
135+
5. `bestVariant` is set to the variant `* bar {{Any and bar}}`.
136+
6. `keys` is set to `{foo, *}`.
137+
7. `match` is set to SelectorsMatch(`{foo, bar}`, `{foo, *}`).
138+
The result of SelectorsMatch(`{foo, bar}`, `{foo, *}`) is
139+
determined as follows:
140+
1. `result` is set to true.
141+
2. `i` is set to 0.
142+
3. `k` is set to the string `foo`.
143+
4. `sel` is set to a resolved value corresponding to the string `foo`.
144+
5. Match(`sel`, `'foo'`) is true.
145+
6. `i` is set to 1.
146+
7. `i` is set to 2.
147+
8. The result of SelectorsMatch(`{foo, bar}`, `{foo, *}`) is true.
148+
8. `bestVariantKeys` is set to `{*, bar}`.
149+
9. SelectorsCompare(`{foo, bar}`, `{foo, *}`, `{*, bar}`) is
150+
determined as follows:
151+
1. `result` is set to false.
152+
1. `i` is set to 0.
153+
1. `key1` is set to `foo`.
154+
1. `key2` is set to `'*'`
155+
1. The result of SelectorsCompare(`{foo, bar}`, `{foo, *}`, `{*, bar}`) is true.
156+
10. `bestVariant` is set to `foo * {{Foo and any}}`.
157+
11. `keys` is set to `{foo, bar}`.
158+
12. `match` is set to SelectorsMatch(`{foo, bar}`, `{foo, bar}`).
159+
1. `match` is true (details elided)
160+
13. `bestVariantKeys` is set to `{foo, *}`.
161+
14. SelectorsCompare(`{foo, bar}`, `{foo, bar}`, `{foo, *}`) is
162+
determined as follows:
163+
1. `result` is set to false.
164+
1. `i` is set to 0.
165+
1. `key1` is set to `foo`.
166+
1. `key2` is set to `foo`.
167+
1. `k1` is set to `foo`.
168+
1. `k2` is set to `foo`.
169+
1. `sel` is set to a resolved value corresponding to `foo`.
170+
1. `i` is set to 1.
171+
1. `key1` is set to `bar`.
172+
1. `key2` is set to `*`.
173+
1. The result of SelectorsCompare(`{foo, bar}`, `{foo, bar}`, `{foo, *}`)
174+
is true.
175+
15. `bestVariant` is set to `foo bar {{Foo and bar}}`.
176+
16. `keys` is set to `* *`.
177+
17. `match` is set to true (details elided).
178+
18. `bestVariantKeys` is set to `foo bar`.
179+
19. SelectorsCompare(`{foo, bar}`, `{*, *}`, `{foo, bar}`} is false
180+
(details elided).
181+
182+
The pattern `{{Foo and bar}}` is selected.
183+
184+
##### Selection Example 3
185+
186+
A more-complex example is the matching found in selection APIs
187+
such as ICU's `PluralFormat`.
188+
Suppose that this API is represented here by the function `:number`.
189+
This `:number` function can match a given numeric value to a specific number _literal_
190+
and **_also_** to a plural category (`zero`, `one`, `two`, `few`, `many`, `other`)
191+
according to locale rules defined in CLDR.
192+
193+
Given a variable reference `$count` whose value resolves to the number `1`
194+
and an `en` (English) locale,
195+
the pattern selection proceeds as follows for this message:
196+
197+
```
198+
.input {$count :number}
199+
.match $count
200+
one {{Category match for {$count}}}
201+
1 {{Exact match for {$count}}}
202+
* {{Other match for {$count}}}
203+
```
204+
205+
1. Each selector is resolved, yielding the list `{1}`.
206+
1. `bestVariant` is set to `UNSET`.
207+
1. `keys` is set to `{one}`.
208+
1. `match` is set to SelectorsMatch(`{1}`, `{one}`).
209+
The result of SelectorsMatch(`{1}`, `{one}`) is
210+
determined as follows:
211+
1. `result` is set to true.
212+
1. `i` is set to 0.
213+
1. `k` is set to `one`.
214+
1. `sel` is set to `1`.
215+
1. Match(`sel`, `one`) is true.
216+
1. `i` is set to 1.
217+
1. The result of SelectorsMatch(`{1}`, `{one}`) is true.
218+
1. `bestVariant` is set to `one {{Category match for {$count}}}`.
219+
1. `keys` is set to `1`.
220+
1. `match` is set to SelectorsMatch(`{1}`, `{one}`).
221+
1. The details are the same as the previous case,
222+
as Match(`sel`, `1`) is also true.
223+
1. `bestVariantKeys` is set to `{one}`.
224+
1. SelectorsCompare(`{1}`, `{1}`, `{one}`) is determined as follows:
225+
1. `result` is set to false.
226+
1. `i` is set to 0.
227+
1. `key1` is set to `1`.
228+
1. `key2` is set to `one`.
229+
1. `k1` is set to `1`.
230+
1. `k2` is set to `one`.
231+
1. `sel` is set to `1`.
232+
1. `result` is set to BetterThan(`sel`, `1`, `one`), which is true.
233+
1. NOTE: The specification of the `:number` selector function
234+
states that the exact match `1` is a better match than
235+
the category match `one`.
236+
1. `bestVariant` is set to `1 {{Exact match for {$count}}}`.
237+
1. `keys` is set to `*`
238+
1. Details elided; since `*` is the catch-all key,
239+
BetterThan(`{1}`, `{1}`, `{*}`) is false.
240+
1. The pattern `{{Exact match for {$count}}}` is selected.
241+
46242
### Acknowledgements
47243

48244
Special thanks to the following people for their contributions to making the Unicode MessageFormat Standard.

0 commit comments

Comments
 (0)