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)