Diff
Modified: trunk/LayoutTests/ChangeLog (206836 => 206837)
--- trunk/LayoutTests/ChangeLog 2016-10-05 23:47:34 UTC (rev 206836)
+++ trunk/LayoutTests/ChangeLog 2016-10-06 00:07:21 UTC (rev 206837)
@@ -1,3 +1,13 @@
+2016-10-05 Andy VanWagoner <[email protected]>
+
+ [INTL] Implement Intl.getCanonicalLocales
+ https://bugs.webkit.org/show_bug.cgi?id=162768
+
+ Reviewed by Benjamin Poulain.
+
+ * js/intl-expected.txt: Added tests for Intl.getCanonicalLocales
+ * js/script-tests/intl.js: Added test for Intl.getCanonicalLocales
+
2016-10-05 Ryan Haddad <[email protected]>
Marking inspector/formatting/formatting-_javascript_.html as a flaky crash on mac-wk1.
Modified: trunk/LayoutTests/js/intl-expected.txt (206836 => 206837)
--- trunk/LayoutTests/js/intl-expected.txt 2016-10-05 23:47:34 UTC (rev 206836)
+++ trunk/LayoutTests/js/intl-expected.txt 2016-10-06 00:07:21 UTC (rev 206837)
@@ -12,6 +12,52 @@
PASS Object.keys(Intl).length is 0
PASS delete Intl; is true
PASS 'Intl' in global() is false
+PASS Intl.getCanonicalLocales.length is 1
+PASS Intl.getCanonicalLocales() is an instance of Array
+PASS Intl.getCanonicalLocales.call(null, 'en') is [ 'en' ]
+PASS Intl.getCanonicalLocales.call({}, 'en') is [ 'en' ]
+PASS Intl.getCanonicalLocales.call(1, 'en') is [ 'en' ]
+PASS Intl.getCanonicalLocales(9) is []
+PASS Intl.getCanonicalLocales('en') is [ 'en' ]
+PASS Intl.getCanonicalLocales({ length: 4, 1: 'en', 0: 'es', 3: 'de' }) is [ 'es', 'en', 'de' ]
+PASS Intl.getCanonicalLocales([ 'en', 'pt', 'en', 'es' ]) is [ 'en', 'pt', 'es' ]
+PASS Intl.getCanonicalLocales('En-laTn-us-variant2-variant1-1abc-U-ko-tRue-A-aa-aaa-x-RESERVED') is [ 'en-Latn-US-variant2-variant1-1abc-a-aa-aaa-u-ko-true-x-reserved' ]
+PASS Intl.getCanonicalLocales('no-bok') is [ 'nb' ]
+PASS Intl.getCanonicalLocales('X-some-thing') is [ 'x-some-thing' ]
+PASS Intl.getCanonicalLocales(Object.create(null, { length: { get() { throw Error('a') } } })) threw exception Error: a.
+PASS Intl.getCanonicalLocales(Object.create(null, { length: { value: 1 }, 0: { get() { throw Error('b') } } })) threw exception Error: b.
+PASS Intl.getCanonicalLocales([ { toString() { throw Error('c') } } ]) threw exception Error: c.
+PASS Intl.getCanonicalLocales([ 5 ]) threw exception TypeError: locale value must be a string or object.
+PASS Intl.getCanonicalLocales('') threw exception RangeError: invalid language tag: .
+PASS Intl.getCanonicalLocales('a') threw exception RangeError: invalid language tag: a.
+PASS Intl.getCanonicalLocales('abcdefghij') threw exception RangeError: invalid language tag: abcdefghij.
+PASS Intl.getCanonicalLocales('#$') threw exception RangeError: invalid language tag: #$.
+PASS Intl.getCanonicalLocales('en-@-abc') threw exception RangeError: invalid language tag: en-@-abc.
+PASS Intl.getCanonicalLocales('en-u') threw exception RangeError: invalid language tag: en-u.
+PASS Intl.getCanonicalLocales('en-u-kn-true-u-ko-true') threw exception RangeError: invalid language tag: en-u-kn-true-u-ko-true.
+PASS Intl.getCanonicalLocales('en-x') threw exception RangeError: invalid language tag: en-x.
+PASS Intl.getCanonicalLocales('en-*') threw exception RangeError: invalid language tag: en-*.
+PASS Intl.getCanonicalLocales('en-') threw exception RangeError: invalid language tag: en-.
+PASS Intl.getCanonicalLocales('en--US') threw exception RangeError: invalid language tag: en--US.
+PASS Intl.getCanonicalLocales('de') did not throw exception.
+PASS Intl.getCanonicalLocales('de-DE') did not throw exception.
+PASS Intl.getCanonicalLocales('DE-de') did not throw exception.
+PASS Intl.getCanonicalLocales('cmn') did not throw exception.
+PASS Intl.getCanonicalLocales('cmn-Hans') did not throw exception.
+PASS Intl.getCanonicalLocales('CMN-hANS') did not throw exception.
+PASS Intl.getCanonicalLocales('cmn-hans-cn') did not throw exception.
+PASS Intl.getCanonicalLocales('es-419') did not throw exception.
+PASS Intl.getCanonicalLocales('es-419-u-nu-latn-cu-bob') did not throw exception.
+PASS Intl.getCanonicalLocales('i-klingon') did not throw exception.
+PASS Intl.getCanonicalLocales('cmn-hans-cn-t-ca-u-ca-x-t-u') did not throw exception.
+PASS Intl.getCanonicalLocales('enochian-enochian') did not throw exception.
+PASS Intl.getCanonicalLocales('de-gregory-u-ca-gregory') did not throw exception.
+PASS Intl.getCanonicalLocales('aa-a-foo-x-a-foo-bar') did not throw exception.
+PASS Intl.getCanonicalLocales('x-en-US-12345') did not throw exception.
+PASS Intl.getCanonicalLocales('x-12345-12345-en-US') did not throw exception.
+PASS Intl.getCanonicalLocales('x-en-US-12345-12345') did not throw exception.
+PASS Intl.getCanonicalLocales('x-en-u-foo') did not throw exception.
+PASS Intl.getCanonicalLocales('x-en-u-foo-u-bar') did not throw exception.
PASS successfullyParsed is true
TEST COMPLETE
Modified: trunk/LayoutTests/js/script-tests/intl.js (206836 => 206837)
--- trunk/LayoutTests/js/script-tests/intl.js 2016-10-05 23:47:34 UTC (rev 206836)
+++ trunk/LayoutTests/js/script-tests/intl.js 2016-10-06 00:07:21 UTC (rev 206837)
@@ -30,3 +30,71 @@
Intl = __Intl;
+// 8.2.1 Intl.getCanonicalLocales(locales)
+
+// The value of the length property of the getCanonicalLocales method is 1.
+shouldBe("Intl.getCanonicalLocales.length", "1");
+
+// Returns Locales
+shouldBeType("Intl.getCanonicalLocales()", "Array");
+// Doesn't care about `this`.
+shouldBe("Intl.getCanonicalLocales.call(null, 'en')", "[ 'en' ]");
+shouldBe("Intl.getCanonicalLocales.call({}, 'en')", "[ 'en' ]");
+shouldBe("Intl.getCanonicalLocales.call(1, 'en')", "[ 'en' ]");
+// Ignores non-object, non-string list.
+shouldBe("Intl.getCanonicalLocales(9)", "[]");
+// Makes an array of tags.
+shouldBe("Intl.getCanonicalLocales('en')", "[ 'en' ]");
+// Handles array-like objects with holes.
+shouldBe("Intl.getCanonicalLocales({ length: 4, 1: 'en', 0: 'es', 3: 'de' })", "[ 'es', 'en', 'de' ]");
+// Deduplicates tags.
+shouldBe("Intl.getCanonicalLocales([ 'en', 'pt', 'en', 'es' ])", "[ 'en', 'pt', 'es' ]");
+// Canonicalizes tags.
+shouldBe("Intl.getCanonicalLocales('En-laTn-us-variant2-variant1-1abc-U-ko-tRue-A-aa-aaa-x-RESERVED')", "[ 'en-Latn-US-variant2-variant1-1abc-a-aa-aaa-u-ko-true-x-reserved' ]");
+// Replaces outdated tags.
+shouldBe("Intl.getCanonicalLocales('no-bok')", "[ 'nb' ]");
+// Canonicalizes private tags.
+shouldBe("Intl.getCanonicalLocales('X-some-thing')", "[ 'x-some-thing' ]");
+// Throws on problems with length, get, or toString.
+shouldThrow("Intl.getCanonicalLocales(Object.create(null, { length: { get() { throw Error('a') } } }))", "'Error: a'");
+shouldThrow("Intl.getCanonicalLocales(Object.create(null, { length: { value: 1 }, 0: { get() { throw Error('b') } } }))", "'Error: b'");
+shouldThrow("Intl.getCanonicalLocales([ { toString() { throw Error('c') } } ])", "'Error: c'");
+// Throws on bad tags.
+shouldThrow("Intl.getCanonicalLocales([ 5 ])", "'TypeError: locale value must be a string or object'");
+shouldThrow("Intl.getCanonicalLocales('')", "'RangeError: invalid language tag: '");
+shouldThrow("Intl.getCanonicalLocales('a')", "'RangeError: invalid language tag: a'");
+shouldThrow("Intl.getCanonicalLocales('abcdefghij')", "'RangeError: invalid language tag: abcdefghij'");
+shouldThrow("Intl.getCanonicalLocales('#$')", "'RangeError: invalid language tag: #$'");
+shouldThrow("Intl.getCanonicalLocales('en-@-abc')", "'RangeError: invalid language tag: en-@-abc'");
+shouldThrow("Intl.getCanonicalLocales('en-u')", "'RangeError: invalid language tag: en-u'");
+shouldThrow("Intl.getCanonicalLocales('en-u-kn-true-u-ko-true')", "'RangeError: invalid language tag: en-u-kn-true-u-ko-true'");
+shouldThrow("Intl.getCanonicalLocales('en-x')", "'RangeError: invalid language tag: en-x'");
+shouldThrow("Intl.getCanonicalLocales('en-*')", "'RangeError: invalid language tag: en-*'");
+shouldThrow("Intl.getCanonicalLocales('en-')", "'RangeError: invalid language tag: en-'");
+shouldThrow("Intl.getCanonicalLocales('en--US')", "'RangeError: invalid language tag: en--US'");
+// Accepts valid tags
+var validLanguageTags = [
+ "de", // ISO 639 language code
+ "de-DE", // + ISO 3166-1 country code
+ "DE-de", // tags are case-insensitive
+ "cmn", // ISO 639 language code
+ "cmn-Hans", // + script code
+ "CMN-hANS", // tags are case-insensitive
+ "cmn-hans-cn", // + ISO 3166-1 country code
+ "es-419", // + UN M.49 region code
+ "es-419-u-nu-latn-cu-bob", // + Unicode locale extension sequence
+ "i-klingon", // grandfathered tag
+ "cmn-hans-cn-t-ca-u-ca-x-t-u", // singleton subtags can also be used as private use subtags
+ "enochian-enochian", // language and variant subtags may be the same
+ "de-gregory-u-ca-gregory", // variant and extension subtags may be the same
+ "aa-a-foo-x-a-foo-bar", // variant subtags can also be used as private use subtags
+ "x-en-US-12345", // anything goes in private use tags
+ "x-12345-12345-en-US",
+ "x-en-US-12345-12345",
+ "x-en-u-foo",
+ "x-en-u-foo-u-bar"
+];
+for (var validLanguageTag of validLanguageTags) {
+ shouldNotThrow("Intl.getCanonicalLocales('" + validLanguageTag + "')");
+}
+
Modified: trunk/Source/_javascript_Core/ChangeLog (206836 => 206837)
--- trunk/Source/_javascript_Core/ChangeLog 2016-10-05 23:47:34 UTC (rev 206836)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-10-06 00:07:21 UTC (rev 206837)
@@ -1,3 +1,19 @@
+2016-10-05 Andy VanWagoner <[email protected]>
+
+ [INTL] Implement Intl.getCanonicalLocales
+ https://bugs.webkit.org/show_bug.cgi?id=162768
+
+ Reviewed by Benjamin Poulain.
+
+ Implement Intl.getCanonicalLocales from ECMA 402 (3rd edition)
+ http://ecma-international.org/ecma-402/3.0/index.html#sec-intl.getcanonicallocales
+
+ Reuse canonicalizeLocaleList and copy the results into a new JSArray.
+
+ * runtime/IntlObject.cpp:
+ (JSC::IntlObject::finishCreation):
+ (JSC::intlObjectFuncGetCanonicalLocales):
+
2016-10-05 Michael Saboff <[email protected]>
Bad ASSERT in ClonedArguments::createByCopyingFrom()
Modified: trunk/Source/_javascript_Core/runtime/IntlObject.cpp (206836 => 206837)
--- trunk/Source/_javascript_Core/runtime/IntlObject.cpp 2016-10-05 23:47:34 UTC (rev 206836)
+++ trunk/Source/_javascript_Core/runtime/IntlObject.cpp 2016-10-06 00:07:21 UTC (rev 206837)
@@ -56,6 +56,8 @@
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IntlObject);
+static EncodedJSValue JSC_HOST_CALL intlObjectFuncGetCanonicalLocales(ExecState*);
+
}
namespace JSC {
@@ -110,6 +112,10 @@
putDirectWithoutTransition(vm, vm.propertyNames->Collator, collatorConstructor, DontEnum);
putDirectWithoutTransition(vm, vm.propertyNames->NumberFormat, numberFormatConstructor, DontEnum);
putDirectWithoutTransition(vm, vm.propertyNames->DateTimeFormat, dateTimeFormatConstructor, DontEnum);
+
+ // 8.2 Function Properties of the Intl Object
+ // https://tc39.github.io/ecma402/#sec-function-properties-of-the-intl-object
+ putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "getCanonicalLocales"), 1, intlObjectFuncGetCanonicalLocales, NoIntrinsic, DontEnum);
}
Structure* IntlObject::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
@@ -1010,6 +1016,33 @@
return numberingSystems;
}
+EncodedJSValue JSC_HOST_CALL intlObjectFuncGetCanonicalLocales(ExecState* state)
+{
+ VM& vm = state->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ // https://tc39.github.io/ecma402/#sec-intl.getcanonicallocales
+ // 8.2.1 Intl.getCanonicalLocales(locales) (ECMA-402 4.0)
+
+ // 1. Let ll be ? CanonicalizeLocaleList(locales).
+ Vector<String> localeList = canonicalizeLocaleList(*state, state->argument(0));
+ RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+ // 2. Return CreateArrayFromList(ll).
+ JSGlobalObject* globalObject = state->callee()->globalObject();
+ JSArray* localeArray = JSArray::tryCreateUninitialized(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), localeList.size());
+ if (!localeArray) {
+ throwOutOfMemoryError(state, scope);
+ return encodedJSValue();
+ }
+
+ auto length = localeList.size();
+ for (size_t i = 0; i < length; ++i) {
+ localeArray->initializeIndex(vm, i, jsString(state, localeList[i]));
+ RETURN_IF_EXCEPTION(scope, encodedJSValue());
+ }
+ return JSValue::encode(localeArray);
+}
+
} // namespace JSC
#endif // ENABLE(INTL)