Title: [268956] trunk
Revision
268956
Author
[email protected]
Date
2020-10-24 23:20:47 -0700 (Sat, 24 Oct 2020)

Log Message

[ECMA-402] Implement Intl.ListFormat
https://bugs.webkit.org/show_bug.cgi?id=209775

Reviewed by Ross Kirsling.

JSTests:

* stress/intl-listformat.js: Added.
(shouldBe):
(shouldNotThrow):
(shouldThrow):
(test.DerivedListFormat):
(test.get shouldThrow):
(test):

Source/_javascript_Core:

This patch implements Intl.ListFormat. Intl.ListFormat requires ulistfmt_openForType.
But it is available after ICU 67, and it is draft (unstable) API in ICU 67.
But now, this function is stable in ICU 68 without signature change and no major
change happened to this API. Thus, we can assume that this API signature won't be changed.
We specially undef U_HIDE_DRAFT_API for unicode/ulistformatter.h to use this draft (but stable) APIs.

While macOS / iOS shipping ICU (AppleICU) is ICU 66, AppleICU has ulistfmt_openForType and related APIs
even in ICU 66. We use these APIs in AppleICU 66 to implement Intl.ListFormat.

* CMakeLists.txt:
* DerivedSources-input.xcfilelist:
* DerivedSources-output.xcfilelist:
* DerivedSources.make:
* _javascript_Core.xcodeproj/project.pbxproj:
* Sources.txt:
* runtime/CommonIdentifiers.h:
* runtime/IntlDisplayNames.cpp:
(JSC::IntlDisplayNames::initializeDisplayNames):
* runtime/IntlListFormat.cpp: Added.
(JSC::UListFormatterDeleter::operator()):
(JSC::IntlListFormat::create):
(JSC::IntlListFormat::createStructure):
(JSC::IntlListFormat::IntlListFormat):
(JSC::IntlListFormat::finishCreation):
(JSC::IntlListFormat::initializeListFormat):
(JSC::stringListFromIterable):
(JSC::ListFormatInput::ListFormatInput):
(JSC::ListFormatInput::size const):
(JSC::ListFormatInput::stringPointers const):
(JSC::ListFormatInput::stringLengths const):
(JSC::IntlListFormat::format const):
(JSC::IntlListFormat::formatToParts const):
(JSC::IntlListFormat::resolvedOptions const):
(JSC::IntlListFormat::styleString):
(JSC::IntlListFormat::typeString):
* runtime/IntlListFormat.h: Added.
* runtime/IntlListFormatConstructor.cpp: Added.
(JSC::IntlListFormatConstructor::create):
(JSC::IntlListFormatConstructor::createStructure):
(JSC::IntlListFormatConstructor::IntlListFormatConstructor):
(JSC::IntlListFormatConstructor::finishCreation):
(JSC::JSC_DEFINE_HOST_FUNCTION):
* runtime/IntlListFormatConstructor.h: Added.
* runtime/IntlListFormatPrototype.cpp: Added.
(JSC::IntlListFormatPrototype::create):
(JSC::IntlListFormatPrototype::createStructure):
(JSC::IntlListFormatPrototype::IntlListFormatPrototype):
(JSC::IntlListFormatPrototype::finishCreation):
(JSC::JSC_DEFINE_HOST_FUNCTION):
* runtime/IntlListFormatPrototype.h: Added.
* runtime/IntlObject.cpp:
(JSC::createListFormatConstructor):
(JSC::IntlObject::finishCreation):
* runtime/IntlObject.h:
(JSC::intlListFormatAvailableLocales):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::listFormatStructure):
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (268955 => 268956)


--- trunk/JSTests/ChangeLog	2020-10-25 04:27:10 UTC (rev 268955)
+++ trunk/JSTests/ChangeLog	2020-10-25 06:20:47 UTC (rev 268956)
@@ -1,3 +1,18 @@
+2020-10-24  Yusuke Suzuki  <[email protected]>
+
+        [ECMA-402] Implement Intl.ListFormat
+        https://bugs.webkit.org/show_bug.cgi?id=209775
+
+        Reviewed by Ross Kirsling.
+
+        * stress/intl-listformat.js: Added.
+        (shouldBe):
+        (shouldNotThrow):
+        (shouldThrow):
+        (test.DerivedListFormat):
+        (test.get shouldThrow):
+        (test):
+
 2020-10-24  Caio Lima  <[email protected]>
 
         [EWS][ARMv7] Flaky test stress/json-stringify-stack-overflow.js

Added: trunk/JSTests/stress/intl-listformat.js (0 => 268956)


--- trunk/JSTests/stress/intl-listformat.js	                        (rev 0)
+++ trunk/JSTests/stress/intl-listformat.js	2020-10-25 06:20:47 UTC (rev 268956)
@@ -0,0 +1,221 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`expected ${expected} but got ${actual}`);
+}
+
+function shouldNotThrow(func) {
+    func();
+}
+
+function shouldThrow(func, errorType) {
+    let error;
+    try {
+        func();
+    } catch (e) {
+        error = e;
+    }
+
+    if (!(error instanceof errorType))
+        throw new Error(`Expected ${errorType.name}!`);
+}
+
+function test() {
+    {
+        // https://tc39.github.io/ecma402/#pluralrules-objects
+        // The Intl.ListFormat Constructor
+
+        // The ListFormat constructor is the %ListFormat% intrinsic object and a standard built-in property of the Intl object.
+        shouldBe(Intl.ListFormat instanceof Function, true);
+
+        // Intl.ListFormat ([ locales [, options ] ])
+
+        // If NewTarget is undefined, throw a TypeError exception.
+        shouldThrow(() => Intl.ListFormat(), TypeError);
+        shouldThrow(() => Intl.ListFormat.call({}), TypeError);
+
+        shouldThrow(() => new Intl.ListFormat('$'), RangeError);
+        shouldThrow(() => new Intl.ListFormat('en', null), TypeError);
+        shouldBe(new Intl.ListFormat() instanceof Intl.ListFormat, true);
+
+        // Subclassable
+        {
+            class DerivedListFormat extends Intl.ListFormat {};
+            shouldBe((new DerivedListFormat) instanceof DerivedListFormat, true);
+            shouldBe((new DerivedListFormat) instanceof Intl.ListFormat, true);
+            shouldBe(new DerivedListFormat('en').format(['Orange', 'Apple', 'Lemon']), 'Orange, Apple, and Lemon');
+            shouldBe(Object.getPrototypeOf(new DerivedListFormat), DerivedListFormat.prototype);
+            shouldBe(Object.getPrototypeOf(Object.getPrototypeOf(new DerivedListFormat)), Intl.ListFormat.prototype);
+        }
+
+        // Properties of the Intl.ListFormat Constructor
+
+        // length property (whose value is 0)
+        shouldBe(Intl.ListFormat.length, 0);
+
+        // Intl.ListFormat.prototype
+
+        // This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.
+        shouldBe(Object.getOwnPropertyDescriptor(Intl.ListFormat, 'prototype').writable, false);
+        shouldBe(Object.getOwnPropertyDescriptor(Intl.ListFormat, 'prototype').enumerable, false);
+        shouldBe(Object.getOwnPropertyDescriptor(Intl.ListFormat, 'prototype').configurable, false);
+
+        // Intl.ListFormat.supportedLocalesOf (locales [, options ])
+
+        // The value of the length property of the supportedLocalesOf method is 1.
+        shouldBe(Intl.ListFormat.supportedLocalesOf.length, 1);
+
+        // Returns SupportedLocales
+        shouldBe(Intl.ListFormat.supportedLocalesOf() instanceof Array, true);
+        // Doesn't care about `this`.
+        shouldBe(JSON.stringify(Intl.ListFormat.supportedLocalesOf.call(null, 'en')), '["en"]');
+        shouldBe(JSON.stringify(Intl.ListFormat.supportedLocalesOf.call({}, 'en')), '["en"]');
+        shouldBe(JSON.stringify(Intl.ListFormat.supportedLocalesOf.call(1, 'en')), '["en"]');
+        // Ignores non-object, non-string list.
+        shouldBe(JSON.stringify(Intl.ListFormat.supportedLocalesOf(9)), '[]');
+        // Makes an array of tags.
+        shouldBe(JSON.stringify(Intl.ListFormat.supportedLocalesOf('en')), '["en"]');
+        // Handles array-like objects with holes.
+        shouldBe(JSON.stringify(Intl.ListFormat.supportedLocalesOf({ length: 4, 1: 'en', 0: 'es', 3: 'de' })), '["es","en","de"]');
+        // Deduplicates tags.
+        shouldBe(JSON.stringify(Intl.ListFormat.supportedLocalesOf([ 'en', 'pt', 'en', 'es' ])), '["en","pt","es"]');
+        // Canonicalizes tags.
+        shouldBe(
+            JSON.stringify(Intl.ListFormat.supportedLocalesOf('En-laTn-us-variAnt-fOObar-1abc-U-kn-tRue-A-aa-aaa-x-RESERVED')),
+            $vm.icuVersion() >= 67
+                ? '["en-Latn-US-1abc-foobar-variant-a-aa-aaa-u-kn-x-reserved"]'
+                : '["en-Latn-US-variant-foobar-1abc-a-aa-aaa-u-kn-x-reserved"]'
+        );
+        // Throws on problems with length, get, or toString.
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf(Object.create(null, { length: { get() { throw new Error(); } } })), Error);
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf(Object.create(null, { length: { value: 1 }, 0: { get() { throw new Error(); } } })), Error);
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf([ { toString() { throw new Error(); } } ]), Error);
+        // Throws on bad tags.
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf('no-bok'), RangeError);
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf('x-some-thing'), RangeError);
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf([ 5 ]), TypeError);
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf(''), RangeError);
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf('a'), RangeError);
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf('abcdefghij'), RangeError);
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf('#$'), RangeError);
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf('en-@-abc'), RangeError);
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf('en-u'), RangeError);
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf('en-u-kn-true-u-ko-true'), RangeError);
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf('en-x'), RangeError);
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf('en-*'), RangeError);
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf('en-'), RangeError);
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf('en--US'), RangeError);
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf('i-klingon'), RangeError); // grandfathered tag is not accepted by IsStructurallyValidLanguageTag
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf('x-en-US-12345'), RangeError);
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf('x-12345-12345-en-US'), RangeError);
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf('x-en-US-12345-12345'), RangeError);
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf('x-en-u-foo'), RangeError);
+        shouldThrow(() => Intl.ListFormat.supportedLocalesOf('x-en-u-foo-u-bar'), RangeError);
+
+        // 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
+            '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
+        ];
+        for (var validLanguageTag of validLanguageTags)
+            shouldNotThrow(() => Intl.ListFormat.supportedLocalesOf(validLanguageTag));
+
+        // Properties of the Intl.ListFormat Prototype Object
+
+        // The Intl.ListFormat prototype object is itself an ordinary object.
+        shouldBe(Object.getPrototypeOf(Intl.ListFormat.prototype), Object.prototype);
+
+        // Intl.ListFormat.prototype.constructor
+        // The initial value of Intl.ListFormat.prototype.constructor is the intrinsic object %ListFormat%.
+        shouldBe(Intl.ListFormat.prototype.constructor, Intl.ListFormat);
+
+        // Intl.ListFormat.prototype [ @@toStringTag ]
+        // The initial value of the @@toStringTag property is the string value "Intl.ListFormat".
+        shouldBe(Intl.ListFormat.prototype[Symbol.toStringTag], 'Intl.ListFormat');
+        shouldBe(Object.prototype.toString.call(Intl.ListFormat.prototype), '[object Intl.ListFormat]');
+        // This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+        shouldBe(Object.getOwnPropertyDescriptor(Intl.ListFormat.prototype, Symbol.toStringTag).writable, false);
+        shouldBe(Object.getOwnPropertyDescriptor(Intl.ListFormat.prototype, Symbol.toStringTag).enumerable, false);
+        shouldBe(Object.getOwnPropertyDescriptor(Intl.ListFormat.prototype, Symbol.toStringTag).configurable, true);
+    }
+    {
+        const lf = new Intl.ListFormat("en", {
+            localeMatcher: "best fit",
+            type: "conjunction",
+            style: "long",
+        });
+        shouldBe(lf.format(['Motorcycle', 'Truck' , 'Car']), `Motorcycle, Truck, and Car`);
+        shouldBe(lf.format([]), ``);
+        shouldBe(lf.format(), ``);
+        shouldBe(lf.format(undefined), ``);
+        shouldBe(lf.format("Apple"), `A, p, p, l, and e`);
+        shouldThrow(() => lf.format(42), TypeError);
+        shouldThrow(() => lf.format(null), TypeError);
+        shouldThrow(() => lf.format([null]), TypeError);
+        shouldBe(JSON.stringify(lf.resolvedOptions()), `{"locale":"en","type":"conjunction","style":"long"}`);
+        shouldBe(JSON.stringify(Reflect.getOwnPropertyDescriptor(Intl.ListFormat.prototype, Symbol.toStringTag)), `{"value":"Intl.ListFormat","writable":false,"enumerable":false,"configurable":true}`);
+    }
+    {
+        const list = ['Motorcycle', 'Bus', 'Car'];
+        shouldBe(new Intl.ListFormat('en-GB', { style: 'long', type: 'conjunction' }).format(list), `Motorcycle, Bus and Car`);
+        shouldBe(new Intl.ListFormat('en-GB', { style: 'short', type: 'conjunction' }).format(list), `Motorcycle, Bus and Car`);
+        shouldBe(new Intl.ListFormat('en-GB', { style: 'narrow', type: 'conjunction' }).format(list), `Motorcycle, Bus, Car`);
+        shouldBe(new Intl.ListFormat('en-GB', { style: 'long', type: 'disjunction' }).format(list), `Motorcycle, Bus or Car`);
+        shouldBe(new Intl.ListFormat('en-GB', { style: 'short', type: 'disjunction' }).format(list), `Motorcycle, Bus or Car`);
+        shouldBe(new Intl.ListFormat('en-GB', { style: 'narrow', type: 'disjunction' }).format(list), `Motorcycle, Bus or Car`);
+        shouldBe(new Intl.ListFormat('en-GB', { style: 'long', type: 'unit' }).format(list), `Motorcycle, Bus, Car`);
+        shouldBe(new Intl.ListFormat('en-GB', { style: 'short', type: 'unit' }).format(list), `Motorcycle, Bus, Car`);
+        shouldBe(new Intl.ListFormat('en-GB', { style: 'narrow', type: 'unit' }).format(list), `Motorcycle Bus Car`);
+    }
+    {
+        const list = ['バイク', 'バス', '車'];
+        shouldBe(new Intl.ListFormat('ja-JP', { style: 'long', type: 'conjunction' }).format(list), `バイク、バス、車`);
+        shouldBe(new Intl.ListFormat('ja-JP', { style: 'short', type: 'conjunction' }).format(list), `バイク、バス、車`);
+        shouldBe(new Intl.ListFormat('ja-JP', { style: 'narrow', type: 'conjunction' }).format(list), `バイク、バス、車`);
+        shouldBe(new Intl.ListFormat('ja-JP', { style: 'long', type: 'disjunction' }).format(list), `バイク、バス、または車`);
+        shouldBe(new Intl.ListFormat('ja-JP', { style: 'short', type: 'disjunction' }).format(list), `バイク、バス、または車`);
+        shouldBe(new Intl.ListFormat('ja-JP', { style: 'narrow', type: 'disjunction' }).format(list), `バイク、バス、または車`);
+        shouldBe(new Intl.ListFormat('ja-JP', { style: 'long', type: 'unit' }).format(list), `バイク バス 車`);
+        shouldBe(new Intl.ListFormat('ja-JP', { style: 'short', type: 'unit' }).format(list), `バイク バス 車`);
+        shouldBe(new Intl.ListFormat('ja-JP', { style: 'narrow', type: 'unit' }).format(list), `バイクバス車`);
+    }
+    {
+        const list = ['Motorcycle', 'Bus', 'Car'];
+        const expected = [
+            { "type": "element", "value": "Motorcycle" },
+            { "type": "literal", "value": ", " },
+            { "type": "element", "value": "Bus" },
+            { "type": "literal", "value": " and " },
+            { "type": "element", "value": "Car" }
+        ];
+
+        const lf = new Intl.ListFormat('en-GB', { style: 'long', type: 'conjunction' });
+        const parts = lf.formatToParts(list);
+        shouldBe(parts.length, expected.length);
+        for (let i = 0; i < parts.length; ++i) {
+            shouldBe(parts[i].type, expected[i].type);
+            shouldBe(parts[i].value, expected[i].value);
+        }
+
+        shouldBe(JSON.stringify(lf.formatToParts([])), `[]`);
+        shouldBe(JSON.stringify(lf.formatToParts()), `[]`);
+        shouldBe(JSON.stringify(lf.formatToParts(undefined)), `[]`);
+        shouldBe(JSON.stringify(lf.formatToParts("Apple")), `[{"type":"element","value":"A"},{"type":"literal","value":", "},{"type":"element","value":"p"},{"type":"literal","value":", "},{"type":"element","value":"p"},{"type":"literal","value":", "},{"type":"element","value":"l"},{"type":"literal","value":" and "},{"type":"element","value":"e"}]`);
+        shouldThrow(() => lf.formatToParts(42), TypeError);
+        shouldThrow(() => lf.formatToParts(null), TypeError);
+        shouldThrow(() => lf.formatToParts([null]), TypeError);
+    }
+}
+
+if (typeof Intl.ListFormat !== 'undefined')
+    test();

Modified: trunk/Source/_javascript_Core/CMakeLists.txt (268955 => 268956)


--- trunk/Source/_javascript_Core/CMakeLists.txt	2020-10-25 04:27:10 UTC (rev 268955)
+++ trunk/Source/_javascript_Core/CMakeLists.txt	2020-10-25 06:20:47 UTC (rev 268956)
@@ -72,6 +72,8 @@
     runtime/IntlDateTimeFormatPrototype.cpp
     runtime/IntlDisplayNamesConstructor.cpp
     runtime/IntlDisplayNamesPrototype.cpp
+    runtime/IntlListFormatConstructor.cpp
+    runtime/IntlListFormatPrototype.cpp
     runtime/IntlLocalePrototype.cpp
     runtime/IntlNumberFormatConstructor.cpp
     runtime/IntlNumberFormatPrototype.cpp

Modified: trunk/Source/_javascript_Core/ChangeLog (268955 => 268956)


--- trunk/Source/_javascript_Core/ChangeLog	2020-10-25 04:27:10 UTC (rev 268955)
+++ trunk/Source/_javascript_Core/ChangeLog	2020-10-25 06:20:47 UTC (rev 268956)
@@ -1,3 +1,74 @@
+2020-10-24  Yusuke Suzuki  <[email protected]>
+
+        [ECMA-402] Implement Intl.ListFormat
+        https://bugs.webkit.org/show_bug.cgi?id=209775
+
+        Reviewed by Ross Kirsling.
+
+        This patch implements Intl.ListFormat. Intl.ListFormat requires ulistfmt_openForType.
+        But it is available after ICU 67, and it is draft (unstable) API in ICU 67.
+        But now, this function is stable in ICU 68 without signature change and no major
+        change happened to this API. Thus, we can assume that this API signature won't be changed.
+        We specially undef U_HIDE_DRAFT_API for unicode/ulistformatter.h to use this draft (but stable) APIs.
+
+        While macOS / iOS shipping ICU (AppleICU) is ICU 66, AppleICU has ulistfmt_openForType and related APIs
+        even in ICU 66. We use these APIs in AppleICU 66 to implement Intl.ListFormat.
+
+        * CMakeLists.txt:
+        * DerivedSources-input.xcfilelist:
+        * DerivedSources-output.xcfilelist:
+        * DerivedSources.make:
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * Sources.txt:
+        * runtime/CommonIdentifiers.h:
+        * runtime/IntlDisplayNames.cpp:
+        (JSC::IntlDisplayNames::initializeDisplayNames):
+        * runtime/IntlListFormat.cpp: Added.
+        (JSC::UListFormatterDeleter::operator()):
+        (JSC::IntlListFormat::create):
+        (JSC::IntlListFormat::createStructure):
+        (JSC::IntlListFormat::IntlListFormat):
+        (JSC::IntlListFormat::finishCreation):
+        (JSC::IntlListFormat::initializeListFormat):
+        (JSC::stringListFromIterable):
+        (JSC::ListFormatInput::ListFormatInput):
+        (JSC::ListFormatInput::size const):
+        (JSC::ListFormatInput::stringPointers const):
+        (JSC::ListFormatInput::stringLengths const):
+        (JSC::IntlListFormat::format const):
+        (JSC::IntlListFormat::formatToParts const):
+        (JSC::IntlListFormat::resolvedOptions const):
+        (JSC::IntlListFormat::styleString):
+        (JSC::IntlListFormat::typeString):
+        * runtime/IntlListFormat.h: Added.
+        * runtime/IntlListFormatConstructor.cpp: Added.
+        (JSC::IntlListFormatConstructor::create):
+        (JSC::IntlListFormatConstructor::createStructure):
+        (JSC::IntlListFormatConstructor::IntlListFormatConstructor):
+        (JSC::IntlListFormatConstructor::finishCreation):
+        (JSC::JSC_DEFINE_HOST_FUNCTION):
+        * runtime/IntlListFormatConstructor.h: Added.
+        * runtime/IntlListFormatPrototype.cpp: Added.
+        (JSC::IntlListFormatPrototype::create):
+        (JSC::IntlListFormatPrototype::createStructure):
+        (JSC::IntlListFormatPrototype::IntlListFormatPrototype):
+        (JSC::IntlListFormatPrototype::finishCreation):
+        (JSC::JSC_DEFINE_HOST_FUNCTION):
+        * runtime/IntlListFormatPrototype.h: Added.
+        * runtime/IntlObject.cpp:
+        (JSC::createListFormatConstructor):
+        (JSC::IntlObject::finishCreation):
+        * runtime/IntlObject.h:
+        (JSC::intlListFormatAvailableLocales):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        (JSC::JSGlobalObject::visitChildren):
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::listFormatStructure):
+        * runtime/VM.cpp:
+        (JSC::VM::VM):
+        * runtime/VM.h:
+
 2020-10-23  Keith Miller  <[email protected]>
 
         Using WASM function size as the cap for choosing a register allocator causes performance regressions.

Modified: trunk/Source/_javascript_Core/DerivedSources-input.xcfilelist (268955 => 268956)


--- trunk/Source/_javascript_Core/DerivedSources-input.xcfilelist	2020-10-25 04:27:10 UTC (rev 268955)
+++ trunk/Source/_javascript_Core/DerivedSources-input.xcfilelist	2020-10-25 06:20:47 UTC (rev 268956)
@@ -139,6 +139,8 @@
 $(PROJECT_DIR)/runtime/IntlDateTimeFormatPrototype.cpp
 $(PROJECT_DIR)/runtime/IntlDisplayNamesConstructor.cpp
 $(PROJECT_DIR)/runtime/IntlDisplayNamesPrototype.cpp
+$(PROJECT_DIR)/runtime/IntlListFormatConstructor.cpp
+$(PROJECT_DIR)/runtime/IntlListFormatPrototype.cpp
 $(PROJECT_DIR)/runtime/IntlLocalePrototype.cpp
 $(PROJECT_DIR)/runtime/IntlNumberFormatConstructor.cpp
 $(PROJECT_DIR)/runtime/IntlNumberFormatPrototype.cpp

Modified: trunk/Source/_javascript_Core/DerivedSources-output.xcfilelist (268955 => 268956)


--- trunk/Source/_javascript_Core/DerivedSources-output.xcfilelist	2020-10-25 04:27:10 UTC (rev 268955)
+++ trunk/Source/_javascript_Core/DerivedSources-output.xcfilelist	2020-10-25 06:20:47 UTC (rev 268956)
@@ -29,6 +29,8 @@
 $(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlDateTimeFormatPrototype.lut.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlDisplayNamesConstructor.lut.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlDisplayNamesPrototype.lut.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlListFormatConstructor.lut.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlListFormatPrototype.lut.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlLocalePrototype.lut.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlNumberFormatConstructor.lut.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlNumberFormatPrototype.lut.h

Modified: trunk/Source/_javascript_Core/DerivedSources.make (268955 => 268956)


--- trunk/Source/_javascript_Core/DerivedSources.make	2020-10-25 04:27:10 UTC (rev 268955)
+++ trunk/Source/_javascript_Core/DerivedSources.make	2020-10-25 06:20:47 UTC (rev 268956)
@@ -160,6 +160,8 @@
     IntlDateTimeFormatPrototype.lut.h \
     IntlDisplayNamesConstructor.lut.h \
     IntlDisplayNamesPrototype.lut.h \
+    IntlListFormatConstructor.lut.h \
+    IntlListFormatPrototype.lut.h \
     IntlLocalePrototype.lut.h \
     IntlNumberFormatConstructor.lut.h \
     IntlNumberFormatPrototype.lut.h \

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (268955 => 268956)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2020-10-25 04:27:10 UTC (rev 268955)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2020-10-25 06:20:47 UTC (rev 268956)
@@ -1795,6 +1795,9 @@
 		E31179AA2288386100514B2C /* SymbolTableOrScopeDepth.h in Headers */ = {isa = PBXBuildFile; fileRef = E31179A92288385D00514B2C /* SymbolTableOrScopeDepth.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E31618131EC5FE170006A218 /* DOMAnnotation.h in Headers */ = {isa = PBXBuildFile; fileRef = E31618101EC5FE080006A218 /* DOMAnnotation.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E31618151EC5FE270006A218 /* DOMAttributeGetterSetter.h in Headers */ = {isa = PBXBuildFile; fileRef = E31618121EC5FE080006A218 /* DOMAttributeGetterSetter.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		E318CA6B254406B6004DC129 /* IntlListFormatConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = E318CA65254406B4004DC129 /* IntlListFormatConstructor.h */; };
+		E318CA6C254406B6004DC129 /* IntlListFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = E318CA66254406B4004DC129 /* IntlListFormat.h */; };
+		E318CA6D254406B6004DC129 /* IntlListFormatPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = E318CA67254406B5004DC129 /* IntlListFormatPrototype.h */; };
 		E318CBC11B8AEF5100A2929D /* JSModuleNamespaceObject.h in Headers */ = {isa = PBXBuildFile; fileRef = E318CBBF1B8AEF5100A2929D /* JSModuleNamespaceObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E31C31322511AFD700E7A3A0 /* IntlCache.h in Headers */ = {isa = PBXBuildFile; fileRef = E31C31302511AFD600E7A3A0 /* IntlCache.h */; };
 		E3201C1D1F8E82360076A032 /* JSScriptFetchParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = E38D060B1F8E814100649CF2 /* JSScriptFetchParameters.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -1846,6 +1849,7 @@
 		E3637EE9236E56B00096BD0A /* LinkTimeConstant.h in Headers */ = {isa = PBXBuildFile; fileRef = E3637EE7236E56B00096BD0A /* LinkTimeConstant.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E365F33A24AA623900C991B2 /* IntlDisplayNamesConstructor.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = E365F33924AA621200C991B2 /* IntlDisplayNamesConstructor.lut.h */; };
 		E365F33B24AA623B00C991B2 /* IntlDisplayNamesPrototype.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = E365F33824AA621100C991B2 /* IntlDisplayNamesPrototype.lut.h */; };
+		E366441E254409B30001876F /* IntlListFormat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E318CA69254406B5004DC129 /* IntlListFormat.cpp */; };
 		E36B767022F8D61900D09818 /* WasmOMGForOSREntryPlan.h in Headers */ = {isa = PBXBuildFile; fileRef = E36B766F22F8D61100D09818 /* WasmOMGForOSREntryPlan.h */; };
 		E36CC9472086314F0051FFD6 /* WasmCreationMode.h in Headers */ = {isa = PBXBuildFile; fileRef = E36CC9462086314F0051FFD6 /* WasmCreationMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E36EDCE524F0975700E60DA2 /* Concurrency.h in Headers */ = {isa = PBXBuildFile; fileRef = E36EDCE424F0975700E60DA2 /* Concurrency.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -4972,6 +4976,12 @@
 		E31618101EC5FE080006A218 /* DOMAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMAnnotation.h; sourceTree = "<group>"; };
 		E31618111EC5FE080006A218 /* DOMAttributeGetterSetter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMAttributeGetterSetter.cpp; sourceTree = "<group>"; };
 		E31618121EC5FE080006A218 /* DOMAttributeGetterSetter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMAttributeGetterSetter.h; sourceTree = "<group>"; };
+		E318CA65254406B4004DC129 /* IntlListFormatConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlListFormatConstructor.h; sourceTree = "<group>"; };
+		E318CA66254406B4004DC129 /* IntlListFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlListFormat.h; sourceTree = "<group>"; };
+		E318CA67254406B5004DC129 /* IntlListFormatPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlListFormatPrototype.h; sourceTree = "<group>"; };
+		E318CA68254406B5004DC129 /* IntlListFormatPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntlListFormatPrototype.cpp; sourceTree = "<group>"; };
+		E318CA69254406B5004DC129 /* IntlListFormat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntlListFormat.cpp; sourceTree = "<group>"; };
+		E318CA6A254406B5004DC129 /* IntlListFormatConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntlListFormatConstructor.cpp; sourceTree = "<group>"; };
 		E318CBBE1B8AEF5100A2929D /* JSModuleNamespaceObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSModuleNamespaceObject.cpp; sourceTree = "<group>"; };
 		E318CBBF1B8AEF5100A2929D /* JSModuleNamespaceObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSModuleNamespaceObject.h; sourceTree = "<group>"; };
 		E31C31302511AFD600E7A3A0 /* IntlCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlCache.h; sourceTree = "<group>"; };
@@ -7332,6 +7342,12 @@
 				E353C11824AA4CB6003FBDF3 /* IntlDisplayNamesConstructor.h */,
 				E353C11924AA4CB6003FBDF3 /* IntlDisplayNamesPrototype.cpp */,
 				E353C11B24AA4CB7003FBDF3 /* IntlDisplayNamesPrototype.h */,
+				E318CA69254406B5004DC129 /* IntlListFormat.cpp */,
+				E318CA66254406B4004DC129 /* IntlListFormat.h */,
+				E318CA6A254406B5004DC129 /* IntlListFormatConstructor.cpp */,
+				E318CA65254406B4004DC129 /* IntlListFormatConstructor.h */,
+				E318CA68254406B5004DC129 /* IntlListFormatPrototype.cpp */,
+				E318CA67254406B5004DC129 /* IntlListFormatPrototype.h */,
 				A3AFF92D245A3CFA00C9BA3B /* IntlLocale.cpp */,
 				A3AFF92B245A3CF900C9BA3B /* IntlLocale.h */,
 				A3AFF92F245A3CFB00C9BA3B /* IntlLocaleConstructor.cpp */,
@@ -9845,6 +9861,9 @@
 				E365F33A24AA623900C991B2 /* IntlDisplayNamesConstructor.lut.h in Headers */,
 				E353C12124AA4CB7003FBDF3 /* IntlDisplayNamesPrototype.h in Headers */,
 				E365F33B24AA623B00C991B2 /* IntlDisplayNamesPrototype.lut.h in Headers */,
+				E318CA6C254406B6004DC129 /* IntlListFormat.h in Headers */,
+				E318CA6B254406B6004DC129 /* IntlListFormatConstructor.h in Headers */,
+				E318CA6D254406B6004DC129 /* IntlListFormatPrototype.h in Headers */,
 				E307178E24C7829D00DF0644 /* IntlLocale.h in Headers */,
 				E307178D24C7829A00DF0644 /* IntlLocaleConstructor.h in Headers */,
 				E307178C24C7829800DF0644 /* IntlLocalePrototype.h in Headers */,
@@ -11349,6 +11368,7 @@
 				5333BBDD2110F7E1007618EC /* DFGSpeculativeJIT64.cpp in Sources */,
 				33B2A548226543BF005A0F79 /* FTLLowerDFGToB3.cpp in Sources */,
 				5C4196622270E0000047B7CD /* InspectorBackendDispatcherCompatibility.cpp in Sources */,
+				E366441E254409B30001876F /* IntlListFormat.cpp in Sources */,
 				536B319E1F735F160037FC33 /* LowLevelInterpreter.cpp in Sources */,
 				0FF4274A158EBE91004CB9FF /* udis86.c in Sources */,
 				0FF42740158EBE8B004CB9FF /* udis86_decode.c in Sources */,

Modified: trunk/Source/_javascript_Core/Sources.txt (268955 => 268956)


--- trunk/Source/_javascript_Core/Sources.txt	2020-10-25 04:27:10 UTC (rev 268955)
+++ trunk/Source/_javascript_Core/Sources.txt	2020-10-25 06:20:47 UTC (rev 268956)
@@ -819,6 +819,10 @@
 runtime/IntlDisplayNames.cpp
 runtime/IntlDisplayNamesConstructor.cpp
 runtime/IntlDisplayNamesPrototype.cpp
+// Confine U_HIDE_DRAFT_API's effect in this file.
+runtime/IntlListFormat.cpp @no-unify
+runtime/IntlListFormatConstructor.cpp
+runtime/IntlListFormatPrototype.cpp
 runtime/IntlLocale.cpp
 runtime/IntlLocaleConstructor.cpp
 runtime/IntlLocalePrototype.cpp

Modified: trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h (268955 => 268956)


--- trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h	2020-10-25 04:27:10 UTC (rev 268955)
+++ trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h	2020-10-25 06:20:47 UTC (rev 268956)
@@ -41,6 +41,7 @@
     macro(Function) \
     macro(Infinity) \
     macro(Intl) \
+    macro(ListFormat) \
     macro(Loader) \
     macro(Locale) \
     macro(Map) \

Modified: trunk/Source/_javascript_Core/runtime/IntlDisplayNames.cpp (268955 => 268956)


--- trunk/Source/_javascript_Core/runtime/IntlDisplayNames.cpp	2020-10-25 04:27:10 UTC (rev 268955)
+++ trunk/Source/_javascript_Core/runtime/IntlDisplayNames.cpp	2020-10-25 06:20:47 UTC (rev 268956)
@@ -83,12 +83,12 @@
         return { };
     };
 
-    auto& availableLocales = intlNumberFormatAvailableLocales();
+    auto& availableLocales = intlDisplayNamesAvailableLocales();
     auto resolved = resolveLocale(globalObject, availableLocales, requestedLocales, localeMatcher, localeOptions, { }, localeData);
 
     m_locale = resolved.locale;
     if (m_locale.isEmpty()) {
-        throwTypeError(globalObject, scope, "failed to initialize DisplayName due to invalid locale"_s);
+        throwTypeError(globalObject, scope, "failed to initialize DisplayNames due to invalid locale"_s);
         return;
     }
 

Added: trunk/Source/_javascript_Core/runtime/IntlListFormat.cpp (0 => 268956)


--- trunk/Source/_javascript_Core/runtime/IntlListFormat.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlListFormat.cpp	2020-10-25 06:20:47 UTC (rev 268956)
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IntlListFormat.h"
+
+#include "IntlObjectInlines.h"
+#include "IteratorOperations.h"
+#include "JSCInlines.h"
+#include "ObjectConstructor.h"
+
+// While UListFormatter APIs are draft in ICU 67, they are stable in ICU 68 with the same function signatures.
+// So we can assume that these signatures of draft APIs are stable.
+#if HAVE(ICU_U_LIST_FORMATTER)
+#ifdef U_HIDE_DRAFT_API
+#undef U_HIDE_DRAFT_API
+#endif
+#endif
+#include <unicode/ulistformatter.h>
+#if HAVE(ICU_U_LIST_FORMATTER)
+#define U_HIDE_DRAFT_API 1
+#endif
+
+#if HAVE(ICU_U_LIST_FORMATTER)
+#include <unicode/uformattedvalue.h>
+#endif
+
+namespace JSC {
+
+const ClassInfo IntlListFormat::s_info = { "Object", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(IntlListFormat) };
+
+// We do not use ICUDeleter<ulistfmt_close> because we do not want to include ulistformatter.h in IntlListFormat.h.
+// ulistformatter.h needs to be included with #undef U_HIDE_DRAFT_API, and we would like to minimize this effect in IntlListFormat.cpp.
+void UListFormatterDeleter::operator()(UListFormatter* formatter)
+{
+    if (formatter)
+        ulistfmt_close(formatter);
+}
+
+IntlListFormat* IntlListFormat::create(VM& vm, Structure* structure)
+{
+    auto* object = new (NotNull, allocateCell<IntlListFormat>(vm.heap)) IntlListFormat(vm, structure);
+    object->finishCreation(vm);
+    return object;
+}
+
+Structure* IntlListFormat::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+    return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+IntlListFormat::IntlListFormat(VM& vm, Structure* structure)
+    : Base(vm, structure)
+{
+}
+
+void IntlListFormat::finishCreation(VM& vm)
+{
+    Base::finishCreation(vm);
+    ASSERT(inherits(vm, info()));
+}
+
+// https://tc39.es/proposal-intl-list-format/#sec-Intl.ListFormat
+void IntlListFormat::initializeListFormat(JSGlobalObject* globalObject, JSValue locales, JSValue optionsValue)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto requestedLocales = canonicalizeLocaleList(globalObject, locales);
+    RETURN_IF_EXCEPTION(scope, void());
+
+    JSObject* options;
+    if (optionsValue.isUndefined())
+        options = constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
+    else {
+        options = optionsValue.toObject(globalObject);
+        RETURN_IF_EXCEPTION(scope, void());
+    }
+
+    ResolveLocaleOptions localeOptions;
+
+    LocaleMatcher localeMatcher = intlOption<LocaleMatcher>(globalObject, options, vm.propertyNames->localeMatcher, { { "lookup"_s, LocaleMatcher::Lookup }, { "best fit"_s, LocaleMatcher::BestFit } }, "localeMatcher must be either \"lookup\" or \"best fit\""_s, LocaleMatcher::BestFit);
+    RETURN_IF_EXCEPTION(scope, void());
+
+    auto localeData = [](const String&, RelevantExtensionKey) -> Vector<String> {
+        return { };
+    };
+
+    auto& availableLocales = intlListFormatAvailableLocales();
+    auto resolved = resolveLocale(globalObject, availableLocales, requestedLocales, localeMatcher, localeOptions, { }, localeData);
+
+    m_locale = resolved.locale;
+    if (m_locale.isEmpty()) {
+        throwTypeError(globalObject, scope, "failed to initialize ListFormat due to invalid locale"_s);
+        return;
+    }
+
+    m_type = intlOption<Type>(globalObject, options, vm.propertyNames->type, { { "conjunction"_s, Type::Conjunction }, { "disjunction"_s, Type::Disjunction }, { "unit"_s, Type::Unit } }, "type must be either \"conjunction\", \"disjunction\", or \"unit\""_s, Type::Conjunction);
+    RETURN_IF_EXCEPTION(scope, void());
+
+    m_style = intlOption<Style>(globalObject, options, vm.propertyNames->style, { { "long"_s, Style::Long }, { "short"_s, Style::Short }, { "narrow"_s, Style::Narrow } }, "style must be either \"long\", \"short\", or \"narrow\""_s, Style::Long);
+    RETURN_IF_EXCEPTION(scope, void());
+
+#if HAVE(ICU_U_LIST_FORMATTER)
+    auto toUListFormatterType = [](Type type) {
+        switch (type) {
+        case Type::Conjunction:
+            return ULISTFMT_TYPE_AND;
+        case Type::Disjunction:
+            return ULISTFMT_TYPE_OR;
+        case Type::Unit:
+            return ULISTFMT_TYPE_UNITS;
+        }
+        return ULISTFMT_TYPE_AND;
+    };
+
+    auto toUListFormatterWidth = [](Style style) {
+        switch (style) {
+        case Style::Long:
+            return ULISTFMT_WIDTH_WIDE;
+        case Style::Short:
+            return ULISTFMT_WIDTH_SHORT;
+        case Style::Narrow:
+            return ULISTFMT_WIDTH_NARROW;
+        }
+        return ULISTFMT_WIDTH_WIDE;
+    };
+
+    UErrorCode status = U_ZERO_ERROR;
+    m_listFormat = std::unique_ptr<UListFormatter, UListFormatterDeleter>(ulistfmt_openForType(m_locale.utf8().data(), toUListFormatterType(m_type), toUListFormatterWidth(m_style), &status));
+    if (U_FAILURE(status)) {
+        throwTypeError(globalObject, scope, "failed to initialize ListFormat"_s);
+        return;
+    }
+#else
+    throwTypeError(globalObject, scope, "Failed to initialize Intl.ListFormat since this feature is not supported in the linked ICU version"_s);
+    return;
+#endif
+}
+
+#if HAVE(ICU_U_LIST_FORMATTER)
+static Vector<String, 4> stringListFromIterable(JSGlobalObject* globalObject, JSValue iterable)
+{
+    Vector<String, 4> result;
+
+    if (iterable.isUndefined())
+        return result;
+
+    forEachInIterable(globalObject, iterable, [&](VM& vm, JSGlobalObject* globalObject, JSValue value) {
+        auto scope = DECLARE_THROW_SCOPE(vm);
+        if (!value.isString()) {
+            throwTypeError(globalObject, scope, "Iterable passed to ListFormat includes non String"_s);
+            return;
+        }
+        String item = value.toWTFString(globalObject);
+        RETURN_IF_EXCEPTION(scope, void());
+        result.append(item);
+    });
+    return result;
+}
+
+class ListFormatInput {
+    WTF_MAKE_NONCOPYABLE(ListFormatInput);
+public:
+    ListFormatInput(Vector<String, 4>&& strings)
+        : m_strings(WTFMove(strings))
+    {
+        m_stringPointers.reserveInitialCapacity(m_strings.size());
+        m_stringLengths.reserveInitialCapacity(m_strings.size());
+        for (auto& string : m_strings) {
+            if (string.is8Bit()) {
+                auto vector = makeUnique<Vector<UChar>>();
+                vector->resize(string.length());
+                StringImpl::copyCharacters(vector->data(), string.characters8(), string.length());
+                m_retainedUpconvertedStrings.append(WTFMove(vector));
+                m_stringPointers.append(m_retainedUpconvertedStrings.last()->data());
+            } else
+                m_stringPointers.append(string.characters16());
+            m_stringLengths.append(string.length());
+        }
+    }
+
+    int32_t size() const { return m_stringPointers.size(); }
+    const UChar* const* stringPointers() const { return m_stringPointers.data(); }
+    const int32_t* stringLengths() const { return m_stringLengths.data(); }
+
+private:
+    Vector<String, 4> m_strings;
+    Vector<std::unique_ptr<Vector<UChar>>, 4> m_retainedUpconvertedStrings;
+    Vector<const UChar*, 4> m_stringPointers;
+    Vector<int32_t, 4> m_stringLengths;
+};
+#endif
+
+// https://tc39.es/proposal-intl-list-format/#sec-Intl.ListFormat.prototype.format
+JSValue IntlListFormat::format(JSGlobalObject* globalObject, JSValue list) const
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+#if HAVE(ICU_U_LIST_FORMATTER)
+    auto stringList = stringListFromIterable(globalObject, list);
+    RETURN_IF_EXCEPTION(scope, { });
+
+    ListFormatInput input(WTFMove(stringList));
+
+    Vector<UChar, 32> result;
+    auto status = callBufferProducingFunction(ulistfmt_format, m_listFormat.get(), input.stringPointers(), input.stringLengths(), input.size(), result);
+    if (U_FAILURE(status))
+        return throwTypeError(globalObject, scope, "failed to format list of strings"_s);
+
+    return jsString(vm, String(result));
+#else
+    UNUSED_PARAM(list);
+    return throwTypeError(globalObject, scope, "failed to format list of strings"_s);
+#endif
+}
+
+// https://tc39.es/proposal-intl-list-format/#sec-Intl.ListFormat.prototype.formatToParts
+JSValue IntlListFormat::formatToParts(JSGlobalObject* globalObject, JSValue list) const
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+#if HAVE(ICU_U_LIST_FORMATTER)
+    auto stringList = stringListFromIterable(globalObject, list);
+    RETURN_IF_EXCEPTION(scope, { });
+
+    ListFormatInput input(WTFMove(stringList));
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    auto result = std::unique_ptr<UFormattedList, ICUDeleter<ulistfmt_closeResult>>(ulistfmt_openResult(&status));
+    if (U_FAILURE(status))
+        return throwTypeError(globalObject, scope, "failed to format list of strings"_s);
+
+    ulistfmt_formatStringsToResult(m_listFormat.get(), input.stringPointers(), input.stringLengths(), input.size(), result.get(), &status);
+    if (U_FAILURE(status))
+        return throwTypeError(globalObject, scope, "failed to format list of strings"_s);
+
+    // UFormattedValue is owned by UFormattedList. We do not need to close it.
+    auto formattedValue = ulistfmt_resultAsValue(result.get(), &status);
+    if (U_FAILURE(status))
+        return throwTypeError(globalObject, scope, "failed to format list of strings"_s);
+
+    JSArray* parts = JSArray::tryCreate(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), 0);
+    if (!parts)
+        return throwOutOfMemoryError(globalObject, scope);
+
+    int32_t formattedStringLength = 0;
+    const UChar* formattedStringPointer = ufmtval_getString(formattedValue, &formattedStringLength, &status);
+    if (U_FAILURE(status))
+        return throwTypeError(globalObject, scope, "failed to format list of strings"_s);
+    String resultString(formattedStringPointer, formattedStringLength);
+
+    auto iterator = std::unique_ptr<UConstrainedFieldPosition, ICUDeleter<ucfpos_close>>(ucfpos_open(&status));
+    if (U_FAILURE(status))
+        return throwTypeError(globalObject, scope, "failed to format list of strings"_s);
+
+    ucfpos_constrainField(iterator.get(), UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, &status);
+    if (U_FAILURE(status))
+        return throwTypeError(globalObject, scope, "failed to format list of strings"_s);
+
+    auto literalString = jsNontrivialString(vm, "literal"_s);
+    auto elementString = jsNontrivialString(vm, "element"_s);
+
+    auto createPart = [&] (JSString* type, JSString* value) {
+        JSObject* part = constructEmptyObject(globalObject);
+        part->putDirect(vm, vm.propertyNames->type, type);
+        part->putDirect(vm, vm.propertyNames->value, value);
+        return part;
+    };
+
+    int32_t resultLength = resultString.length();
+    int32_t previousEndIndex = 0;
+    while (true) {
+        bool next = ufmtval_nextPosition(formattedValue, iterator.get(), &status);
+        if (U_FAILURE(status))
+            return throwTypeError(globalObject, scope, "failed to format list of strings"_s);
+        if (!next)
+            break;
+
+        int32_t beginIndex = 0;
+        int32_t endIndex = 0;
+        ucfpos_getIndexes(iterator.get(), &beginIndex, &endIndex, &status);
+        if (U_FAILURE(status))
+            return throwTypeError(globalObject, scope, "failed to format list of strings"_s);
+
+        if (previousEndIndex < beginIndex) {
+            auto value = jsString(vm, resultString.substring(previousEndIndex, beginIndex - previousEndIndex));
+            JSObject* part = createPart(literalString, value);
+            parts->push(globalObject, part);
+            RETURN_IF_EXCEPTION(scope, { });
+        }
+        previousEndIndex = endIndex;
+
+        auto value = jsString(vm, resultString.substring(beginIndex, endIndex - beginIndex));
+        JSObject* part = createPart(elementString, value);
+        parts->push(globalObject, part);
+        RETURN_IF_EXCEPTION(scope, { });
+    }
+
+    if (previousEndIndex < resultLength) {
+        auto value = jsString(vm, resultString.substring(previousEndIndex, resultLength - previousEndIndex));
+        JSObject* part = createPart(literalString, value);
+        parts->push(globalObject, part);
+        RETURN_IF_EXCEPTION(scope, { });
+    }
+
+    return parts;
+#else
+    UNUSED_PARAM(list);
+    return throwTypeError(globalObject, scope, "failed to format list of strings"_s);
+#endif
+}
+
+// https://tc39.es/proposal-intl-list-format/#sec-Intl.ListFormat.prototype.resolvedOptions
+JSObject* IntlListFormat::resolvedOptions(JSGlobalObject* globalObject) const
+{
+    VM& vm = globalObject->vm();
+    JSObject* options = constructEmptyObject(globalObject);
+    options->putDirect(vm, vm.propertyNames->locale, jsString(vm, m_locale));
+    options->putDirect(vm, vm.propertyNames->type, jsNontrivialString(vm, typeString(m_type)));
+    options->putDirect(vm, vm.propertyNames->style, jsNontrivialString(vm, styleString(m_style)));
+    return options;
+}
+
+ASCIILiteral IntlListFormat::styleString(Style style)
+{
+    switch (style) {
+    case Style::Long:
+        return "long"_s;
+    case Style::Short:
+        return "short"_s;
+    case Style::Narrow:
+        return "narrow"_s;
+    }
+    ASSERT_NOT_REACHED();
+    return ASCIILiteral::null();
+}
+
+ASCIILiteral IntlListFormat::typeString(Type type)
+{
+    switch (type) {
+    case Type::Conjunction:
+        return "conjunction"_s;
+    case Type::Disjunction:
+        return "disjunction"_s;
+    case Type::Unit:
+        return "unit"_s;
+    }
+    ASSERT_NOT_REACHED();
+    return ASCIILiteral::null();
+}
+
+} // namespace JSC

Added: trunk/Source/_javascript_Core/runtime/IntlListFormat.h (0 => 268956)


--- trunk/Source/_javascript_Core/runtime/IntlListFormat.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlListFormat.h	2020-10-25 06:20:47 UTC (rev 268956)
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "JSObject.h"
+#include <wtf/unicode/icu/ICUHelpers.h>
+
+#if !defined(HAVE_ICU_U_LIST_FORMATTER)
+#if U_ICU_VERSION_MAJOR_NUM >= 67 || (U_ICU_VERSION_MAJOR_NUM >= 66 && USE(APPLE_INTERNAL_SDK))
+#define HAVE_ICU_U_LIST_FORMATTER 1
+#endif
+#endif
+
+struct UListFormatter;
+
+namespace JSC {
+
+enum class RelevantExtensionKey : uint8_t;
+
+struct UListFormatterDeleter {
+    JS_EXPORT_PRIVATE void operator()(UListFormatter*);
+};
+
+class IntlListFormat final : public JSNonFinalObject {
+public:
+    using Base = JSNonFinalObject;
+
+    static constexpr bool needsDestruction = true;
+
+    static void destroy(JSCell* cell)
+    {
+        static_cast<IntlListFormat*>(cell)->IntlListFormat::~IntlListFormat();
+    }
+
+    template<typename CellType, SubspaceAccess mode>
+    static IsoSubspace* subspaceFor(VM& vm)
+    {
+        return vm.intlListFormatSpace<mode>();
+    }
+
+    static IntlListFormat* create(VM&, Structure*);
+    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+    DECLARE_INFO;
+
+    void initializeListFormat(JSGlobalObject*, JSValue localesValue, JSValue optionsValue);
+
+    JSValue format(JSGlobalObject*, JSValue) const;
+    JSValue formatToParts(JSGlobalObject*, JSValue) const;
+    JSObject* resolvedOptions(JSGlobalObject*) const;
+
+private:
+    IntlListFormat(VM&, Structure*);
+    void finishCreation(VM&);
+
+    enum class Type : uint8_t { Conjunction, Disjunction, Unit };
+    enum class Style : uint8_t { Short, Long, Narrow };
+
+    static ASCIILiteral typeString(Type);
+    static ASCIILiteral styleString(Style);
+
+    std::unique_ptr<UListFormatter, UListFormatterDeleter> m_listFormat;
+    String m_locale;
+    Type m_type { Type::Conjunction };
+    Style m_style { Style::Long };
+};
+
+} // namespace JSC

Added: trunk/Source/_javascript_Core/runtime/IntlListFormatConstructor.cpp (0 => 268956)


--- trunk/Source/_javascript_Core/runtime/IntlListFormatConstructor.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlListFormatConstructor.cpp	2020-10-25 06:20:47 UTC (rev 268956)
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IntlListFormatConstructor.h"
+
+#include "IntlListFormat.h"
+#include "IntlListFormatPrototype.h"
+#include "JSCInlines.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IntlListFormatConstructor);
+
+static JSC_DECLARE_HOST_FUNCTION(IntlListFormatConstructorSupportedLocalesOf);
+
+}
+
+#include "IntlListFormatConstructor.lut.h"
+
+namespace JSC {
+
+const ClassInfo IntlListFormatConstructor::s_info = { "Function", &Base::s_info, &listFormatConstructorTable, nullptr, CREATE_METHOD_TABLE(IntlListFormatConstructor) };
+
+/* Source for IntlListFormatConstructor.lut.h
+@begin listFormatConstructorTable
+  supportedLocalesOf             IntlListFormatConstructorSupportedLocalesOf             DontEnum|Function 1
+@end
+*/
+
+IntlListFormatConstructor* IntlListFormatConstructor::create(VM& vm, Structure* structure, IntlListFormatPrototype* listFormatPrototype)
+{
+    auto* constructor = new (NotNull, allocateCell<IntlListFormatConstructor>(vm.heap)) IntlListFormatConstructor(vm, structure);
+    constructor->finishCreation(vm, listFormatPrototype);
+    return constructor;
+}
+
+Structure* IntlListFormatConstructor::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+    return Structure::create(vm, globalObject, prototype, TypeInfo(InternalFunctionType, StructureFlags), info());
+}
+
+static JSC_DECLARE_HOST_FUNCTION(callIntlListFormat);
+static JSC_DECLARE_HOST_FUNCTION(constructIntlListFormat);
+
+IntlListFormatConstructor::IntlListFormatConstructor(VM& vm, Structure* structure)
+    : Base(vm, structure, callIntlListFormat, constructIntlListFormat)
+{
+}
+
+void IntlListFormatConstructor::finishCreation(VM& vm, IntlListFormatPrototype* listFormatPrototype)
+{
+    Base::finishCreation(vm, 0, "ListFormat"_s, PropertyAdditionMode::WithoutStructureTransition);
+    putDirectWithoutTransition(vm, vm.propertyNames->prototype, listFormatPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
+    listFormatPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, this, static_cast<unsigned>(PropertyAttribute::DontEnum));
+}
+
+// https://tc39.es/proposal-intl-list-format/#sec-Intl.ListFormat
+JSC_DEFINE_HOST_FUNCTION(constructIntlListFormat, (JSGlobalObject* globalObject, CallFrame* callFrame))
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    JSObject* newTarget = asObject(callFrame->newTarget());
+    Structure* structure = newTarget == callFrame->jsCallee()
+        ? globalObject->listFormatStructure()
+        : InternalFunction::createSubclassStructure(globalObject, newTarget, getFunctionRealm(vm, newTarget)->listFormatStructure());
+    RETURN_IF_EXCEPTION(scope, { });
+
+    IntlListFormat* listFormat = IntlListFormat::create(vm, structure);
+    ASSERT(listFormat);
+
+    scope.release();
+    listFormat->initializeListFormat(globalObject, callFrame->argument(0), callFrame->argument(1));
+    return JSValue::encode(listFormat);
+}
+
+// https://tc39.es/proposal-intl-list-format/#sec-Intl.ListFormat
+JSC_DEFINE_HOST_FUNCTION(callIntlListFormat, (JSGlobalObject* globalObject, CallFrame*))
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    return JSValue::encode(throwConstructorCannotBeCalledAsFunctionTypeError(globalObject, scope, "ListFormat"));
+}
+
+JSC_DEFINE_HOST_FUNCTION(IntlListFormatConstructorSupportedLocalesOf, (JSGlobalObject* globalObject, CallFrame* callFrame))
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    // Intl.ListFormat.supportedLocalesOf(locales [, options])
+    // https://tc39.es/proposal-intl-list-format/#sec-Intl.ListFormat.supportedLocalesOf
+
+    // 1. Let availableLocales be %ListFormat%.[[availableLocales]].
+    const HashSet<String>& availableLocales = intlListFormatAvailableLocales();
+
+    // 2. Let requestedLocales be CanonicalizeLocaleList(locales).
+    Vector<String> requestedLocales = canonicalizeLocaleList(globalObject, callFrame->argument(0));
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+    // 3. Return SupportedLocales(availableLocales, requestedLocales, options).
+    RELEASE_AND_RETURN(scope, JSValue::encode(supportedLocales(globalObject, availableLocales, requestedLocales, callFrame->argument(1))));
+}
+
+
+} // namespace JSC

Added: trunk/Source/_javascript_Core/runtime/IntlListFormatConstructor.h (0 => 268956)


--- trunk/Source/_javascript_Core/runtime/IntlListFormatConstructor.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlListFormatConstructor.h	2020-10-25 06:20:47 UTC (rev 268956)
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "InternalFunction.h"
+#include "IntlObject.h"
+
+namespace JSC {
+
+class IntlListFormatPrototype;
+
+class IntlListFormatConstructor final : public InternalFunction {
+public:
+    using Base = InternalFunction;
+    static constexpr unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable;
+
+    static IntlListFormatConstructor* create(VM&, Structure*, IntlListFormatPrototype*);
+    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+    DECLARE_INFO;
+
+private:
+    IntlListFormatConstructor(VM&, Structure*);
+    void finishCreation(VM&, IntlListFormatPrototype*);
+};
+STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(IntlListFormatConstructor, InternalFunction);
+
+} // namespace JSC

Added: trunk/Source/_javascript_Core/runtime/IntlListFormatPrototype.cpp (0 => 268956)


--- trunk/Source/_javascript_Core/runtime/IntlListFormatPrototype.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlListFormatPrototype.cpp	2020-10-25 06:20:47 UTC (rev 268956)
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IntlListFormatPrototype.h"
+
+#include "IntlListFormat.h"
+#include "JSCInlines.h"
+
+namespace JSC {
+
+static JSC_DECLARE_HOST_FUNCTION(IntlListFormatPrototypeFuncFormat);
+static JSC_DECLARE_HOST_FUNCTION(IntlListFormatPrototypeFuncFormatToParts);
+static JSC_DECLARE_HOST_FUNCTION(IntlListFormatPrototypeFuncResolvedOptions);
+
+}
+
+#include "IntlListFormatPrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo IntlListFormatPrototype::s_info = { "Intl.ListFormat", &Base::s_info, &listFormatPrototypeTable, nullptr, CREATE_METHOD_TABLE(IntlListFormatPrototype) };
+
+/* Source for IntlListFormatPrototype.lut.h
+@begin listFormatPrototypeTable
+  format           IntlListFormatPrototypeFuncFormat             DontEnum|Function 1
+  formatToParts    IntlListFormatPrototypeFuncFormatToParts      DontEnum|Function 1
+  resolvedOptions  IntlListFormatPrototypeFuncResolvedOptions    DontEnum|Function 0
+@end
+*/
+
+IntlListFormatPrototype* IntlListFormatPrototype::create(VM& vm, Structure* structure)
+{
+    auto* object = new (NotNull, allocateCell<IntlListFormatPrototype>(vm.heap)) IntlListFormatPrototype(vm, structure);
+    object->finishCreation(vm);
+    return object;
+}
+
+Structure* IntlListFormatPrototype::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+    return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+IntlListFormatPrototype::IntlListFormatPrototype(VM& vm, Structure* structure)
+    : Base(vm, structure)
+{
+}
+
+void IntlListFormatPrototype::finishCreation(VM& vm)
+{
+    Base::finishCreation(vm);
+    ASSERT(inherits(vm, info()));
+    JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
+}
+
+// https://tc39.es/proposal-intl-list-format/#sec-Intl.ListFormat.prototype.format
+JSC_DEFINE_HOST_FUNCTION(IntlListFormatPrototypeFuncFormat, (JSGlobalObject* globalObject, CallFrame* callFrame))
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* listFormat = jsDynamicCast<IntlListFormat*>(vm, callFrame->thisValue());
+    if (!listFormat)
+        return throwVMTypeError(globalObject, scope, "Intl.ListFormat.prototype.format called on value that's not an object initialized as a ListFormat"_s);
+
+    RELEASE_AND_RETURN(scope, JSValue::encode(listFormat->format(globalObject, callFrame->argument(0))));
+}
+
+// https://tc39.es/proposal-intl-list-format/#sec-Intl.ListFormat.prototype.formatToParts
+JSC_DEFINE_HOST_FUNCTION(IntlListFormatPrototypeFuncFormatToParts, (JSGlobalObject* globalObject, CallFrame* callFrame))
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* listFormat = jsDynamicCast<IntlListFormat*>(vm, callFrame->thisValue());
+    if (!listFormat)
+        return throwVMTypeError(globalObject, scope, "Intl.ListFormat.prototype.formatToParts called on value that's not an object initialized as a ListFormat"_s);
+
+    RELEASE_AND_RETURN(scope, JSValue::encode(listFormat->formatToParts(globalObject, callFrame->argument(0))));
+}
+
+// https://tc39.es/proposal-intl-list-format/#sec-Intl.ListFormat.prototype.resolvedOptions
+JSC_DEFINE_HOST_FUNCTION(IntlListFormatPrototypeFuncResolvedOptions, (JSGlobalObject* globalObject, CallFrame* callFrame))
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* listFormat = jsDynamicCast<IntlListFormat*>(vm, callFrame->thisValue());
+    if (!listFormat)
+        return throwVMTypeError(globalObject, scope, "Intl.ListFormat.prototype.resolvedOptions called on value that's not an object initialized as a ListFormat"_s);
+
+    RELEASE_AND_RETURN(scope, JSValue::encode(listFormat->resolvedOptions(globalObject)));
+}
+
+} // namespace JSC

Added: trunk/Source/_javascript_Core/runtime/IntlListFormatPrototype.h (0 => 268956)


--- trunk/Source/_javascript_Core/runtime/IntlListFormatPrototype.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlListFormatPrototype.h	2020-10-25 06:20:47 UTC (rev 268956)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class IntlListFormatPrototype final : public JSNonFinalObject {
+public:
+    using Base = JSNonFinalObject;
+    static constexpr unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable;
+
+    template<typename CellType, SubspaceAccess>
+    static IsoSubspace* subspaceFor(VM& vm)
+    {
+        STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(IntlListFormatPrototype, Base);
+        return &vm.plainObjectSpace;
+    }
+
+    static IntlListFormatPrototype* create(VM&, Structure*);
+    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+    DECLARE_INFO;
+
+private:
+    IntlListFormatPrototype(VM&, Structure*);
+    void finishCreation(VM&);
+};
+
+} // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/IntlObject.cpp (268955 => 268956)


--- trunk/Source/_javascript_Core/runtime/IntlObject.cpp	2020-10-25 04:27:10 UTC (rev 268955)
+++ trunk/Source/_javascript_Core/runtime/IntlObject.cpp	2020-10-25 06:20:47 UTC (rev 268956)
@@ -39,6 +39,9 @@
 #include "IntlDisplayNames.h"
 #include "IntlDisplayNamesConstructor.h"
 #include "IntlDisplayNamesPrototype.h"
+#include "IntlListFormat.h"
+#include "IntlListFormatConstructor.h"
+#include "IntlListFormatPrototype.h"
 #include "IntlLocale.h"
 #include "IntlLocaleConstructor.h"
 #include "IntlLocalePrototype.h"
@@ -93,6 +96,13 @@
     return IntlDisplayNamesConstructor::create(vm, IntlDisplayNamesConstructor::createStructure(vm, globalObject, globalObject->functionPrototype()), jsCast<IntlDisplayNamesPrototype*>(globalObject->displayNamesStructure()->storedPrototypeObject()));
 }
 
+static JSValue createListFormatConstructor(VM& vm, JSObject* object)
+{
+    IntlObject* intlObject = jsCast<IntlObject*>(object);
+    JSGlobalObject* globalObject = intlObject->globalObject(vm);
+    return IntlListFormatConstructor::create(vm, IntlListFormatConstructor::createStructure(vm, globalObject, globalObject->functionPrototype()), jsCast<IntlListFormatPrototype*>(globalObject->listFormatStructure()->storedPrototypeObject()));
+}
+
 static JSValue createLocaleConstructor(VM& vm, JSObject* object)
 {
     IntlObject* intlObject = jsCast<IntlObject*>(object);
@@ -181,8 +191,13 @@
 #if HAVE(ICU_U_LOCALE_DISPLAY_NAMES)
     putDirectWithoutTransition(vm, vm.propertyNames->DisplayNames, createDisplayNamesConstructor(vm, this), static_cast<unsigned>(PropertyAttribute::DontEnum));
 #else
-    UNUSED_PARAM(createDisplayNamesConstructor);
+    UNUSED_PARAM(&createDisplayNamesConstructor);
 #endif
+#if HAVE(ICU_U_LIST_FORMATTER)
+    putDirectWithoutTransition(vm, vm.propertyNames->ListFormat, createListFormatConstructor(vm, this), static_cast<unsigned>(PropertyAttribute::DontEnum));
+#else
+    UNUSED_PARAM(&createListFormatConstructor);
+#endif
 }
 
 Structure* IntlObject::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)

Modified: trunk/Source/_javascript_Core/runtime/IntlObject.h (268955 => 268956)


--- trunk/Source/_javascript_Core/runtime/IntlObject.h	2020-10-25 04:27:10 UTC (rev 268955)
+++ trunk/Source/_javascript_Core/runtime/IntlObject.h	2020-10-25 06:20:47 UTC (rev 268956)
@@ -89,6 +89,7 @@
 inline const HashSet<String>& intlNumberFormatAvailableLocales() { return intlAvailableLocales(); }
 inline const HashSet<String>& intlPluralRulesAvailableLocales() { return intlAvailableLocales(); }
 inline const HashSet<String>& intlRelativeTimeFormatAvailableLocales() { return intlAvailableLocales(); }
+inline const HashSet<String>& intlListFormatAvailableLocales() { return intlAvailableLocales(); }
 
 TriState intlBooleanOption(JSGlobalObject*, JSValue options, PropertyName);
 String intlStringOption(JSGlobalObject*, JSValue options, PropertyName, std::initializer_list<const char*> values, const char* notFound, const char* fallback);

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (268955 => 268956)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2020-10-25 04:27:10 UTC (rev 268955)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2020-10-25 06:20:47 UTC (rev 268956)
@@ -78,6 +78,8 @@
 #include "IntlDateTimeFormatPrototype.h"
 #include "IntlDisplayNames.h"
 #include "IntlDisplayNamesPrototype.h"
+#include "IntlListFormat.h"
+#include "IntlListFormatPrototype.h"
 #include "IntlLocale.h"
 #include "IntlLocalePrototype.h"
 #include "IntlNumberFormat.h"
@@ -1022,6 +1024,12 @@
             IntlDisplayNamesPrototype* displayNamesPrototype = IntlDisplayNamesPrototype::create(init.vm, IntlDisplayNamesPrototype::createStructure(init.vm, globalObject, globalObject->objectPrototype()));
             init.set(IntlDisplayNames::createStructure(init.vm, globalObject, displayNamesPrototype));
         });
+    m_listFormatStructure.initLater(
+        [] (const Initializer<Structure>& init) {
+            JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner);
+            IntlListFormatPrototype* listFormatPrototype = IntlListFormatPrototype::create(init.vm, IntlListFormatPrototype::createStructure(init.vm, globalObject, globalObject->objectPrototype()));
+            init.set(IntlListFormat::createStructure(init.vm, globalObject, listFormatPrototype));
+        });
     m_localeStructure.initLater(
         [] (const Initializer<Structure>& init) {
             JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner);
@@ -1910,6 +1918,7 @@
     thisObject->m_defaultCollator.visit(visitor);
     thisObject->m_collatorStructure.visit(visitor);
     thisObject->m_displayNamesStructure.visit(visitor);
+    thisObject->m_listFormatStructure.visit(visitor);
     thisObject->m_localeStructure.visit(visitor);
     thisObject->m_pluralRulesStructure.visit(visitor);
     thisObject->m_relativeTimeFormatStructure.visit(visitor);

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (268955 => 268956)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2020-10-25 04:27:10 UTC (rev 268955)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2020-10-25 06:20:47 UTC (rev 268956)
@@ -310,6 +310,7 @@
     LazyProperty<JSGlobalObject, IntlCollator> m_defaultCollator;
     LazyProperty<JSGlobalObject, Structure> m_collatorStructure;
     LazyProperty<JSGlobalObject, Structure> m_displayNamesStructure;
+    LazyProperty<JSGlobalObject, Structure> m_listFormatStructure;
     LazyProperty<JSGlobalObject, Structure> m_localeStructure;
     LazyProperty<JSGlobalObject, Structure> m_pluralRulesStructure;
     LazyProperty<JSGlobalObject, Structure> m_relativeTimeFormatStructure;
@@ -823,6 +824,7 @@
     Structure* collatorStructure() { return m_collatorStructure.get(this); }
     Structure* dateTimeFormatStructure() { return m_dateTimeFormatStructure.get(this); }
     Structure* displayNamesStructure() { return m_displayNamesStructure.get(this); }
+    Structure* listFormatStructure() { return m_listFormatStructure.get(this); }
     Structure* numberFormatStructure() { return m_numberFormatStructure.get(this); }
     Structure* localeStructure() { return m_localeStructure.get(this); }
     Structure* pluralRulesStructure() { return m_pluralRulesStructure.get(this); }

Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (268955 => 268956)


--- trunk/Source/_javascript_Core/runtime/VM.cpp	2020-10-25 04:27:10 UTC (rev 268955)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp	2020-10-25 06:20:47 UTC (rev 268956)
@@ -68,6 +68,7 @@
 #include "IntlCollator.h"
 #include "IntlDateTimeFormat.h"
 #include "IntlDisplayNames.h"
+#include "IntlListFormat.h"
 #include "IntlLocale.h"
 #include "IntlNumberFormat.h"
 #include "IntlPluralRules.h"
@@ -314,6 +315,7 @@
     , intlCollatorHeapCellType(IsoHeapCellType::create<IntlCollator>())
     , intlDateTimeFormatHeapCellType(IsoHeapCellType::create<IntlDateTimeFormat>())
     , intlDisplayNamesHeapCellType(IsoHeapCellType::create<IntlDisplayNames>())
+    , intlListFormatHeapCellType(IsoHeapCellType::create<IntlListFormat>())
     , intlLocaleHeapCellType(IsoHeapCellType::create<IntlLocale>())
     , intlNumberFormatHeapCellType(IsoHeapCellType::create<IntlNumberFormat>())
     , intlPluralRulesHeapCellType(IsoHeapCellType::create<IntlPluralRules>())
@@ -1544,6 +1546,7 @@
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlCollatorSpace, intlCollatorHeapCellType.get(), IntlCollator)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlDateTimeFormatSpace, intlDateTimeFormatHeapCellType.get(), IntlDateTimeFormat)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlDisplayNamesSpace, intlDisplayNamesHeapCellType.get(), IntlDisplayNames)
+DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlListFormatSpace, intlListFormatHeapCellType.get(), IntlListFormat)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlLocaleSpace, intlLocaleHeapCellType.get(), IntlLocale)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlNumberFormatSpace, intlNumberFormatHeapCellType.get(), IntlNumberFormat)
 DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlPluralRulesSpace, intlPluralRulesHeapCellType.get(), IntlPluralRules)

Modified: trunk/Source/_javascript_Core/runtime/VM.h (268955 => 268956)


--- trunk/Source/_javascript_Core/runtime/VM.h	2020-10-25 04:27:10 UTC (rev 268955)
+++ trunk/Source/_javascript_Core/runtime/VM.h	2020-10-25 06:20:47 UTC (rev 268956)
@@ -128,6 +128,7 @@
 class IntlCollator;
 class IntlDateTimeFormat;
 class IntlDisplayNames;
+class IntlListFormat;
 class IntlLocale;
 class IntlNumberFormat;
 class IntlPluralRules;
@@ -408,6 +409,7 @@
     std::unique_ptr<IsoHeapCellType> intlCollatorHeapCellType;
     std::unique_ptr<IsoHeapCellType> intlDateTimeFormatHeapCellType;
     std::unique_ptr<IsoHeapCellType> intlDisplayNamesHeapCellType;
+    std::unique_ptr<IsoHeapCellType> intlListFormatHeapCellType;
     std::unique_ptr<IsoHeapCellType> intlLocaleHeapCellType;
     std::unique_ptr<IsoHeapCellType> intlNumberFormatHeapCellType;
     std::unique_ptr<IsoHeapCellType> intlPluralRulesHeapCellType;
@@ -570,6 +572,7 @@
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlCollatorSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlDateTimeFormatSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlDisplayNamesSpace)
+    DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlListFormatSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlLocaleSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlNumberFormatSpace)
     DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlPluralRulesSpace)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to