Diff
Modified: trunk/JSTests/ChangeLog (260348 => 260349)
--- trunk/JSTests/ChangeLog 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/JSTests/ChangeLog 2020-04-20 05:15:35 UTC (rev 260349)
@@ -1,3 +1,20 @@
+2020-04-19 Ross Kirsling <[email protected]>
+
+ [ECMA-402] Intl.RelativeTimeFormat missing in WebKit
+ https://bugs.webkit.org/show_bug.cgi?id=209770
+
+ Reviewed by Darin Adler.
+
+ * stress/intl-relativetimeformat.js: Added.
+
+ * test262/config.yaml:
+ Enable Intl.RelativeTimeFormat feature with flag.
+
+ * test262/expectations.yaml:
+ Mark known failures.
+ Test for locale validation is not specific to RelativeTimeFormat and should be investigated separately.
+ Tests for Polish appear to be wrong and should be corrected in test262.
+
2020-04-18 Keith Miller <[email protected]>
Unreviewed, mark test passing.
Added: trunk/JSTests/stress/intl-relativetimeformat.js (0 => 260349)
--- trunk/JSTests/stress/intl-relativetimeformat.js (rev 0)
+++ trunk/JSTests/stress/intl-relativetimeformat.js 2020-04-20 05:15:35 UTC (rev 260349)
@@ -0,0 +1,273 @@
+//@ runIntlRelativeTimeFormatEnabled
+
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error(`expected ${expected} but got ${actual}`);
+}
+
+const icuVersion = $vm.icuVersion();
+function shouldBeForICUVersion(minimumVersion, actual, expected) {
+ if (icuVersion < minimumVersion)
+ return;
+
+ 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}!`);
+}
+
+shouldBe(Intl.RelativeTimeFormat instanceof Function, true);
+shouldBe(Intl.RelativeTimeFormat.length, 0);
+shouldBe(Object.getOwnPropertyDescriptor(Intl.RelativeTimeFormat, 'prototype').writable, false);
+shouldBe(Object.getOwnPropertyDescriptor(Intl.RelativeTimeFormat, 'prototype').enumerable, false);
+shouldBe(Object.getOwnPropertyDescriptor(Intl.RelativeTimeFormat, 'prototype').configurable, false);
+
+shouldThrow(() => Intl.RelativeTimeFormat(), TypeError);
+shouldThrow(() => Intl.RelativeTimeFormat.call({}), TypeError);
+
+shouldThrow(() => new Intl.RelativeTimeFormat('$'), RangeError);
+shouldThrow(() => new Intl.RelativeTimeFormat('en', null), TypeError);
+
+shouldBe(new Intl.RelativeTimeFormat() instanceof Intl.RelativeTimeFormat, true);
+
+{
+ class DerivedRelativeTimeFormat extends Intl.RelativeTimeFormat {}
+
+ const drtf = new DerivedRelativeTimeFormat();
+ shouldBe(drtf instanceof DerivedRelativeTimeFormat, true);
+ shouldBe(drtf instanceof Intl.RelativeTimeFormat, true);
+ shouldBe(drtf.format, Intl.RelativeTimeFormat.prototype.format);
+ shouldBe(drtf.formatToParts, Intl.RelativeTimeFormat.prototype.formatToParts);
+ shouldBe(Object.getPrototypeOf(drtf), DerivedRelativeTimeFormat.prototype);
+ shouldBe(Object.getPrototypeOf(DerivedRelativeTimeFormat.prototype), Intl.RelativeTimeFormat.prototype);
+}
+
+shouldBe(Intl.RelativeTimeFormat.supportedLocalesOf.length, 1);
+shouldBe(Intl.RelativeTimeFormat.supportedLocalesOf() instanceof Array, true);
+shouldBe(JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf.call(null, 'en')), '["en"]');
+shouldBe(JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf.call({}, 'en')), '["en"]');
+shouldBe(JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf.call(1, 'en')), '["en"]');
+shouldBe(JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf(9)), '[]');
+shouldBe(JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf('en')), '["en"]');
+shouldBe(JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf({ length: 4, 1: 'en', 0: 'es', 3: 'de' })), '["es","en","de"]');
+shouldBe(JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf(['en', 'pt', 'en', 'es'])), '["en","pt","es"]');
+shouldBe(JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf('En-laTn-us-variant2-variant1-1abc-U-ko-tRue-A-aa-aaa-x-RESERVED')), '["en-Latn-US-variant2-variant1-1abc-a-aa-aaa-u-ko-x-reserved"]');
+shouldBe(JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf('no-bok')), '["nb"]');
+shouldBe(JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf('x-some-thing')), '[]');
+
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf(Object.create(null, { length: { get() { throw new Error(); } } })), Error);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf(Object.create(null, { length: { value: 1 }, 0: { get() { throw new Error(); } } })), Error);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf([{ toString() { throw new Error(); } }]), Error);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf([5]), TypeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf(''), RangeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf('a'), RangeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf('abcdefghij'), RangeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf('#$'), RangeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf('en-@-abc'), RangeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf('en-u'), RangeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf('en-u-kn-true-u-ko-true'), RangeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf('en-x'), RangeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf('en-*'), RangeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf('en-'), RangeError);
+shouldThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf('en--US'), RangeError);
+
+const validLanguageTags = [
+ 'de', // ISO 639 language code
+ 'de-DE', // + ISO 3166-1 country code
+ 'DE-de', // tags are case-insensitive
+ 'cmn', // ISO 639 language code
+ 'cmn-Hans', // + script code
+ 'CMN-hANS', // tags are case-insensitive
+ 'cmn-hans-cn', // + ISO 3166-1 country code
+ 'es-419', // + UN M.49 region code
+ 'es-419-u-nu-latn-cu-bob', // + Unicode locale extension sequence
+ 'i-klingon', // grandfathered tag
+ 'cmn-hans-cn-t-ca-u-ca-x-t-u', // singleton subtags can also be used as private use subtags
+ 'enochian-enochian', // language and variant subtags may be the same
+ 'de-gregory-u-ca-gregory', // variant and extension subtags may be the same
+ 'aa-a-foo-x-a-foo-bar', // variant subtags can also be used as private use subtags
+ 'x-en-US-12345', // anything goes in private use tags
+ 'x-12345-12345-en-US',
+ 'x-en-US-12345-12345',
+ 'x-en-u-foo',
+ 'x-en-u-foo-u-bar'
+];
+for (let validLanguageTag of validLanguageTags)
+ shouldNotThrow(() => Intl.RelativeTimeFormat.supportedLocalesOf(validLanguageTag));
+
+shouldBe(Object.getPrototypeOf(Intl.RelativeTimeFormat.prototype), Object.prototype);
+
+shouldBe(Intl.RelativeTimeFormat.prototype.constructor, Intl.RelativeTimeFormat);
+
+shouldBe(Intl.RelativeTimeFormat.prototype[Symbol.toStringTag], 'Intl.RelativeTimeFormat');
+shouldBe(Object.prototype.toString.call(Intl.RelativeTimeFormat.prototype), '[object Intl.RelativeTimeFormat]');
+shouldBe(Object.getOwnPropertyDescriptor(Intl.RelativeTimeFormat.prototype, Symbol.toStringTag).writable, false);
+shouldBe(Object.getOwnPropertyDescriptor(Intl.RelativeTimeFormat.prototype, Symbol.toStringTag).enumerable, false);
+shouldBe(Object.getOwnPropertyDescriptor(Intl.RelativeTimeFormat.prototype, Symbol.toStringTag).configurable, true);
+
+shouldThrow(() => new Intl.RelativeTimeFormat('en', { localeMatcher: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.RelativeTimeFormat('en', { localeMatcher:'bad' }), RangeError);
+shouldNotThrow(() => new Intl.RelativeTimeFormat('en', { localeMatcher:'lookup' }));
+shouldNotThrow(() => new Intl.RelativeTimeFormat('en', { localeMatcher:'best fit' }));
+
+const defaultRTF = new Intl.RelativeTimeFormat('en');
+
+shouldBe(Intl.RelativeTimeFormat.prototype.resolvedOptions.length, 0);
+shouldThrow(() => Intl.RelativeTimeFormat.prototype.resolvedOptions.call(5), TypeError);
+shouldThrow(() => Intl.RelativeTimeFormat.prototype.resolvedOptions.call({}), TypeError);
+shouldBe(defaultRTF.resolvedOptions() instanceof Object, true);
+shouldBe(defaultRTF.resolvedOptions() !== defaultRTF.resolvedOptions(), true);
+shouldBe(defaultRTF.resolvedOptions().locale, 'en');
+shouldBe(defaultRTF.resolvedOptions().style, 'long');
+shouldBe(defaultRTF.resolvedOptions().numeric, 'always');
+shouldBe(defaultRTF.resolvedOptions().numberingSystem, 'latn');
+
+shouldBe(new Intl.RelativeTimeFormat('en-u-nu-hanidec').resolvedOptions().locale, 'en-u-nu-hanidec');
+shouldBe(new Intl.RelativeTimeFormat('en-u-nu-hanidec', { numberingSystem: 'gujr' }).resolvedOptions().locale, 'en');
+shouldBe(new Intl.RelativeTimeFormat('en', { numberingSystem: 'hanidec' }).resolvedOptions().locale, 'en');
+shouldBe(new Intl.RelativeTimeFormat('en-u-ca-chinese').resolvedOptions().locale, 'en');
+
+shouldThrow(() => new Intl.RelativeTimeFormat('en', { style: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.RelativeTimeFormat('en', { style: 'bad' }), RangeError);
+shouldBe(new Intl.RelativeTimeFormat('en', { style: 'long' }).resolvedOptions().style, 'long');
+shouldBe(new Intl.RelativeTimeFormat('en', { style: 'short' }).resolvedOptions().style, 'short');
+shouldBe(new Intl.RelativeTimeFormat('en', { style: 'narrow' }).resolvedOptions().style, 'narrow');
+
+shouldThrow(() => new Intl.RelativeTimeFormat('en', { numeric: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.RelativeTimeFormat('en', { numeric: 'bad' }), RangeError);
+shouldBe(new Intl.RelativeTimeFormat('en', { numeric: 'always' }).resolvedOptions().numeric, 'always');
+shouldBe(new Intl.RelativeTimeFormat('en', { numeric: 'auto' }).resolvedOptions().numeric, 'auto');
+
+const numberingSystems = [
+ 'arab', 'arabext', 'bali', 'beng', 'deva', 'fullwide', 'gujr', 'guru',
+ 'hanidec', 'khmr', 'knda', 'laoo', 'latn', 'limb', 'mlym', 'mong', 'mymr',
+ 'orya', 'tamldec', 'telu', 'thai', 'tibt'
+]
+for (let numberingSystem of numberingSystems) {
+ shouldBe(new Intl.RelativeTimeFormat('en', { numberingSystem }).resolvedOptions().numberingSystem, numberingSystem);
+ shouldBe(new Intl.RelativeTimeFormat(`en-u-nu-${numberingSystem}`).resolvedOptions().numberingSystem, numberingSystem);
+}
+
+shouldBe(Intl.RelativeTimeFormat.prototype.format.length, 2);
+shouldThrow(() => Intl.RelativeTimeFormat.prototype.format.call({}, 3, 'days'), TypeError);
+shouldThrow(() => defaultRTF.format(Symbol(), 'days'), TypeError);
+shouldThrow(() => defaultRTF.format(3, Symbol()), TypeError);
+shouldThrow(() => defaultRTF.format(Infinity, 'days'), RangeError);
+shouldThrow(() => defaultRTF.format(3, 'centuries'), RangeError);
+
+const units = ['second', 'minute', 'hour', 'day', 'week', 'month', 'year'];
+if (icuVersion >= 63)
+ units.push('quarter');
+
+for (let unit of units) {
+ shouldBe(defaultRTF.format(10, unit), defaultRTF.format(10, `${unit}s`));
+
+ shouldBe(defaultRTF.format(10000.5, unit), `in 10,000.5 ${unit}s`);
+ shouldBe(defaultRTF.format(10, unit), `in 10 ${unit}s`);
+ shouldBe(defaultRTF.format(0, unit), `in 0 ${unit}s`);
+ shouldBe(defaultRTF.format(-10, unit), `10 ${unit}s ago`);
+ shouldBe(defaultRTF.format(-10000.5, unit), `10,000.5 ${unit}s ago`);
+
+ shouldBeForICUVersion(64, defaultRTF.format(1, unit), `in 1 ${unit}`);
+ shouldBeForICUVersion(63, defaultRTF.format(-0, unit), `0 ${unit}s ago`);
+ shouldBeForICUVersion(64, defaultRTF.format(-1, unit), `1 ${unit} ago`);
+}
+
+shouldBe(new Intl.RelativeTimeFormat('en', { style: 'short' }).format(10, 'second'), 'in 10 sec.');
+shouldBe(new Intl.RelativeTimeFormat('ru', { style: 'short' }).format(10, 'second'), 'через 10 сек.');
+shouldBe(new Intl.RelativeTimeFormat('en', { style: 'narrow' }).format(10, 'second'), 'in 10 sec.');
+shouldBe(new Intl.RelativeTimeFormat('ru', { style: 'narrow' }).format(10, 'second'), '+10 с');
+
+shouldBe(new Intl.RelativeTimeFormat('en', { numeric: 'auto' }).format(0, 'second'), 'now');
+shouldBe(new Intl.RelativeTimeFormat('ja', { numeric: 'auto' }).format(0, 'second'), '今');
+shouldBe(new Intl.RelativeTimeFormat('en', { numeric: 'auto' }).format(0, 'day'), 'today');
+shouldBe(new Intl.RelativeTimeFormat('ja', { numeric: 'auto' }).format(0, 'day'), '今日');
+shouldBe(new Intl.RelativeTimeFormat('en', { numeric: 'auto' }).format(0, 'year'), 'this year');
+shouldBe(new Intl.RelativeTimeFormat('ja', { numeric: 'auto' }).format(0, 'year'), '今年');
+
+shouldBe(new Intl.RelativeTimeFormat('en', { numberingSystem: 'thai' }).format(-10, 'hour'), '๑๐ hours ago');
+shouldBe(new Intl.RelativeTimeFormat('en-u-nu-thai').format(-10, 'hour'), '๑๐ hours ago');
+shouldBe(new Intl.RelativeTimeFormat('ko', { numberingSystem: 'hanidec' }).format(-10, 'hour'), '一〇시간 전');
+shouldBe(new Intl.RelativeTimeFormat('ko-u-nu-hanidec').format(-10, 'hour'), '一〇시간 전');
+
+shouldBe(Intl.RelativeTimeFormat.prototype.formatToParts.length, 2);
+shouldThrow(() => Intl.RelativeTimeFormat.prototype.formatToParts.call({}, 3, 'days'), TypeError);
+shouldThrow(() => defaultRTF.formatToParts(Symbol(), 'days'), TypeError);
+shouldThrow(() => defaultRTF.formatToParts(3, Symbol()), TypeError);
+shouldThrow(() => defaultRTF.formatToParts(Infinity, 'days'), RangeError);
+shouldThrow(() => defaultRTF.formatToParts(3, 'centuries'), RangeError);
+
+for (let unit of units) {
+ shouldBe(JSON.stringify(defaultRTF.formatToParts(10, unit)), JSON.stringify(defaultRTF.formatToParts(10, `${unit}s`)));
+
+ const concatenateValues = (parts) => parts.map(part => part.value).join('');
+
+ shouldBe(concatenateValues(defaultRTF.formatToParts(10000.5, unit)), `in 10,000.5 ${unit}s`);
+ shouldBe(concatenateValues(defaultRTF.formatToParts(10, unit)), `in 10 ${unit}s`);
+ shouldBe(concatenateValues(defaultRTF.formatToParts(0, unit)), `in 0 ${unit}s`);
+ shouldBe(concatenateValues(defaultRTF.formatToParts(-10, unit)), `10 ${unit}s ago`);
+ shouldBe(concatenateValues(defaultRTF.formatToParts(-10000.5, unit)), `10,000.5 ${unit}s ago`);
+
+ shouldBeForICUVersion(64, concatenateValues(defaultRTF.formatToParts(1, unit)), `in 1 ${unit}`);
+ shouldBeForICUVersion(63, concatenateValues(defaultRTF.formatToParts(-0, unit)), `0 ${unit}s ago`);
+ shouldBeForICUVersion(64, concatenateValues(defaultRTF.formatToParts(-1, unit)), `1 ${unit} ago`);
+}
+
+shouldBe(
+ JSON.stringify(defaultRTF.formatToParts(10000.5, 'day')),
+ JSON.stringify([
+ { type: 'literal', value: 'in ' },
+ { type: 'integer', value: '10', unit: 'day' },
+ { type: 'group', value: ',', unit: 'day' },
+ { type: 'integer', value: '000', unit: 'day' },
+ { type: 'decimal', value: '.', unit: 'day' },
+ { type: 'fraction', value: '5', unit: 'day' },
+ { type: 'literal', value: ' days' }
+ ])
+);
+
+shouldBe(
+ JSON.stringify(new Intl.RelativeTimeFormat('sw').formatToParts(10, 'year')),
+ JSON.stringify([
+ { type: 'literal', value: 'baada ya miaka ' },
+ { type: 'integer', value: '10', unit: 'year' },
+ ])
+);
+
+shouldBe(
+ JSON.stringify(new Intl.RelativeTimeFormat('ru', { style: 'narrow' }).formatToParts(10, 'second')),
+ JSON.stringify([
+ { type: 'literal', value: '+' },
+ { type: 'integer', value: '10', unit: 'second' },
+ { type: 'literal', value: ' с' }
+ ])
+);
+
+shouldBe(
+ JSON.stringify(new Intl.RelativeTimeFormat('ja', { numeric: 'auto' }).formatToParts(0, 'week')),
+ JSON.stringify([
+ { type: 'literal', value: '今週' }
+ ])
+);
+
+shouldBe(
+ JSON.stringify(new Intl.RelativeTimeFormat('ko', { numberingSystem: 'hanidec' }).formatToParts(-10, 'hour')),
+ JSON.stringify([
+ { type: 'integer', value: '一〇', unit: 'hour' },
+ { type: 'literal', value: '시간 전' }
+ ])
+);
Modified: trunk/JSTests/test262/config.yaml (260348 => 260349)
--- trunk/JSTests/test262/config.yaml 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/JSTests/test262/config.yaml 2020-04-20 05:15:35 UTC (rev 260349)
@@ -2,6 +2,7 @@
---
flags:
BigInt: useBigInt
+ Intl.RelativeTimeFormat: useIntlRelativeTimeFormat
WeakRef: useWeakRefs
class-fields-public: usePublicClassFields
logical-assignment-operators: useLogicalAssignmentOperators
@@ -30,7 +31,6 @@
- Intl.ListFormat
- Intl.Locale
- Intl.NumberFormat-unified
- - Intl.RelativeTimeFormat
- Intl.Segmenter
paths:
- test/built-ins/DataView/prototype/getBigInt64
@@ -153,3 +153,7 @@
# https://bugs.webkit.org/show_bug.cgi?id=209783
- test/intl402/DateTimeFormat/prototype/format/related-year-zh.js
- test/intl402/DateTimeFormat/prototype/formatToParts/related-year-zh.js
+
+ # requires ICU 65 (https://unicode-org.atlassian.net/browse/ICU-20654)
+ - test/intl402/RelativeTimeFormat/prototype/format/en-us-numeric-auto.js
+ - test/intl402/RelativeTimeFormat/prototype/formatToParts/en-us-numeric-auto.js
Modified: trunk/JSTests/test262/expectations.yaml (260348 => 260349)
--- trunk/JSTests/test262/expectations.yaml 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/JSTests/test262/expectations.yaml 2020-04-20 05:15:35 UTC (rev 260349)
@@ -1935,12 +1935,33 @@
test/intl402/PluralRules/proto-from-ctor-realm.js:
default: 'Test262Error: newTarget.prototype is undefined Expected SameValue(«[object Object]», «[object Object]») to be true'
strict mode: 'Test262Error: newTarget.prototype is undefined Expected SameValue(«[object Object]», «[object Object]») to be true'
+test/intl402/RelativeTimeFormat/constructor/constructor/locales-valid.js:
+ default: 'Test262Error: Grandfathered Expected a RangeError to be thrown but no exception was thrown at all'
+ strict mode: 'Test262Error: Grandfathered Expected a RangeError to be thrown but no exception was thrown at all'
+test/intl402/RelativeTimeFormat/constructor/constructor/proto-from-ctor-realm.js:
+ default: 'Test262Error: newTarget.prototype is undefined Expected SameValue(«[object Intl.RelativeTimeFormat]», «[object Intl.RelativeTimeFormat]») to be true'
+ strict mode: 'Test262Error: newTarget.prototype is undefined Expected SameValue(«[object Intl.RelativeTimeFormat]», «[object Intl.RelativeTimeFormat]») to be true'
+test/intl402/RelativeTimeFormat/prototype/format/pl-pl-style-long.js:
+ default: 'Test262Error: Expected SameValue(«za 1000 sekund», «za 1 000 sekund») to be true'
+ strict mode: 'Test262Error: Expected SameValue(«za 1000 sekund», «za 1 000 sekund») to be true'
+test/intl402/RelativeTimeFormat/prototype/format/pl-pl-style-narrow.js:
+ default: 'Test262Error: Expected SameValue(«za 1000 s», «za 1 000 s») to be true'
+ strict mode: 'Test262Error: Expected SameValue(«za 1000 s», «za 1 000 s») to be true'
+test/intl402/RelativeTimeFormat/prototype/format/pl-pl-style-short.js:
+ default: 'Test262Error: Expected SameValue(«za 1000 sek.», «za 1 000 sek.») to be true'
+ strict mode: 'Test262Error: Expected SameValue(«za 1000 sek.», «za 1 000 sek.») to be true'
+test/intl402/RelativeTimeFormat/prototype/formatToParts/pl-pl-style-long.js:
+ default: 'Test262Error: formatToParts(1000, second): length Expected SameValue(«3», «5») to be true'
+ strict mode: 'Test262Error: formatToParts(1000, second): length Expected SameValue(«3», «5») to be true'
+test/intl402/RelativeTimeFormat/prototype/formatToParts/pl-pl-style-narrow.js:
+ default: 'Test262Error: formatToParts(1000, second): length Expected SameValue(«3», «5») to be true'
+ strict mode: 'Test262Error: formatToParts(1000, second): length Expected SameValue(«3», «5») to be true'
+test/intl402/RelativeTimeFormat/prototype/formatToParts/pl-pl-style-short.js:
+ default: 'Test262Error: formatToParts(1000, second): length Expected SameValue(«3», «5») to be true'
+ strict mode: 'Test262Error: formatToParts(1000, second): length Expected SameValue(«3», «5») to be true'
test/intl402/language-tags-invalid.js:
default: 'Test262Error: Test data "de-gregory-gregory" is a canonicalized and structurally valid language tag.'
strict mode: 'Test262Error: Test data "de-gregory-gregory" is a canonicalized and structurally valid language tag.'
-test/intl402/supportedLocalesOf-returned-array-elements-are-not-frozen.js:
- default: 'Test262Error: Property 0 of object returned by SupportedLocales is not writable. Expected SameValue(«false», «true») to be true (Testing with Collator.)'
- strict mode: 'Test262Error: Property 0 of object returned by SupportedLocales is not writable. Expected SameValue(«false», «true») to be true (Testing with Collator.)'
test/language/arguments-object/mapped/nonconfigurable-nonenumerable-nonwritable-descriptors-set-by-arguments.js:
default: 'Test262Error: Expected obj[0] to have enumerable:false.'
test/language/arguments-object/mapped/nonconfigurable-nonenumerable-nonwritable-descriptors-set-by-param.js:
Modified: trunk/Source/_javascript_Core/CMakeLists.txt (260348 => 260349)
--- trunk/Source/_javascript_Core/CMakeLists.txt 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/CMakeLists.txt 2020-04-20 05:15:35 UTC (rev 260349)
@@ -75,6 +75,8 @@
runtime/IntlObject.cpp
runtime/IntlPluralRulesConstructor.cpp
runtime/IntlPluralRulesPrototype.cpp
+ runtime/IntlRelativeTimeFormatConstructor.cpp
+ runtime/IntlRelativeTimeFormatPrototype.cpp
runtime/JSDataViewPrototype.cpp
runtime/JSGlobalObject.cpp
runtime/JSInternalPromiseConstructor.cpp
Modified: trunk/Source/_javascript_Core/ChangeLog (260348 => 260349)
--- trunk/Source/_javascript_Core/ChangeLog 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/ChangeLog 2020-04-20 05:15:35 UTC (rev 260349)
@@ -1,3 +1,94 @@
+2020-04-19 Ross Kirsling <[email protected]>
+
+ [ECMA-402] Intl.RelativeTimeFormat missing in WebKit
+ https://bugs.webkit.org/show_bug.cgi?id=209770
+
+ Reviewed by Darin Adler.
+
+ This patch implements the recent ECMA-402 feature Intl.RelativeTimeFormat.
+
+ RelativeTimeFormat has format / formatToParts functions like NumberFormat / DateTimeFormat
+ and is used to turn a number and unit into a formatted relative time string, e.g.:
+
+ new Intl.RelativeTimeFormat('en').format(10, 'day')
+ > 'in 10 days'
+
+ new Intl.RelativeTimeFormat('en', { numeric: 'auto' }).format(0, 'day')
+ > 'today'
+
+ Implementation of RelativeTimeFormat#formatToParts makes direct use of NumberFormat#formatToParts,
+ as the relative time string consists of at most one formatted number with optional literal text on either side.
+
+ This feature is runtime-guarded by the `useIntlRelativeTimeFormat` option.
+
+ * CMakeLists.txt:
+ * DerivedSources-input.xcfilelist:
+ * DerivedSources-output.xcfilelist:
+ * DerivedSources.make:
+ * _javascript_Core.xcodeproj/project.pbxproj:
+ * Sources.txt:
+ * runtime/CommonIdentifiers.h:
+ * runtime/IntlRelativeTimeFormat.cpp: Added.
+ * runtime/IntlRelativeTimeFormat.h: Added.
+ * runtime/IntlRelativeTimeFormatConstructor.cpp: Added.
+ * runtime/IntlRelativeTimeFormatConstructor.h: Added.
+ * runtime/IntlRelativeTimeFormatPrototype.cpp: Added.
+ * runtime/IntlRelativeTimeFormatPrototype.h: Added.
+ * runtime/JSGlobalObject.cpp:
+ (JSC::JSGlobalObject::init):
+ (JSC::JSGlobalObject::visitChildren):
+ * runtime/JSGlobalObject.h:
+ (JSC::JSGlobalObject::relativeTimeFormatStructure):
+ * runtime/OptionsList.h:
+ * runtime/VM.cpp:
+ (JSC::VM::VM):
+ * runtime/VM.h:
+ Add feature and runtime option.
+
+ * runtime/IntlDateTimeFormat.cpp:
+ (JSC::IntlDateTimeFormat::formatToParts):
+ * runtime/IntlPluralRules.cpp:
+ (JSC::IntlPluralRules::initializePluralRules):
+ (JSC::IntlPluralRules::resolvedOptions):
+ Make "type" a property name.
+
+ * runtime/IntlNumberFormat.cpp:
+ (JSC::IntlNumberFormat::initializeNumberFormat):
+ (JSC::IntlNumberFormat::resolvedOptions):
+ (JSC::IntlNumberFormat::formatToPartsInternal):
+ (JSC::IntlNumberFormat::formatToParts):
+ * runtime/IntlNumberFormat.h:
+ Factor out formatToPartsInternal so that RelativeTimeFormat can use it with its own UNumberFormat.
+ (This logic is too complicated to duplicate; it's because ICU won't split, e.g., "10,000" into parts for us.)
+
+ * runtime/IntlObject.cpp:
+ (JSC::IntlObject::IntlObject):
+ (JSC::IntlObject::create):
+ (JSC::IntlObject::finishCreation):
+ (JSC::intlAvailableLocales):
+ (JSC::intlCollatorAvailableLocales):
+ (JSC::isUnicodeLocaleIdentifierType):
+ (JSC::supportedLocales):
+ (JSC::intlDateTimeFormatAvailableLocales): Deleted.
+ (JSC::intlNumberFormatAvailableLocales): Deleted.
+ * runtime/IntlObject.h:
+ (JSC::intlDateTimeFormatAvailableLocales):
+ (JSC::intlNumberFormatAvailableLocales):
+ (JSC::intlPluralRulesAvailableLocales):
+ (JSC::intlRelativeTimeFormatAvailableLocales):
+ Perform three corrections for Intl classes:
+ 1. Collator should be the only class with unique "available locales".
+ [unum|udat]_getAvailable exist but they've deferred to uloc_getAvailable for 20 years.
+ 2. isUnicodeLocaleIdentifierType isn't just `alphanum{3,8}` but rather `alphanum{3,8} (sep alphanum{3,8})*`.
+ This is my own mistake from r239941.
+ 3. supportedLocalesOf entries should not be frozen.
+ Changed in https://github.com/tc39/ecma402/pull/278.
+
+ * tools/JSDollarVM.cpp:
+ (JSC::functionICUVersion):
+ (JSC::JSDollarVM::finishCreation):
+ Add $vm.icuVersion so that we can add per-line skips to stress tests.
+
2020-04-19 Yusuke Suzuki <[email protected]>
[JSC] SlowPathCall is not supported by callOperation in Windows
Modified: trunk/Source/_javascript_Core/DerivedSources-input.xcfilelist (260348 => 260349)
--- trunk/Source/_javascript_Core/DerivedSources-input.xcfilelist 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/DerivedSources-input.xcfilelist 2020-04-20 05:15:35 UTC (rev 260349)
@@ -142,6 +142,8 @@
$(PROJECT_DIR)/runtime/IntlObject.cpp
$(PROJECT_DIR)/runtime/IntlPluralRulesConstructor.cpp
$(PROJECT_DIR)/runtime/IntlPluralRulesPrototype.cpp
+$(PROJECT_DIR)/runtime/IntlRelativeTimeFormatConstructor.cpp
+$(PROJECT_DIR)/runtime/IntlRelativeTimeFormatPrototype.cpp
$(PROJECT_DIR)/runtime/JSDataViewPrototype.cpp
$(PROJECT_DIR)/runtime/JSGlobalObject.cpp
$(PROJECT_DIR)/runtime/JSInternalPromiseConstructor.cpp
Modified: trunk/Source/_javascript_Core/DerivedSources-output.xcfilelist (260348 => 260349)
--- trunk/Source/_javascript_Core/DerivedSources-output.xcfilelist 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/DerivedSources-output.xcfilelist 2020-04-20 05:15:35 UTC (rev 260349)
@@ -33,6 +33,8 @@
$(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlObject.lut.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlPluralRulesConstructor.lut.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlPluralRulesPrototype.lut.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlRelativeTimeFormatConstructor.lut.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlRelativeTimeFormatPrototype.lut.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/JSCBuiltins.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/JSDataViewPrototype.lut.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/JSGlobalObject.lut.h
Modified: trunk/Source/_javascript_Core/DerivedSources.make (260348 => 260349)
--- trunk/Source/_javascript_Core/DerivedSources.make 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/DerivedSources.make 2020-04-20 05:15:35 UTC (rev 260349)
@@ -153,6 +153,8 @@
IntlObject.lut.h \
IntlPluralRulesConstructor.lut.h \
IntlPluralRulesPrototype.lut.h \
+ IntlRelativeTimeFormatConstructor.lut.h \
+ IntlRelativeTimeFormatPrototype.lut.h \
JSDataViewPrototype.lut.h \
JSGlobalObject.lut.h \
JSInternalPromiseConstructor.lut.h \
Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (260348 => 260349)
--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2020-04-20 05:15:35 UTC (rev 260349)
@@ -4334,6 +4334,12 @@
A1E0451B1C25B4B100BB663C /* StringPrototype.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = StringPrototype.js; sourceTree = "<group>"; };
A1FE1EB01C2C537E00A289FF /* DatePrototype.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = DatePrototype.js; sourceTree = "<group>"; };
A27958D7FA1142B0AC9E364D /* WasmContextInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmContextInlines.h; sourceTree = "<group>"; };
+ A3BF884B24480BDE001B9F35 /* IntlRelativeTimeFormatPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntlRelativeTimeFormatPrototype.cpp; sourceTree = "<group>"; };
+ A3BF884C24480BDF001B9F35 /* IntlRelativeTimeFormatPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlRelativeTimeFormatPrototype.h; sourceTree = "<group>"; };
+ A3BF884D24480BDF001B9F35 /* IntlRelativeTimeFormatConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntlRelativeTimeFormatConstructor.cpp; sourceTree = "<group>"; };
+ A3BF884E24480BE0001B9F35 /* IntlRelativeTimeFormatConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlRelativeTimeFormatConstructor.h; sourceTree = "<group>"; };
+ A3BF884F24480BE0001B9F35 /* IntlRelativeTimeFormat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntlRelativeTimeFormat.cpp; sourceTree = "<group>"; };
+ A3BF885024480BE1001B9F35 /* IntlRelativeTimeFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlRelativeTimeFormat.h; sourceTree = "<group>"; };
A3FF9BC52234746600B1A9AB /* YarrFlags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YarrFlags.h; path = yarr/YarrFlags.h; sourceTree = "<group>"; };
A3FF9BC62234746600B1A9AB /* YarrFlags.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = YarrFlags.cpp; path = yarr/YarrFlags.cpp; sourceTree = "<group>"; };
A503FA13188E0FAF00110F14 /* _javascript_CallFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = _javascript_CallFrame.cpp; sourceTree = "<group>"; };
@@ -7265,6 +7271,12 @@
7D5FB19020744BF1005DDF64 /* IntlPluralRulesConstructor.h */,
7D5FB19120744BF1005DDF64 /* IntlPluralRulesPrototype.cpp */,
7D5FB18D20744AE8005DDF64 /* IntlPluralRulesPrototype.h */,
+ A3BF884F24480BE0001B9F35 /* IntlRelativeTimeFormat.cpp */,
+ A3BF885024480BE1001B9F35 /* IntlRelativeTimeFormat.h */,
+ A3BF884D24480BDF001B9F35 /* IntlRelativeTimeFormatConstructor.cpp */,
+ A3BF884E24480BE0001B9F35 /* IntlRelativeTimeFormatConstructor.h */,
+ A3BF884B24480BDE001B9F35 /* IntlRelativeTimeFormatPrototype.cpp */,
+ A3BF884C24480BDF001B9F35 /* IntlRelativeTimeFormatPrototype.h */,
0F275F2C1ECE079600620D47 /* Intrinsic.cpp */,
86BF642A148DB2B5004DE36A /* Intrinsic.h */,
8B9F6D551D5912FA001C739F /* IterationKind.h */,
Modified: trunk/Source/_javascript_Core/Sources.txt (260348 => 260349)
--- trunk/Source/_javascript_Core/Sources.txt 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/Sources.txt 2020-04-20 05:15:35 UTC (rev 260349)
@@ -819,6 +819,9 @@
runtime/IntlPluralRules.cpp
runtime/IntlPluralRulesConstructor.cpp
runtime/IntlPluralRulesPrototype.cpp
+runtime/IntlRelativeTimeFormat.cpp
+runtime/IntlRelativeTimeFormatConstructor.cpp
+runtime/IntlRelativeTimeFormatPrototype.cpp
runtime/IteratorOperations.cpp
runtime/IteratorPrototype.cpp
runtime/JSArray.cpp
Modified: trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h (260348 => 260349)
--- trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h 2020-04-20 05:15:35 UTC (rev 260349)
@@ -49,6 +49,7 @@
macro(Promise) \
macro(Reflect) \
macro(RegExp) \
+ macro(RelativeTimeFormat) \
macro(RemotePlayback) \
macro(Set) \
macro(SharedArrayBuffer) \
@@ -178,6 +179,7 @@
macro(stack) \
macro(stackTraceLimit) \
macro(sticky) \
+ macro(style) \
macro(subarray) \
macro(summary) \
macro(target) \
@@ -193,6 +195,7 @@
macro(toLocaleString) \
macro(toPrecision) \
macro(toString) \
+ macro(type) \
macro(uid) \
macro(unicode) \
macro(usage) \
Modified: trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.cpp (260348 => 260349)
--- trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.cpp 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.cpp 2020-04-20 05:15:35 UTC (rev 260349)
@@ -1029,7 +1029,6 @@
return throwOutOfMemoryError(globalObject, scope);
auto resultString = String(result.data(), resultLength);
- auto typePropertyName = Identifier::fromString(vm, "type");
auto literalString = jsNontrivialString(vm, "literal"_s);
int32_t previousEndIndex = 0;
@@ -1043,7 +1042,7 @@
if (previousEndIndex < beginIndex) {
auto value = jsString(vm, resultString.substring(previousEndIndex, beginIndex - previousEndIndex));
JSObject* part = constructEmptyObject(globalObject);
- part->putDirect(vm, typePropertyName, literalString);
+ part->putDirect(vm, vm.propertyNames->type, literalString);
part->putDirect(vm, vm.propertyNames->value, value);
parts->push(globalObject, part);
RETURN_IF_EXCEPTION(scope, { });
@@ -1054,7 +1053,7 @@
auto type = jsString(vm, partTypeString(UDateFormatField(fieldType)));
auto value = jsString(vm, resultString.substring(beginIndex, endIndex - beginIndex));
JSObject* part = constructEmptyObject(globalObject);
- part->putDirect(vm, typePropertyName, type);
+ part->putDirect(vm, vm.propertyNames->type, type);
part->putDirect(vm, vm.propertyNames->value, value);
parts->push(globalObject, part);
RETURN_IF_EXCEPTION(scope, { });
Modified: trunk/Source/_javascript_Core/runtime/IntlNumberFormat.cpp (260348 => 260349)
--- trunk/Source/_javascript_Core/runtime/IntlNumberFormat.cpp 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/IntlNumberFormat.cpp 2020-04-20 05:15:35 UTC (rev 260349)
@@ -2,6 +2,7 @@
* Copyright (C) 2015 Andy VanWagoner ([email protected])
* Copyright (C) 2016 Sukolsak Sakshuwong ([email protected])
* Copyright (C) 2016-2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2020 Sony Interactive Entertainment Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -195,7 +196,7 @@
m_numberingSystem = result.get("nu"_s);
- String styleString = intlStringOption(globalObject, options, Identifier::fromString(vm, "style"), { "decimal", "percent", "currency" }, "style must be either \"decimal\", \"percent\", or \"currency\"", "decimal");
+ String styleString = intlStringOption(globalObject, options, vm.propertyNames->style, { "decimal", "percent", "currency" }, "style must be either \"decimal\", \"percent\", or \"currency\"", "decimal");
RETURN_IF_EXCEPTION(scope, void());
if (styleString == "decimal")
m_style = Style::Decimal;
@@ -441,7 +442,7 @@
JSObject* options = constructEmptyObject(globalObject);
options->putDirect(vm, vm.propertyNames->locale, jsString(vm, m_locale));
options->putDirect(vm, vm.propertyNames->numberingSystem, jsString(vm, m_numberingSystem));
- options->putDirect(vm, Identifier::fromString(vm, "style"), jsNontrivialString(vm, styleString(m_style)));
+ options->putDirect(vm, vm.propertyNames->style, jsNontrivialString(vm, styleString(m_style)));
if (m_style == Style::Currency) {
options->putDirect(vm, Identifier::fromString(vm, "currency"), jsNontrivialString(vm, m_currency));
options->putDirect(vm, Identifier::fromString(vm, "currencyDisplay"), jsNontrivialString(vm, currencyDisplayString(m_currencyDisplay)));
@@ -503,6 +504,52 @@
return "unknown"_s;
}
+void IntlNumberFormat::formatToPartsInternal(JSGlobalObject* globalObject, double value, const String& formatted, UFieldPositionIterator* iterator, JSArray* parts, JSString* unit)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto stringLength = formatted.length();
+
+ int32_t literalFieldType = -1;
+ auto literalField = IntlNumberFormatField(literalFieldType, stringLength);
+ Vector<IntlNumberFormatField, 32> fields(stringLength, literalField);
+ int32_t beginIndex = 0;
+ int32_t endIndex = 0;
+ auto fieldType = ufieldpositer_next(iterator, &beginIndex, &endIndex);
+ while (fieldType >= 0) {
+ auto size = endIndex - beginIndex;
+ for (auto i = beginIndex; i < endIndex; ++i) {
+ // Only override previous value if new value is more specific.
+ if (fields[i].size >= size)
+ fields[i] = IntlNumberFormatField(fieldType, size);
+ }
+ fieldType = ufieldpositer_next(iterator, &beginIndex, &endIndex);
+ }
+
+ auto literalString = jsNontrivialString(vm, "literal"_s);
+ Identifier unitName;
+ if (unit)
+ unitName = Identifier::fromString(vm, "unit");
+
+ size_t currentIndex = 0;
+ while (currentIndex < stringLength) {
+ auto startIndex = currentIndex;
+ auto fieldType = fields[currentIndex].type;
+ while (currentIndex < stringLength && fields[currentIndex].type == fieldType)
+ ++currentIndex;
+ auto partType = fieldType == literalFieldType ? literalString : jsString(vm, partTypeString(UNumberFormatFields(fieldType), value));
+ auto partValue = jsSubstring(vm, formatted, startIndex, currentIndex - startIndex);
+ JSObject* part = constructEmptyObject(globalObject);
+ part->putDirect(vm, vm.propertyNames->type, partType);
+ part->putDirect(vm, vm.propertyNames->value, partValue);
+ if (unit)
+ part->putDirect(vm, unitName, unit);
+ parts->push(globalObject, part);
+ RETURN_IF_EXCEPTION(scope, void());
+ }
+}
+
JSValue IntlNumberFormat::formatToParts(JSGlobalObject* globalObject, double value)
{
VM& vm = globalObject->vm();
@@ -520,7 +567,6 @@
if (U_FAILURE(status))
return throwTypeError(globalObject, scope, "failed to open field position iterator"_s);
- status = U_ZERO_ERROR;
Vector<UChar, 32> result(32);
auto resultLength = unum_formatDoubleForFields(m_numberFormat.get(), value, result.data(), result.size(), fieldItr.get(), &status);
if (status == U_BUFFER_OVERFLOW_ERROR) {
@@ -531,46 +577,15 @@
if (U_FAILURE(status))
return throwTypeError(globalObject, scope, "failed to format a number."_s);
- int32_t literalFieldType = -1;
- auto literalField = IntlNumberFormatField(literalFieldType, resultLength);
- Vector<IntlNumberFormatField> fields(resultLength, literalField);
- int32_t beginIndex = 0;
- int32_t endIndex = 0;
- auto fieldType = ufieldpositer_next(fieldItr.get(), &beginIndex, &endIndex);
- while (fieldType >= 0) {
- auto size = endIndex - beginIndex;
- for (auto i = beginIndex; i < endIndex; ++i) {
- // Only override previous value if new value is more specific.
- if (fields[i].size >= size)
- fields[i] = IntlNumberFormatField(fieldType, size);
- }
- fieldType = ufieldpositer_next(fieldItr.get(), &beginIndex, &endIndex);
- }
+ auto resultString = String(result.data(), resultLength);
JSArray* parts = JSArray::tryCreate(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), 0);
if (!parts)
return throwOutOfMemoryError(globalObject, scope);
- unsigned index = 0;
- auto resultString = String(result.data(), resultLength);
- auto typePropertyName = Identifier::fromString(vm, "type");
- auto literalString = jsNontrivialString(vm, "literal"_s);
+ formatToPartsInternal(globalObject, value, resultString, fieldItr.get(), parts);
+ RETURN_IF_EXCEPTION(scope, { });
- int32_t currentIndex = 0;
- while (currentIndex < resultLength) {
- auto startIndex = currentIndex;
- auto fieldType = fields[currentIndex].type;
- while (currentIndex < resultLength && fields[currentIndex].type == fieldType)
- ++currentIndex;
- auto partType = fieldType == literalFieldType ? literalString : jsString(vm, partTypeString(UNumberFormatFields(fieldType), value));
- auto partValue = jsSubstring(vm, resultString, startIndex, currentIndex - startIndex);
- JSObject* part = constructEmptyObject(globalObject);
- part->putDirect(vm, typePropertyName, partType);
- part->putDirect(vm, vm.propertyNames->value, partValue);
- parts->putDirectIndex(globalObject, index++, part);
- RETURN_IF_EXCEPTION(scope, { });
- }
-
return parts;
}
Modified: trunk/Source/_javascript_Core/runtime/IntlNumberFormat.h (260348 => 260349)
--- trunk/Source/_javascript_Core/runtime/IntlNumberFormat.h 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/IntlNumberFormat.h 2020-04-20 05:15:35 UTC (rev 260349)
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Andy VanWagoner ([email protected])
+ * Copyright (C) 2020 Sony Interactive Entertainment Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -57,12 +58,14 @@
void initializeNumberFormat(JSGlobalObject*, JSValue locales, JSValue optionsValue);
JSValue format(JSGlobalObject*, double);
JSValue format(JSGlobalObject*, JSBigInt*);
- JSValue formatToParts(JSGlobalObject*, double value);
+ JSValue formatToParts(JSGlobalObject*, double);
JSObject* resolvedOptions(JSGlobalObject*);
JSBoundFunction* boundFormat() const { return m_boundFormat.get(); }
void setBoundFormat(VM&, JSBoundFunction*);
+ static void formatToPartsInternal(JSGlobalObject*, double, const String& formatted, UFieldPositionIterator*, JSArray*, JSString* unit = nullptr);
+
protected:
IntlNumberFormat(VM&, Structure*);
void finishCreation(VM&);
Modified: trunk/Source/_javascript_Core/runtime/IntlObject.cpp (260348 => 260349)
--- trunk/Source/_javascript_Core/runtime/IntlObject.cpp 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/IntlObject.cpp 2020-04-20 05:15:35 UTC (rev 260349)
@@ -2,6 +2,7 @@
* Copyright (C) 2015 Andy VanWagoner ([email protected])
* Copyright (C) 2015 Sukolsak Sakshuwong ([email protected])
* Copyright (C) 2016-2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2020 Sony Interactive Entertainment Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -39,6 +40,8 @@
#include "IntlNumberFormatPrototype.h"
#include "IntlPluralRulesConstructor.h"
#include "IntlPluralRulesPrototype.h"
+#include "IntlRelativeTimeFormatConstructor.h"
+#include "IntlRelativeTimeFormatPrototype.h"
#include "JSCInlines.h"
#include "JSCJSValueInlines.h"
#include "Lookup.h"
@@ -45,9 +48,7 @@
#include "ObjectPrototype.h"
#include "Options.h"
#include <unicode/ucol.h>
-#include <unicode/udat.h>
#include <unicode/uloc.h>
-#include <unicode/unum.h>
#include <unicode/unumsys.h>
#include <wtf/Assertions.h>
#include <wtf/Language.h>
@@ -114,17 +115,26 @@
const ClassInfo IntlObject::s_info = { "Object", &Base::s_info, &intlObjectTable, nullptr, CREATE_METHOD_TABLE(IntlObject) };
IntlObject::IntlObject(VM& vm, Structure* structure)
- : JSNonFinalObject(vm, structure)
+ : Base(vm, structure)
{
}
-IntlObject* IntlObject::create(VM& vm, Structure* structure)
+IntlObject* IntlObject::create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
{
IntlObject* object = new (NotNull, allocateCell<IntlObject>(vm.heap)) IntlObject(vm, structure);
- object->finishCreation(vm);
+ object->finishCreation(vm, globalObject);
return object;
}
+void IntlObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
+{
+ Base::finishCreation(vm);
+ if (Options::useIntlRelativeTimeFormat()) {
+ auto* relativeTimeFormatConstructor = IntlRelativeTimeFormatConstructor::create(vm, IntlRelativeTimeFormatConstructor::createStructure(vm, globalObject, globalObject->functionPrototype()), jsCast<IntlRelativeTimeFormatPrototype*>(globalObject->relativeTimeFormatStructure()->storedPrototypeObject()));
+ putDirectWithoutTransition(vm, vm.propertyNames->RelativeTimeFormat, relativeTimeFormatConstructor, static_cast<unsigned>(PropertyAttribute::DontEnum));
+ }
+}
+
Structure* IntlObject::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
@@ -164,7 +174,7 @@
availableLocales.add(zh_TW_String.get());
}
-const HashSet<String>& intlCollatorAvailableLocales()
+const HashSet<String>& intlAvailableLocales()
{
static NeverDestroyed<HashSet<String>> cachedAvailableLocales;
HashSet<String>& availableLocales = cachedAvailableLocales.get();
@@ -172,9 +182,9 @@
static std::once_flag initializeOnce;
std::call_once(initializeOnce, [&] {
ASSERT(availableLocales.isEmpty());
- int32_t count = ucol_countAvailable();
+ int32_t count = uloc_countAvailable();
for (int32_t i = 0; i < count; ++i) {
- String locale = convertICULocaleToBCP47LanguageTag(ucol_getAvailable(i));
+ String locale = convertICULocaleToBCP47LanguageTag(uloc_getAvailable(i));
if (!locale.isEmpty())
availableLocales.add(locale);
}
@@ -183,7 +193,7 @@
return availableLocales;
}
-const HashSet<String>& intlDateTimeFormatAvailableLocales()
+const HashSet<String>& intlCollatorAvailableLocales()
{
static NeverDestroyed<HashSet<String>> cachedAvailableLocales;
HashSet<String>& availableLocales = cachedAvailableLocales.get();
@@ -191,9 +201,9 @@
static std::once_flag initializeOnce;
std::call_once(initializeOnce, [&] {
ASSERT(availableLocales.isEmpty());
- int32_t count = udat_countAvailable();
+ int32_t count = ucol_countAvailable();
for (int32_t i = 0; i < count; ++i) {
- String locale = convertICULocaleToBCP47LanguageTag(udat_getAvailable(i));
+ String locale = convertICULocaleToBCP47LanguageTag(ucol_getAvailable(i));
if (!locale.isEmpty())
availableLocales.add(locale);
}
@@ -202,25 +212,6 @@
return availableLocales;
}
-const HashSet<String>& intlNumberFormatAvailableLocales()
-{
- static NeverDestroyed<HashSet<String>> cachedAvailableLocales;
- HashSet<String>& availableLocales = cachedAvailableLocales.get();
-
- static std::once_flag initializeOnce;
- std::call_once(initializeOnce, [&] {
- ASSERT(availableLocales.isEmpty());
- int32_t count = unum_countAvailable();
- for (int32_t i = 0; i < count; ++i) {
- String locale = convertICULocaleToBCP47LanguageTag(unum_getAvailable(i));
- if (!locale.isEmpty())
- availableLocales.add(locale);
- }
- addMissingScriptLocales(availableLocales);
- });
- return availableLocales;
-}
-
bool intlBooleanOption(JSGlobalObject* globalObject, JSValue options, PropertyName property, bool& usesFallback)
{
// GetOption (options, property, type="boolean", values, fallback)
@@ -328,13 +319,15 @@
{
ASSERT(!string.isNull());
- auto length = string.length();
- if (length < 3 || length > 8)
- return false;
+ for (auto part : string.splitAllowingEmptyEntries('-')) {
+ auto length = part.length();
+ if (length < 3 || length > 8)
+ return false;
- for (auto character : string.codeUnits()) {
- if (!isASCIIAlphanumeric(character))
- return false;
+ for (auto character : part.codeUnits()) {
+ if (!isASCIIAlphanumeric(character))
+ return false;
+ }
}
return true;
@@ -979,8 +972,6 @@
RETURN_IF_EXCEPTION(scope, JSValue());
PropertyDescriptor desc;
- desc.setConfigurable(false);
- desc.setWritable(false);
size_t len = keys.size();
for (size_t i = 0; i < len; ++i) {
Modified: trunk/Source/_javascript_Core/runtime/IntlObject.h (260348 => 260349)
--- trunk/Source/_javascript_Core/runtime/IntlObject.h 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/IntlObject.h 2020-04-20 05:15:35 UTC (rev 260349)
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2015 Andy VanWagoner ([email protected])
* Copyright (C) 2019-2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2020 Sony Interactive Entertainment Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -43,7 +44,7 @@
return &vm.plainObjectSpace;
}
- static IntlObject* create(VM&, Structure*);
+ static IntlObject* create(VM&, JSGlobalObject*, Structure*);
static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
DECLARE_INFO;
@@ -50,13 +51,16 @@
private:
IntlObject(VM&, Structure*);
+ void finishCreation(VM&, JSGlobalObject*);
};
String defaultLocale(JSGlobalObject*);
+const HashSet<String>& intlAvailableLocales();
const HashSet<String>& intlCollatorAvailableLocales();
-const HashSet<String>& intlDateTimeFormatAvailableLocales();
-const HashSet<String>& intlNumberFormatAvailableLocales();
-inline const HashSet<String>& intlPluralRulesAvailableLocales() { return intlNumberFormatAvailableLocales(); }
+inline const HashSet<String>& intlDateTimeFormatAvailableLocales() { return intlAvailableLocales(); }
+inline const HashSet<String>& intlNumberFormatAvailableLocales() { return intlAvailableLocales(); }
+inline const HashSet<String>& intlPluralRulesAvailableLocales() { return intlAvailableLocales(); }
+inline const HashSet<String>& intlRelativeTimeFormatAvailableLocales() { return intlAvailableLocales(); }
bool intlBooleanOption(JSGlobalObject*, JSValue options, PropertyName, bool& usesFallback);
String intlStringOption(JSGlobalObject*, JSValue options, PropertyName, std::initializer_list<const char*> values, const char* notFound, const char* fallback);
Modified: trunk/Source/_javascript_Core/runtime/IntlPluralRules.cpp (260348 => 260349)
--- trunk/Source/_javascript_Core/runtime/IntlPluralRules.cpp 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/IntlPluralRules.cpp 2020-04-20 05:15:35 UTC (rev 260349)
@@ -127,7 +127,7 @@
return;
}
- String typeString = intlStringOption(globalObject, options, Identifier::fromString(vm, "type"), { "cardinal", "ordinal" }, "type must be \"cardinal\" or \"ordinal\"", "cardinal");
+ String typeString = intlStringOption(globalObject, options, vm.propertyNames->type, { "cardinal", "ordinal" }, "type must be \"cardinal\" or \"ordinal\"", "cardinal");
RETURN_IF_EXCEPTION(scope, void());
m_type = typeString == "ordinal" ? UPLURAL_TYPE_ORDINAL : UPLURAL_TYPE_CARDINAL;
@@ -201,7 +201,7 @@
JSObject* options = constructEmptyObject(globalObject);
options->putDirect(vm, vm.propertyNames->locale, jsNontrivialString(vm, m_locale));
- options->putDirect(vm, Identifier::fromString(vm, "type"), jsNontrivialString(vm, m_type == UPLURAL_TYPE_ORDINAL ? "ordinal"_s : "cardinal"_s));
+ options->putDirect(vm, vm.propertyNames->type, jsNontrivialString(vm, m_type == UPLURAL_TYPE_ORDINAL ? "ordinal"_s : "cardinal"_s));
options->putDirect(vm, Identifier::fromString(vm, "minimumIntegerDigits"), jsNumber(m_minimumIntegerDigits));
options->putDirect(vm, Identifier::fromString(vm, "minimumFractionDigits"), jsNumber(m_minimumFractionDigits));
options->putDirect(vm, Identifier::fromString(vm, "maximumFractionDigits"), jsNumber(m_maximumFractionDigits));
Added: trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormat.cpp (0 => 260349)
--- trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormat.cpp (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormat.cpp 2020-04-20 05:15:35 UTC (rev 260349)
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2020 Sony Interactive Entertainment Inc.
+ *
+ * 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 "IntlRelativeTimeFormat.h"
+
+#include "Error.h"
+#include "IntlNumberFormat.h"
+#include "IntlObject.h"
+#include "JSCInlines.h"
+#include "ObjectConstructor.h"
+
+namespace JSC {
+
+const ClassInfo IntlRelativeTimeFormat::s_info = { "Object", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(IntlRelativeTimeFormat) };
+
+constexpr const char* relevantExtensionKeys[1] = { "nu" };
+
+struct UFieldPositionIteratorDeleter {
+ void operator()(UFieldPositionIterator* iterator) const
+ {
+ if (iterator)
+ ufieldpositer_close(iterator);
+ }
+};
+
+void IntlRelativeTimeFormat::URelativeDateTimeFormatterDeleter::operator()(URelativeDateTimeFormatter* relativeDateTimeFormatter) const
+{
+ if (relativeDateTimeFormatter)
+ ureldatefmt_close(relativeDateTimeFormatter);
+}
+
+void IntlRelativeTimeFormat::UNumberFormatDeleter::operator()(UNumberFormat* numberFormat) const
+{
+ if (numberFormat)
+ unum_close(numberFormat);
+}
+
+IntlRelativeTimeFormat* IntlRelativeTimeFormat::create(VM& vm, Structure* structure)
+{
+ auto* format = new (NotNull, allocateCell<IntlRelativeTimeFormat>(vm.heap)) IntlRelativeTimeFormat(vm, structure);
+ format->finishCreation(vm);
+ return format;
+}
+
+Structure* IntlRelativeTimeFormat::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+IntlRelativeTimeFormat::IntlRelativeTimeFormat(VM& vm, Structure* structure)
+ : Base(vm, structure)
+{
+}
+
+void IntlRelativeTimeFormat::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(vm, info()));
+}
+
+void IntlRelativeTimeFormat::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ auto* thisObject = jsCast<IntlRelativeTimeFormat*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+
+ Base::visitChildren(thisObject, visitor);
+}
+
+static Vector<String> localeData(const String& locale, size_t keyIndex)
+{
+ // The index of the extension key "nu" in relevantExtensionKeys is 0.
+ ASSERT_UNUSED(keyIndex, !keyIndex);
+ return numberingSystemsForLocale(locale);
+}
+
+// https://tc39.es/ecma402/#sec-InitializeRelativeTimeFormat
+void IntlRelativeTimeFormat::initializeRelativeTimeFormat(JSGlobalObject* globalObject, JSValue locales, JSValue optionsValue)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ Vector<String> 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());
+ }
+
+ HashMap<String, String> opt;
+ String localeMatcher = intlStringOption(globalObject, options, vm.propertyNames->localeMatcher, { "lookup", "best fit" }, "localeMatcher must be either \"lookup\" or \"best fit\"", "best fit");
+ RETURN_IF_EXCEPTION(scope, void());
+ opt.add(vm.propertyNames->localeMatcher.string(), localeMatcher);
+
+ String numberingSystem = intlStringOption(globalObject, options, vm.propertyNames->numberingSystem, { }, nullptr, nullptr);
+ RETURN_IF_EXCEPTION(scope, void());
+ if (!numberingSystem.isNull()) {
+ if (!isUnicodeLocaleIdentifierType(numberingSystem)) {
+ throwRangeError(globalObject, scope, "numberingSystem is not a well-formed numbering system value"_s);
+ return;
+ }
+ opt.add("nu"_s, numberingSystem);
+ }
+
+ const HashSet<String>& availableLocales = intlRelativeTimeFormatAvailableLocales();
+ HashMap<String, String> resolved = resolveLocale(globalObject, availableLocales, requestedLocales, opt, relevantExtensionKeys, WTF_ARRAY_LENGTH(relevantExtensionKeys), localeData);
+ m_locale = resolved.get(vm.propertyNames->locale.string());
+ if (m_locale.isEmpty()) {
+ throwTypeError(globalObject, scope, "failed to initialize RelativeTimeFormat due to invalid locale"_s);
+ return;
+ }
+
+ m_numberingSystem = resolved.get("nu"_s);
+ CString dataLocaleWithExtensions = makeString(resolved.get("dataLocale"_s), "-u-nu-", m_numberingSystem).utf8();
+
+ String style = intlStringOption(globalObject, options, vm.propertyNames->style, { "long", "short", "narrow" }, "style must be either \"long\", \"short\", or \"narrow\"", "long");
+ RETURN_IF_EXCEPTION(scope, void());
+ if (style == "long")
+ m_style = UDAT_STYLE_LONG;
+ else if (style == "short")
+ m_style = UDAT_STYLE_SHORT;
+ else if (style == "narrow")
+ m_style = UDAT_STYLE_NARROW;
+ else
+ ASSERT_NOT_REACHED();
+
+ String numeric = intlStringOption(globalObject, options, vm.propertyNames->numeric, { "always", "auto" }, "numeric must be either \"always\" or \"auto\"", "always");
+ RETURN_IF_EXCEPTION(scope, void());
+ m_numeric = (numeric == "always");
+
+ UErrorCode status = U_ZERO_ERROR;
+ m_numberFormat = std::unique_ptr<UNumberFormat, UNumberFormatDeleter>(unum_open(UNUM_DECIMAL, nullptr, 0, dataLocaleWithExtensions.data(), nullptr, &status));
+ if (UNLIKELY(U_FAILURE(status))) {
+ throwTypeError(globalObject, scope, "failed to initialize RelativeTimeFormat"_s);
+ return;
+ }
+
+ m_relativeDateTimeFormatter = std::unique_ptr<URelativeDateTimeFormatter, URelativeDateTimeFormatterDeleter>(ureldatefmt_open(dataLocaleWithExtensions.data(), m_numberFormat.get(), m_style, UDISPCTX_CAPITALIZATION_FOR_STANDALONE, &status));
+ if (UNLIKELY(U_FAILURE(status))) {
+ throwTypeError(globalObject, scope, "failed to initialize RelativeTimeFormat"_s);
+ return;
+ }
+}
+
+static ASCIILiteral styleString(UDateRelativeDateTimeFormatterStyle style)
+{
+ switch (style) {
+ case UDAT_STYLE_LONG:
+ return "long"_s;
+ case UDAT_STYLE_SHORT:
+ return "short"_s;
+ case UDAT_STYLE_NARROW:
+ return "narrow"_s;
+ }
+ ASSERT_NOT_REACHED();
+ return ASCIILiteral::null();
+}
+
+static ASCIILiteral numericString(bool numeric)
+{
+ return numeric ? "always"_s : "auto"_s;
+}
+
+// https://tc39.es/ecma402/#sec-intl.relativetimeformat.prototype.resolvedoptions
+JSObject* IntlRelativeTimeFormat::resolvedOptions(JSGlobalObject* globalObject)
+{
+ VM& vm = globalObject->vm();
+ JSObject* options = constructEmptyObject(globalObject);
+ options->putDirect(vm, vm.propertyNames->locale, jsNontrivialString(vm, m_locale));
+ options->putDirect(vm, vm.propertyNames->style, jsNontrivialString(vm, styleString(m_style)));
+ options->putDirect(vm, vm.propertyNames->numeric, jsNontrivialString(vm, numericString(m_numeric)));
+ options->putDirect(vm, vm.propertyNames->numberingSystem, jsNontrivialString(vm, m_numberingSystem));
+ return options;
+}
+
+static StringView singularUnit(StringView unit)
+{
+ // Plurals are allowed, but thankfully they're all just a simple -s.
+ return unit.endsWith("s") ? unit.left(unit.length() - 1) : unit;
+}
+
+// https://tc39.es/ecma402/#sec-singularrelativetimeunit
+static Optional<URelativeDateTimeUnit> relativeTimeUnitType(StringView unit)
+{
+ StringView singular = singularUnit(unit);
+
+ if (singular == "second")
+ return UDAT_REL_UNIT_SECOND;
+ if (singular == "minute")
+ return UDAT_REL_UNIT_MINUTE;
+ if (singular == "hour")
+ return UDAT_REL_UNIT_HOUR;
+ if (singular == "day")
+ return UDAT_REL_UNIT_DAY;
+ if (singular == "week")
+ return UDAT_REL_UNIT_WEEK;
+ if (singular == "month")
+ return UDAT_REL_UNIT_MONTH;
+ if (singular == "quarter")
+ return UDAT_REL_UNIT_QUARTER;
+ if (singular == "year")
+ return UDAT_REL_UNIT_YEAR;
+
+ return WTF::nullopt;
+}
+
+String IntlRelativeTimeFormat::formatInternal(JSGlobalObject* globalObject, double value, StringView unit)
+{
+ ASSERT(m_relativeDateTimeFormatter);
+
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ if (!std::isfinite(value)) {
+ throwRangeError(globalObject, scope, "number argument must be finite"_s);
+ return String();
+ }
+
+ auto unitType = relativeTimeUnitType(unit);
+ if (!unitType) {
+ throwRangeError(globalObject, scope, "unit argument is not a recognized unit type"_s);
+ return String();
+ }
+
+ auto formatRelativeTime = m_numeric ? ureldatefmt_formatNumeric : ureldatefmt_format;
+
+ UErrorCode status = U_ZERO_ERROR;
+ Vector<UChar, 32> result(32);
+ auto resultLength = formatRelativeTime(m_relativeDateTimeFormatter.get(), value, unitType.value(), result.data(), result.size(), &status);
+ if (status == U_BUFFER_OVERFLOW_ERROR) {
+ status = U_ZERO_ERROR;
+ result.grow(resultLength);
+ formatRelativeTime(m_relativeDateTimeFormatter.get(), value, unitType.value(), result.data(), resultLength, &status);
+ }
+ if (UNLIKELY(U_FAILURE(status))) {
+ throwTypeError(globalObject, scope, "failed to format relative time"_s);
+ return String();
+ }
+
+ return String(result.data(), resultLength);
+}
+
+// https://tc39.es/ecma402/#sec-FormatRelativeTime
+JSValue IntlRelativeTimeFormat::format(JSGlobalObject* globalObject, double value, StringView unit)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ String result = formatInternal(globalObject, value, unit);
+ RETURN_IF_EXCEPTION(scope, { });
+
+ return jsString(vm, result);
+}
+
+// https://tc39.es/ecma402/#sec-FormatRelativeTimeToParts
+JSValue IntlRelativeTimeFormat::formatToParts(JSGlobalObject* globalObject, double value, StringView unit)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ String formattedRelativeTime = formatInternal(globalObject, value, unit);
+ RETURN_IF_EXCEPTION(scope, { });
+
+ UErrorCode status = U_ZERO_ERROR;
+ auto iterator = std::unique_ptr<UFieldPositionIterator, UFieldPositionIteratorDeleter>(ufieldpositer_open(&status));
+ ASSERT(U_SUCCESS(status));
+
+ double absValue = std::abs(value);
+
+ Vector<UChar, 32> buffer(32);
+ auto numberLength = unum_formatDoubleForFields(m_numberFormat.get(), absValue, buffer.data(), buffer.size(), iterator.get(), &status);
+ if (status == U_BUFFER_OVERFLOW_ERROR) {
+ status = U_ZERO_ERROR;
+ buffer.grow(numberLength);
+ unum_formatDoubleForFields(m_numberFormat.get(), absValue, buffer.data(), numberLength, iterator.get(), &status);
+ }
+ if (U_FAILURE(status))
+ return throwTypeError(globalObject, scope, "failed to format relative time"_s);
+
+ auto formattedNumber = String(buffer.data(), numberLength);
+
+ JSArray* parts = JSArray::tryCreate(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), 0);
+ if (!parts)
+ return throwOutOfMemoryError(globalObject, scope);
+
+ JSString* literalString = jsNontrivialString(vm, "literal"_s);
+
+ // We only have one input number, so our relative time will have at most one numeric substring,
+ // but we need to list all of the numeric parts separately.
+ size_t numberEnd = 0;
+ size_t numberStart = formattedRelativeTime.find(formattedNumber);
+ if (numberStart != notFound) {
+ numberEnd = numberStart + numberLength;
+
+ // Add initial literal if there is one.
+ if (numberStart) {
+ JSObject* part = constructEmptyObject(globalObject);
+ part->putDirect(vm, vm.propertyNames->type, literalString);
+ part->putDirect(vm, vm.propertyNames->value, jsSubstring(vm, formattedRelativeTime, 0, numberStart));
+ parts->push(globalObject, part);
+ RETURN_IF_EXCEPTION(scope, { });
+ }
+
+ IntlNumberFormat::formatToPartsInternal(globalObject, absValue, formattedNumber, iterator.get(), parts, jsString(vm, singularUnit(unit).toString()));
+ RETURN_IF_EXCEPTION(scope, { });
+ }
+
+ // Add final literal if there is one.
+ auto stringLength = formattedRelativeTime.length();
+ if (numberEnd != stringLength) {
+ JSObject* part = constructEmptyObject(globalObject);
+ part->putDirect(vm, vm.propertyNames->type, literalString);
+ part->putDirect(vm, vm.propertyNames->value, jsSubstring(vm, formattedRelativeTime, numberEnd, stringLength - numberEnd));
+ parts->push(globalObject, part);
+ RETURN_IF_EXCEPTION(scope, { });
+ }
+
+ return parts;
+}
+
+} // namespace JSC
Copied: trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormat.h (from rev 260348, trunk/Source/_javascript_Core/runtime/IntlNumberFormat.h) (0 => 260349)
--- trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormat.h (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormat.h 2020-04-20 05:15:35 UTC (rev 260349)
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2020 Sony Interactive Entertainment Inc.
+ *
+ * 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 <unicode/ufieldpositer.h>
+#include <unicode/ureldatefmt.h>
+
+namespace JSC {
+
+class IntlRelativeTimeFormat final : public JSNonFinalObject {
+public:
+ using Base = JSNonFinalObject;
+
+ static constexpr bool needsDestruction = true;
+
+ static void destroy(JSCell* cell)
+ {
+ static_cast<IntlRelativeTimeFormat*>(cell)->IntlRelativeTimeFormat::~IntlRelativeTimeFormat();
+ }
+
+ template<typename CellType, SubspaceAccess mode>
+ static IsoSubspace* subspaceFor(VM& vm)
+ {
+ return vm.intlRelativeTimeFormatSpace<mode>();
+ }
+
+ static IntlRelativeTimeFormat* create(VM&, Structure*);
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+ DECLARE_INFO;
+
+ void initializeRelativeTimeFormat(JSGlobalObject*, JSValue locales, JSValue options);
+ JSValue format(JSGlobalObject*, double, StringView unitString);
+ JSValue formatToParts(JSGlobalObject*, double, StringView unitString);
+ JSObject* resolvedOptions(JSGlobalObject*);
+
+private:
+ IntlRelativeTimeFormat(VM&, Structure*);
+ void finishCreation(VM&);
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ String formatInternal(JSGlobalObject*, double, StringView unit);
+
+ struct URelativeDateTimeFormatterDeleter {
+ void operator()(URelativeDateTimeFormatter*) const;
+ };
+ struct UNumberFormatDeleter {
+ void operator()(UNumberFormat*) const;
+ };
+
+ std::unique_ptr<URelativeDateTimeFormatter, URelativeDateTimeFormatterDeleter> m_relativeDateTimeFormatter;
+ std::unique_ptr<UNumberFormat, UNumberFormatDeleter> m_numberFormat;
+
+ String m_locale;
+ String m_numberingSystem;
+ UDateRelativeDateTimeFormatterStyle m_style { UDAT_STYLE_LONG };
+ bool m_numeric { true };
+};
+
+} // namespace JSC
Added: trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatConstructor.cpp (0 => 260349)
--- trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatConstructor.cpp (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatConstructor.cpp 2020-04-20 05:15:35 UTC (rev 260349)
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2020 Sony Interactive Entertainment Inc.
+ *
+ * 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 "IntlRelativeTimeFormatConstructor.h"
+
+#include "Error.h"
+#include "IntlObject.h"
+#include "IntlRelativeTimeFormat.h"
+#include "IntlRelativeTimeFormatPrototype.h"
+#include "JSCInlines.h"
+#include "Lookup.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IntlRelativeTimeFormatConstructor);
+
+static EncodedJSValue JSC_HOST_CALL IntlRelativeTimeFormatConstructorFuncSupportedLocalesOf(JSGlobalObject*, CallFrame*);
+
+}
+
+#include "IntlRelativeTimeFormatConstructor.lut.h"
+
+namespace JSC {
+
+const ClassInfo IntlRelativeTimeFormatConstructor::s_info = { "Function", &InternalFunction::s_info, &relativeTimeFormatConstructorTable, nullptr, CREATE_METHOD_TABLE(IntlRelativeTimeFormatConstructor) };
+
+/* Source for IntlRelativeTimeFormatConstructor.lut.h
+@begin relativeTimeFormatConstructorTable
+ supportedLocalesOf IntlRelativeTimeFormatConstructorFuncSupportedLocalesOf DontEnum|Function 1
+@end
+*/
+
+IntlRelativeTimeFormatConstructor* IntlRelativeTimeFormatConstructor::create(VM& vm, Structure* structure, IntlRelativeTimeFormatPrototype* relativeTimeFormatPrototype)
+{
+ auto* constructor = new (NotNull, allocateCell<IntlRelativeTimeFormatConstructor>(vm.heap)) IntlRelativeTimeFormatConstructor(vm, structure);
+ constructor->finishCreation(vm, relativeTimeFormatPrototype);
+ return constructor;
+}
+
+Structure* IntlRelativeTimeFormatConstructor::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(InternalFunctionType, StructureFlags), info());
+}
+
+static EncodedJSValue JSC_HOST_CALL callIntlRelativeTimeFormat(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL constructIntlRelativeTimeFormat(JSGlobalObject*, CallFrame*);
+
+IntlRelativeTimeFormatConstructor::IntlRelativeTimeFormatConstructor(VM& vm, Structure* structure)
+ : Base(vm, structure, callIntlRelativeTimeFormat, constructIntlRelativeTimeFormat)
+{
+}
+
+void IntlRelativeTimeFormatConstructor::finishCreation(VM& vm, IntlRelativeTimeFormatPrototype* relativeTimeFormatPrototype)
+{
+ Base::finishCreation(vm, "RelativeTimeFormat"_s, NameAdditionMode::WithoutStructureTransition);
+ putDirectWithoutTransition(vm, vm.propertyNames->prototype, relativeTimeFormatPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
+ putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
+ relativeTimeFormatPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, this, static_cast<unsigned>(PropertyAttribute::DontEnum));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat
+static EncodedJSValue JSC_HOST_CALL constructIntlRelativeTimeFormat(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ Structure* structure = InternalFunction::createSubclassStructure(globalObject, callFrame->jsCallee(), callFrame->newTarget(), jsCast<IntlRelativeTimeFormatConstructor*>(callFrame->jsCallee())->relativeTimeFormatStructure(vm));
+ RETURN_IF_EXCEPTION(scope, encodedJSValue());
+ IntlRelativeTimeFormat* relativeTimeFormat = IntlRelativeTimeFormat::create(vm, structure);
+ ASSERT(relativeTimeFormat);
+
+ scope.release();
+ relativeTimeFormat->initializeRelativeTimeFormat(globalObject, callFrame->argument(0), callFrame->argument(1));
+ return JSValue::encode(relativeTimeFormat);
+}
+
+// https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat
+static EncodedJSValue JSC_HOST_CALL callIntlRelativeTimeFormat(JSGlobalObject* globalObject, CallFrame*)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ return JSValue::encode(throwConstructorCannotBeCalledAsFunctionTypeError(globalObject, scope, "RelativeTimeFormat"));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat.supportedLocalesOf
+EncodedJSValue JSC_HOST_CALL IntlRelativeTimeFormatConstructorFuncSupportedLocalesOf(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto& availableLocales = intlRelativeTimeFormatAvailableLocales();
+
+ auto requestedLocales = canonicalizeLocaleList(globalObject, callFrame->argument(0));
+ RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+ RELEASE_AND_RETURN(scope, JSValue::encode(supportedLocales(globalObject, availableLocales, requestedLocales, callFrame->argument(1))));
+}
+
+} // namespace JSC
Added: trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatConstructor.h (0 => 260349)
--- trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatConstructor.h (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatConstructor.h 2020-04-20 05:15:35 UTC (rev 260349)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 Sony Interactive Entertainment Inc.
+ *
+ * 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 IntlRelativeTimeFormatPrototype;
+
+class IntlRelativeTimeFormatConstructor final : public InternalFunction {
+public:
+ using Base = InternalFunction;
+ static constexpr unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable;
+
+ static IntlRelativeTimeFormatConstructor* create(VM&, Structure*, IntlRelativeTimeFormatPrototype*);
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+ DECLARE_INFO;
+
+ Structure* relativeTimeFormatStructure(VM&) const { return globalObject()->relativeTimeFormatStructure(); }
+
+protected:
+ void finishCreation(VM&, IntlRelativeTimeFormatPrototype*);
+
+private:
+ IntlRelativeTimeFormatConstructor(VM&, Structure*);
+};
+STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(IntlRelativeTimeFormatConstructor, InternalFunction);
+
+} // namespace JSC
Added: trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatPrototype.cpp (0 => 260349)
--- trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatPrototype.cpp (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatPrototype.cpp 2020-04-20 05:15:35 UTC (rev 260349)
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2020 Sony Interactive Entertainment Inc.
+ *
+ * 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 "IntlRelativeTimeFormatPrototype.h"
+
+#include "Error.h"
+#include "IntlRelativeTimeFormat.h"
+#include "JSCInlines.h"
+#include "JSObjectInlines.h"
+
+namespace JSC {
+
+static EncodedJSValue JSC_HOST_CALL IntlRelativeTimeFormatPrototypeFuncFormat(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlRelativeTimeFormatPrototypeFuncFormatToParts(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlRelativeTimeFormatPrototypeFuncResolvedOptions(JSGlobalObject*, CallFrame*);
+
+}
+
+#include "IntlRelativeTimeFormatPrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo IntlRelativeTimeFormatPrototype::s_info = { "Object", &Base::s_info, &relativeTimeFormatPrototypeTable, nullptr, CREATE_METHOD_TABLE(IntlRelativeTimeFormatPrototype) };
+
+/* Source for IntlRelativeTimeFormatPrototype.lut.h
+@begin relativeTimeFormatPrototypeTable
+ format IntlRelativeTimeFormatPrototypeFuncFormat DontEnum|Function 2
+ formatToParts IntlRelativeTimeFormatPrototypeFuncFormatToParts DontEnum|Function 2
+ resolvedOptions IntlRelativeTimeFormatPrototypeFuncResolvedOptions DontEnum|Function 0
+@end
+*/
+
+IntlRelativeTimeFormatPrototype* IntlRelativeTimeFormatPrototype::create(VM& vm, Structure* structure)
+{
+ auto* object = new (NotNull, allocateCell<IntlRelativeTimeFormatPrototype>(vm.heap)) IntlRelativeTimeFormatPrototype(vm, structure);
+ object->finishCreation(vm);
+ return object;
+}
+
+Structure* IntlRelativeTimeFormatPrototype::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+IntlRelativeTimeFormatPrototype::IntlRelativeTimeFormatPrototype(VM& vm, Structure* structure)
+ : Base(vm, structure)
+{
+}
+
+void IntlRelativeTimeFormatPrototype::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsNontrivialString(vm, "Intl.RelativeTimeFormat"_s), PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
+}
+
+// https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat.prototype.format
+EncodedJSValue JSC_HOST_CALL IntlRelativeTimeFormatPrototypeFuncFormat(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* relativeTimeFormat = jsDynamicCast<IntlRelativeTimeFormat*>(vm, callFrame->thisValue());
+ if (!relativeTimeFormat)
+ return JSValue::encode(throwTypeError(globalObject, scope, "Intl.RelativeTimeFormat.prototype.format called on value that's not an object initialized as a RelativeTimeFormat"_s));
+
+ double value = callFrame->argument(0).toNumber(globalObject);
+ RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+ String unit = callFrame->argument(1).toWTFString(globalObject);
+ RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+ RELEASE_AND_RETURN(scope, JSValue::encode(relativeTimeFormat->format(globalObject, value, unit)));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.RelativeTimeFormat.prototype.formatToParts
+EncodedJSValue JSC_HOST_CALL IntlRelativeTimeFormatPrototypeFuncFormatToParts(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* relativeTimeFormat = jsDynamicCast<IntlRelativeTimeFormat*>(vm, callFrame->thisValue());
+ if (!relativeTimeFormat)
+ return JSValue::encode(throwTypeError(globalObject, scope, "Intl.RelativeTimeFormat.prototype.formatToParts called on value that's not an object initialized as a RelativeTimeFormat"_s));
+
+ double value = callFrame->argument(0).toNumber(globalObject);
+ RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+ String unit = callFrame->argument(1).toWTFString(globalObject);
+ RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+ RELEASE_AND_RETURN(scope, JSValue::encode(relativeTimeFormat->formatToParts(globalObject, value, unit)));
+}
+
+// https://tc39.es/ecma402/#sec-intl.relativetimeformat.prototype.resolvedoptions
+EncodedJSValue JSC_HOST_CALL IntlRelativeTimeFormatPrototypeFuncResolvedOptions(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* relativeTimeFormat = jsDynamicCast<IntlRelativeTimeFormat*>(vm, callFrame->thisValue());
+ if (!relativeTimeFormat)
+ return JSValue::encode(throwTypeError(globalObject, scope, "Intl.RelativeTimeFormat.prototype.resolvedOptions called on value that's not an object initialized as a RelativeTimeFormat"_s));
+
+ RELEASE_AND_RETURN(scope, JSValue::encode(relativeTimeFormat->resolvedOptions(globalObject)));
+}
+
+} // namespace JSC
Added: trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatPrototype.h (0 => 260349)
--- trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatPrototype.h (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlRelativeTimeFormatPrototype.h 2020-04-20 05:15:35 UTC (rev 260349)
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 Sony Interactive Entertainment Inc.
+ *
+ * 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 IntlRelativeTimeFormatPrototype 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(IntlRelativeTimeFormatPrototype, Base);
+ return &vm.plainObjectSpace;
+ }
+
+ static IntlRelativeTimeFormatPrototype* create(VM&, Structure*);
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+ DECLARE_INFO;
+
+protected:
+ void finishCreation(VM&);
+
+private:
+ IntlRelativeTimeFormatPrototype(VM&, Structure*);
+};
+
+} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (260348 => 260349)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2020-04-20 05:15:35 UTC (rev 260349)
@@ -86,6 +86,8 @@
#include "IntlObject.h"
#include "IntlPluralRules.h"
#include "IntlPluralRulesPrototype.h"
+#include "IntlRelativeTimeFormat.h"
+#include "IntlRelativeTimeFormatPrototype.h"
#include "IteratorPrototype.h"
#include "JSAPIWrapperObject.h"
#include "JSArrayBuffer.h"
@@ -959,6 +961,12 @@
IntlPluralRulesPrototype* pluralRulesPrototype = IntlPluralRulesPrototype::create(init.vm, globalObject, IntlPluralRulesPrototype::createStructure(init.vm, globalObject, globalObject->objectPrototype()));
init.set(IntlPluralRules::createStructure(init.vm, globalObject, pluralRulesPrototype));
});
+ m_relativeTimeFormatStructure.initLater(
+ [] (const Initializer<Structure>& init) {
+ JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner);
+ IntlRelativeTimeFormatPrototype* relativeTimeFormatPrototype = IntlRelativeTimeFormatPrototype::create(init.vm, IntlRelativeTimeFormatPrototype::createStructure(init.vm, globalObject, globalObject->objectPrototype()));
+ init.set(IntlRelativeTimeFormat::createStructure(init.vm, globalObject, relativeTimeFormatPrototype));
+ });
m_defaultCollator.initLater(
[] (const Initializer<IntlCollator>& init) {
JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner);
@@ -970,7 +978,7 @@
init.set(collator);
});
- IntlObject* intl = IntlObject::create(vm, IntlObject::createStructure(vm, this, m_objectPrototype.get()));
+ IntlObject* intl = IntlObject::create(vm, this, IntlObject::createStructure(vm, this, m_objectPrototype.get()));
putDirectWithoutTransition(vm, vm.propertyNames->Intl, intl, static_cast<unsigned>(PropertyAttribute::DontEnum));
m_moduleLoader.initLater(
@@ -1769,6 +1777,7 @@
thisObject->m_numberFormatStructure.visit(visitor);
thisObject->m_dateTimeFormatStructure.visit(visitor);
thisObject->m_pluralRulesStructure.visit(visitor);
+ thisObject->m_relativeTimeFormatStructure.visit(visitor);
visitor.append(thisObject->m_nullGetterFunction);
visitor.append(thisObject->m_nullSetterFunction);
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (260348 => 260349)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h 2020-04-20 05:15:35 UTC (rev 260349)
@@ -294,6 +294,7 @@
LazyProperty<JSGlobalObject, Structure> m_numberFormatStructure;
LazyProperty<JSGlobalObject, Structure> m_dateTimeFormatStructure;
LazyProperty<JSGlobalObject, Structure> m_pluralRulesStructure;
+ LazyProperty<JSGlobalObject, Structure> m_relativeTimeFormatStructure;
WriteBarrier<NullGetterFunction> m_nullGetterFunction;
WriteBarrier<NullSetterFunction> m_nullSetterFunction;
@@ -788,6 +789,7 @@
Structure* numberFormatStructure() { return m_numberFormatStructure.get(this); }
Structure* dateTimeFormatStructure() { return m_dateTimeFormatStructure.get(this); }
Structure* pluralRulesStructure() { return m_pluralRulesStructure.get(this); }
+ Structure* relativeTimeFormatStructure() { return m_relativeTimeFormatStructure.get(this); }
JS_EXPORT_PRIVATE void setRemoteDebuggingEnabled(bool);
JS_EXPORT_PRIVATE bool remoteDebuggingEnabled() const;
Modified: trunk/Source/_javascript_Core/runtime/OptionsList.h (260348 => 260349)
--- trunk/Source/_javascript_Core/runtime/OptionsList.h 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/OptionsList.h 2020-04-20 05:15:35 UTC (rev 260349)
@@ -484,6 +484,7 @@
v(Bool, useWebAssemblyMultiValues, true, Normal, "Allow types from the wasm mulit-values spec.") \
v(Bool, useWeakRefs, false, Normal, "Expose the WeakRef constructor.") \
v(Bool, useBigInt, true, Normal, "If true, we will enable BigInt support.") \
+ v(Bool, useIntlRelativeTimeFormat, false, Normal, "Expose the Intl.RelativeTimeFormat constructor.") \
v(Bool, useArrayAllocationProfiling, true, Normal, "If true, we will use our normal array allocation profiling. If false, the allocation profile will always claim to be undecided.") \
v(Bool, forcePolyProto, false, Normal, "If true, create_this will always create an object with a poly proto structure.") \
v(Bool, forceMiniVMMode, false, Normal, "If true, it will force mini VM mode on.") \
Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (260348 => 260349)
--- trunk/Source/_javascript_Core/runtime/VM.cpp 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp 2020-04-20 05:15:35 UTC (rev 260349)
@@ -77,6 +77,7 @@
#include "IntlDateTimeFormat.h"
#include "IntlNumberFormat.h"
#include "IntlPluralRules.h"
+#include "IntlRelativeTimeFormat.h"
#include "IsoHeapCellType.h"
#include "IsoInlinedHeapCellType.h"
#include "JITCode.h"
@@ -340,6 +341,7 @@
, intlDateTimeFormatHeapCellType(IsoHeapCellType::create<IntlDateTimeFormat>())
, intlNumberFormatHeapCellType(IsoHeapCellType::create<IntlNumberFormat>())
, intlPluralRulesHeapCellType(IsoHeapCellType::create<IntlPluralRules>())
+ , intlRelativeTimeFormatHeapCellType(IsoHeapCellType::create<IntlRelativeTimeFormat>())
#if ENABLE(WEBASSEMBLY)
, webAssemblyCodeBlockHeapCellType(IsoHeapCellType::create<JSWebAssemblyCodeBlock>())
, webAssemblyFunctionHeapCellType(IsoHeapCellType::create<WebAssemblyFunction>())
@@ -1511,6 +1513,7 @@
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlDateTimeFormatSpace, intlDateTimeFormatHeapCellType.get(), IntlDateTimeFormat)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlNumberFormatSpace, intlNumberFormatHeapCellType.get(), IntlNumberFormat)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlPluralRulesSpace, intlPluralRulesHeapCellType.get(), IntlPluralRules)
+DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlRelativeTimeFormatSpace, intlRelativeTimeFormatHeapCellType.get(), IntlRelativeTimeFormat)
#if ENABLE(WEBASSEMBLY)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(jsToWasmICCalleeSpace, cellHeapCellType.get(), JSToWasmICCallee)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(webAssemblyCodeBlockSpace, webAssemblyCodeBlockHeapCellType.get(), JSWebAssemblyCodeBlock) // Hash:0x9ad995cd
Modified: trunk/Source/_javascript_Core/runtime/VM.h (260348 => 260349)
--- trunk/Source/_javascript_Core/runtime/VM.h 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/runtime/VM.h 2020-04-20 05:15:35 UTC (rev 260349)
@@ -128,6 +128,7 @@
class IntlDateTimeFormat;
class IntlNumberFormat;
class IntlPluralRules;
+class IntlRelativeTimeFormat;
class JSAPIGlobalObject;
class JSAPIWrapperGlobalObject;
class JSAPIWrapperObject;
@@ -401,6 +402,7 @@
std::unique_ptr<IsoHeapCellType> intlDateTimeFormatHeapCellType;
std::unique_ptr<IsoHeapCellType> intlNumberFormatHeapCellType;
std::unique_ptr<IsoHeapCellType> intlPluralRulesHeapCellType;
+ std::unique_ptr<IsoHeapCellType> intlRelativeTimeFormatHeapCellType;
#if ENABLE(WEBASSEMBLY)
std::unique_ptr<IsoHeapCellType> webAssemblyCodeBlockHeapCellType;
std::unique_ptr<IsoHeapCellType> webAssemblyFunctionHeapCellType;
@@ -557,6 +559,7 @@
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlDateTimeFormatSpace)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlNumberFormatSpace)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlPluralRulesSpace)
+ DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlRelativeTimeFormatSpace)
#if ENABLE(WEBASSEMBLY)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(jsToWasmICCalleeSpace)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(webAssemblyCodeBlockSpace)
Modified: trunk/Source/_javascript_Core/tools/JSDollarVM.cpp (260348 => 260349)
--- trunk/Source/_javascript_Core/tools/JSDollarVM.cpp 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Source/_javascript_Core/tools/JSDollarVM.cpp 2020-04-20 05:15:35 UTC (rev 260349)
@@ -53,6 +53,7 @@
#include "TypeProfilerLog.h"
#include "VMInspector.h"
#include "WasmCapabilities.h"
+#include <unicode/uversion.h>
#include <wtf/Atomics.h>
#include <wtf/CPUTime.h>
#include <wtf/DataLog.h>
@@ -2977,6 +2978,13 @@
return JSValue::encode(jsUndefined());
}
+static EncodedJSValue JSC_HOST_CALL functionICUVersion(JSGlobalObject*, CallFrame*)
+{
+ UVersionInfo versionInfo;
+ u_getVersion(versionInfo);
+ return JSValue::encode(jsNumber(versionInfo[0]));
+}
+
void JSDollarVM::finishCreation(VM& vm)
{
DollarVMAssertScope assertScope;
@@ -3114,6 +3122,7 @@
addFunction(vm, "rejectPromiseAsHandled", functionRejectPromiseAsHandled, 1);
addFunction(vm, "setUserPreferredLanguages", functionSetUserPreferredLanguages, 1);
+ addFunction(vm, "icuVersion", functionICUVersion, 0);
m_objectDoingSideEffectPutWithoutCorrectSlotStatusStructure.set(vm, this, ObjectDoingSideEffectPutWithoutCorrectSlotStatus::createStructure(vm, globalObject, jsNull()));
}
Modified: trunk/Tools/ChangeLog (260348 => 260349)
--- trunk/Tools/ChangeLog 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Tools/ChangeLog 2020-04-20 05:15:35 UTC (rev 260349)
@@ -1,3 +1,13 @@
+2020-04-19 Ross Kirsling <[email protected]>
+
+ [ECMA-402] Intl.RelativeTimeFormat missing in WebKit
+ https://bugs.webkit.org/show_bug.cgi?id=209770
+
+ Reviewed by Darin Adler.
+
+ * Scripts/run-jsc-stress-tests:
+ Add runIntlRelativeTimeFormatEnabled.
+
2020-04-19 Don Olmstead <[email protected]>
[CMake] Consolidate TestNetscapePlugin build
Modified: trunk/Tools/Scripts/run-jsc-stress-tests (260348 => 260349)
--- trunk/Tools/Scripts/run-jsc-stress-tests 2020-04-20 03:46:40 UTC (rev 260348)
+++ trunk/Tools/Scripts/run-jsc-stress-tests 2020-04-20 05:15:35 UTC (rev 260349)
@@ -710,6 +710,10 @@
run("big-int-enabled-baseline", "--useBigInt=true", "--useDFGJIT=0", *optionalTestSpecificOptions)
end
+def runIntlRelativeTimeFormatEnabled(*optionalTestSpecificOptions)
+ run("intl-relativetimeformat-enabled", "--useIntlRelativeTimeFormat=true" , *(FTL_OPTIONS + optionalTestSpecificOptions))
+end
+
def runFTLNoCJIT(*optionalTestSpecificOptions)
run("misc-ftl-no-cjit", *(FTL_OPTIONS + NO_CJIT_OPTIONS + optionalTestSpecificOptions))
end