File: | out/../deps/v8/src/objects/js-collator.cc |
Warning: | line 447, column 3 Value stored to 'status' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | // Copyright 2018 the V8 project authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | #ifndef V8_INTL_SUPPORT1 |
6 | #error Internationalization is expected to be enabled. |
7 | #endif // V8_INTL_SUPPORT |
8 | |
9 | #include "src/objects/js-collator.h" |
10 | |
11 | #include "src/execution/isolate.h" |
12 | #include "src/objects/js-collator-inl.h" |
13 | #include "src/objects/js-locale.h" |
14 | #include "src/objects/managed-inl.h" |
15 | #include "src/objects/objects-inl.h" |
16 | #include "src/objects/option-utils.h" |
17 | #include "unicode/coll.h" |
18 | #include "unicode/locid.h" |
19 | #include "unicode/strenum.h" |
20 | #include "unicode/ucol.h" |
21 | #include "unicode/udata.h" |
22 | #include "unicode/uloc.h" |
23 | #include "unicode/utypes.h" |
24 | |
25 | namespace v8 { |
26 | namespace internal { |
27 | |
28 | namespace { |
29 | |
30 | enum class Usage { |
31 | SORT, |
32 | SEARCH, |
33 | }; |
34 | |
35 | enum class Sensitivity { |
36 | kBase, |
37 | kAccent, |
38 | kCase, |
39 | kVariant, |
40 | kUndefined, |
41 | }; |
42 | |
43 | // enum for "caseFirst" option. |
44 | enum class CaseFirst { kUndefined, kUpper, kLower, kFalse }; |
45 | |
46 | Maybe<CaseFirst> GetCaseFirst(Isolate* isolate, Handle<JSReceiver> options, |
47 | const char* method_name) { |
48 | return GetStringOption<CaseFirst>( |
49 | isolate, options, "caseFirst", method_name, {"upper", "lower", "false"}, |
50 | {CaseFirst::kUpper, CaseFirst::kLower, CaseFirst::kFalse}, |
51 | CaseFirst::kUndefined); |
52 | } |
53 | |
54 | // TODO(gsathya): Consider internalizing the value strings. |
55 | void CreateDataPropertyForOptions(Isolate* isolate, Handle<JSObject> options, |
56 | Handle<String> key, const char* value) { |
57 | DCHECK_NOT_NULL(value)((void) 0); |
58 | Handle<String> value_str = |
59 | isolate->factory()->NewStringFromAsciiChecked(value); |
60 | |
61 | // This is a brand new JSObject that shouldn't already have the same |
62 | // key so this shouldn't fail. |
63 | Maybe<bool> maybe = JSReceiver::CreateDataProperty( |
64 | isolate, options, key, value_str, Just(kDontThrow)); |
65 | DCHECK(maybe.FromJust())((void) 0); |
66 | USE(maybe)do { ::v8::base::Use unused_tmp_array_for_use_macro[]{maybe}; (void)unused_tmp_array_for_use_macro; } while (false); |
67 | } |
68 | |
69 | void CreateDataPropertyForOptions(Isolate* isolate, Handle<JSObject> options, |
70 | Handle<String> key, bool value) { |
71 | Handle<Object> value_obj = isolate->factory()->ToBoolean(value); |
72 | |
73 | // This is a brand new JSObject that shouldn't already have the same |
74 | // key so this shouldn't fail. |
75 | Maybe<bool> maybe = JSReceiver::CreateDataProperty( |
76 | isolate, options, key, value_obj, Just(kDontThrow)); |
77 | DCHECK(maybe.FromJust())((void) 0); |
78 | USE(maybe)do { ::v8::base::Use unused_tmp_array_for_use_macro[]{maybe}; (void)unused_tmp_array_for_use_macro; } while (false); |
79 | } |
80 | |
81 | } // anonymous namespace |
82 | |
83 | // static |
84 | Handle<JSObject> JSCollator::ResolvedOptions(Isolate* isolate, |
85 | Handle<JSCollator> collator) { |
86 | Handle<JSObject> options = |
87 | isolate->factory()->NewJSObject(isolate->object_function()); |
88 | |
89 | icu::Collator* icu_collator = collator->icu_collator().raw(); |
90 | DCHECK_NOT_NULL(icu_collator)((void) 0); |
91 | |
92 | UErrorCode status = U_ZERO_ERROR; |
93 | bool numeric = |
94 | icu_collator->getAttribute(UCOL_NUMERIC_COLLATION, status) == UCOL_ON; |
95 | DCHECK(U_SUCCESS(status))((void) 0); |
96 | |
97 | const char* case_first = nullptr; |
98 | status = U_ZERO_ERROR; |
99 | switch (icu_collator->getAttribute(UCOL_CASE_FIRST, status)) { |
100 | case UCOL_LOWER_FIRST: |
101 | case_first = "lower"; |
102 | break; |
103 | case UCOL_UPPER_FIRST: |
104 | case_first = "upper"; |
105 | break; |
106 | default: |
107 | case_first = "false"; |
108 | } |
109 | DCHECK(U_SUCCESS(status))((void) 0); |
110 | |
111 | const char* sensitivity = nullptr; |
112 | status = U_ZERO_ERROR; |
113 | switch (icu_collator->getAttribute(UCOL_STRENGTH, status)) { |
114 | case UCOL_PRIMARY: { |
115 | DCHECK(U_SUCCESS(status))((void) 0); |
116 | status = U_ZERO_ERROR; |
117 | // case level: true + s1 -> case, s1 -> base. |
118 | if (UCOL_ON == icu_collator->getAttribute(UCOL_CASE_LEVEL, status)) { |
119 | sensitivity = "case"; |
120 | } else { |
121 | sensitivity = "base"; |
122 | } |
123 | DCHECK(U_SUCCESS(status))((void) 0); |
124 | break; |
125 | } |
126 | case UCOL_SECONDARY: |
127 | sensitivity = "accent"; |
128 | break; |
129 | case UCOL_TERTIARY: |
130 | sensitivity = "variant"; |
131 | break; |
132 | case UCOL_QUATERNARY: |
133 | // We shouldn't get quaternary and identical from ICU, but if we do |
134 | // put them into variant. |
135 | sensitivity = "variant"; |
136 | break; |
137 | default: |
138 | sensitivity = "variant"; |
139 | } |
140 | DCHECK(U_SUCCESS(status))((void) 0); |
141 | |
142 | status = U_ZERO_ERROR; |
143 | bool ignore_punctuation = icu_collator->getAttribute(UCOL_ALTERNATE_HANDLING, |
144 | status) == UCOL_SHIFTED; |
145 | DCHECK(U_SUCCESS(status))((void) 0); |
146 | |
147 | status = U_ZERO_ERROR; |
148 | |
149 | icu::Locale icu_locale(icu_collator->getLocale(ULOC_VALID_LOCALE, status)); |
150 | DCHECK(U_SUCCESS(status))((void) 0); |
151 | |
152 | const char* collation = "default"; |
153 | const char* usage = "sort"; |
154 | const char* collation_key = "co"; |
155 | status = U_ZERO_ERROR; |
156 | std::string collation_value = |
157 | icu_locale.getUnicodeKeywordValue<std::string>(collation_key, status); |
158 | |
159 | std::string locale; |
160 | if (U_SUCCESS(status)) { |
161 | if (collation_value == "search") { |
162 | usage = "search"; |
163 | |
164 | // Search is disallowed as a collation value per spec. Let's |
165 | // use `default`, instead. |
166 | // |
167 | // https://tc39.github.io/ecma402/#sec-properties-of-intl-collator-instances |
168 | collation = "default"; |
169 | |
170 | // We clone the icu::Locale because we don't want the |
171 | // icu_collator to be affected when we remove the collation key |
172 | // below. |
173 | icu::Locale new_icu_locale = icu_locale; |
174 | |
175 | // The spec forbids the search as a collation value in the |
176 | // locale tag, so let's filter it out. |
177 | status = U_ZERO_ERROR; |
178 | new_icu_locale.setUnicodeKeywordValue(collation_key, nullptr, status); |
179 | DCHECK(U_SUCCESS(status))((void) 0); |
180 | |
181 | locale = Intl::ToLanguageTag(new_icu_locale).FromJust(); |
182 | } else { |
183 | collation = collation_value.c_str(); |
184 | locale = Intl::ToLanguageTag(icu_locale).FromJust(); |
185 | } |
186 | } else { |
187 | locale = Intl::ToLanguageTag(icu_locale).FromJust(); |
188 | } |
189 | |
190 | // 5. For each row of Table 2, except the header row, in table order, do |
191 | // ... |
192 | // Table 2: Resolved Options of Collator Instances |
193 | // Internal Slot Property Extension Key |
194 | // [[Locale] "locale" |
195 | // [[Usage] "usage" |
196 | // [[Sensitivity]] "sensitivity" |
197 | // [[IgnorePunctuation]] "ignorePunctuation" |
198 | // [[Collation]] "collation" |
199 | // [[Numeric]] "numeric" kn |
200 | // [[CaseFirst]] "caseFirst" kf |
201 | |
202 | // If the collator return the locale differ from what got requested, we stored |
203 | // it in the collator->locale. Otherwise, we just use the one from the |
204 | // collator. |
205 | if (collator->locale().length() != 0) { |
206 | // Get the locale from collator->locale() since we know in some cases |
207 | // collator won't be able to return the requested one, such as zh_CN. |
208 | Handle<String> locale_from_collator(collator->locale(), isolate); |
209 | Maybe<bool> maybe = JSReceiver::CreateDataProperty( |
210 | isolate, options, isolate->factory()->locale_string(), |
211 | locale_from_collator, Just(kDontThrow)); |
212 | DCHECK(maybe.FromJust())((void) 0); |
213 | USE(maybe)do { ::v8::base::Use unused_tmp_array_for_use_macro[]{maybe}; (void)unused_tmp_array_for_use_macro; } while (false); |
214 | } else { |
215 | // Just return from the collator for most of the cases that we can recover |
216 | // from the collator. |
217 | CreateDataPropertyForOptions( |
218 | isolate, options, isolate->factory()->locale_string(), locale.c_str()); |
219 | } |
220 | |
221 | CreateDataPropertyForOptions(isolate, options, |
222 | isolate->factory()->usage_string(), usage); |
223 | CreateDataPropertyForOptions( |
224 | isolate, options, isolate->factory()->sensitivity_string(), sensitivity); |
225 | CreateDataPropertyForOptions(isolate, options, |
226 | isolate->factory()->ignorePunctuation_string(), |
227 | ignore_punctuation); |
228 | CreateDataPropertyForOptions( |
229 | isolate, options, isolate->factory()->collation_string(), collation); |
230 | CreateDataPropertyForOptions(isolate, options, |
231 | isolate->factory()->numeric_string(), numeric); |
232 | CreateDataPropertyForOptions( |
233 | isolate, options, isolate->factory()->caseFirst_string(), case_first); |
234 | return options; |
235 | } |
236 | |
237 | namespace { |
238 | |
239 | CaseFirst ToCaseFirst(const char* str) { |
240 | if (strcmp(str, "upper") == 0) return CaseFirst::kUpper; |
241 | if (strcmp(str, "lower") == 0) return CaseFirst::kLower; |
242 | if (strcmp(str, "false") == 0) return CaseFirst::kFalse; |
243 | return CaseFirst::kUndefined; |
244 | } |
245 | |
246 | UColAttributeValue ToUColAttributeValue(CaseFirst case_first) { |
247 | switch (case_first) { |
248 | case CaseFirst::kUpper: |
249 | return UCOL_UPPER_FIRST; |
250 | case CaseFirst::kLower: |
251 | return UCOL_LOWER_FIRST; |
252 | case CaseFirst::kFalse: |
253 | case CaseFirst::kUndefined: |
254 | return UCOL_OFF; |
255 | } |
256 | } |
257 | |
258 | void SetNumericOption(icu::Collator* icu_collator, bool numeric) { |
259 | DCHECK_NOT_NULL(icu_collator)((void) 0); |
260 | UErrorCode status = U_ZERO_ERROR; |
261 | icu_collator->setAttribute(UCOL_NUMERIC_COLLATION, |
262 | numeric ? UCOL_ON : UCOL_OFF, status); |
263 | DCHECK(U_SUCCESS(status))((void) 0); |
264 | } |
265 | |
266 | void SetCaseFirstOption(icu::Collator* icu_collator, CaseFirst case_first) { |
267 | DCHECK_NOT_NULL(icu_collator)((void) 0); |
268 | UErrorCode status = U_ZERO_ERROR; |
269 | icu_collator->setAttribute(UCOL_CASE_FIRST, ToUColAttributeValue(case_first), |
270 | status); |
271 | DCHECK(U_SUCCESS(status))((void) 0); |
272 | } |
273 | |
274 | } // anonymous namespace |
275 | |
276 | // static |
277 | MaybeHandle<JSCollator> JSCollator::New(Isolate* isolate, Handle<Map> map, |
278 | Handle<Object> locales, |
279 | Handle<Object> options_obj, |
280 | const char* service) { |
281 | // 1. Let requestedLocales be ? CanonicalizeLocaleList(locales). |
282 | Maybe<std::vector<std::string>> maybe_requested_locales = |
283 | Intl::CanonicalizeLocaleList(isolate, locales); |
284 | MAYBE_RETURN(maybe_requested_locales, Handle<JSCollator>())do { if ((maybe_requested_locales).IsNothing()) return Handle <JSCollator>(); } while (false); |
285 | std::vector<std::string> requested_locales = |
286 | maybe_requested_locales.FromJust(); |
287 | |
288 | // 2. Set options to ? CoerceOptionsToObject(options). |
289 | Handle<JSReceiver> options; |
290 | ASSIGN_RETURN_ON_EXCEPTION(do { if (!(CoerceOptionsToObject(isolate, options_obj, service )).ToHandle(&options)) { ((void) 0); return MaybeHandle< JSCollator>(); } } while (false) |
291 | isolate, options, CoerceOptionsToObject(isolate, options_obj, service),do { if (!(CoerceOptionsToObject(isolate, options_obj, service )).ToHandle(&options)) { ((void) 0); return MaybeHandle< JSCollator>(); } } while (false) |
292 | JSCollator)do { if (!(CoerceOptionsToObject(isolate, options_obj, service )).ToHandle(&options)) { ((void) 0); return MaybeHandle< JSCollator>(); } } while (false); |
293 | |
294 | // 4. Let usage be ? GetOption(options, "usage", "string", « "sort", |
295 | // "search" », "sort"). |
296 | Maybe<Usage> maybe_usage = GetStringOption<Usage>( |
297 | isolate, options, "usage", service, {"sort", "search"}, |
298 | {Usage::SORT, Usage::SEARCH}, Usage::SORT); |
299 | MAYBE_RETURN(maybe_usage, MaybeHandle<JSCollator>())do { if ((maybe_usage).IsNothing()) return MaybeHandle<JSCollator >(); } while (false); |
300 | Usage usage = maybe_usage.FromJust(); |
301 | |
302 | // 9. Let matcher be ? GetOption(options, "localeMatcher", "string", |
303 | // « "lookup", "best fit" », "best fit"). |
304 | // 10. Set opt.[[localeMatcher]] to matcher. |
305 | Maybe<Intl::MatcherOption> maybe_locale_matcher = |
306 | Intl::GetLocaleMatcher(isolate, options, service); |
307 | MAYBE_RETURN(maybe_locale_matcher, MaybeHandle<JSCollator>())do { if ((maybe_locale_matcher).IsNothing()) return MaybeHandle <JSCollator>(); } while (false); |
308 | Intl::MatcherOption matcher = maybe_locale_matcher.FromJust(); |
309 | |
310 | // x. Let _collation_ be ? GetOption(_options_, *"collation"*, *"string"*, |
311 | // *undefined*, *undefined*). |
312 | std::unique_ptr<char[]> collation_str = nullptr; |
313 | const std::vector<const char*> empty_values = {}; |
314 | Maybe<bool> maybe_collation = GetStringOption( |
315 | isolate, options, "collation", empty_values, service, &collation_str); |
316 | MAYBE_RETURN(maybe_collation, MaybeHandle<JSCollator>())do { if ((maybe_collation).IsNothing()) return MaybeHandle< JSCollator>(); } while (false); |
317 | // x. If _collation_ is not *undefined*, then |
318 | if (maybe_collation.FromJust() && collation_str != nullptr) { |
319 | // 1. If _collation_ does not match the Unicode Locale Identifier `type` |
320 | // nonterminal, throw a *RangeError* exception. |
321 | if (!JSLocale::Is38AlphaNumList(collation_str.get())) { |
322 | THROW_NEW_ERROR_RETURN_VALUE(do { auto* __isolate__ = (isolate); __isolate__->Throw(*__isolate__ ->factory()->NewRangeError(MessageTemplate::kInvalid, isolate ->factory()->collation_string(), isolate->factory()-> NewStringFromAsciiChecked( collation_str.get()))); return MaybeHandle <JSCollator>(); } while (false) |
323 | isolate,do { auto* __isolate__ = (isolate); __isolate__->Throw(*__isolate__ ->factory()->NewRangeError(MessageTemplate::kInvalid, isolate ->factory()->collation_string(), isolate->factory()-> NewStringFromAsciiChecked( collation_str.get()))); return MaybeHandle <JSCollator>(); } while (false) |
324 | NewRangeError(MessageTemplate::kInvalid,do { auto* __isolate__ = (isolate); __isolate__->Throw(*__isolate__ ->factory()->NewRangeError(MessageTemplate::kInvalid, isolate ->factory()->collation_string(), isolate->factory()-> NewStringFromAsciiChecked( collation_str.get()))); return MaybeHandle <JSCollator>(); } while (false) |
325 | isolate->factory()->collation_string(),do { auto* __isolate__ = (isolate); __isolate__->Throw(*__isolate__ ->factory()->NewRangeError(MessageTemplate::kInvalid, isolate ->factory()->collation_string(), isolate->factory()-> NewStringFromAsciiChecked( collation_str.get()))); return MaybeHandle <JSCollator>(); } while (false) |
326 | isolate->factory()->NewStringFromAsciiChecked(do { auto* __isolate__ = (isolate); __isolate__->Throw(*__isolate__ ->factory()->NewRangeError(MessageTemplate::kInvalid, isolate ->factory()->collation_string(), isolate->factory()-> NewStringFromAsciiChecked( collation_str.get()))); return MaybeHandle <JSCollator>(); } while (false) |
327 | collation_str.get())),do { auto* __isolate__ = (isolate); __isolate__->Throw(*__isolate__ ->factory()->NewRangeError(MessageTemplate::kInvalid, isolate ->factory()->collation_string(), isolate->factory()-> NewStringFromAsciiChecked( collation_str.get()))); return MaybeHandle <JSCollator>(); } while (false) |
328 | MaybeHandle<JSCollator>())do { auto* __isolate__ = (isolate); __isolate__->Throw(*__isolate__ ->factory()->NewRangeError(MessageTemplate::kInvalid, isolate ->factory()->collation_string(), isolate->factory()-> NewStringFromAsciiChecked( collation_str.get()))); return MaybeHandle <JSCollator>(); } while (false); |
329 | } |
330 | } |
331 | // x. Set _opt_.[[co]] to _collation_. |
332 | |
333 | // 11. Let numeric be ? GetOption(options, "numeric", "boolean", |
334 | // undefined, undefined). |
335 | // 12. If numeric is not undefined, then |
336 | // a. Let numeric be ! ToString(numeric). |
337 | // |
338 | // Note: We omit the ToString(numeric) operation as it's not |
339 | // observable. GetBoolOption returns a Boolean and |
340 | // ToString(Boolean) is not side-effecting. |
341 | // |
342 | // 13. Set opt.[[kn]] to numeric. |
343 | bool numeric; |
344 | Maybe<bool> found_numeric = |
345 | GetBoolOption(isolate, options, "numeric", service, &numeric); |
346 | MAYBE_RETURN(found_numeric, MaybeHandle<JSCollator>())do { if ((found_numeric).IsNothing()) return MaybeHandle<JSCollator >(); } while (false); |
347 | |
348 | // 14. Let caseFirst be ? GetOption(options, "caseFirst", "string", |
349 | // « "upper", "lower", "false" », undefined). |
350 | Maybe<CaseFirst> maybe_case_first = GetCaseFirst(isolate, options, service); |
351 | MAYBE_RETURN(maybe_case_first, MaybeHandle<JSCollator>())do { if ((maybe_case_first).IsNothing()) return MaybeHandle< JSCollator>(); } while (false); |
352 | CaseFirst case_first = maybe_case_first.FromJust(); |
353 | |
354 | // The relevant unicode extensions accepted by Collator as specified here: |
355 | // https://tc39.github.io/ecma402/#sec-intl-collator-internal-slots |
356 | // |
357 | // 16. Let relevantExtensionKeys be %Collator%.[[RelevantExtensionKeys]]. |
358 | std::set<std::string> relevant_extension_keys{"co", "kn", "kf"}; |
359 | |
360 | // 17. Let r be ResolveLocale(%Collator%.[[AvailableLocales]], |
361 | // requestedLocales, opt, %Collator%.[[RelevantExtensionKeys]], |
362 | // localeData). |
363 | Maybe<Intl::ResolvedLocale> maybe_resolve_locale = |
364 | Intl::ResolveLocale(isolate, JSCollator::GetAvailableLocales(), |
365 | requested_locales, matcher, relevant_extension_keys); |
366 | if (maybe_resolve_locale.IsNothing()) { |
367 | THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError),do { auto* __isolate__ = (isolate); return __isolate__->template Throw<JSCollator>(__isolate__->factory()->NewRangeError (MessageTemplate::kIcuError)); } while (false) |
368 | JSCollator)do { auto* __isolate__ = (isolate); return __isolate__->template Throw<JSCollator>(__isolate__->factory()->NewRangeError (MessageTemplate::kIcuError)); } while (false); |
369 | } |
370 | Intl::ResolvedLocale r = maybe_resolve_locale.FromJust(); |
371 | |
372 | // 18. Set collator.[[Locale]] to r.[[locale]]. |
373 | icu::Locale icu_locale = r.icu_locale; |
374 | DCHECK(!icu_locale.isBogus())((void) 0); |
375 | |
376 | // 19. Let collation be r.[[co]]. |
377 | UErrorCode status = U_ZERO_ERROR; |
378 | if (collation_str != nullptr) { |
379 | auto co_extension_it = r.extensions.find("co"); |
380 | if (co_extension_it != r.extensions.end() && |
381 | co_extension_it->second != collation_str.get()) { |
382 | icu_locale.setUnicodeKeywordValue("co", nullptr, status); |
383 | DCHECK(U_SUCCESS(status))((void) 0); |
384 | } |
385 | } |
386 | |
387 | // 5. Set collator.[[Usage]] to usage. |
388 | // |
389 | // 6. If usage is "sort", then |
390 | // a. Let localeData be %Collator%.[[SortLocaleData]]. |
391 | // 7. Else, |
392 | // a. Let localeData be %Collator%.[[SearchLocaleData]]. |
393 | // |
394 | // The Intl spec doesn't allow us to use "search" as an extension |
395 | // value for collation as per: |
396 | // https://tc39.github.io/ecma402/#sec-intl-collator-internal-slots |
397 | // |
398 | // But the only way to pass the value "search" for collation from |
399 | // the options object to ICU is to use the 'co' extension keyword. |
400 | // |
401 | // This will need to be filtered out when creating the |
402 | // resolvedOptions object. |
403 | if (usage == Usage::SEARCH) { |
404 | UErrorCode set_status = U_ZERO_ERROR; |
405 | icu_locale.setUnicodeKeywordValue("co", "search", set_status); |
406 | DCHECK(U_SUCCESS(set_status))((void) 0); |
407 | } else { |
408 | if (collation_str != nullptr && |
409 | Intl::IsValidCollation(icu_locale, collation_str.get())) { |
410 | icu_locale.setUnicodeKeywordValue("co", collation_str.get(), status); |
411 | DCHECK(U_SUCCESS(status))((void) 0); |
412 | } |
413 | } |
414 | |
415 | // 20. If collation is null, let collation be "default". |
416 | // 21. Set collator.[[Collation]] to collation. |
417 | // |
418 | // We don't store the collation value as per the above two steps |
419 | // here. The collation value can be looked up from icu::Collator on |
420 | // demand, as part of Intl.Collator.prototype.resolvedOptions. |
421 | |
422 | std::unique_ptr<icu::Collator> icu_collator( |
423 | icu::Collator::createInstance(icu_locale, status)); |
424 | if (U_FAILURE(status) || icu_collator.get() == nullptr) { |
425 | status = U_ZERO_ERROR; |
426 | // Remove extensions and try again. |
427 | icu::Locale no_extension_locale(icu_locale.getBaseName()); |
428 | icu_collator.reset( |
429 | icu::Collator::createInstance(no_extension_locale, status)); |
430 | |
431 | if (U_FAILURE(status) || icu_collator.get() == nullptr) { |
432 | THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError),do { auto* __isolate__ = (isolate); return __isolate__->template Throw<JSCollator>(__isolate__->factory()->NewRangeError (MessageTemplate::kIcuError)); } while (false) |
433 | JSCollator)do { auto* __isolate__ = (isolate); return __isolate__->template Throw<JSCollator>(__isolate__->factory()->NewRangeError (MessageTemplate::kIcuError)); } while (false); |
434 | } |
435 | } |
436 | DCHECK(U_SUCCESS(status))((void) 0); |
437 | |
438 | icu::Locale collator_locale( |
439 | icu_collator->getLocale(ULOC_VALID_LOCALE, status)); |
440 | |
441 | // 22. If relevantExtensionKeys contains "kn", then |
442 | // a. Set collator.[[Numeric]] to ! SameValue(r.[[kn]], "true"). |
443 | // |
444 | // If the numeric value is passed in through the options object, |
445 | // then we use it. Otherwise, we check if the numeric value is |
446 | // passed in through the unicode extensions. |
447 | status = U_ZERO_ERROR; |
Value stored to 'status' is never read | |
448 | if (found_numeric.FromJust()) { |
449 | SetNumericOption(icu_collator.get(), numeric); |
450 | } else { |
451 | auto kn_extension_it = r.extensions.find("kn"); |
452 | if (kn_extension_it != r.extensions.end()) { |
453 | SetNumericOption(icu_collator.get(), (kn_extension_it->second == "true")); |
454 | } |
455 | } |
456 | |
457 | // 23. If relevantExtensionKeys contains "kf", then |
458 | // a. Set collator.[[CaseFirst]] to r.[[kf]]. |
459 | // |
460 | // If the caseFirst value is passed in through the options object, |
461 | // then we use it. Otherwise, we check if the caseFirst value is |
462 | // passed in through the unicode extensions. |
463 | if (case_first != CaseFirst::kUndefined) { |
464 | SetCaseFirstOption(icu_collator.get(), case_first); |
465 | } else { |
466 | auto kf_extension_it = r.extensions.find("kf"); |
467 | if (kf_extension_it != r.extensions.end()) { |
468 | SetCaseFirstOption(icu_collator.get(), |
469 | ToCaseFirst(kf_extension_it->second.c_str())); |
470 | } |
471 | } |
472 | |
473 | // Normalization is always on, by the spec. We are free to optimize |
474 | // if the strings are already normalized (but we don't have a way to tell |
475 | // that right now). |
476 | status = U_ZERO_ERROR; |
477 | icu_collator->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status); |
478 | DCHECK(U_SUCCESS(status))((void) 0); |
479 | |
480 | // 24. Let sensitivity be ? GetOption(options, "sensitivity", |
481 | // "string", « "base", "accent", "case", "variant" », undefined). |
482 | Maybe<Sensitivity> maybe_sensitivity = |
483 | GetStringOption<Sensitivity>(isolate, options, "sensitivity", service, |
484 | {"base", "accent", "case", "variant"}, |
485 | {Sensitivity::kBase, Sensitivity::kAccent, |
486 | Sensitivity::kCase, Sensitivity::kVariant}, |
487 | Sensitivity::kUndefined); |
488 | MAYBE_RETURN(maybe_sensitivity, MaybeHandle<JSCollator>())do { if ((maybe_sensitivity).IsNothing()) return MaybeHandle< JSCollator>(); } while (false); |
489 | Sensitivity sensitivity = maybe_sensitivity.FromJust(); |
490 | |
491 | // 25. If sensitivity is undefined, then |
492 | if (sensitivity == Sensitivity::kUndefined) { |
493 | // 25. a. If usage is "sort", then |
494 | if (usage == Usage::SORT) { |
495 | // 25. a. i. Let sensitivity be "variant". |
496 | sensitivity = Sensitivity::kVariant; |
497 | } |
498 | } |
499 | // 26. Set collator.[[Sensitivity]] to sensitivity. |
500 | switch (sensitivity) { |
501 | case Sensitivity::kBase: |
502 | icu_collator->setStrength(icu::Collator::PRIMARY); |
503 | break; |
504 | case Sensitivity::kAccent: |
505 | icu_collator->setStrength(icu::Collator::SECONDARY); |
506 | break; |
507 | case Sensitivity::kCase: |
508 | icu_collator->setStrength(icu::Collator::PRIMARY); |
509 | status = U_ZERO_ERROR; |
510 | icu_collator->setAttribute(UCOL_CASE_LEVEL, UCOL_ON, status); |
511 | DCHECK(U_SUCCESS(status))((void) 0); |
512 | break; |
513 | case Sensitivity::kVariant: |
514 | icu_collator->setStrength(icu::Collator::TERTIARY); |
515 | break; |
516 | case Sensitivity::kUndefined: |
517 | break; |
518 | } |
519 | |
520 | // 27.Let ignorePunctuation be ? GetOption(options, |
521 | // "ignorePunctuation", "boolean", undefined, false). |
522 | bool ignore_punctuation; |
523 | Maybe<bool> found_ignore_punctuation = GetBoolOption( |
524 | isolate, options, "ignorePunctuation", service, &ignore_punctuation); |
525 | MAYBE_RETURN(found_ignore_punctuation, MaybeHandle<JSCollator>())do { if ((found_ignore_punctuation).IsNothing()) return MaybeHandle <JSCollator>(); } while (false); |
526 | |
527 | // 28. Set collator.[[IgnorePunctuation]] to ignorePunctuation. |
528 | if (found_ignore_punctuation.FromJust() && ignore_punctuation) { |
529 | status = U_ZERO_ERROR; |
530 | icu_collator->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, status); |
531 | DCHECK(U_SUCCESS(status))((void) 0); |
532 | } |
533 | |
534 | Handle<Managed<icu::Collator>> managed_collator = |
535 | Managed<icu::Collator>::FromUniquePtr(isolate, 0, |
536 | std::move(icu_collator)); |
537 | |
538 | // We only need to do so if it is different from the collator would return. |
539 | Handle<String> locale_str = isolate->factory()->NewStringFromAsciiChecked( |
540 | (collator_locale != icu_locale) ? r.locale.c_str() : ""); |
541 | // Now all properties are ready, so we can allocate the result object. |
542 | Handle<JSCollator> collator = Handle<JSCollator>::cast( |
543 | isolate->factory()->NewFastOrSlowJSObjectFromMap(map)); |
544 | DisallowGarbageCollection no_gc; |
545 | collator->set_icu_collator(*managed_collator); |
546 | collator->set_locale(*locale_str); |
547 | |
548 | // 29. Return collator. |
549 | return collator; |
550 | } |
551 | |
552 | namespace { |
553 | |
554 | class CollatorAvailableLocales { |
555 | public: |
556 | CollatorAvailableLocales() { |
557 | int32_t num_locales = 0; |
558 | const icu::Locale* icu_available_locales = |
559 | icu::Collator::getAvailableLocales(num_locales); |
560 | std::vector<std::string> locales; |
561 | for (int32_t i = 0; i < num_locales; ++i) { |
562 | locales.push_back( |
563 | Intl::ToLanguageTag(icu_available_locales[i]).FromJust()); |
564 | } |
565 | #define U_ICUDATA_COLL U_ICUDATA_NAME"icudt" "71" "l" U_TREE_SEPARATOR_STRING"-" "coll" |
566 | set_ = Intl::BuildLocaleSet(locales, U_ICUDATA_COLL, nullptr); |
567 | #undef U_ICUDATA_COLL |
568 | } |
569 | virtual ~CollatorAvailableLocales() = default; |
570 | const std::set<std::string>& Get() const { return set_; } |
571 | |
572 | private: |
573 | std::set<std::string> set_; |
574 | }; |
575 | |
576 | } // namespace |
577 | |
578 | const std::set<std::string>& JSCollator::GetAvailableLocales() { |
579 | static base::LazyInstance<CollatorAvailableLocales>::type available_locales = |
580 | LAZY_INSTANCE_INITIALIZER{ { 0 }, { {} } }; |
581 | return available_locales.Pointer()->Get(); |
582 | } |
583 | |
584 | } // namespace internal |
585 | } // namespace v8 |