Commit 520f38fc authored by jshin's avatar jshin Committed by Commit bot

Expose getCanonicalLocales() for Intl object.

Also add a test for the return object of getCanonicalLocaleList().

See https://github.com/tc39/test262/issues/745 for more details.

BUG=v8:5012
TEST=test262/intl402/Intl/getCanonicalLocales/*
TEST=intl/general/getCanonicalLocales

Review-Url: https://codereview.chromium.org/2239523002
Cr-Commit-Position: refs/heads/master@{#38733}
parent 2d3a53c9
...@@ -587,6 +587,7 @@ function setOptions(inOptions, extensionMap, keyValues, getOption, outOptions) { ...@@ -587,6 +587,7 @@ function setOptions(inOptions, extensionMap, keyValues, getOption, outOptions) {
* Given an array-like, outputs an Array with the numbered * Given an array-like, outputs an Array with the numbered
* properties copied over and defined * properties copied over and defined
* configurable: false, writable: false, enumerable: true. * configurable: false, writable: false, enumerable: true.
* When |expandable| is true, the result array can be expanded.
*/ */
function freezeArray(input) { function freezeArray(input) {
var array = []; var array = [];
...@@ -604,6 +605,12 @@ function freezeArray(input) { ...@@ -604,6 +605,12 @@ function freezeArray(input) {
return array; return array;
} }
/* Make JS array[] out of InternalArray */
function makeArray(input) {
var array = [];
%MoveArrayContents(input, array);
return array;
}
/** /**
* It's sometimes desireable to leave user requested locale instead of ICU * It's sometimes desireable to leave user requested locale instead of ICU
...@@ -738,6 +745,7 @@ function toTitleCaseTimezoneLocation(location) { ...@@ -738,6 +745,7 @@ function toTitleCaseTimezoneLocation(location) {
/** /**
* Canonicalizes the language tag, or throws in case the tag is invalid. * Canonicalizes the language tag, or throws in case the tag is invalid.
* ECMA 402 9.2.1 steps 7.c ii ~ v.
*/ */
function canonicalizeLanguageTag(localeID) { function canonicalizeLanguageTag(localeID) {
// null is typeof 'object' so we have to do extra check. // null is typeof 'object' so we have to do extra check.
...@@ -755,11 +763,14 @@ function canonicalizeLanguageTag(localeID) { ...@@ -755,11 +763,14 @@ function canonicalizeLanguageTag(localeID) {
var localeString = TO_STRING(localeID); var localeString = TO_STRING(localeID);
if (isValidLanguageTag(localeString) === false) { if (isStructuallyValidLanguageTag(localeString) === false) {
throw %make_range_error(kInvalidLanguageTag, localeString); throw %make_range_error(kInvalidLanguageTag, localeString);
} }
// ECMA 402 6.2.3
var tag = %CanonicalizeLanguageTag(localeString); var tag = %CanonicalizeLanguageTag(localeString);
// TODO(jshin): This should not happen because the structual validity
// is already checked. If that's the case, remove this.
if (tag === 'invalid-tag') { if (tag === 'invalid-tag') {
throw %make_range_error(kInvalidLanguageTag, localeString); throw %make_range_error(kInvalidLanguageTag, localeString);
} }
...@@ -769,20 +780,22 @@ function canonicalizeLanguageTag(localeID) { ...@@ -769,20 +780,22 @@ function canonicalizeLanguageTag(localeID) {
/** /**
* Returns an array where all locales are canonicalized and duplicates removed. * Returns an InternalArray where all locales are canonicalized and duplicates
* removed.
* Throws on locales that are not well formed BCP47 tags. * Throws on locales that are not well formed BCP47 tags.
* ECMA 402 8.2.1 steps 1 (ECMA 402 9.2.1) and 2.
*/ */
function initializeLocaleList(locales) { function canonicalizeLocaleList(locales) {
var seen = new InternalArray(); var seen = new InternalArray();
if (!IS_UNDEFINED(locales)) { if (!IS_UNDEFINED(locales)) {
// We allow single string localeID. // We allow single string localeID.
if (typeof locales === 'string') { if (typeof locales === 'string') {
%_Call(ArrayPush, seen, canonicalizeLanguageTag(locales)); %_Call(ArrayPush, seen, canonicalizeLanguageTag(locales));
return freezeArray(seen); return seen;
} }
var o = TO_OBJECT(locales); var o = TO_OBJECT(locales);
var len = TO_UINT32(o.length); var len = TO_LENGTH(o.length);
for (var k = 0; k < len; k++) { for (var k = 0; k < len; k++) {
if (k in o) { if (k in o) {
...@@ -797,20 +810,30 @@ function initializeLocaleList(locales) { ...@@ -797,20 +810,30 @@ function initializeLocaleList(locales) {
} }
} }
return freezeArray(seen); return seen;
} }
function initializeLocaleList(locales) {
return freezeArray(canonicalizeLocaleList(locales));
}
/** /**
* Validates the language tag. Section 2.2.9 of the bcp47 spec * Check the structual Validity of the language tag per ECMA 402 6.2.2:
* defines a valid tag. * - Well-formed per RFC 5646 2.1
* - There are no duplicate variant subtags
* - There are no duplicate singletion (extension) subtags
*
* One extra-check is done (from RFC 5646 2.2.9): the tag is compared
* against the list of grandfathered tags. However, subtags for
* primary/extended language, script, region, variant are not checked
* against the IANA language subtag registry.
* *
* ICU is too permissible and lets invalid tags, like * ICU is too permissible and lets invalid tags, like
* hant-cmn-cn, through. * hant-cmn-cn, through.
* *
* Returns false if the language tag is invalid. * Returns false if the language tag is invalid.
*/ */
function isValidLanguageTag(locale) { function isStructuallyValidLanguageTag(locale) {
// Check if it's well-formed, including grandfadered tags. // Check if it's well-formed, including grandfadered tags.
if (IS_NULL(InternalRegExpMatch(GetLanguageTagRE(), locale))) { if (IS_NULL(InternalRegExpMatch(GetLanguageTagRE(), locale))) {
return false; return false;
...@@ -905,6 +928,16 @@ var resolvedAccessor = { ...@@ -905,6 +928,16 @@ var resolvedAccessor = {
} }
}; };
// ECMA 402 section 8.2.1
InstallFunction(Intl, 'getCanonicalLocales', function(locales) {
if (!IS_UNDEFINED(new.target)) {
throw %make_type_error(kOrdinaryFunctionCalledAsConstructor);
}
return makeArray(canonicalizeLocaleList(locales));
}
);
/** /**
* Initializes the given object so it's a valid Collator instance. * Initializes the given object so it's a valid Collator instance.
* Useful for subclassing. * Useful for subclassing.
......
...@@ -63,6 +63,7 @@ const UChar* GetUCharBufferFromFlat(const String::FlatContent& flat, ...@@ -63,6 +63,7 @@ const UChar* GetUCharBufferFromFlat(const String::FlatContent& flat,
} // namespace } // namespace
// ECMA 402 6.2.3
RUNTIME_FUNCTION(Runtime_CanonicalizeLanguageTag) { RUNTIME_FUNCTION(Runtime_CanonicalizeLanguageTag) {
HandleScope scope(isolate); HandleScope scope(isolate);
Factory* factory = isolate->factory(); Factory* factory = isolate->factory();
...@@ -73,6 +74,8 @@ RUNTIME_FUNCTION(Runtime_CanonicalizeLanguageTag) { ...@@ -73,6 +74,8 @@ RUNTIME_FUNCTION(Runtime_CanonicalizeLanguageTag) {
v8::String::Utf8Value locale_id(v8::Utils::ToLocal(locale_id_str)); v8::String::Utf8Value locale_id(v8::Utils::ToLocal(locale_id_str));
// Return value which denotes invalid language tag. // Return value which denotes invalid language tag.
// TODO(jshin): Can uloc_{for,to}TanguageTag fail even for structually valid
// language tags? If not, just add CHECK instead of returning 'invalid-tag'.
const char* const kInvalidTag = "invalid-tag"; const char* const kInvalidTag = "invalid-tag";
UErrorCode error = U_ZERO_ERROR; UErrorCode error = U_ZERO_ERROR;
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var locales = ['en-US', 'fr'];
var result = Intl.getCanonicalLocales(locales);
var len = result.length
// TODO(jshin): Remove the following when
// https://github.com/tc39/test262/issues/745 is resolved and
// test262 in v8 is updated.
assertEquals(Object.getPrototypeOf(result), Array.prototype);
assertEquals(result.constructor, Array);
for (var key in result) {
var desc = Object.getOwnPropertyDescriptor(result, key);
assertTrue(desc.writable);
assertTrue(desc.configurable);
assertTrue(desc.enumerable);
}
var desc = Object.getOwnPropertyDescriptor(result, 'length');
assertTrue(desc.writable);
assertEquals(result.push('de'), desc.value + 1);
...@@ -330,7 +330,10 @@ ...@@ -330,7 +330,10 @@
'language/module-code/*': [SKIP], 'language/module-code/*': [SKIP],
# https://bugs.chromium.org/p/v8/issues/detail?id=5012 # https://bugs.chromium.org/p/v8/issues/detail?id=5012
'intl402/Intl/getCanonicalLocales/*': [FAIL], # http://bugs.icu-project.org/trac/ticket/12671
'intl402/Intl/getCanonicalLocales/weird-cases': [FAIL],
# https://github.com/tc39/test262/issues/743
'intl402/Intl/getCanonicalLocales/main': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=5115 # https://bugs.chromium.org/p/v8/issues/detail?id=5115
'language/statements/class/subclass/class-definition-null-proto-missing-return-override': [FAIL], 'language/statements/class/subclass/class-definition-null-proto-missing-return-override': [FAIL],
......
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