diff options
Diffstat (limited to 'deps/v8/src/objects/js-locale.cc')
-rw-r--r-- | deps/v8/src/objects/js-locale.cc | 215 |
1 files changed, 70 insertions, 145 deletions
diff --git a/deps/v8/src/objects/js-locale.cc b/deps/v8/src/objects/js-locale.cc index 4e35c16b0f..509f9a3069 100644 --- a/deps/v8/src/objects/js-locale.cc +++ b/deps/v8/src/objects/js-locale.cc @@ -13,14 +13,15 @@ #include <string> #include <vector> -#include "src/api.h" -#include "src/global-handles.h" +#include "src/api/api.h" +#include "src/execution/isolate.h" +#include "src/handles/global-handles.h" #include "src/heap/factory.h" -#include "src/isolate.h" -#include "src/objects-inl.h" #include "src/objects/intl-objects.h" #include "src/objects/js-locale-inl.h" +#include "src/objects/objects-inl.h" #include "unicode/char16ptr.h" +#include "unicode/localebuilder.h" #include "unicode/locid.h" #include "unicode/uloc.h" #include "unicode/unistr.h" @@ -30,21 +31,6 @@ namespace internal { namespace { -// Helper function to check a locale is valid. It will return false if -// the length of the extension fields are incorrect. For example, en-u-a or -// en-u-co-b will return false. -bool IsValidLocale(const icu::Locale& locale) { - // icu::Locale::toLanguageTag won't return U_STRING_NOT_TERMINATED_WARNING for - // incorrect locale yet. So we still need the following uloc_toLanguageTag - // TODO(ftang): Change to use icu::Locale::toLanguageTag once it indicate - // error. - char result[ULOC_FULLNAME_CAPACITY]; - UErrorCode status = U_ZERO_ERROR; - uloc_toLanguageTag(locale.getName(), result, ULOC_FULLNAME_CAPACITY, true, - &status); - return U_SUCCESS(status) && status != U_STRING_NOT_TERMINATED_WARNING; -} - struct OptionData { const char* name; const char* key; @@ -55,9 +41,8 @@ struct OptionData { // Inserts tags from options into locale string. Maybe<bool> InsertOptionsIntoLocale(Isolate* isolate, Handle<JSReceiver> options, - icu::Locale* icu_locale) { + icu::LocaleBuilder* builder) { CHECK(isolate); - CHECK(!icu_locale->isBogus()); const std::vector<const char*> hour_cycle_values = {"h11", "h12", "h23", "h24"}; @@ -75,7 +60,6 @@ Maybe<bool> InsertOptionsIntoLocale(Isolate* isolate, // TODO(cira): Pass in values as per the spec to make this to be // spec compliant. - UErrorCode status = U_ZERO_ERROR; for (const auto& option_to_bcp47 : kOptionToUnicodeTagMap) { std::unique_ptr<char[]> value_str = nullptr; bool value_bool = false; @@ -99,32 +83,18 @@ Maybe<bool> InsertOptionsIntoLocale(Isolate* isolate, DCHECK_NOT_NULL(value_str.get()); // Overwrite existing, or insert new key-value to the locale string. - if (uloc_toLegacyType(uloc_toLegacyKey(option_to_bcp47.key), - value_str.get())) { - // Only call setUnicodeKeywordValue if that value is a valid one. - icu_locale->setUnicodeKeywordValue(option_to_bcp47.key, value_str.get(), - status); - if (U_FAILURE(status)) { - return Just(false); - } - } else { + if (!uloc_toLegacyType(uloc_toLegacyKey(option_to_bcp47.key), + value_str.get())) { return Just(false); } + builder->setUnicodeLocaleKeyword(option_to_bcp47.key, value_str.get()); } - - // Check all the unicode extension fields are in the right length. - if (!IsValidLocale(*icu_locale)) { - THROW_NEW_ERROR_RETURN_VALUE( - isolate, NewRangeError(MessageTemplate::kLocaleBadParameters), - Nothing<bool>()); - } - return Just(true); } Handle<Object> UnicodeKeywordValue(Isolate* isolate, Handle<JSLocale> locale, const char* key) { - icu::Locale* icu_locale = locale->icu_locale()->raw(); + icu::Locale* icu_locale = locale->icu_locale().raw(); UErrorCode status = U_ZERO_ERROR; std::string value = icu_locale->getUnicodeKeywordValue<std::string>(key, status); @@ -237,32 +207,29 @@ bool StartsWithUnicodeLanguageId(const std::string& value) { return true; } -Maybe<std::string> ApplyOptionsToTag(Isolate* isolate, Handle<String> tag, - Handle<JSReceiver> options) { +Maybe<bool> ApplyOptionsToTag(Isolate* isolate, Handle<String> tag, + Handle<JSReceiver> options, + icu::LocaleBuilder* builder) { v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); if (tag->length() == 0) { THROW_NEW_ERROR_RETURN_VALUE( isolate, NewRangeError(MessageTemplate::kLocaleNotEmpty), - Nothing<std::string>()); + Nothing<bool>()); } v8::String::Utf8Value bcp47_tag(v8_isolate, v8::Utils::ToLocal(tag)); + builder->setLanguageTag({*bcp47_tag, bcp47_tag.length()}); CHECK_LT(0, bcp47_tag.length()); CHECK_NOT_NULL(*bcp47_tag); // 2. If IsStructurallyValidLanguageTag(tag) is false, throw a RangeError // exception. if (!StartsWithUnicodeLanguageId(*bcp47_tag)) { - THROW_NEW_ERROR_RETURN_VALUE( - isolate, NewRangeError(MessageTemplate::kLocaleBadParameters), - Nothing<std::string>()); + return Just(false); } UErrorCode status = U_ZERO_ERROR; - icu::Locale icu_locale = - icu::Locale::forLanguageTag({*bcp47_tag, bcp47_tag.length()}, status); + builder->build(status); if (U_FAILURE(status)) { - THROW_NEW_ERROR_RETURN_VALUE( - isolate, NewRangeError(MessageTemplate::kLocaleBadParameters), - Nothing<std::string>()); + return Just(false); } // 3. Let language be ? GetOption(options, "language", "string", undefined, @@ -272,15 +239,16 @@ Maybe<std::string> ApplyOptionsToTag(Isolate* isolate, Handle<String> tag, Maybe<bool> maybe_language = Intl::GetStringOption(isolate, options, "language", empty_values, "ApplyOptionsToTag", &language_str); - MAYBE_RETURN(maybe_language, Nothing<std::string>()); + MAYBE_RETURN(maybe_language, Nothing<bool>()); // 4. If language is not undefined, then if (maybe_language.FromJust()) { + builder->setLanguage(language_str.get()); + builder->build(status); // a. If language does not match the unicode_language_subtag production, // throw a RangeError exception. - if (!IsUnicodeLanguageSubtag(language_str.get())) { - THROW_NEW_ERROR_RETURN_VALUE( - isolate, NewRangeError(MessageTemplate::kLocaleBadParameters), - Nothing<std::string>()); + if (U_FAILURE(status) || language_str[0] == '\0' || + IsAlpha(language_str.get(), 4, 4)) { + return Just(false); } } // 5. Let script be ? GetOption(options, "script", "string", undefined, @@ -289,15 +257,15 @@ Maybe<std::string> ApplyOptionsToTag(Isolate* isolate, Handle<String> tag, Maybe<bool> maybe_script = Intl::GetStringOption(isolate, options, "script", empty_values, "ApplyOptionsToTag", &script_str); - MAYBE_RETURN(maybe_script, Nothing<std::string>()); + MAYBE_RETURN(maybe_script, Nothing<bool>()); // 6. If script is not undefined, then if (maybe_script.FromJust()) { + builder->setScript(script_str.get()); + builder->build(status); // a. If script does not match the unicode_script_subtag production, throw // a RangeError exception. - if (!IsUnicodeScriptSubtag(script_str.get())) { - THROW_NEW_ERROR_RETURN_VALUE( - isolate, NewRangeError(MessageTemplate::kLocaleBadParameters), - Nothing<std::string>()); + if (U_FAILURE(status) || script_str[0] == '\0') { + return Just(false); } } // 7. Let region be ? GetOption(options, "region", "string", undefined, @@ -306,85 +274,41 @@ Maybe<std::string> ApplyOptionsToTag(Isolate* isolate, Handle<String> tag, Maybe<bool> maybe_region = Intl::GetStringOption(isolate, options, "region", empty_values, "ApplyOptionsToTag", ®ion_str); - MAYBE_RETURN(maybe_region, Nothing<std::string>()); + MAYBE_RETURN(maybe_region, Nothing<bool>()); // 8. If region is not undefined, then if (maybe_region.FromJust()) { // a. If region does not match the region production, throw a RangeError // exception. - if (!IsUnicodeRegionSubtag(region_str.get())) { - THROW_NEW_ERROR_RETURN_VALUE( - isolate, NewRangeError(MessageTemplate::kLocaleBadParameters), - Nothing<std::string>()); + builder->setRegion(region_str.get()); + builder->build(status); + if (U_FAILURE(status) || region_str[0] == '\0') { + return Just(false); } } - // 9. Set tag to CanonicalizeLanguageTag(tag). - Maybe<std::string> maybe_canonicalized = - Intl::CanonicalizeLanguageTag(isolate, tag); - MAYBE_RETURN(maybe_canonicalized, Nothing<std::string>()); - - std::vector<std::string> tokens; - std::string token; - std::istringstream token_stream(maybe_canonicalized.FromJust()); - while (std::getline(token_stream, token, '-')) { - tokens.push_back(token); - } + // 9. Set tag to CanonicalizeLanguageTag(tag). // 10. If language is not undefined, - std::string locale_str; - if (maybe_language.FromJust()) { - // a. Assert: tag matches the unicode_locale_id production. - // b. Set tag to tag with the substring corresponding to the - // unicode_language_subtag production replaced by the string language. - tokens[0] = language_str.get(); - } - + // a. Assert: tag matches the unicode_locale_id production. + // b. Set tag to tag with the substring corresponding to the + // unicode_language_subtag production replaced by the string language. // 11. If script is not undefined, then - if (maybe_script.FromJust()) { - // a. If tag does not contain a unicode_script_subtag production, then - if (tokens.size() < 2 || !IsUnicodeScriptSubtag(tokens[1])) { - // i. Set tag to the concatenation of the unicode_language_subtag - // production of tag, "-", script, and the rest of tag. - tokens.insert(tokens.begin() + 1, script_str.get()); - // b. Else, - } else { - // i. Set tag to tag with the substring corresponding to the - // unicode_script_subtag production replaced by the string script. - tokens[1] = script_str.get(); - } - } + // a. If tag does not contain a unicode_script_subtag production, then + // i. Set tag to the concatenation of the unicode_language_subtag + // production of tag, "-", script, and the rest of tag. + // b. Else, + // i. Set tag to tag with the substring corresponding to the + // unicode_script_subtag production replaced by the string script. // 12. If region is not undefined, then - if (maybe_region.FromJust()) { - // a. If tag does not contain a unicode_region_subtag production, then - // i. Set tag to the concatenation of the unicode_language_subtag - // production of tag, the substring corresponding to the "-" - // unicode_script_subtag production if present, "-", region, and - // the rest of tag. - // b. Else, - // i. Set tag to tag with the substring corresponding to the - // unicode_region_subtag production replaced by the string region. - if (tokens.size() > 1 && IsUnicodeRegionSubtag(tokens[1])) { - tokens[1] = region_str.get(); - } else if (tokens.size() > 1 && IsUnicodeScriptSubtag(tokens[1])) { - if (tokens.size() > 2 && IsUnicodeRegionSubtag(tokens[2])) { - tokens[2] = region_str.get(); - } else { - tokens.insert(tokens.begin() + 2, region_str.get()); - } - } else { - tokens.insert(tokens.begin() + 1, region_str.get()); - } - } - - std::string replaced; - for (auto it = tokens.begin(); it != tokens.end(); it++) { - replaced += *it; - if (it + 1 != tokens.end()) { - replaced += '-'; - } - } - + // a. If tag does not contain a unicode_region_subtag production, then + // i. Set tag to the concatenation of the unicode_language_subtag + // production of tag, the substring corresponding to the "-" + // unicode_script_subtag production if present, "-", region, and + // the rest of tag. + // b. Else, + // i. Set tag to tag with the substring corresponding to the + // unicode_region_subtag production replaced by the string region. // 13. Return CanonicalizeLanguageTag(tag). - return Intl::CanonicalizeLanguageTag(isolate, replaced); + return Just(true); } } // namespace @@ -393,21 +317,22 @@ MaybeHandle<JSLocale> JSLocale::Initialize(Isolate* isolate, Handle<JSLocale> locale, Handle<String> locale_str, Handle<JSReceiver> options) { - Maybe<std::string> maybe_locale = - ApplyOptionsToTag(isolate, locale_str, options); - MAYBE_RETURN(maybe_locale, MaybeHandle<JSLocale>()); - UErrorCode status = U_ZERO_ERROR; - icu::Locale icu_locale = - icu::Locale::forLanguageTag(maybe_locale.FromJust().c_str(), status); - if (U_FAILURE(status)) { + icu::LocaleBuilder builder; + Maybe<bool> maybe_apply = + ApplyOptionsToTag(isolate, locale_str, options, &builder); + MAYBE_RETURN(maybe_apply, MaybeHandle<JSLocale>()); + if (!maybe_apply.FromJust()) { THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kLocaleBadParameters), JSLocale); } - Maybe<bool> error = InsertOptionsIntoLocale(isolate, options, &icu_locale); - MAYBE_RETURN(error, MaybeHandle<JSLocale>()); - if (!error.FromJust()) { + Maybe<bool> maybe_insert = + InsertOptionsIntoLocale(isolate, options, &builder); + MAYBE_RETURN(maybe_insert, MaybeHandle<JSLocale>()); + UErrorCode status = U_ZERO_ERROR; + icu::Locale icu_locale = builder.build(status); + if (!maybe_insert.FromJust() || U_FAILURE(status)) { THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kLocaleBadParameters), JSLocale); @@ -458,28 +383,28 @@ Handle<String> JSLocale::Minimize(Isolate* isolate, String locale) { Handle<Object> JSLocale::Language(Isolate* isolate, Handle<JSLocale> locale) { Factory* factory = isolate->factory(); - const char* language = locale->icu_locale()->raw()->getLanguage(); + const char* language = locale->icu_locale().raw()->getLanguage(); if (strlen(language) == 0) return factory->undefined_value(); return factory->NewStringFromAsciiChecked(language); } Handle<Object> JSLocale::Script(Isolate* isolate, Handle<JSLocale> locale) { Factory* factory = isolate->factory(); - const char* script = locale->icu_locale()->raw()->getScript(); + const char* script = locale->icu_locale().raw()->getScript(); if (strlen(script) == 0) return factory->undefined_value(); return factory->NewStringFromAsciiChecked(script); } Handle<Object> JSLocale::Region(Isolate* isolate, Handle<JSLocale> locale) { Factory* factory = isolate->factory(); - const char* region = locale->icu_locale()->raw()->getCountry(); + const char* region = locale->icu_locale().raw()->getCountry(); if (strlen(region) == 0) return factory->undefined_value(); return factory->NewStringFromAsciiChecked(region); } Handle<String> JSLocale::BaseName(Isolate* isolate, Handle<JSLocale> locale) { icu::Locale icu_locale = - icu::Locale::createFromName(locale->icu_locale()->raw()->getBaseName()); + icu::Locale::createFromName(locale->icu_locale().raw()->getBaseName()); std::string base_name = Intl::ToLanguageTag(icu_locale).FromJust(); return isolate->factory()->NewStringFromAsciiChecked(base_name.c_str()); } @@ -502,7 +427,7 @@ Handle<Object> JSLocale::HourCycle(Isolate* isolate, Handle<JSLocale> locale) { Handle<Object> JSLocale::Numeric(Isolate* isolate, Handle<JSLocale> locale) { Factory* factory = isolate->factory(); - icu::Locale* icu_locale = locale->icu_locale()->raw(); + icu::Locale* icu_locale = locale->icu_locale().raw(); UErrorCode status = U_ZERO_ERROR; std::string numeric = icu_locale->getUnicodeKeywordValue<std::string>("kn", status); @@ -515,7 +440,7 @@ Handle<Object> JSLocale::NumberingSystem(Isolate* isolate, } std::string JSLocale::ToString(Handle<JSLocale> locale) { - icu::Locale* icu_locale = locale->icu_locale()->raw(); + icu::Locale* icu_locale = locale->icu_locale().raw(); return Intl::ToLanguageTag(*icu_locale).FromJust(); } |