Commit cd306d91 authored by Michael Hablich's avatar Michael Hablich Committed by Commit Bot

Revert "Implement ResolveLocale in C++."

This reverts commit 1a225459.

Reason for revert: Makes GC stress unhappy: https://ci.chromium.org/p/v8/builders/luci.v8.ci/V8%20Linux%20-%20gc%20stress/18325 and blocks the roll

Original change's description:
> Implement ResolveLocale in C++.
> 
> Bug: v8:8065, v8:5751
> Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng
> Change-Id: Id9dc16455d63b7c436126c21758d64fae0ec8de9
> Reviewed-on: https://chromium-review.googlesource.com/1211402
> Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org>
> Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#55925}

TBR=bstell@chromium.org,gsathya@chromium.org

# Not skipping CQ checks because original CL landed > 1 day ago.

Bug: v8:8065, v8:5751
Change-Id: I4d71adb31ffd5ab0d2ae42c0255d0a05edbaad29
Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng
Reviewed-on: https://chromium-review.googlesource.com/1226646Reviewed-by: 's avatarMichael Hablich <hablich@chromium.org>
Commit-Queue: Michael Hablich <hablich@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55932}
parent c8fd2870
......@@ -96,6 +96,7 @@ enum ContextLookupFlags {
V(REFERENCE_ERROR_FUNCTION_INDEX, JSFunction, reference_error_function) \
V(CACHED_OR_NEW_SERVICE_LOCALE_FUNCTION_INDEX, JSFunction, \
cached_or_new_service) \
V(RESOLVE_LOCALE_FUNCTION_INDEX, JSFunction, resolve_locale) \
V(SET_ADD_INDEX, JSFunction, set_add) \
V(SET_DELETE_INDEX, JSFunction, set_delete) \
V(SET_HAS_INDEX, JSFunction, set_has) \
......
......@@ -12,25 +12,6 @@
"use strict";
// TODO(gsathya): determine if kDefaultOptionsMissing can be removed?
// TODO(gsathya): determine if kValueOutOfRange can be removed?
// TODO(gsathya): determine if kWrongServiceType can be removed?
// TODO(gsathya): determine if kWrongValueType can be removed?
// TODO(gsathya): determine if %AvailableLocalesOf can be removed?
// TODO(gsathya): determine if %GetDefaultICULocale can be removed?
// TODO(gsathya): determine if %make_error can be removed?
// TODO(gsathya): determine if %make_range_error can be removed?
// TODO(gsathya): determine if %object_define_property can be removed?
// TODO(gsathya): determine if %regexp_internal_match can be removed?
// TODO(gsathya): determine if %RegExpInternalReplace can be removed?
// TODO(gsathya): determine if %StringLastIndexOf can be removed?
// TODO(gsathya): determine if HAS_OWN_PROPERTY can be removed?
// TODO(gsathya): determine if IS_NULL can be removed?
// TODO(gsathya): determine if TO_BOOLEAN can be removed?
// TODO(gsathya): determine if TO_STRING can be removed?
%CheckIsBootstrapping();
// -------------------------------------------------------------------
......@@ -64,6 +45,253 @@ utils.Import(function(from) {
// -------------------------------------------------------------------
/**
* Caches available locales for each service.
*/
var AVAILABLE_LOCALES = {
__proto__ : null,
'collator': UNDEFINED,
'numberformat': UNDEFINED,
'dateformat': UNDEFINED,
'breakiterator': UNDEFINED,
'pluralrules': UNDEFINED,
'relativetimeformat': UNDEFINED,
'listformat': UNDEFINED,
};
/**
* Unicode extension regular expression.
*/
var UNICODE_EXTENSION_RE = UNDEFINED;
function GetUnicodeExtensionRE() {
if (IS_UNDEFINED(UNDEFINED)) {
UNICODE_EXTENSION_RE = new GlobalRegExp('-u(-[a-z0-9]{2,8})+', 'g');
}
return UNICODE_EXTENSION_RE;
}
/**
* Matches any Unicode extension.
*/
var ANY_EXTENSION_RE = UNDEFINED;
function GetAnyExtensionRE() {
if (IS_UNDEFINED(ANY_EXTENSION_RE)) {
ANY_EXTENSION_RE = new GlobalRegExp('-[a-z0-9]{1}-.*', 'g');
}
return ANY_EXTENSION_RE;
}
/**
* Matches valid service name.
*/
var SERVICE_RE = UNDEFINED;
function GetServiceRE() {
if (IS_UNDEFINED(SERVICE_RE)) {
SERVICE_RE =
new GlobalRegExp('^(' + %_Call(ArrayJoin, ObjectKeys(AVAILABLE_LOCALES), '|') + ')$');
}
return SERVICE_RE;
}
/**
* Returns a getOption function that extracts property value for given
* options object. If property is missing it returns defaultValue. If value
* is out of range for that property it throws RangeError.
*/
function getGetOption(options, caller) {
if (IS_UNDEFINED(options)) throw %make_error(kDefaultOptionsMissing, caller);
// Ecma 402 #sec-getoption
var getOption = function (property, type, values, fallback) {
// 1. Let value be ? Get(options, property).
var value = options[property];
// 2. If value is not undefined, then
if (!IS_UNDEFINED(value)) {
switch (type) {
// If type is "boolean", then let value be ToBoolean(value).
case 'boolean':
value = TO_BOOLEAN(value);
break;
// If type is "string", then let value be ToString(value).
case 'string':
value = TO_STRING(value);
break;
// Assert: type is "boolean" or "string".
default:
throw %make_error(kWrongValueType);
}
// d. If values is not undefined, then
// If values does not contain an element equal to value, throw a
// RangeError exception.
if (!IS_UNDEFINED(values) && %ArrayIndexOf(values, value, 0) === -1) {
throw %make_range_error(kValueOutOfRange, value, caller, property);
}
return value;
}
return fallback;
}
return getOption;
}
/**
* Ecma 402 9.2.5
* TODO(jshin): relevantExtensionKeys and localeData need to be taken into
* account per spec.
* Compares a BCP 47 language priority list requestedLocales against the locales
* in availableLocales and determines the best available language to meet the
* request. Two algorithms are available to match the locales: the Lookup
* algorithm described in RFC 4647 section 3.4, and an implementation dependent
* best-fit algorithm. Independent of the locale matching algorithm, options
* specified through Unicode locale extension sequences are negotiated
* separately, taking the caller's relevant extension keys and locale data as
* well as client-provided options into consideration. Returns an object with
* a locale property whose value is the language tag of the selected locale,
* and properties for each key in relevantExtensionKeys providing the selected
* value for that key.
*/
function resolveLocale(service, requestedLocales, options) {
requestedLocales = initializeLocaleList(requestedLocales);
var getOption = getGetOption(options, service);
var matcher = getOption('localeMatcher', 'string',
['lookup', 'best fit'], 'best fit');
var resolved;
if (matcher === 'lookup') {
resolved = lookupMatcher(service, requestedLocales);
} else {
resolved = bestFitMatcher(service, requestedLocales);
}
return resolved;
}
%InstallToContext([
"resolve_locale", resolveLocale
]);
/**
* Look up the longest non-empty prefix of |locale| that is an element of
* |availableLocales|. Returns undefined when the |locale| is completely
* unsupported by |availableLocales|.
*/
function bestAvailableLocale(availableLocales, locale) {
do {
if (!IS_UNDEFINED(availableLocales[locale])) {
return locale;
}
// Truncate locale if possible.
var pos = %StringLastIndexOf(locale, '-');
if (pos === -1) {
break;
}
locale = %_Call(StringSubstring, locale, 0, pos);
} while (true);
return UNDEFINED;
}
/**
* Try to match any mutation of |requestedLocale| against |availableLocales|.
*/
function attemptSingleLookup(availableLocales, requestedLocale) {
// Remove all extensions.
var noExtensionsLocale = %RegExpInternalReplace(
GetAnyExtensionRE(), requestedLocale, '');
var availableLocale = bestAvailableLocale(
availableLocales, requestedLocale);
if (!IS_UNDEFINED(availableLocale)) {
// Return the resolved locale and extension.
var extensionMatch = %regexp_internal_match(
GetUnicodeExtensionRE(), requestedLocale);
var extension = IS_NULL(extensionMatch) ? '' : extensionMatch[0];
return {
__proto__: null,
locale: availableLocale,
extension: extension,
localeWithExtension: availableLocale + extension,
};
}
return UNDEFINED;
}
/**
* Returns best matched supported locale and extension info using basic
* lookup algorithm.
*/
function lookupMatcher(service, requestedLocales) {
if (IS_NULL(%regexp_internal_match(GetServiceRE(), service))) {
throw %make_error(kWrongServiceType, service);
}
var availableLocales = getAvailableLocalesOf(service);
for (var i = 0; i < requestedLocales.length; ++i) {
var result = attemptSingleLookup(availableLocales, requestedLocales[i]);
if (!IS_UNDEFINED(result)) {
return result;
}
}
var defLocale = %GetDefaultICULocale();
// While ECMA-402 returns defLocale directly, we have to check if it is
// supported, as such support is not guaranteed.
var result = attemptSingleLookup(availableLocales, defLocale);
if (!IS_UNDEFINED(result)) {
return result;
}
// Didn't find a match, return default.
return {
__proto__: null,
locale: 'und',
extension: '',
localeWithExtension: 'und',
};
}
/**
* Returns best matched supported locale and extension info using
* implementation dependend algorithm.
*/
function bestFitMatcher(service, requestedLocales) {
// TODO(cira): implement better best fit algorithm.
return lookupMatcher(service, requestedLocales);
}
/**
* Given an array-like, outputs an Array with the numbered
* properties copied over and defined
* configurable: false, writable: false, enumerable: true.
* When |expandable| is true, the result array can be expanded.
*/
function freezeArray(input) {
var array = [];
var l = input.length;
for (var i = 0; i < l; i++) {
if (i in input) {
%object_define_property(array, i, {value: input[i],
configurable: false,
writable: false,
enumerable: true});
}
}
%object_define_property(array, 'length', {value: l, writable: false});
return array;
}
/* Make JS array[] out of InternalArray */
function makeArray(input) {
var array = [];
......@@ -71,6 +299,37 @@ function makeArray(input) {
return array;
}
/**
* Returns an Object that contains all of supported locales for a given
* service.
* In addition to the supported locales we add xx-ZZ locale for each xx-Yyyy-ZZ
* that is supported. This is required by the spec.
*/
function getAvailableLocalesOf(service) {
// Cache these, they don't ever change per service.
if (!IS_UNDEFINED(AVAILABLE_LOCALES[service])) {
return AVAILABLE_LOCALES[service];
}
var available = %AvailableLocalesOf(service);
for (var i in available) {
if (HAS_OWN_PROPERTY(available, i)) {
var parts = %regexp_internal_match(
/^([a-z]{2,3})-([A-Z][a-z]{3})-([A-Z]{2})$/, i);
if (!IS_NULL(parts)) {
// Build xx-ZZ. We don't care about the actual value,
// as long it's not undefined.
available[parts[1] + '-' + parts[3]] = null;
}
}
}
AVAILABLE_LOCALES[service] = available;
return available;
}
/**
* Returns an InternalArray where all locales are canonicalized and duplicates
* removed.
......@@ -113,6 +372,10 @@ function canonicalizeLocaleList(locales) {
]);
function initializeLocaleList(locales) {
return freezeArray(canonicalizeLocaleList(locales));
}
// ECMA 402 section 8.2.1
DEFINE_METHOD(
GlobalIntl,
......
......@@ -492,6 +492,26 @@ icu::RegexMatcher* GetLanguageVariantRegexMatcher(Isolate* isolate) {
} // anonymous namespace
MaybeHandle<JSObject> Intl::ResolveLocale(Isolate* isolate, const char* service,
Handle<Object> requestedLocales,
Handle<Object> options) {
Handle<String> service_str =
isolate->factory()->NewStringFromAsciiChecked(service);
Handle<JSFunction> resolve_locale_function = isolate->resolve_locale();
Handle<Object> result;
Handle<Object> undefined_value = isolate->factory()->undefined_value();
Handle<Object> args[] = {service_str, requestedLocales, options};
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result,
Execution::Call(isolate, resolve_locale_function, undefined_value,
arraysize(args), args),
JSObject);
return Handle<JSObject>::cast(result);
}
MaybeHandle<JSObject> Intl::CanonicalizeLocaleListJS(Isolate* isolate,
Handle<Object> locales) {
Handle<JSFunction> canonicalize_locale_list_function =
......@@ -1186,18 +1206,6 @@ std::string BestAvailableLocale(std::set<std::string> available_locales,
} while (true);
}
#define UNICODE_EXTENSION_REGEXP "-u(-[a-z0-9]{2,8})+"
std::unique_ptr<icu::RegexMatcher> GetUnicodeExtensionRegexpMatcher() {
UErrorCode status = U_ZERO_ERROR;
std::unique_ptr<icu::RegexMatcher> matcher(new icu::RegexMatcher(
icu::UnicodeString(UNICODE_EXTENSION_REGEXP, -1, US_INV), 0, status));
DCHECK(U_SUCCESS(status));
return matcher;
}
#undef UNICODE_EXTENSION_REGEXP
#define ANY_EXTENSION_REGEXP "-[a-z0-9]{1}-.*"
std::unique_ptr<icu::RegexMatcher> GetAnyExtensionRegexpMatcher() {
......@@ -1275,104 +1283,6 @@ std::vector<std::string> BestFitSupportedLocales(
enum MatcherOption { kBestFit, kLookup };
// ECMA 9.2.3 LookupMatcher(availableLocales, requestedLocales)
// https://tc39.github.io/ecma402/#sec-lookupmatcher
Intl::ResolvedLocale* LookupMatcher(
Isolate* isolate, std::set<std::string> available_locales,
std::vector<std::string> requested_locales) {
std::unique_ptr<icu::RegexMatcher> matcher = GetAnyExtensionRegexpMatcher();
// 1. Let result be a new Record.
Intl::ResolvedLocale* r = new Intl::ResolvedLocale;
// 2. For each element locale of requestedLocales in List order, do
for (auto locale : requested_locales) {
// 2.a. Let noExtensionsLocale be the String value that is locale with all
// Unicode locale extension sequences removed.
icu::UnicodeString locale_uni(locale.c_str(), -1, US_INV);
// TODO(bstell): look at using uloc_forLanguageTag to convert the language
// tag to locale id
// TODO(bstell): look at using uloc_getBaseName to just get the name without
// all the keywords
matcher->reset(locale_uni);
UErrorCode status = U_ZERO_ERROR;
// TODO(bstell): need to determine if this is the correct behavior.
// This matches the JS implementation but might not match the spec.
// According to
// https://tc39.github.io/ecma402/#sec-unicode-locale-extension-sequences:
//
// This standard uses the term "Unicode locale extension sequence" for
// any substring of a language tag that is not part of a private use
// subtag sequence, starts with a separator "-" and the singleton "u",
// and includes the maximum sequence of following non-singleton subtags
// and their preceding "-" separators.
//
// According to the spec a locale "en-t-aaa-u-bbb-v-ccc-x-u-ddd", should
// remove only the "-u-bbb" part, and keep everything else, whereas this
// regexp matcher would leave only the "en".
icu::UnicodeString no_extensions_locale_uni =
matcher->replaceAll("", status);
DCHECK(U_SUCCESS(status));
std::string no_extensions_locale;
no_extensions_locale_uni.toUTF8String(no_extensions_locale);
// 2.b. Let availableLocale be BestAvailableLocale(availableLocales,
// noExtensionsLocale).
std::string available_locale =
BestAvailableLocale(available_locales, no_extensions_locale);
// 2.c If availableLocale is not undefined, then
if (!available_locale.empty()) {
// 2.c.i. Set result.[[locale]] to availableLocale.
r->locale = available_locale;
// 2.c.ii. If locale and noExtensionsLocale are not the same String value,
// then
if (locale.compare(no_extensions_locale) != 0) {
// 2.c.ii.1. Let extension be the String value consisting of the first
// substring of locale that is a Unicode locale extension
// sequence.
icu::UnicodeString locale_uni(locale.c_str(), -1, US_INV);
std::unique_ptr<icu::RegexMatcher> unicode_extension_matcher =
GetUnicodeExtensionRegexpMatcher();
unicode_extension_matcher->reset(locale_uni);
status = U_ZERO_ERROR;
bool found = unicode_extension_matcher->find(status);
DCHECK(U_SUCCESS(status));
if (found) {
icu::UnicodeString us_unicode_extension =
unicode_extension_matcher->group(status);
DCHECK(U_SUCCESS(status));
std::string unicode_extensions;
us_unicode_extension.toUTF8String(unicode_extensions);
// 2.c.ii.2. Set result.[[extension]] to extension.
r->unicode_extensions = unicode_extensions;
}
}
// 2.c.iii. Return result.
return r;
}
}
// 3. Let defLocale be DefaultLocale().
// 4. Set result.[[locale]] to defLocale.
r->locale = Intl::DefaultLocale(isolate);
// 5. Return result.
return r;
}
// ECMA 9.2.4 BestFitMatcher(availableLocales, requestedLocales)
// https://tc39.github.io/ecma402/#sec-bestfitmatcher
// Note: extensions are handled in the caller so only need to return a string.
Intl::ResolvedLocale* BestFitMatcher(
Isolate* isolate, std::set<std::string> available_locales,
std::vector<std::string> requested_locales) {
// TODO(cira): implement better best fit algorithm.
return LookupMatcher(isolate, available_locales, requested_locales);
}
// TODO(bstell): should this be moved somewhere where it is reusable?
// Implement steps 5, 6, 7 for ECMA 402 9.2.9 SupportedLocales
// https://tc39.github.io/ecma402/#sec-supportedlocales
......@@ -1476,126 +1386,6 @@ MaybeHandle<JSObject> SupportedLocales(
}
} // namespace
// 9.2.6 ResolveLocale
// https://tc39.github.io/ecma402/#sec-resolvelocale
// Please see https://bugs.chromium.org/p/v8/issues/detail?id=8065 for more
// information on the design of this routine.
Maybe<Intl::ResolvedLocale*> Intl::ResolveLocale(
Isolate* isolate, const char* service,
const std::set<std::string>& available_locales,
const std::vector<std::string>& requested_locales,
const std::set<std::string>& relevant_extension_keys,
Handle<JSReceiver> options) {
// (1) Call out to Intl::GetStringOption to get the matcher option.
MatcherOption matcher = kBestFit;
Handle<JSReceiver> options_obj;
std::unique_ptr<char[]> matcher_str = nullptr;
std::vector<const char*> matcher_values = {"lookup", "best fit"};
Maybe<bool> maybe_found_matcher = Intl::GetStringOption(
isolate, options, "localeMatcher", matcher_values, service, &matcher_str);
MAYBE_RETURN(maybe_found_matcher, Nothing<Intl::ResolvedLocale*>());
if (maybe_found_matcher.FromJust()) {
DCHECK_NOT_NULL(matcher_str.get());
if (strcmp(matcher_str.get(), "lookup") == 0) {
matcher = kLookup;
}
}
// (2) Call Intl::BestFitSupportedLocales or Intl::LookupSupportedLocales
// based on the matcher option to get a bcp47 locale.
ResolvedLocale* r;
if (matcher == kLookup) {
r = LookupMatcher(isolate, available_locales, requested_locales);
} else {
DCHECK_EQ(matcher, kBestFit);
r = BestFitMatcher(isolate, available_locales, requested_locales);
}
// (3) Create a icu::Locale using the bcp47 locale.
UErrorCode status = U_ZERO_ERROR;
char icu_result[ULOC_FULLNAME_CAPACITY];
int icu_length = 0;
// r->locale should be a canonicalized language tag, which
// means this shouldn't fail.
std::string locale_with_unicode_extensions =
r->locale + r->unicode_extensions;
uloc_forLanguageTag(locale_with_unicode_extensions.c_str(), icu_result,
ULOC_FULLNAME_CAPACITY, &icu_length, &status);
CHECK(U_SUCCESS(status));
CHECK_LT(0, icu_length);
icu::Locale icu_locale(icu_result);
if (icu_locale.isBogus()) {
FATAL("Failed to create ICU locale, are ICU data files missing?");
}
// (4) Delete the private use subtag using
// icu::Locale::setKeywordValue(..., NULL, ...) (where the value is NULL)
status = U_ZERO_ERROR;
const char* private_use_key = uloc_toLegacyKey("x");
CHECK_NOT_NULL(private_use_key);
const char* value = uloc_toLegacyType(private_use_key, "search");
CHECK_NOT_NULL(value);
icu_locale.setKeywordValue(private_use_key, NULL, status);
CHECK(U_SUCCESS(status));
// (5) Iterate over the extensions using icu::Locale::createKeywords
std::unique_ptr<icu::StringEnumeration> keywords(
icu_locale.createKeywords(status));
if (U_SUCCESS(status) && keywords) {
char value[ULOC_FULLNAME_CAPACITY];
int32_t length;
status = U_ZERO_ERROR;
for (const char* keyword = keywords->next(&length, status);
keyword != nullptr; keyword = keywords->next(&length, status)) {
// Ignore failures in ICU and skip to the next keyword.
//
// This is fine.™
if (U_FAILURE(status)) {
status = U_ZERO_ERROR;
continue;
}
icu_locale.getKeywordValue(keyword, value, ULOC_FULLNAME_CAPACITY,
status);
// Ignore failures in ICU and skip to the next keyword.
//
// This is fine.™
if (U_FAILURE(status)) {
status = U_ZERO_ERROR;
continue;
}
const char* bcp47_key = uloc_toUnicodeLocaleKey(keyword);
// (6) Store the value for the extension if the extension is present in
// the relevant_extension_keys
if (bcp47_key && (relevant_extension_keys.find(bcp47_key) !=
relevant_extension_keys.end())) {
std::string bcp47_value = uloc_toUnicodeLocaleType(bcp47_key, value);
r->extensions.insert(
std::pair<std::string, std::string>(bcp47_key, bcp47_value));
}
}
}
// (7) Return the std::map of extension value pairs and the locale.
// The concatenated version is also returned since this is what the callers
// (currently) expect.
if (r->extensions.size()) {
r->locale_with_extensions = r->locale + "-u";
for (auto extension : r->extensions) {
r->locale_with_extensions +=
"-" + extension.first + "-" + extension.second;
}
} else {
r->locale_with_extensions = r->locale;
}
return Just(r);
}
// ECMA 402 Intl.*.supportedLocalesOf
// https://tc39.github.io/ecma402/#sec-intl.collator.supportedlocalesof
// https://tc39.github.io/ecma402/#sec-intl.numberformat.supportedlocalesof
......
......@@ -89,13 +89,6 @@ class Intl {
static bool RemoveLocaleScriptTag(const std::string& icu_locale,
std::string* locale_less_script);
struct ResolvedLocale {
std::string locale; // The bcp47 locale to use.
std::string unicode_extensions;
std::map<std::string, std::string> extensions;
std::string locale_with_extensions;
};
// The ResolveLocale abstract operation compares a BCP 47 language
// priority list requestedLocales against the locales in
// availableLocales and determines the best available language to
......@@ -105,15 +98,14 @@ class Intl {
//
// #ecma402/sec-partitiondatetimepattern
//
// Returns an object with two properties:
// Returns a JSObject with two properties:
// (1) locale
// (2) extension
V8_WARN_UNUSED_RESULT static Maybe<ResolvedLocale*> ResolveLocale(
Isolate* isolate, const char* service,
const std::set<std::string>& available_locales,
const std::vector<std::string>& requested_locales,
const std::set<std::string>& relevant_extension_keys,
Handle<JSReceiver> options);
//
// To access either, use JSObject::GetDataProperty.
V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> ResolveLocale(
Isolate* isolate, const char* service, Handle<Object> requestedLocales,
Handle<Object> options);
// This currently calls out to the JavaScript implementation of
// CanonicalizeLocaleList.
......
......@@ -28,9 +28,6 @@ MaybeHandle<JSV8BreakIterator> JSV8BreakIterator::InitializeV8BreakIterator(
Isolate* isolate, Handle<JSV8BreakIterator> break_iterator_holder,
Handle<Object> locales, Handle<Object> options_obj) {
Factory* factory = isolate->factory();
Maybe<std::vector<std::string>> requested_locales =
Intl::CanonicalizeLocaleList(isolate, locales, false);
MAYBE_RETURN(requested_locales, MaybeHandle<JSV8BreakIterator>());
Handle<JSReceiver> options;
if (options_obj->IsUndefined(isolate)) {
......@@ -43,18 +40,15 @@ MaybeHandle<JSV8BreakIterator> JSV8BreakIterator::InitializeV8BreakIterator(
}
// Extract locale string
const std::set<std::string> relevant_extension_keys;
std::set<std::string> available_locales =
Intl::GetAvailableLocales(IcuService::kListFormatter);
Maybe<Intl::ResolvedLocale*> maybe_resolved_locale = Intl::ResolveLocale(
isolate, "breakiterator", available_locales, requested_locales.FromJust(),
relevant_extension_keys, options);
MAYBE_RETURN(maybe_resolved_locale, MaybeHandle<JSV8BreakIterator>());
std::unique_ptr<Intl::ResolvedLocale> r(maybe_resolved_locale.FromJust());
CHECK_NOT_NULL(r.get());
Handle<String> locale =
isolate->factory()->NewStringFromAsciiChecked(r.get()->locale.c_str());
Handle<JSObject> r;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, r,
Intl::ResolveLocale(isolate, "breakiterator", locales, options),
JSV8BreakIterator);
Handle<Object> locale_obj =
JSObject::GetDataProperty(r, factory->locale_string());
CHECK(locale_obj->IsString());
Handle<String> locale = Handle<String>::cast(locale_obj);
// Extract type from options
std::unique_ptr<char[]> type_str = nullptr;
......
......@@ -221,9 +221,10 @@ MaybeHandle<JSCollator> JSCollator::InitializeCollator(
Isolate* isolate, Handle<JSCollator> collator, Handle<Object> locales,
Handle<Object> options_obj) {
// 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
Maybe<std::vector<std::string>> requested_locales =
Intl::CanonicalizeLocaleList(isolate, locales, false);
MAYBE_RETURN(requested_locales, MaybeHandle<JSCollator>());
Handle<JSObject> requested_locales;
ASSIGN_RETURN_ON_EXCEPTION(isolate, requested_locales,
Intl::CanonicalizeLocaleListJS(isolate, locales),
JSCollator);
// 2. If options is undefined, then
if (options_obj->IsUndefined(isolate)) {
......@@ -256,7 +257,10 @@ MaybeHandle<JSCollator> JSCollator::InitializeCollator(
}
}
// Steps 9 and 10 are done as part of the Intl::ResolveLocale call below.
// TODO(gsathya): This is currently done as part of the
// Intl::ResolveLocale call below. Fix this once resolveLocale is
// changed to not do the lookup.
//
// 9. Let matcher be ? GetOption(options, "localeMatcher", "string",
// « "lookup", "best fit" », "best fit").
// 10. Set opt.[[localeMatcher]] to matcher.
......@@ -312,20 +316,25 @@ MaybeHandle<JSCollator> JSCollator::InitializeCollator(
// requestedLocales, opt, %Collator%.[[RelevantExtensionKeys]],
// localeData).
// 18. Set collator.[[Locale]] to r.[[locale]].
std::set<std::string> available_locales =
Intl::GetAvailableLocales(IcuService::kCollator);
Maybe<Intl::ResolvedLocale*> maybe_resolved_locale = Intl::ResolveLocale(
isolate, "collator", available_locales, requested_locales.FromJust(),
relevant_extension_keys, options);
MAYBE_RETURN(maybe_resolved_locale, MaybeHandle<JSCollator>());
std::unique_ptr<Intl::ResolvedLocale> r(maybe_resolved_locale.FromJust());
CHECK_NOT_NULL(r.get());
std::string locale_with_extension = r.get()->locale_with_extensions;
Handle<String> locale = isolate->factory()->NewStringFromAsciiChecked(
locale_with_extension.c_str());
icu::Locale icu_locale = Intl::CreateICULocale(isolate, locale);
Handle<JSObject> r;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, r,
Intl::ResolveLocale(isolate, "collator", requested_locales, options),
JSCollator);
Handle<String> locale_with_extension_str =
isolate->factory()->NewStringFromStaticChars("localeWithExtension");
Handle<Object> locale_with_extension_obj =
JSObject::GetDataProperty(r, locale_with_extension_str);
// The locale_with_extension has to be a string. Either a user
// provided canonicalized string or the default locale.
CHECK(locale_with_extension_obj->IsString());
Handle<String> locale_with_extension =
Handle<String>::cast(locale_with_extension_obj);
icu::Locale icu_locale =
Intl::CreateICULocale(isolate, locale_with_extension);
DCHECK(!icu_locale.isBogus());
std::map<std::string, std::string> extensions =
......
......@@ -775,12 +775,7 @@ enum FormatMatcherOption { kBestFit, kBasic };
// ecma402/#sec-initializedatetimeformat
MaybeHandle<JSDateTimeFormat> JSDateTimeFormat::Initialize(
Isolate* isolate, Handle<JSDateTimeFormat> date_time_format,
Handle<Object> locales, Handle<Object> input_options) {
// 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
Maybe<std::vector<std::string>> requested_locales =
Intl::CanonicalizeLocaleList(isolate, locales, false);
MAYBE_RETURN(requested_locales, MaybeHandle<JSDateTimeFormat>());
Handle<Object> requested_locales, Handle<Object> input_options) {
// 2. Let options be ? ToDateTimeOptions(options, "any", "date").
Handle<JSObject> options;
ASSIGN_RETURN_ON_EXCEPTION(
......@@ -789,26 +784,29 @@ MaybeHandle<JSDateTimeFormat> JSDateTimeFormat::Initialize(
isolate, input_options, RequiredOption::kAny, DefaultsOption::kDate),
JSDateTimeFormat);
const std::set<std::string> relevant_extension_keys{"ca", "nu", "hc"};
// 11. Let r be ResolveLocale( %DateTimeFormat%.[[AvailableLocales]],
// requestedLocales, opt, %DateTimeFormat%.[[RelevantExtensionKeys]],
// localeData).
const char* kService = "Intl.DateTimeFormat";
std::set<std::string> available_locales =
Intl::GetAvailableLocales(IcuService::kRelativeDateTimeFormatter);
Maybe<Intl::ResolvedLocale*> maybe_resolved_locale = Intl::ResolveLocale(
isolate, "datetimeformat", available_locales,
requested_locales.FromJust(), relevant_extension_keys, options);
MAYBE_RETURN(maybe_resolved_locale, MaybeHandle<JSDateTimeFormat>());
std::unique_ptr<Intl::ResolvedLocale> r(maybe_resolved_locale.FromJust());
CHECK_NOT_NULL(r.get());
std::string locale_with_extension = r.get()->locale_with_extensions;
Handle<String> locale = isolate->factory()->NewStringFromAsciiChecked(
locale_with_extension.c_str());
icu::Locale icu_locale = Intl::CreateICULocale(isolate, locale);
Handle<JSObject> r;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, r,
Intl::ResolveLocale(isolate, "dateformat", requested_locales, options),
JSDateTimeFormat);
Handle<String> locale_with_extension_str =
isolate->factory()->NewStringFromStaticChars("localeWithExtension");
Handle<Object> locale_with_extension_obj =
JSObject::GetDataProperty(r, locale_with_extension_str);
// The locale_with_extension has to be a string. Either a user
// provided canonicalized string or the default locale.
CHECK(locale_with_extension_obj->IsString());
Handle<String> locale_with_extension =
Handle<String>::cast(locale_with_extension_obj);
icu::Locale icu_locale =
Intl::CreateICULocale(isolate, locale_with_extension);
DCHECK(!icu_locale.isBogus());
// We implement only best fit algorithm, but still need to check
......
......@@ -122,10 +122,7 @@ JSListFormat::Type get_type(const char* str) {
MaybeHandle<JSListFormat> JSListFormat::InitializeListFormat(
Isolate* isolate, Handle<JSListFormat> list_format_holder,
Handle<Object> input_locales, Handle<Object> input_options) {
Maybe<std::vector<std::string>> requested_locales =
Intl::CanonicalizeLocaleList(isolate, input_locales, false);
MAYBE_RETURN(requested_locales, MaybeHandle<JSListFormat>());
Factory* factory = isolate->factory();
list_format_holder->set_flags(0);
Handle<JSReceiver> options;
......@@ -173,23 +170,23 @@ MaybeHandle<JSListFormat> JSListFormat::InitializeListFormat(
// 10. Let r be ResolveLocale(%ListFormat%.[[AvailableLocales]],
// requestedLocales, opt, undefined, localeData).
const std::set<std::string> relevant_extension_keys;
std::set<std::string> available_locales =
Intl::GetAvailableLocales(IcuService::kListFormatter);
Maybe<Intl::ResolvedLocale*> maybe_resolved_locale = Intl::ResolveLocale(
isolate, "listformatter", available_locales, requested_locales.FromJust(),
relevant_extension_keys, options);
MAYBE_RETURN(maybe_resolved_locale, MaybeHandle<JSListFormat>());
std::unique_ptr<Intl::ResolvedLocale> r(maybe_resolved_locale.FromJust());
CHECK_NOT_NULL(r.get());
Handle<String> locale =
isolate->factory()->NewStringFromAsciiChecked(r.get()->locale.c_str());
Handle<JSObject> r;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, r,
Intl::ResolveLocale(isolate, "listformat", input_locales, options),
JSListFormat);
Handle<Object> locale_obj =
JSObject::GetDataProperty(r, factory->locale_string());
Handle<String> locale;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, locale, Object::ToString(isolate, locale_obj), JSListFormat);
// 18. Set listFormat.[[Locale]] to the value of r.[[Locale]].
list_format_holder->set_locale(*locale);
icu::Locale icu_locale(r.get()->locale.c_str());
std::unique_ptr<char[]> locale_name = locale->ToCString();
icu::Locale icu_locale(locale_name.get());
UErrorCode status = U_ZERO_ERROR;
icu::ListFormatter* formatter = icu::ListFormatter::createInstance(
icu_locale, GetIcuStyleString(style_enum, type_enum), status);
......
......@@ -189,9 +189,10 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::Initialize(
number_format->set_flags(0);
Factory* factory = isolate->factory();
// 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
Maybe<std::vector<std::string>> requested_locales =
Intl::CanonicalizeLocaleList(isolate, locales, false);
MAYBE_RETURN(requested_locales, MaybeHandle<JSNumberFormat>());
Handle<JSObject> requested_locales;
ASSIGN_RETURN_ON_EXCEPTION(isolate, requested_locales,
Intl::CanonicalizeLocaleListJS(isolate, locales),
JSNumberFormat);
// 2. If options is undefined, then
if (options_obj->IsUndefined(isolate)) {
......@@ -211,8 +212,6 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::Initialize(
// 4. Let opt be a new Record.
//
// Steps 5 and 6 are currently done as part of the
// Intl::ResolveLocale call below.
// 5. Let matcher be ? GetOption(options, "localeMatcher", "string", «
// "lookup", "best fit" », "best fit").
//
......@@ -226,26 +225,29 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::Initialize(
//
// 9. Set numberFormat.[[Locale]] to r.[[locale]].
std::set<std::string> available_locales =
Intl::GetAvailableLocales(IcuService::kNumberFormat);
// 13.3.3 Internal slots
// https://tc39.github.io/ecma402/#sec-intl.numberformat-internal-slots
const std::set<std::string> relevant_extension_keys{"nu"};
Maybe<Intl::ResolvedLocale*> maybe_resolved_locale = Intl::ResolveLocale(
isolate, "numberformat", available_locales, requested_locales.FromJust(),
relevant_extension_keys, options);
MAYBE_RETURN(maybe_resolved_locale, MaybeHandle<JSNumberFormat>());
std::unique_ptr<Intl::ResolvedLocale> r(maybe_resolved_locale.FromJust());
CHECK_NOT_NULL(r.get());
std::string locale_with_extension = r.get()->locale_with_extensions;
Handle<String> locale = isolate->factory()->NewStringFromAsciiChecked(
locale_with_extension.c_str());
icu::Locale icu_locale = Intl::CreateICULocale(isolate, locale);
number_format->set_locale(*locale);
Handle<JSObject> r;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, r,
Intl::ResolveLocale(isolate, "numberformat", requested_locales, options),
JSNumberFormat);
Handle<String> locale_with_extension_str =
isolate->factory()->NewStringFromStaticChars("localeWithExtension");
Handle<Object> locale_with_extension_obj =
JSObject::GetDataProperty(r, locale_with_extension_str);
// The locale_with_extension has to be a string. Either a user
// provided canonicalized string or the default locale.
CHECK(locale_with_extension_obj->IsString());
Handle<String> locale_with_extension =
Handle<String>::cast(locale_with_extension_obj);
icu::Locale icu_locale =
Intl::CreateICULocale(isolate, locale_with_extension);
number_format->set_locale(*locale_with_extension);
DCHECK(!icu_locale.isBogus());
std::set<std::string> relevant_extension_keys{"nu"};
std::map<std::string, std::string> extensions =
Intl::LookupUnicodeExtensions(icu_locale, relevant_extension_keys);
......
......@@ -89,9 +89,12 @@ MaybeHandle<JSPluralRules> JSPluralRules::InitializePluralRules(
Isolate* isolate, Handle<JSPluralRules> plural_rules,
Handle<Object> locales, Handle<Object> options_obj) {
// 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
Maybe<std::vector<std::string>> requested_locales =
Intl::CanonicalizeLocaleList(isolate, locales, false);
MAYBE_RETURN(requested_locales, MaybeHandle<JSPluralRules>());
// TODO(jkummerow): Port ResolveLocale, then use the C++ version of
// CanonicalizeLocaleList here.
Handle<JSObject> requested_locales;
ASSIGN_RETURN_ON_EXCEPTION(isolate, requested_locales,
Intl::CanonicalizeLocaleListJS(isolate, locales),
JSPluralRules);
// 2. If options is undefined, then
if (options_obj->IsUndefined(isolate)) {
......@@ -109,8 +112,10 @@ MaybeHandle<JSPluralRules> JSPluralRules::InitializePluralRules(
// At this point, options_obj can either be a JSObject or a JSProxy only.
Handle<JSReceiver> options = Handle<JSReceiver>::cast(options_obj);
// Steps 5 and 6 are currently done as part of the
// Intl::ResolveLocale call below.
// TODO(gsathya): This is currently done as part of the
// Intl::ResolveLocale call below. Fix this once resolveLocale is
// changed to not do the lookup.
//
// 5. Let matcher be ? GetOption(options, "localeMatcher", "string",
// « "lookup", "best fit" », "best fit").
// 6. Set opt.[[localeMatcher]] to matcher.
......@@ -141,21 +146,19 @@ MaybeHandle<JSPluralRules> JSPluralRules::InitializePluralRules(
// 11. Let r be ResolveLocale(%PluralRules%.[[AvailableLocales]],
// requestedLocales, opt, %PluralRules%.[[RelevantExtensionKeys]],
// localeData).
std::set<std::string> available_locales =
Intl::GetAvailableLocales(IcuService::kPluralRules);
// 13.3.3 Internal slots
// https://tc39.github.io/ecma402/#sec-intl.pluralrules-internal-slots
// The value of the [[RelevantExtensionKeys]] internal slot is [].
const std::set<std::string> relevant_extension_keys;
Maybe<Intl::ResolvedLocale*> maybe_resolved_locale = Intl::ResolveLocale(
isolate, "pluralrules", available_locales, requested_locales.FromJust(),
relevant_extension_keys, options);
MAYBE_RETURN(maybe_resolved_locale, MaybeHandle<JSPluralRules>());
std::unique_ptr<Intl::ResolvedLocale> r(maybe_resolved_locale.FromJust());
CHECK_NOT_NULL(r.get());
Handle<String> locale =
isolate->factory()->NewStringFromAsciiChecked(r.get()->locale.c_str());
Handle<JSObject> r;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, r,
Intl::ResolveLocale(isolate, "pluralrules", requested_locales, options),
JSPluralRules);
Handle<String> locale_str = isolate->factory()->locale_string();
Handle<Object> locale_obj = JSObject::GetDataProperty(r, locale_str);
// The locale has to be a string. Either a user provided
// canonicalized string or the default locale.
CHECK(locale_obj->IsString());
Handle<String> locale = Handle<String>::cast(locale_obj);
// 12. Set pluralRules.[[Locale]] to the value of r.[[locale]].
plural_rules->set_locale(*locale);
......
......@@ -59,10 +59,7 @@ MaybeHandle<JSRelativeTimeFormat>
JSRelativeTimeFormat::InitializeRelativeTimeFormat(
Isolate* isolate, Handle<JSRelativeTimeFormat> relative_time_format_holder,
Handle<Object> input_locales, Handle<Object> input_options) {
Maybe<std::vector<std::string>> requested_locales =
Intl::CanonicalizeLocaleList(isolate, input_locales, false);
MAYBE_RETURN(requested_locales, MaybeHandle<JSRelativeTimeFormat>());
Factory* factory = isolate->factory();
relative_time_format_holder->set_flags(0);
// 4. If options is undefined, then
Handle<JSReceiver> options;
......@@ -81,20 +78,17 @@ JSRelativeTimeFormat::InitializeRelativeTimeFormat(
// requestedLocales, opt,
// %RelativeTimeFormat%.[[RelevantExtensionKeys]],
// localeData).
std::set<std::string> available_locales =
Intl::GetAvailableLocales(IcuService::kRelativeDateTimeFormatter);
// 13.3.3 Internal slots
// The value of the [[RelevantExtensionKeys]] internal slot is [].
const std::set<std::string> relevant_extension_keys;
Maybe<Intl::ResolvedLocale*> maybe_resolved_locale = Intl::ResolveLocale(
isolate, "relativetimeformat", available_locales,
requested_locales.FromJust(), relevant_extension_keys, options);
MAYBE_RETURN(maybe_resolved_locale, MaybeHandle<JSRelativeTimeFormat>());
std::unique_ptr<Intl::ResolvedLocale> r(maybe_resolved_locale.FromJust());
CHECK_NOT_NULL(r.get());
Handle<String> locale =
isolate->factory()->NewStringFromAsciiChecked(r.get()->locale.c_str());
Handle<JSObject> r;
ASSIGN_RETURN_ON_EXCEPTION(isolate, r,
Intl::ResolveLocale(isolate, "relativetimeformat",
input_locales, options),
JSRelativeTimeFormat);
Handle<Object> locale_obj =
JSObject::GetDataProperty(r, factory->locale_string());
Handle<String> locale;
ASSIGN_RETURN_ON_EXCEPTION(isolate, locale,
Object::ToString(isolate, locale_obj),
JSRelativeTimeFormat);
// 11. Let locale be r.[[Locale]].
// 12. Set relativeTimeFormat.[[Locale]] to locale.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment