Diff
Modified: trunk/JSTests/ChangeLog (261214 => 261215)
--- trunk/JSTests/ChangeLog 2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/JSTests/ChangeLog 2020-05-06 06:01:07 UTC (rev 261215)
@@ -1,3 +1,20 @@
+2020-05-05 Ross Kirsling <ross.kirsl...@sony.com>
+
+ [ECMA-402] Implement Intl.Locale
+ https://bugs.webkit.org/show_bug.cgi?id=209772
+
+ Reviewed by Darin Adler and Saam Barati.
+
+ * stress/intl-locale.js: Added.
+ * stress/intl-locale-as-intl-param.js: Added.
+
+ * test262/config.yaml:
+ Enable Intl.Locale feature with flag.
+
+ * test262/expectations.yaml:
+ Mark known failures.
+ None of these should be specific to Intl.Locale.
+
2020-05-05 Yusuke Suzuki <ysuz...@apple.com>
[JSC] Implement BigInt.asIntN and BigInt.asUintN
Added: trunk/JSTests/stress/intl-locale-as-intl-param.js (0 => 261215)
--- trunk/JSTests/stress/intl-locale-as-intl-param.js (rev 0)
+++ trunk/JSTests/stress/intl-locale-as-intl-param.js 2020-05-06 06:01:07 UTC (rev 261215)
@@ -0,0 +1,45 @@
+//@ runIntlLocaleEnabled("--useIntlRelativeTimeFormat=true")
+
+const tag = 'ja-Hant-KR-u-ca-buddhist-co-eor-hc-h11-kf-lower-kn-false-nu-thai';
+const locale = new Intl.Locale(tag);
+
+function shouldBeSameWithTagOrLocale(func) {
+ const actual = func(locale);
+ const expected = func(tag);
+ if (actual !== expected)
+ throw new Error(`expected ${expected} but got ${actual}`);
+}
+
+shouldBeSameWithTagOrLocale(tagOrLocale => tagOrLocale.toString());
+shouldBeSameWithTagOrLocale(tagOrLocale => new Intl.Locale(tagOrLocale).toString());
+
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.getCanonicalLocales(tagOrLocale)));
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.getCanonicalLocales(['en', tagOrLocale, 'fr'])));
+
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.Collator.supportedLocalesOf(tagOrLocale)));
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.Collator.supportedLocalesOf(['en', tagOrLocale, 'fr'])));
+shouldBeSameWithTagOrLocale(tagOrLocale => new Intl.Collator(tagOrLocale).resolvedOptions().locale);
+
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.DateTimeFormat.supportedLocalesOf(tagOrLocale)));
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.DateTimeFormat.supportedLocalesOf(['en', tagOrLocale, 'fr'])));
+shouldBeSameWithTagOrLocale(tagOrLocale => new Intl.DateTimeFormat(tagOrLocale).resolvedOptions().locale);
+
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.NumberFormat.supportedLocalesOf(tagOrLocale)));
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.NumberFormat.supportedLocalesOf(['en', tagOrLocale, 'fr'])));
+shouldBeSameWithTagOrLocale(tagOrLocale => new Intl.NumberFormat(tagOrLocale).resolvedOptions().locale);
+
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.PluralRules.supportedLocalesOf(tagOrLocale)));
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.PluralRules.supportedLocalesOf(['en', tagOrLocale, 'fr'])));
+shouldBeSameWithTagOrLocale(tagOrLocale => new Intl.PluralRules(tagOrLocale).resolvedOptions().locale);
+
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf(tagOrLocale)));
+shouldBeSameWithTagOrLocale(tagOrLocale => JSON.stringify(Intl.RelativeTimeFormat.supportedLocalesOf(['en', tagOrLocale, 'fr'])));
+shouldBeSameWithTagOrLocale(tagOrLocale => new Intl.RelativeTimeFormat(tagOrLocale).resolvedOptions().locale);
+
+shouldBeSameWithTagOrLocale(tagOrLocale => [3].toLocaleString(tagOrLocale));
+shouldBeSameWithTagOrLocale(tagOrLocale => 3n.toLocaleString(tagOrLocale));
+shouldBeSameWithTagOrLocale(tagOrLocale => new Date(0).toLocaleString(tagOrLocale, { timeZone: 'UTC' }));
+shouldBeSameWithTagOrLocale(tagOrLocale => 3..toLocaleString(tagOrLocale));
+shouldBeSameWithTagOrLocale(tagOrLocale => 'ä'.localeCompare('a', tagOrLocale));
+shouldBeSameWithTagOrLocale(tagOrLocale => 'Æ'.toLocaleLowerCase(tagOrLocale));
+shouldBeSameWithTagOrLocale(tagOrLocale => 'æ'.toLocaleUpperCase(tagOrLocale));
Added: trunk/JSTests/stress/intl-locale.js (0 => 261215)
--- trunk/JSTests/stress/intl-locale.js (rev 0)
+++ trunk/JSTests/stress/intl-locale.js 2020-05-06 06:01:07 UTC (rev 261215)
@@ -0,0 +1,226 @@
+//@ runIntlLocaleEnabled
+
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error(`expected ${expected} but got ${actual}`);
+}
+
+function shouldNotThrow(func) {
+ func();
+}
+
+function shouldThrow(func, errorType) {
+ let error;
+ try {
+ func();
+ } catch (e) {
+ error = e;
+ }
+
+ if (!(error instanceof errorType))
+ throw new Error(`Expected ${errorType.name}!`);
+}
+
+shouldBe(Intl.Locale instanceof Function, true);
+shouldBe(Intl.Locale.length, 1);
+shouldBe(Object.getOwnPropertyDescriptor(Intl.Locale, 'prototype').writable, false);
+shouldBe(Object.getOwnPropertyDescriptor(Intl.Locale, 'prototype').enumerable, false);
+shouldBe(Object.getOwnPropertyDescriptor(Intl.Locale, 'prototype').configurable, false);
+
+shouldThrow(() => Intl.Locale(), TypeError);
+shouldThrow(() => Intl.Locale.call({}), TypeError);
+
+shouldThrow(() => new Intl.Locale(), TypeError);
+shouldThrow(() => new Intl.Locale(5), TypeError);
+shouldThrow(() => new Intl.Locale(''), RangeError);
+shouldThrow(() => new Intl.Locale('a'), RangeError);
+shouldThrow(() => new Intl.Locale('abcdefghij'), RangeError);
+shouldThrow(() => new Intl.Locale('#$'), RangeError);
+shouldThrow(() => new Intl.Locale('en-@-abc'), RangeError);
+shouldThrow(() => new Intl.Locale('en-u'), RangeError);
+shouldThrow(() => new Intl.Locale('en-u-kn-true-u-ko-true'), RangeError);
+shouldThrow(() => new Intl.Locale('en-x'), RangeError);
+shouldThrow(() => new Intl.Locale('en-*'), RangeError);
+shouldThrow(() => new Intl.Locale('en-'), RangeError);
+shouldThrow(() => new Intl.Locale('en--US'), RangeError);
+shouldThrow(() => new Intl.Locale(['en', 'ja']), RangeError);
+shouldThrow(() => new Intl.Locale({}), RangeError);
+shouldThrow(() => new Intl.Locale({ toString() { throw new Error(); } }), Error);
+shouldNotThrow(() => new Intl.Locale({ toString() { return 'en'; } }));
+
+shouldThrow(() => new Intl.Locale('en', null), TypeError);
+
+shouldBe(new Intl.Locale('en') instanceof Intl.Locale, true);
+
+{
+ class DerivedLocale extends Intl.Locale {}
+
+ const dl = new DerivedLocale('en');
+ shouldBe(dl instanceof DerivedLocale, true);
+ shouldBe(dl instanceof Intl.Locale, true);
+ shouldBe(dl.maximize, Intl.Locale.prototype.maximize);
+ shouldBe(Object.getPrototypeOf(dl), DerivedLocale.prototype);
+ shouldBe(Object.getPrototypeOf(DerivedLocale.prototype), Intl.Locale.prototype);
+}
+
+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(() => new Intl.Locale(validLanguageTag));
+
+shouldBe(Object.getPrototypeOf(Intl.Locale.prototype), Object.prototype);
+
+shouldBe(Intl.Locale.prototype.constructor, Intl.Locale);
+
+shouldBe(Intl.Locale.prototype[Symbol.toStringTag], 'Intl.Locale');
+shouldBe(Object.prototype.toString.call(Intl.Locale.prototype), '[object Intl.Locale]');
+shouldBe(Object.getOwnPropertyDescriptor(Intl.Locale.prototype, Symbol.toStringTag).writable, false);
+shouldBe(Object.getOwnPropertyDescriptor(Intl.Locale.prototype, Symbol.toStringTag).enumerable, false);
+shouldBe(Object.getOwnPropertyDescriptor(Intl.Locale.prototype, Symbol.toStringTag).configurable, true);
+
+shouldBe(Intl.Locale.prototype.maximize.length, 0);
+shouldBe(Intl.Locale.prototype.minimize.length, 0);
+shouldBe(Intl.Locale.prototype.toString.length, 0);
+shouldThrow(() => Intl.Locale.prototype.maximize.call({ toString() { return 'en'; } }), TypeError);
+shouldThrow(() => Intl.Locale.prototype.minimize.call({ toString() { return 'en'; } }), TypeError);
+shouldThrow(() => Intl.Locale.prototype.toString.call({ toString() { return 'en'; } }), TypeError);
+shouldThrow(() => Intl.Locale.prototype.baseName, TypeError);
+shouldThrow(() => Intl.Locale.prototype.calendar, TypeError);
+shouldThrow(() => Intl.Locale.prototype.caseFirst, TypeError);
+shouldThrow(() => Intl.Locale.prototype.collation, TypeError);
+shouldThrow(() => Intl.Locale.prototype.hourCycle, TypeError);
+shouldThrow(() => Intl.Locale.prototype.numeric, TypeError);
+shouldThrow(() => Intl.Locale.prototype.numberingSystem, TypeError);
+shouldThrow(() => Intl.Locale.prototype.language, TypeError);
+shouldThrow(() => Intl.Locale.prototype.script, TypeError);
+shouldThrow(() => Intl.Locale.prototype.region, TypeError);
+
+shouldBe(new Intl.Locale('en').maximize(), 'en-Latn-US');
+shouldBe(new Intl.Locale('en-Latn-US').maximize(), 'en-Latn-US');
+shouldBe(new Intl.Locale('en-u-nu-thai-x-foo').maximize(), 'en-Latn-US-u-nu-thai-x-foo');
+shouldBe(new Intl.Locale('ja').maximize(), 'ja-Jpan-JP');
+shouldBe(new Intl.Locale('zh').maximize(), 'zh-Hans-CN');
+shouldBe(new Intl.Locale('zh-Hant').maximize(), 'zh-Hant-TW');
+shouldBe(new Intl.Locale('zh', { script: 'Hant' }).maximize(), 'zh-Hant-TW');
+
+shouldBe(new Intl.Locale('en').minimize(), 'en');
+shouldBe(new Intl.Locale('en-Latn-US').minimize(), 'en');
+shouldBe(new Intl.Locale('en-Latn-US-u-nu-thai-x-foo').minimize(), 'en-u-nu-thai-x-foo');
+shouldBe(new Intl.Locale('ja-Jpan-JP').minimize(), 'ja');
+shouldBe(new Intl.Locale('zh-Hans-CN').minimize(), 'zh');
+shouldBe(new Intl.Locale('zh-Hant-TW').minimize(), 'zh-TW');
+shouldBe(new Intl.Locale('zh', { script: 'Hant', region: 'TW' }).minimize(), 'zh-TW');
+
+shouldBe(new Intl.Locale('en').toString(), 'en');
+shouldBe(new Intl.Locale('En-laTn-us-variAnt-fOObar-1abc-U-kn-tRue-A-aa-aaa-x-RESERVED').toString(), 'en-Latn-US-variant-foobar-1abc-a-aa-aaa-u-kn-true-x-reserved');
+shouldBe(new Intl.Locale('cel-gaulish', { script: 'Arab', numberingSystem: 'gujr' }).toString(), 'xtg-Arab-u-nu-gujr-x-cel-gaulish');
+shouldBe(new Intl.Locale('en-Latn-US-u-ca-gregory-co-phonebk-hc-h12-kf-upper-kn-nu-latn').toString(), 'en-Latn-US-u-ca-gregory-co-phonebk-hc-h12-kf-upper-kn-true-nu-latn');
+
+const options = {
+ calendar: 'buddhist',
+ caseFirst: 'lower',
+ collation: 'eor',
+ hourCycle: 'h11',
+ numeric: false,
+ numberingSystem: 'thai',
+ language: 'ja',
+ script: 'Hant',
+ region: 'KR'
+};
+const expected = 'ja-Hant-KR-u-ca-buddhist-co-eor-hc-h11-kf-lower-kn-false-nu-thai';
+shouldBe(new Intl.Locale('en', options).toString(), expected);
+shouldBe(new Intl.Locale('en-Latn-US-u-ca-gregory-co-phonebk-hc-h12-kf-upper-kn-nu-latn', options).toString(), expected);
+
+shouldBe(new Intl.Locale('en').baseName, 'en');
+shouldBe(new Intl.Locale('en-Latn').baseName, 'en-Latn');
+shouldBe(new Intl.Locale('en-US').baseName, 'en-US');
+shouldBe(new Intl.Locale('en-Latn-US').baseName, 'en-Latn-US');
+shouldBe(new Intl.Locale('en-variant-u-kn').baseName, 'en-variant');
+shouldBe(new Intl.Locale('en-Latn-variant-u-kn').baseName, 'en-Latn-variant');
+shouldBe(new Intl.Locale('en-variant-u-kn', { script: 'Latn' }).baseName, 'en-Latn-variant');
+shouldBe(new Intl.Locale('en-US-variant-u-kn').baseName, 'en-US-variant');
+shouldBe(new Intl.Locale('en-variant-u-kn', { region: 'US' }).baseName, 'en-US-variant');
+shouldBe(new Intl.Locale('en-Latn-US-variant-u-kn').baseName, 'en-Latn-US-variant');
+shouldBe(new Intl.Locale('en-variant-u-kn', { script: 'Latn', region: 'US' }).baseName, 'en-Latn-US-variant');
+
+shouldBe(new Intl.Locale('en').calendar, undefined);
+shouldBe(new Intl.Locale('en-u-ca-japanese').calendar, 'japanese');
+shouldBe(new Intl.Locale('en', { calendar: 'japanese' }).calendar, 'japanese');
+shouldBe(new Intl.Locale('en-u-ca-japanese', { calendar: 'dangi' }).calendar, 'dangi');
+shouldBe(new Intl.Locale('en-u-ca-islamicc').calendar, 'islamic-civil');
+shouldBe(new Intl.Locale('en', { calendar: 'islamicc' }).calendar, 'islamic-civil');
+shouldThrow(() => new Intl.Locale('en', { calendar: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.Locale('en', { calendar: 'ng' }), RangeError);
+
+shouldBe(new Intl.Locale('en').collation, undefined);
+shouldBe(new Intl.Locale('en-u-co-phonebk').collation, 'phonebk');
+shouldBe(new Intl.Locale('en', { collation: 'phonebk' }).collation, 'phonebk');
+shouldBe(new Intl.Locale('en-u-co-phonebk', { collation: 'eor' }).collation, 'eor');
+shouldThrow(() => new Intl.Locale('en', { collation: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.Locale('en', { collation: 'ng' }), RangeError);
+
+shouldBe(new Intl.Locale('en').caseFirst, undefined);
+shouldBe(new Intl.Locale('en-u-kf-upper').caseFirst, 'upper');
+shouldBe(new Intl.Locale('en', { caseFirst: 'upper' }).caseFirst, 'upper');
+shouldBe(new Intl.Locale('en-u-kf-upper', { caseFirst: 'lower' }).caseFirst, 'lower');
+shouldThrow(() => new Intl.Locale('en', { caseFirst: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.Locale('en', { caseFirst: 'bad' }), RangeError);
+
+shouldBe(new Intl.Locale('en').numeric, false);
+shouldBe(new Intl.Locale('en-u-kn').numeric, true);
+shouldBe(new Intl.Locale('en-u-kn-true').numeric, true);
+shouldBe(new Intl.Locale('en', { numeric: true }).numeric, true);
+shouldBe(new Intl.Locale('en-u-kn', { numeric: false }).numeric, false);
+shouldBe(new Intl.Locale('en-u-kn-true', { numeric: false }).numeric, false);
+shouldThrow(() => new Intl.Locale('en', { get numeric() { throw new Error(); } }), Error);
+
+shouldBe(new Intl.Locale('en').hourCycle, undefined);
+shouldBe(new Intl.Locale('en-u-hc-h11').hourCycle, 'h11');
+shouldBe(new Intl.Locale('en', { hourCycle: 'h11' }).hourCycle, 'h11');
+shouldBe(new Intl.Locale('en-u-hc-h11', { hourCycle: 'h23' }).hourCycle, 'h23');
+shouldThrow(() => new Intl.Locale('en', { hourCycle: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.Locale('en', { hourCycle: 'bad' }), RangeError);
+
+shouldBe(new Intl.Locale('en').numberingSystem, undefined);
+shouldBe(new Intl.Locale('en-u-nu-hanidec').numberingSystem, 'hanidec');
+shouldBe(new Intl.Locale('en', { numberingSystem: 'hanidec' }).numberingSystem, 'hanidec');
+shouldBe(new Intl.Locale('en-u-nu-hanidec', { numberingSystem: 'gujr' }).numberingSystem, 'gujr');
+shouldThrow(() => new Intl.Locale('en', { numberingSystem: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.Locale('en', { numberingSystem: 'ng' }), RangeError);
+
+shouldBe(new Intl.Locale('en-Latn-US').language, 'en');
+shouldBe(new Intl.Locale('en', { language: 'ar' }).language, 'ar');
+shouldBe(new Intl.Locale('cel-gaulish').language, 'xtg');
+shouldThrow(() => new Intl.Locale('en', { language: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.Locale('en', { language: 'fail' }), RangeError);
+
+shouldBe(new Intl.Locale('en-Latn-US').script, 'Latn');
+shouldBe(new Intl.Locale('en-US').script, undefined);
+shouldBe(new Intl.Locale('en-Latn', { script: 'Kore' }).script, 'Kore');
+shouldThrow(() => new Intl.Locale('en', { script: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.Locale('en', { script: 'bad' }), RangeError);
+
+shouldBe(new Intl.Locale('en-Latn-US').region, 'US');
+shouldBe(new Intl.Locale('en-Latn').region, undefined);
+shouldBe(new Intl.Locale('en-US', { region: 'KR' }).region, 'KR');
+shouldThrow(() => new Intl.Locale('en', { region: { toString() { throw new Error(); } } }), Error);
+shouldThrow(() => new Intl.Locale('en', { region: 'fail' }), RangeError);
Modified: trunk/JSTests/test262/config.yaml (261214 => 261215)
--- trunk/JSTests/test262/config.yaml 2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/JSTests/test262/config.yaml 2020-05-06 06:01:07 UTC (rev 261215)
@@ -2,6 +2,7 @@
---
flags:
BigInt: useBigInt
+ Intl.Locale: useIntlLocale
Intl.RelativeTimeFormat: useIntlRelativeTimeFormat
WeakRef: useWeakRefs
class-fields-public: usePublicClassFields
@@ -30,7 +31,6 @@
- Intl.DateTimeFormat-fractionalSecondDigits
- Intl.DisplayNames
- Intl.ListFormat
- - Intl.Locale
- Intl.NumberFormat-unified
- Intl.Segmenter
paths:
Modified: trunk/JSTests/test262/expectations.yaml (261214 => 261215)
--- trunk/JSTests/test262/expectations.yaml 2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/JSTests/test262/expectations.yaml 2020-05-06 06:01:07 UTC (rev 261215)
@@ -1716,6 +1716,57 @@
test/intl402/Intl/getCanonicalLocales/unicode-ext-key-with-digit.js:
default: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
strict mode: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+test/intl402/Locale/constructor-apply-options-canonicalizes-twice.js:
+ default: 'Test262Error: Expected SameValue(«ru-Armn-SU», «ru-Armn-AM») to be true'
+ strict mode: 'Test262Error: Expected SameValue(«ru-Armn-SU», «ru-Armn-AM») to be true'
+test/intl402/Locale/constructor-non-iana-canon.js:
+ default: 'Test262Error: new Intl.Locale("mo").maximize().toString() returns "ro-Latn-RO" Expected SameValue(«ro», «ro-Latn-RO») to be true'
+ strict mode: 'Test262Error: new Intl.Locale("mo").maximize().toString() returns "ro-Latn-RO" Expected SameValue(«ro», «ro-Latn-RO») to be true'
+test/intl402/Locale/constructor-options-language-valid-undefined.js:
+ default: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+ strict mode: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+test/intl402/Locale/constructor-options-language-valid.js:
+ default: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+ strict mode: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+test/intl402/Locale/constructor-options-numeric-undefined.js:
+ default: 'Test262Error: new Intl.Locale("en-u-kn-true", {numeric: undefined}).toString() returns "en-u-kn" Expected SameValue(«en-u-kn-true», «en-u-kn») to be true'
+ strict mode: 'Test262Error: new Intl.Locale("en-u-kn-true", {numeric: undefined}).toString() returns "en-u-kn" Expected SameValue(«en-u-kn-true», «en-u-kn») to be true'
+test/intl402/Locale/constructor-options-numeric-valid.js:
+ default: 'Test262Error: new Intl.Locale("en", {numeric: true}).toString() returns "true" Expected SameValue(«en-u-kn-true», «en-u-kn») to be true'
+ strict mode: 'Test262Error: new Intl.Locale("en", {numeric: true}).toString() returns "true" Expected SameValue(«en-u-kn-true», «en-u-kn») to be true'
+test/intl402/Locale/constructor-options-region-valid.js:
+ default: "Test262Error: new Intl.Locale('en', {region: \"554\"}).toString() returns \"en-NZ\" Expected SameValue(«en-554», «en-NZ») to be true"
+ strict mode: "Test262Error: new Intl.Locale('en', {region: \"554\"}).toString() returns \"en-NZ\" Expected SameValue(«en-554», «en-NZ») to be true"
+test/intl402/Locale/constructor-parse-twice.js:
+ default: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+ strict mode: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+test/intl402/Locale/constructor-tag.js:
+ default: 'Test262Error: new Intl.Locale("sl-ROZAJ-BISKE-1994").toString() returns "sl-1994-biske-rozaj" Expected SameValue(«sl-rozaj-biske-1994», «sl-1994-biske-rozaj») to be true'
+ strict mode: 'Test262Error: new Intl.Locale("sl-ROZAJ-BISKE-1994").toString() returns "sl-1994-biske-rozaj" Expected SameValue(«sl-rozaj-biske-1994», «sl-1994-biske-rozaj») to be true'
+test/intl402/Locale/extensions-grandfathered.js:
+ default: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+ strict mode: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+test/intl402/Locale/extensions-private.js:
+ default: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+ strict mode: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+test/intl402/Locale/getters-grandfathered.js:
+ default: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+ strict mode: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+test/intl402/Locale/getters.js:
+ default: 'Test262Error: Expected SameValue(«de-Latn-DE-u-ca-gregory-co-phonebk-hc-h23-kf-true-kn-false-nu-latn», «de-Latn-DE-u-ca-gregory-co-phonebk-hc-h23-kf-kn-false-nu-latn») to be true'
+ strict mode: 'Test262Error: Expected SameValue(«de-Latn-DE-u-ca-gregory-co-phonebk-hc-h23-kf-true-kn-false-nu-latn», «de-Latn-DE-u-ca-gregory-co-phonebk-hc-h23-kf-kn-false-nu-latn») to be true'
+test/intl402/Locale/invalid-tag-throws.js:
+ default: 'Test262Error: no-nyn is an invalid tag value Expected a RangeError to be thrown but no exception was thrown at all'
+ strict mode: 'Test262Error: no-nyn is an invalid tag value Expected a RangeError to be thrown but no exception was thrown at all'
+test/intl402/Locale/likely-subtags-grandfathered.js:
+ default: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+ strict mode: 'Test262Error: Expected a RangeError to be thrown but no exception was thrown at all'
+test/intl402/Locale/likely-subtags.js:
+ default: 'Test262Error: "en-u-co".maximize() should be "en-Latn-US-u-co" Expected SameValue(«en-Latn-US-u-co-yes», «en-Latn-US-u-co») to be true'
+ strict mode: 'Test262Error: "en-u-co".maximize() should be "en-Latn-US-u-co" Expected SameValue(«en-Latn-US-u-co-yes», «en-Latn-US-u-co») to be true'
+test/intl402/Locale/prototype/minimize/removing-likely-subtags-first-adds-likely-subtags.js:
+ default: 'Test262Error: "und".minimize() should be "en" Expected SameValue(«en-u-va-posix», «en») to be true'
+ strict mode: 'Test262Error: "und".minimize() should be "en" Expected SameValue(«en-u-va-posix», «en») 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'
Modified: trunk/Source/_javascript_Core/CMakeLists.txt (261214 => 261215)
--- trunk/Source/_javascript_Core/CMakeLists.txt 2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/CMakeLists.txt 2020-05-06 06:01:07 UTC (rev 261215)
@@ -70,6 +70,7 @@
runtime/IntlCollatorPrototype.cpp
runtime/IntlDateTimeFormatConstructor.cpp
runtime/IntlDateTimeFormatPrototype.cpp
+ runtime/IntlLocalePrototype.cpp
runtime/IntlNumberFormatConstructor.cpp
runtime/IntlNumberFormatPrototype.cpp
runtime/IntlObject.cpp
Modified: trunk/Source/_javascript_Core/ChangeLog (261214 => 261215)
--- trunk/Source/_javascript_Core/ChangeLog 2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/ChangeLog 2020-05-06 06:01:07 UTC (rev 261215)
@@ -1,3 +1,63 @@
+2020-05-05 Ross Kirsling <ross.kirsl...@sony.com>
+
+ [ECMA-402] Implement Intl.Locale
+ https://bugs.webkit.org/show_bug.cgi?id=209772
+
+ Reviewed by Darin Adler and Saam Barati.
+
+ This patch implements the recent ECMA-402 feature Intl.Locale.
+
+ This is effectively a wrapper class for all the pieces of uloc.h that ECMA-402 cares about.
+ (If we used the C++ API, there's a LocaleBuilder that would make this much easier, but in sticking to the C API,
+ it's basically an object that has an ICU localeID as data and uloc_* functions as methods / getters.
+ Furthermore, there's no way to modify said data, so every method / getter can be lazy and cache its result.)
+
+ Usage example:
+ >>> locale = new Intl.Locale('ja', { region: 'JP', calendar: 'japanese', numeric: false })
+ "ja-JP-u-ca-japanese-kn-false"
+ >>> locale.baseName
+ "ja-JP"
+
+ Intl.Locale can be used anywhere that Intl APIs accept locale strings as input parameters,
+ and is moreover hoped to be the class by which future Web APIs will handle the current locale.
+
+ This feature is runtime-guarded by the `useIntlLocale` option.
+
+ * CMakeLists.txt:
+ * DerivedSources-input.xcfilelist:
+ * DerivedSources-output.xcfilelist:
+ * DerivedSources.make:
+ * _javascript_Core.xcodeproj/project.pbxproj:
+ * Sources.txt:
+ * runtime/CommonIdentifiers.h:
+ * runtime/IntlLocale.cpp: Added.
+ * runtime/IntlLocale.h: Added.
+ * runtime/IntlLocaleConstructor.cpp: Added.
+ * runtime/IntlLocaleConstructor.h: Added.
+ * runtime/IntlLocalePrototype.cpp: Added.
+ * runtime/IntlLocalePrototype.h: Added.
+ * runtime/IntlObject.cpp:
+ (JSC::IntlObject::finishCreation):
+ (JSC::localeIDBufferForLanguageTag): Added.
+ (JSC::languageTagForLocaleID): Renamed from JSC::convertICULocaleToBCP47LanguageTag.
+ (JSC::intlAvailableLocales):
+ (JSC::intlCollatorAvailableLocales):
+ (JSC::canonicalizeLanguageTag):
+ (JSC::canonicalizeLocaleList):
+ (JSC::defaultLocale):
+ * runtime/IntlObject.h:
+ * runtime/JSGlobalObject.cpp:
+ (JSC::JSGlobalObject::init):
+ (JSC::JSGlobalObject::visitChildren):
+ * runtime/JSGlobalObject.h:
+ (JSC::JSGlobalObject::collatorStructure):
+ (JSC::JSGlobalObject::numberFormatStructure):
+ (JSC::JSGlobalObject::localeStructure):
+ * runtime/OptionsList.h:
+ * runtime/VM.cpp:
+ (JSC::VM::VM):
+ * runtime/VM.h:
+
2020-05-05 Keith Miller <keith_mil...@apple.com>
clobberize validator should use branchTest8 directly.
Modified: trunk/Source/_javascript_Core/DerivedSources-input.xcfilelist (261214 => 261215)
--- trunk/Source/_javascript_Core/DerivedSources-input.xcfilelist 2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/DerivedSources-input.xcfilelist 2020-05-06 06:01:07 UTC (rev 261215)
@@ -136,6 +136,7 @@
$(PROJECT_DIR)/runtime/IntlCollatorPrototype.cpp
$(PROJECT_DIR)/runtime/IntlDateTimeFormatConstructor.cpp
$(PROJECT_DIR)/runtime/IntlDateTimeFormatPrototype.cpp
+$(PROJECT_DIR)/runtime/IntlLocalePrototype.cpp
$(PROJECT_DIR)/runtime/IntlNumberFormatConstructor.cpp
$(PROJECT_DIR)/runtime/IntlNumberFormatPrototype.cpp
$(PROJECT_DIR)/runtime/IntlObject.cpp
Modified: trunk/Source/_javascript_Core/DerivedSources-output.xcfilelist (261214 => 261215)
--- trunk/Source/_javascript_Core/DerivedSources-output.xcfilelist 2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/DerivedSources-output.xcfilelist 2020-05-06 06:01:07 UTC (rev 261215)
@@ -27,6 +27,7 @@
$(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlCollatorPrototype.lut.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlDateTimeFormatConstructor.lut.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlDateTimeFormatPrototype.lut.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlLocalePrototype.lut.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlNumberFormatConstructor.lut.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlNumberFormatPrototype.lut.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/_javascript_Core/IntlObject.lut.h
Modified: trunk/Source/_javascript_Core/DerivedSources.make (261214 => 261215)
--- trunk/Source/_javascript_Core/DerivedSources.make 2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/DerivedSources.make 2020-05-06 06:01:07 UTC (rev 261215)
@@ -147,6 +147,7 @@
IntlCollatorPrototype.lut.h \
IntlDateTimeFormatConstructor.lut.h \
IntlDateTimeFormatPrototype.lut.h \
+ IntlLocalePrototype.lut.h \
IntlNumberFormatConstructor.lut.h \
IntlNumberFormatPrototype.lut.h \
IntlObject.lut.h \
Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (261214 => 261215)
--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2020-05-06 06:01:07 UTC (rev 261215)
@@ -4333,6 +4333,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>"; };
+ A3AFF92B245A3CF900C9BA3B /* IntlLocale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlLocale.h; sourceTree = "<group>"; };
+ A3AFF92C245A3CFA00C9BA3B /* IntlLocaleConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlLocaleConstructor.h; sourceTree = "<group>"; };
+ A3AFF92D245A3CFA00C9BA3B /* IntlLocale.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntlLocale.cpp; sourceTree = "<group>"; };
+ A3AFF92E245A3CFB00C9BA3B /* IntlLocalePrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntlLocalePrototype.cpp; sourceTree = "<group>"; };
+ A3AFF92F245A3CFB00C9BA3B /* IntlLocaleConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntlLocaleConstructor.cpp; sourceTree = "<group>"; };
+ A3AFF930245A3CFC00C9BA3B /* IntlLocalePrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntlLocalePrototype.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>"; };
@@ -7254,6 +7260,12 @@
A1587D6A1B4DC14100D69849 /* IntlDateTimeFormatConstructor.h */,
A1587D6B1B4DC14100D69849 /* IntlDateTimeFormatPrototype.cpp */,
A1587D6C1B4DC14100D69849 /* IntlDateTimeFormatPrototype.h */,
+ A3AFF92D245A3CFA00C9BA3B /* IntlLocale.cpp */,
+ A3AFF92B245A3CF900C9BA3B /* IntlLocale.h */,
+ A3AFF92F245A3CFB00C9BA3B /* IntlLocaleConstructor.cpp */,
+ A3AFF92C245A3CFA00C9BA3B /* IntlLocaleConstructor.h */,
+ A3AFF92E245A3CFB00C9BA3B /* IntlLocalePrototype.cpp */,
+ A3AFF930245A3CFC00C9BA3B /* IntlLocalePrototype.h */,
A1D792F61B43864B004516F5 /* IntlNumberFormat.cpp */,
A1D792F71B43864B004516F5 /* IntlNumberFormat.h */,
A1D792F81B43864B004516F5 /* IntlNumberFormatConstructor.cpp */,
Modified: trunk/Source/_javascript_Core/Sources.txt (261214 => 261215)
--- trunk/Source/_javascript_Core/Sources.txt 2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/Sources.txt 2020-05-06 06:01:07 UTC (rev 261215)
@@ -812,6 +812,9 @@
runtime/IntlDateTimeFormat.cpp
runtime/IntlDateTimeFormatConstructor.cpp
runtime/IntlDateTimeFormatPrototype.cpp
+runtime/IntlLocale.cpp
+runtime/IntlLocaleConstructor.cpp
+runtime/IntlLocalePrototype.cpp
runtime/IntlNumberFormat.cpp
runtime/IntlNumberFormatConstructor.cpp
runtime/IntlNumberFormatPrototype.cpp
Modified: trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h (261214 => 261215)
--- trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h 2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h 2020-05-06 06:01:07 UTC (rev 261215)
@@ -40,6 +40,7 @@
macro(Infinity) \
macro(Intl) \
macro(Loader) \
+ macro(Locale) \
macro(Map) \
macro(NaN) \
macro(Number) \
@@ -137,6 +138,7 @@
macro(isWatchpoint) \
macro(jettisonReason) \
macro(join) \
+ macro(language) \
macro(lastIndex) \
macro(length) \
macro(line) \
@@ -166,8 +168,10 @@
macro(propertyIsEnumerable) \
macro(prototype) \
macro(raw) \
+ macro(region) \
macro(replace) \
macro(resolve) \
+ macro(script) \
macro(second) \
macro(sensitivity) \
macro(set) \
Added: trunk/Source/_javascript_Core/runtime/IntlLocale.cpp (0 => 261215)
--- trunk/Source/_javascript_Core/runtime/IntlLocale.cpp (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlLocale.cpp 2020-05-06 06:01:07 UTC (rev 261215)
@@ -0,0 +1,491 @@
+/*
+ * 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 "IntlLocale.h"
+
+#include "Error.h"
+#include "IntlObject.h"
+#include "JSCInlines.h"
+#include "ObjectConstructor.h"
+#include <unicode/uloc.h>
+#include <wtf/unicode/icu/ICUHelpers.h>
+
+namespace JSC {
+
+const ClassInfo IntlLocale::s_info = { "Object", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(IntlLocale) };
+
+IntlLocale* IntlLocale::create(VM& vm, Structure* structure)
+{
+ auto* object = new (NotNull, allocateCell<IntlLocale>(vm.heap)) IntlLocale(vm, structure);
+ object->finishCreation(vm);
+ return object;
+}
+
+Structure* IntlLocale::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+IntlLocale::IntlLocale(VM& vm, Structure* structure)
+ : Base(vm, structure)
+{
+}
+
+void IntlLocale::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(vm, info()));
+}
+
+void IntlLocale::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ auto* thisObject = jsCast<IntlLocale*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+
+ Base::visitChildren(thisObject, visitor);
+}
+
+class LocaleIDBuilder final {
+public:
+ bool initialize(const CString&);
+ CString toCanonical();
+
+ void overrideLanguageScriptRegion(StringView language, StringView script, StringView region);
+ void setKeywordValue(ASCIILiteral key, StringView value);
+
+private:
+ Vector<char, 32> m_buffer;
+};
+
+bool LocaleIDBuilder::initialize(const CString& tag)
+{
+ m_buffer = localeIDBufferForLanguageTag(tag);
+ return m_buffer.size();
+}
+
+CString LocaleIDBuilder::toCanonical()
+{
+ ASSERT(m_buffer.size());
+
+ UErrorCode status = U_ZERO_ERROR;
+ Vector<char, 32> result(32);
+ auto resultLength = uloc_canonicalize(m_buffer.data(), result.data(), result.size(), &status);
+ if (needsToGrowToProduceBuffer(status)) {
+ result.grow(resultLength);
+ status = U_ZERO_ERROR;
+ uloc_canonicalize(m_buffer.data(), result.data(), resultLength, &status);
+ }
+ if (U_FAILURE(status))
+ return CString();
+
+ return CString(result.data(), resultLength);
+}
+
+// Because ICU's C API doesn't have set[Language|Script|Region] functions...
+void LocaleIDBuilder::overrideLanguageScriptRegion(StringView language, StringView script, StringView region)
+{
+ unsigned length = strlen(m_buffer.data());
+ ASSERT(length);
+
+ StringView localeIDView { m_buffer.data(), length };
+
+ auto endOfLanguageScriptRegionVariant = localeIDView.find(ULOC_KEYWORD_SEPARATOR);
+ if (endOfLanguageScriptRegionVariant == notFound)
+ endOfLanguageScriptRegionVariant = length;
+
+ Vector<StringView> subtags;
+ for (auto subtag : localeIDView.left(endOfLanguageScriptRegionVariant).splitAllowingEmptyEntries('_'))
+ subtags.append(subtag);
+
+ if (!language.isNull())
+ subtags[0] = language;
+
+ bool hasScript = subtags.size() > 1 && subtags[1].length() == 4;
+ if (!script.isNull()) {
+ if (hasScript)
+ subtags[1] = script;
+ else {
+ subtags.insert(1, script);
+ hasScript = true;
+ }
+ }
+
+ if (!region.isNull()) {
+ size_t index = hasScript ? 2 : 1;
+ bool hasRegion = subtags.size() > index && subtags[index].length() < 4;
+ if (hasRegion)
+ subtags[index] = region;
+ else
+ subtags.insert(index, region);
+ }
+
+ Vector<char, 32> buffer;
+ bool hasAppended = false;
+ for (auto subtag : subtags) {
+ if (hasAppended)
+ buffer.append('_');
+ else
+ hasAppended = true;
+
+ ASSERT(subtag.is8Bit() && subtag.isAllASCII());
+ buffer.append(reinterpret_cast<const char*>(subtag.characters8()), subtag.length());
+ }
+
+ if (endOfLanguageScriptRegionVariant != length) {
+ auto rest = localeIDView.right(length - endOfLanguageScriptRegionVariant);
+
+ ASSERT(rest.is8Bit() && rest.isAllASCII());
+ buffer.append(reinterpret_cast<const char*>(rest.characters8()), rest.length());
+ }
+
+ buffer.append('\0');
+ m_buffer.swap(buffer);
+}
+
+void LocaleIDBuilder::setKeywordValue(ASCIILiteral key, StringView value)
+{
+ ASSERT(m_buffer.size());
+
+ ASSERT(value.is8Bit() && value.isAllASCII());
+ CString rawValue { reinterpret_cast<const char*>(value.characters8()), value.length() };
+
+ UErrorCode status = U_ZERO_ERROR;
+ auto length = uloc_setKeywordValue(key.characters(), rawValue.data(), m_buffer.data(), m_buffer.size(), &status);
+ // uloc_setKeywordValue does not set U_STRING_NOT_TERMINATED_WARNING.
+ if (needsToGrowToProduceBuffer(status)) {
+ m_buffer.grow(length + 1);
+ status = U_ZERO_ERROR;
+ uloc_setKeywordValue(key.characters(), rawValue.data(), m_buffer.data(), length + 1, &status);
+ }
+ ASSERT(U_SUCCESS(status));
+}
+
+String IntlLocale::keywordValue(ASCIILiteral key, bool isBoolean) const
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Vector<char, 32> buffer(32);
+ auto bufferLength = uloc_getKeywordValue(m_localeID.data(), key.characters(), buffer.data(), buffer.size(), &status);
+ if (needsToGrowToProduceCString(status)) {
+ buffer.grow(bufferLength + 1);
+ status = U_ZERO_ERROR;
+ uloc_getKeywordValue(m_localeID.data(), key.characters(), buffer.data(), bufferLength + 1, &status);
+ }
+ ASSERT(U_SUCCESS(status));
+
+ const char* value = !isBoolean ? uloc_toUnicodeLocaleType(key.characters(), buffer.data()) : buffer.data();
+ return value ? String(value) : emptyString();
+}
+
+// unicode_language_subtag = alpha{2,3} | alpha{5,8} ;
+static bool isUnicodeLanguageSubtag(StringView string)
+{
+ auto length = string.length();
+ return length >= 2 && length <= 8 && length != 4 && string.isAllSpecialCharacters<isASCIIAlpha>();
+}
+
+// unicode_script_subtag = alpha{4} ;
+static bool isUnicodeScriptSubtag(StringView string)
+{
+ return string.length() == 4 && string.isAllSpecialCharacters<isASCIIAlpha>();
+}
+
+// unicode_region_subtag = alpha{2} | digit{3} ;
+static bool isUnicodeRegionSubtag(StringView string)
+{
+ auto length = string.length();
+ return (length == 2 && string.isAllSpecialCharacters<isASCIIAlpha>())
+ || (length == 3 && string.isAllSpecialCharacters<isASCIIDigit>());
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale
+void IntlLocale::initializeLocale(JSGlobalObject* globalObject, JSValue tagValue, JSValue optionsValue)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ String tag = tagValue.inherits<IntlLocale>(vm) ? jsCast<IntlLocale*>(tagValue)->toString() : tagValue.toWTFString(globalObject);
+ RETURN_IF_EXCEPTION(scope, void());
+
+ JSValue options = optionsValue;
+ if (!optionsValue.isUndefined()) {
+ options = optionsValue.toObject(globalObject);
+ RETURN_IF_EXCEPTION(scope, void());
+ }
+
+ LocaleIDBuilder localeID;
+ if (!localeID.initialize(tag.utf8())) {
+ throwRangeError(globalObject, scope, "invalid language tag"_s);
+ return;
+ }
+
+ String language = intlStringOption(globalObject, options, vm.propertyNames->language, { }, nullptr, nullptr);
+ RETURN_IF_EXCEPTION(scope, void());
+ if (!language.isNull() && !isUnicodeLanguageSubtag(language)) {
+ throwRangeError(globalObject, scope, "language is not a well-formed language value"_s);
+ return;
+ }
+
+ String script = intlStringOption(globalObject, options, vm.propertyNames->script, { }, nullptr, nullptr);
+ RETURN_IF_EXCEPTION(scope, void());
+ if (!script.isNull() && !isUnicodeScriptSubtag(script)) {
+ throwRangeError(globalObject, scope, "script is not a well-formed script value"_s);
+ return;
+ }
+
+ String region = intlStringOption(globalObject, options, vm.propertyNames->region, { }, nullptr, nullptr);
+ RETURN_IF_EXCEPTION(scope, void());
+ if (!region.isNull() && !isUnicodeRegionSubtag(region)) {
+ throwRangeError(globalObject, scope, "region is not a well-formed region value"_s);
+ return;
+ }
+
+ if (!language.isNull() || !script.isNull() || !region.isNull())
+ localeID.overrideLanguageScriptRegion(language, script, region);
+
+ String calendar = intlStringOption(globalObject, options, vm.propertyNames->calendar, { }, nullptr, nullptr);
+ RETURN_IF_EXCEPTION(scope, void());
+ if (!calendar.isNull()) {
+ if (!isUnicodeLocaleIdentifierType(calendar)) {
+ throwRangeError(globalObject, scope, "calendar is not a well-formed calendar value"_s);
+ return;
+ }
+ localeID.setKeywordValue("calendar"_s, calendar);
+ }
+
+ String collation = intlStringOption(globalObject, options, vm.propertyNames->collation, { }, nullptr, nullptr);
+ RETURN_IF_EXCEPTION(scope, void());
+ if (!collation.isNull()) {
+ if (!isUnicodeLocaleIdentifierType(collation)) {
+ throwRangeError(globalObject, scope, "collation is not a well-formed collation value"_s);
+ return;
+ }
+ localeID.setKeywordValue("collation"_s, collation);
+ }
+
+ String hourCycle = intlStringOption(globalObject, options, vm.propertyNames->hourCycle, { "h11", "h12", "h23", "h24" }, "hourCycle must be \"h11\", \"h12\", \"h23\", or \"h24\"", nullptr);
+ RETURN_IF_EXCEPTION(scope, void());
+ if (!hourCycle.isNull())
+ localeID.setKeywordValue("hours"_s, hourCycle);
+
+ String caseFirst = intlStringOption(globalObject, options, vm.propertyNames->caseFirst, { "upper", "lower", "false" }, "caseFirst must be either \"upper\", \"lower\", or \"false\"", nullptr);
+ RETURN_IF_EXCEPTION(scope, void());
+ if (!caseFirst.isNull())
+ localeID.setKeywordValue("colcasefirst"_s, caseFirst);
+
+ TriState numeric = intlBooleanOption(globalObject, options, vm.propertyNames->numeric);
+ RETURN_IF_EXCEPTION(scope, void());
+ if (numeric != TriState::Indeterminate)
+ localeID.setKeywordValue("colnumeric"_s, numeric == TriState::True ? "yes" : "no");
+
+ 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;
+ }
+ localeID.setKeywordValue("numbers"_s, numberingSystem);
+ }
+
+ m_localeID = localeID.toCanonical();
+ if (m_localeID.isNull()) {
+ throwTypeError(globalObject, scope, "failed to initialize Locale"_s);
+ return;
+ }
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.maximize
+const String& IntlLocale::maximize()
+{
+ if (m_maximized.isNull()) {
+ UErrorCode status = U_ZERO_ERROR;
+ Vector<char, 32> buffer(32);
+ auto bufferLength = uloc_addLikelySubtags(m_localeID.data(), buffer.data(), buffer.size(), &status);
+ if (needsToGrowToProduceCString(status)) {
+ buffer.grow(bufferLength + 1);
+ status = U_ZERO_ERROR;
+ uloc_addLikelySubtags(m_localeID.data(), buffer.data(), bufferLength + 1, &status);
+ }
+ ASSERT(U_SUCCESS(status));
+
+ m_maximized = languageTagForLocaleID(buffer.data());
+ }
+ return m_maximized;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.minimize
+const String& IntlLocale::minimize()
+{
+ if (m_minimized.isNull()) {
+ UErrorCode status = U_ZERO_ERROR;
+ Vector<char, 32> buffer(32);
+ auto bufferLength = uloc_minimizeSubtags(m_localeID.data(), buffer.data(), buffer.size(), &status);
+ if (needsToGrowToProduceCString(status)) {
+ buffer.grow(bufferLength + 1);
+ status = U_ZERO_ERROR;
+ uloc_minimizeSubtags(m_localeID.data(), buffer.data(), bufferLength + 1, &status);
+ }
+ ASSERT(U_SUCCESS(status));
+
+ m_minimized = languageTagForLocaleID(buffer.data());
+ }
+ return m_minimized;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.toString
+const String& IntlLocale::toString()
+{
+ if (m_fullString.isNull())
+ m_fullString = languageTagForLocaleID(m_localeID.data());
+ return m_fullString;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.baseName
+const String& IntlLocale::baseName()
+{
+ if (m_baseName.isNull()) {
+ UErrorCode status = U_ZERO_ERROR;
+ Vector<char, 32> buffer(32);
+ auto bufferLength = uloc_getBaseName(m_localeID.data(), buffer.data(), buffer.size(), &status);
+ if (needsToGrowToProduceCString(status)) {
+ buffer.grow(bufferLength + 1);
+ status = U_ZERO_ERROR;
+ uloc_getBaseName(m_localeID.data(), buffer.data(), bufferLength + 1, &status);
+ }
+ ASSERT(U_SUCCESS(status));
+
+ m_baseName = languageTagForLocaleID(buffer.data());
+ }
+ return m_baseName;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.language
+const String& IntlLocale::language()
+{
+ if (m_language.isNull()) {
+ UErrorCode status = U_ZERO_ERROR;
+ Vector<char, 8> buffer(8);
+ auto bufferLength = uloc_getLanguage(m_localeID.data(), buffer.data(), buffer.size(), &status);
+ if (needsToGrowToProduceBuffer(status)) {
+ buffer.grow(bufferLength);
+ status = U_ZERO_ERROR;
+ uloc_getLanguage(m_localeID.data(), buffer.data(), bufferLength, &status);
+ }
+ ASSERT(U_SUCCESS(status));
+
+ m_language = String(buffer.data(), bufferLength);
+ }
+ return m_language;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.script
+const String& IntlLocale::script()
+{
+ if (m_script.isNull()) {
+ UErrorCode status = U_ZERO_ERROR;
+ Vector<char, 4> buffer(4);
+ auto bufferLength = uloc_getScript(m_localeID.data(), buffer.data(), buffer.size(), &status);
+ if (needsToGrowToProduceBuffer(status)) {
+ buffer.grow(bufferLength);
+ status = U_ZERO_ERROR;
+ uloc_getScript(m_localeID.data(), buffer.data(), bufferLength, &status);
+ }
+ ASSERT(U_SUCCESS(status));
+
+ m_script = String(buffer.data(), bufferLength);
+ }
+ return m_script;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.region
+const String& IntlLocale::region()
+{
+ if (m_region.isNull()) {
+ UErrorCode status = U_ZERO_ERROR;
+ Vector<char, 3> buffer(3);
+ auto bufferLength = uloc_getCountry(m_localeID.data(), buffer.data(), buffer.size(), &status);
+ if (needsToGrowToProduceBuffer(status)) {
+ buffer.grow(bufferLength);
+ status = U_ZERO_ERROR;
+ uloc_getCountry(m_localeID.data(), buffer.data(), bufferLength, &status);
+ }
+ ASSERT(U_SUCCESS(status));
+
+ m_region = String(buffer.data(), bufferLength);
+ }
+ return m_region;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.calendar
+const String& IntlLocale::calendar()
+{
+ if (m_calendar.isNull())
+ m_calendar = keywordValue("calendar"_s);
+ return m_calendar;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.caseFirst
+const String& IntlLocale::caseFirst()
+{
+ if (m_caseFirst.isNull())
+ m_caseFirst = keywordValue("colcasefirst"_s);
+ return m_caseFirst;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.collation
+const String& IntlLocale::collation()
+{
+ if (m_collation.isNull())
+ m_collation = keywordValue("collation"_s);
+ return m_collation;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.hourCycle
+const String& IntlLocale::hourCycle()
+{
+ if (m_hourCycle.isNull())
+ m_hourCycle = keywordValue("hours"_s);
+ return m_hourCycle;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.numberingSystem
+const String& IntlLocale::numberingSystem()
+{
+ if (m_numberingSystem.isNull())
+ m_numberingSystem = keywordValue("numbers"_s);
+ return m_numberingSystem;
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.numeric
+TriState IntlLocale::numeric()
+{
+ constexpr bool isBoolean = true;
+ if (m_numeric == TriState::Indeterminate)
+ m_numeric = triState(keywordValue("colnumeric"_s, isBoolean) == "yes");
+ return m_numeric;
+}
+
+} // namespace JSC
Added: trunk/Source/_javascript_Core/runtime/IntlLocale.h (0 => 261215)
--- trunk/Source/_javascript_Core/runtime/IntlLocale.h (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlLocale.h 2020-05-06 06:01:07 UTC (rev 261215)
@@ -0,0 +1,93 @@
+/*
+ * 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 IntlLocale final : public JSNonFinalObject {
+public:
+ using Base = JSNonFinalObject;
+
+ static constexpr bool needsDestruction = true;
+
+ static void destroy(JSCell* cell)
+ {
+ static_cast<IntlLocale*>(cell)->IntlLocale::~IntlLocale();
+ }
+
+ template<typename CellType, SubspaceAccess mode>
+ static IsoSubspace* subspaceFor(VM& vm)
+ {
+ return vm.intlLocaleSpace<mode>();
+ }
+
+ static IntlLocale* create(VM&, Structure*);
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+ DECLARE_INFO;
+
+ void initializeLocale(JSGlobalObject*, JSValue tagValue, JSValue optionsValue);
+ const String& maximize();
+ const String& minimize();
+ const String& toString();
+ const String& baseName();
+ const String& language();
+ const String& script();
+ const String& region();
+ const String& calendar();
+ const String& caseFirst();
+ const String& collation();
+ const String& hourCycle();
+ const String& numberingSystem();
+ TriState numeric();
+
+private:
+ IntlLocale(VM&, Structure*);
+ void finishCreation(VM&);
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ String keywordValue(ASCIILiteral, bool isBoolean = false) const;
+
+ CString m_localeID;
+
+ String m_maximized;
+ String m_minimized;
+ String m_fullString;
+ String m_baseName;
+ String m_language;
+ String m_script;
+ String m_region;
+ String m_calendar;
+ String m_caseFirst;
+ String m_collation;
+ String m_hourCycle;
+ String m_numberingSystem;
+ TriState m_numeric { TriState::Indeterminate };
+};
+
+} // namespace JSC
Added: trunk/Source/_javascript_Core/runtime/IntlLocaleConstructor.cpp (0 => 261215)
--- trunk/Source/_javascript_Core/runtime/IntlLocaleConstructor.cpp (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlLocaleConstructor.cpp 2020-05-06 06:01:07 UTC (rev 261215)
@@ -0,0 +1,103 @@
+/*
+ * 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 "IntlLocaleConstructor.h"
+
+#include "Error.h"
+#include "IntlLocale.h"
+#include "IntlLocalePrototype.h"
+#include "IntlObject.h"
+#include "JSCInlines.h"
+#include "Lookup.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IntlLocaleConstructor);
+
+const ClassInfo IntlLocaleConstructor::s_info = { "Function", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(IntlLocaleConstructor) };
+
+IntlLocaleConstructor* IntlLocaleConstructor::create(VM& vm, Structure* structure, IntlLocalePrototype* localePrototype)
+{
+ auto* constructor = new (NotNull, allocateCell<IntlLocaleConstructor>(vm.heap)) IntlLocaleConstructor(vm, structure);
+ constructor->finishCreation(vm, localePrototype);
+ return constructor;
+}
+
+Structure* IntlLocaleConstructor::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(InternalFunctionType, StructureFlags), info());
+}
+
+static EncodedJSValue JSC_HOST_CALL callIntlLocale(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL constructIntlLocale(JSGlobalObject*, CallFrame*);
+
+IntlLocaleConstructor::IntlLocaleConstructor(VM& vm, Structure* structure)
+ : Base(vm, structure, callIntlLocale, constructIntlLocale)
+{
+}
+
+void IntlLocaleConstructor::finishCreation(VM& vm, IntlLocalePrototype* localePrototype)
+{
+ Base::finishCreation(vm, "Locale"_s, NameAdditionMode::WithoutStructureTransition);
+ putDirectWithoutTransition(vm, vm.propertyNames->prototype, localePrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
+ putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
+ localePrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, this, static_cast<unsigned>(PropertyAttribute::DontEnum));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale
+static EncodedJSValue JSC_HOST_CALL constructIntlLocale(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ JSObject* newTarget = asObject(callFrame->newTarget());
+ Structure* structure = newTarget == callFrame->jsCallee()
+ ? globalObject->localeStructure()
+ : InternalFunction::createSubclassStructure(globalObject, newTarget, getFunctionRealm(vm, newTarget)->localeStructure());
+ RETURN_IF_EXCEPTION(scope, { });
+
+ IntlLocale* locale = IntlLocale::create(vm, structure);
+ ASSERT(locale);
+
+ JSValue tag = callFrame->argument(0);
+ if (!tag.isString() && !tag.isObject())
+ return throwVMTypeError(globalObject, scope, "First argument to Intl.Locale must be a string or an object"_s);
+
+ scope.release();
+ locale->initializeLocale(globalObject, tag, callFrame->argument(1));
+ return JSValue::encode(locale);
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale
+static EncodedJSValue JSC_HOST_CALL callIntlLocale(JSGlobalObject* globalObject, CallFrame*)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ return JSValue::encode(throwConstructorCannotBeCalledAsFunctionTypeError(globalObject, scope, "Locale"));
+}
+
+} // namespace JSC
Added: trunk/Source/_javascript_Core/runtime/IntlLocaleConstructor.h (0 => 261215)
--- trunk/Source/_javascript_Core/runtime/IntlLocaleConstructor.h (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlLocaleConstructor.h 2020-05-06 06:01:07 UTC (rev 261215)
@@ -0,0 +1,51 @@
+/*
+ * 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 IntlLocalePrototype;
+
+class IntlLocaleConstructor final : public InternalFunction {
+public:
+ using Base = InternalFunction;
+ static constexpr unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable;
+
+ static IntlLocaleConstructor* create(VM&, Structure*, IntlLocalePrototype*);
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+ DECLARE_INFO;
+
+private:
+ IntlLocaleConstructor(VM&, Structure*);
+ void finishCreation(VM&, IntlLocalePrototype*);
+};
+STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(IntlLocaleConstructor, InternalFunction);
+
+} // namespace JSC
Added: trunk/Source/_javascript_Core/runtime/IntlLocalePrototype.cpp (0 => 261215)
--- trunk/Source/_javascript_Core/runtime/IntlLocalePrototype.cpp (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlLocalePrototype.cpp 2020-05-06 06:01:07 UTC (rev 261215)
@@ -0,0 +1,276 @@
+/*
+ * 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 "IntlLocalePrototype.h"
+
+#include "Error.h"
+#include "IntlLocale.h"
+#include "JSCInlines.h"
+#include "JSObjectInlines.h"
+
+namespace JSC {
+
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeFuncMaximize(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeFuncMinimize(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeFuncToString(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterBaseName(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterCalendar(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterCaseFirst(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterCollation(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterHourCycle(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterNumeric(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterNumberingSystem(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterLanguage(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterScript(JSGlobalObject*, CallFrame*);
+static EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterRegion(JSGlobalObject*, CallFrame*);
+
+}
+
+#include "IntlLocalePrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo IntlLocalePrototype::s_info = { "Intl.Locale", &Base::s_info, &localePrototypeTable, nullptr, CREATE_METHOD_TABLE(IntlLocalePrototype) };
+
+/* Source for IntlLocalePrototype.lut.h
+@begin localePrototypeTable
+ maximize IntlLocalePrototypeFuncMaximize DontEnum|Function 0
+ minimize IntlLocalePrototypeFuncMinimize DontEnum|Function 0
+ toString IntlLocalePrototypeFuncToString DontEnum|Function 0
+ baseName IntlLocalePrototypeGetterBaseName DontEnum|Accessor
+ calendar IntlLocalePrototypeGetterCalendar DontEnum|Accessor
+ caseFirst IntlLocalePrototypeGetterCaseFirst DontEnum|Accessor
+ collation IntlLocalePrototypeGetterCollation DontEnum|Accessor
+ hourCycle IntlLocalePrototypeGetterHourCycle DontEnum|Accessor
+ numeric IntlLocalePrototypeGetterNumeric DontEnum|Accessor
+ numberingSystem IntlLocalePrototypeGetterNumberingSystem DontEnum|Accessor
+ language IntlLocalePrototypeGetterLanguage DontEnum|Accessor
+ script IntlLocalePrototypeGetterScript DontEnum|Accessor
+ region IntlLocalePrototypeGetterRegion DontEnum|Accessor
+@end
+*/
+
+IntlLocalePrototype* IntlLocalePrototype::create(VM& vm, Structure* structure)
+{
+ auto* object = new (NotNull, allocateCell<IntlLocalePrototype>(vm.heap)) IntlLocalePrototype(vm, structure);
+ object->finishCreation(vm);
+ return object;
+}
+
+Structure* IntlLocalePrototype::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+IntlLocalePrototype::IntlLocalePrototype(VM& vm, Structure* structure)
+ : Base(vm, structure)
+{
+}
+
+void IntlLocalePrototype::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(vm, info()));
+ JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.maximize
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeFuncMaximize(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+ if (!locale)
+ return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.maximize called on value that's not an object initialized as a Locale"_s);
+
+ RELEASE_AND_RETURN(scope, JSValue::encode(jsString(vm, locale->maximize())));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.minimize
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeFuncMinimize(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+ if (!locale)
+ return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.minimize called on value that's not an object initialized as a Locale"_s);
+
+ RELEASE_AND_RETURN(scope, JSValue::encode(jsString(vm, locale->minimize())));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.toString
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeFuncToString(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+ if (!locale)
+ return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.toString called on value that's not an object initialized as a Locale"_s);
+
+ RELEASE_AND_RETURN(scope, JSValue::encode(jsNontrivialString(vm, locale->toString())));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.baseName
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterBaseName(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+ if (!locale)
+ return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.baseName called on value that's not an object initialized as a Locale"_s);
+
+ RELEASE_AND_RETURN(scope, JSValue::encode(jsNontrivialString(vm, locale->baseName())));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.calendar
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterCalendar(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+ if (!locale)
+ return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.calendar called on value that's not an object initialized as a Locale"_s);
+
+ const String& calendar = locale->calendar();
+ RELEASE_AND_RETURN(scope, JSValue::encode(calendar.isEmpty() ? jsUndefined() : jsNontrivialString(vm, calendar)));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.caseFirst
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterCaseFirst(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+ if (!locale)
+ return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.caseFirst called on value that's not an object initialized as a Locale"_s);
+
+ const String& caseFirst = locale->caseFirst();
+ RELEASE_AND_RETURN(scope, JSValue::encode(caseFirst.isEmpty() ? jsUndefined() : jsNontrivialString(vm, caseFirst)));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.collation
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterCollation(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+ if (!locale)
+ return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.collation called on value that's not an object initialized as a Locale"_s);
+
+ const String& collation = locale->collation();
+ RELEASE_AND_RETURN(scope, JSValue::encode(collation.isEmpty() ? jsUndefined() : jsNontrivialString(vm, collation)));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.hourCycle
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterHourCycle(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+ if (!locale)
+ return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.hourCycle called on value that's not an object initialized as a Locale"_s);
+
+ const String& hourCycle = locale->hourCycle();
+ RELEASE_AND_RETURN(scope, JSValue::encode(hourCycle.isEmpty() ? jsUndefined() : jsNontrivialString(vm, hourCycle)));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.numeric
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterNumeric(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+ if (!locale)
+ return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.numeric called on value that's not an object initialized as a Locale"_s);
+
+ RELEASE_AND_RETURN(scope, JSValue::encode(jsBoolean(locale->numeric() == TriState::True)));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.numberingSystem
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterNumberingSystem(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+ if (!locale)
+ return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.numberingSystem called on value that's not an object initialized as a Locale"_s);
+
+ const String& numberingSystem = locale->numberingSystem();
+ RELEASE_AND_RETURN(scope, JSValue::encode(numberingSystem.isEmpty() ? jsUndefined() : jsNontrivialString(vm, numberingSystem)));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.language
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterLanguage(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+ if (!locale)
+ return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.language called on value that's not an object initialized as a Locale"_s);
+
+ RELEASE_AND_RETURN(scope, JSValue::encode(jsNontrivialString(vm, locale->language())));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.script
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterScript(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+ if (!locale)
+ return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.script called on value that's not an object initialized as a Locale"_s);
+
+ const String& script = locale->script();
+ RELEASE_AND_RETURN(scope, JSValue::encode(script.isEmpty() ? jsUndefined() : jsNontrivialString(vm, script)));
+}
+
+// https://tc39.es/ecma402/#sec-Intl.Locale.prototype.region
+EncodedJSValue JSC_HOST_CALL IntlLocalePrototypeGetterRegion(JSGlobalObject* globalObject, CallFrame* callFrame)
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* locale = jsDynamicCast<IntlLocale*>(vm, callFrame->thisValue());
+ if (!locale)
+ return throwVMTypeError(globalObject, scope, "Intl.Locale.prototype.region called on value that's not an object initialized as a Locale"_s);
+
+ const String& region = locale->region();
+ RELEASE_AND_RETURN(scope, JSValue::encode(region.isEmpty() ? jsUndefined() : jsNontrivialString(vm, region)));
+}
+
+} // namespace JSC
Added: trunk/Source/_javascript_Core/runtime/IntlLocalePrototype.h (0 => 261215)
--- trunk/Source/_javascript_Core/runtime/IntlLocalePrototype.h (rev 0)
+++ trunk/Source/_javascript_Core/runtime/IntlLocalePrototype.h 2020-05-06 06:01:07 UTC (rev 261215)
@@ -0,0 +1,54 @@
+/*
+ * 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 IntlLocalePrototype 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(IntlLocalePrototype, Base);
+ return &vm.plainObjectSpace;
+ }
+
+ static IntlLocalePrototype* create(VM&, Structure*);
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+ DECLARE_INFO;
+
+private:
+ IntlLocalePrototype(VM&, Structure*);
+ void finishCreation(VM&);
+};
+
+} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/IntlObject.cpp (261214 => 261215)
--- trunk/Source/_javascript_Core/runtime/IntlObject.cpp 2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/runtime/IntlObject.cpp 2020-05-06 06:01:07 UTC (rev 261215)
@@ -35,6 +35,9 @@
#include "IntlCollatorPrototype.h"
#include "IntlDateTimeFormatConstructor.h"
#include "IntlDateTimeFormatPrototype.h"
+#include "IntlLocale.h"
+#include "IntlLocaleConstructor.h"
+#include "IntlLocalePrototype.h"
#include "IntlNumberFormatConstructor.h"
#include "IntlNumberFormatPrototype.h"
#include "IntlPluralRulesConstructor.h"
@@ -136,6 +139,10 @@
void IntlObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
{
Base::finishCreation(vm);
+ if (Options::useIntlLocale()) {
+ auto* localeConstructor = IntlLocaleConstructor::create(vm, IntlLocaleConstructor::createStructure(vm, globalObject, globalObject->functionPrototype()), jsCast<IntlLocalePrototype*>(globalObject->localeStructure()->storedPrototypeObject()));
+ putDirectWithoutTransition(vm, vm.propertyNames->Locale, localeConstructor, static_cast<unsigned>(PropertyAttribute::DontEnum));
+ }
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));
@@ -147,23 +154,47 @@
return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
}
-static String convertICULocaleToBCP47LanguageTag(const char* localeID)
+Vector<char, 32> localeIDBufferForLanguageTag(const CString& tag)
{
+ if (!tag.length())
+ return { };
+
UErrorCode status = U_ZERO_ERROR;
Vector<char, 32> buffer(32);
+ int32_t parsedLength;
+ auto bufferLength = uloc_forLanguageTag(tag.data(), buffer.data(), buffer.size(), &parsedLength, &status);
+ if (needsToGrowToProduceCString(status)) {
+ // Before ICU 64, there's a chance uloc_forLanguageTag will "buffer overflow" while requesting a *smaller* size.
+ buffer.resize(bufferLength + 1);
+ status = U_ZERO_ERROR;
+ uloc_forLanguageTag(tag.data(), buffer.data(), bufferLength + 1, &parsedLength, &status);
+ }
+ if (U_FAILURE(status) || parsedLength != static_cast<int32_t>(tag.length()))
+ return { };
+
+ ASSERT(buffer.contains('\0'));
+ return buffer;
+}
+
+String languageTagForLocaleID(const char* localeID, bool isImmortal)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Vector<char, 32> buffer(32);
auto length = uloc_toLanguageTag(localeID, buffer.data(), buffer.size(), false, &status);
if (needsToGrowToProduceBuffer(status)) {
buffer.grow(length);
status = U_ZERO_ERROR;
- uloc_toLanguageTag(localeID, buffer.data(), buffer.size(), false, &status);
+ uloc_toLanguageTag(localeID, buffer.data(), length, false, &status);
}
- if (!U_FAILURE(status)) {
- // This is used to store into static variables that may be shared across
- // JSC execution threads. This must be immortal to make concurrent ref/deref
- // safe.
+ if (U_FAILURE(status))
+ return String();
+
+ // This is used to store into static variables that may be shared across JSC execution threads.
+ // This must be immortal to make concurrent ref/deref safe.
+ if (isImmortal)
return String(StringImpl::createStaticStringImpl(buffer.data(), length));
- }
- return String();
+
+ return String(buffer.data(), length);
}
const HashSet<String>& intlAvailableLocales()
@@ -174,9 +205,10 @@
static std::once_flag initializeOnce;
std::call_once(initializeOnce, [&] {
ASSERT(availableLocales.isEmpty());
+ constexpr bool isImmortal = true;
int32_t count = uloc_countAvailable();
for (int32_t i = 0; i < count; ++i) {
- String locale = convertICULocaleToBCP47LanguageTag(uloc_getAvailable(i));
+ String locale = languageTagForLocaleID(uloc_getAvailable(i), isImmortal);
if (!locale.isEmpty())
availableLocales.add(locale);
}
@@ -192,9 +224,10 @@
static std::once_flag initializeOnce;
std::call_once(initializeOnce, [&] {
ASSERT(availableLocales.isEmpty());
+ constexpr bool isImmortal = true;
int32_t count = ucol_countAvailable();
for (int32_t i = 0; i < count; ++i) {
- String locale = convertICULocaleToBCP47LanguageTag(ucol_getAvailable(i));
+ String locale = languageTagForLocaleID(ucol_getAvailable(i), isImmortal);
if (!locale.isEmpty())
availableLocales.add(locale);
}
@@ -316,40 +349,13 @@
// https://tc39.es/ecma402/#sec-isstructurallyvalidlanguagetag
// https://tc39.es/ecma402/#sec-canonicalizeunicodelocaleid
-static String canonicalizeLanguageTag(const CString& input)
+static String canonicalizeLanguageTag(const CString& tag)
{
- if (!input.length())
+ auto buffer = localeIDBufferForLanguageTag(tag);
+ if (buffer.isEmpty())
return String();
- // We need to be careful with the output of uloc_forLanguageTag:
- // - uloc_toLanguageTag doesn't take an input size param so we must ensure the string is null-terminated ourselves
- // - before ICU 64, there's a chance that it will "buffer overflow" while requesting a *smaller* size
- UErrorCode status = U_ZERO_ERROR;
- Vector<char, 32> intermediate(32);
- int32_t parsedLength;
- auto intermediateLength = uloc_forLanguageTag(input.data(), intermediate.data(), intermediate.size(), &parsedLength, &status);
- if (needsToGrowToProduceCString(status)) {
- intermediate.resize(intermediateLength + 1);
- status = U_ZERO_ERROR;
- uloc_forLanguageTag(input.data(), intermediate.data(), intermediateLength + 1, &parsedLength, &status);
- }
- if (U_FAILURE(status) || parsedLength != static_cast<int32_t>(input.length()))
- return String();
-
- ASSERT(intermediate.contains('\0'));
-
- status = U_ZERO_ERROR;
- Vector<char, 32> result(32);
- auto resultLength = uloc_toLanguageTag(intermediate.data(), result.data(), result.size(), false, &status);
- if (needsToGrowToProduceBuffer(status)) {
- result.grow(resultLength);
- status = U_ZERO_ERROR;
- uloc_toLanguageTag(intermediate.data(), result.data(), resultLength, false, &status);
- }
- if (U_FAILURE(status))
- return String();
-
- return String(result.data(), resultLength);
+ return languageTagForLocaleID(buffer.data());
}
Vector<String> canonicalizeLocaleList(JSGlobalObject* globalObject, JSValue locales)
@@ -366,7 +372,7 @@
return seen;
JSObject* localesObject;
- if (locales.isString()) {
+ if (locales.isString() || locales.inherits<IntlLocale>(vm)) {
JSArray* localesArray = JSArray::tryCreate(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous));
if (!localesArray) {
throwOutOfMemoryError(globalObject, scope);
@@ -402,13 +408,18 @@
return { };
}
- JSString* tag = kValue.toString(globalObject);
- RETURN_IF_EXCEPTION(scope, Vector<String>());
+ Expected<CString, UTF8ConversionError> rawTag;
+ if (kValue.inherits<IntlLocale>(vm))
+ rawTag = jsCast<IntlLocale*>(kValue)->toString().tryGetUtf8();
+ else {
+ JSString* tag = kValue.toString(globalObject);
+ RETURN_IF_EXCEPTION(scope, Vector<String>());
- auto tagValue = tag->value(globalObject);
- RETURN_IF_EXCEPTION(scope, Vector<String>());
+ auto tagValue = tag->value(globalObject);
+ RETURN_IF_EXCEPTION(scope, Vector<String>());
- auto rawTag = tagValue.tryGetUtf8();
+ rawTag = tagValue.tryGetUtf8();
+ }
if (!rawTag) {
if (rawTag.error() == UTF8ConversionError::OutOfMemory)
throwOutOfMemoryError(globalObject, scope);
@@ -417,7 +428,7 @@
String canonicalizedTag = canonicalizeLanguageTag(rawTag.value());
if (canonicalizedTag.isNull()) {
- String errorMessage = tryMakeString("invalid language tag: ", tagValue);
+ String errorMessage = tryMakeString("invalid language tag: ", rawTag->data());
if (UNLIKELY(!errorMessage)) {
throwException(globalObject, scope, createOutOfMemoryError(globalObject));
return { };
@@ -483,7 +494,8 @@
static NeverDestroyed<String> icuDefaultLocalString;
static std::once_flag initializeOnce;
std::call_once(initializeOnce, [&] {
- icuDefaultLocalString.get() = convertICULocaleToBCP47LanguageTag(uloc_getDefault());
+ constexpr bool isImmortal = true;
+ icuDefaultLocalString.get() = languageTagForLocaleID(uloc_getDefault(), isImmortal);
});
if (!icuDefaultLocalString->isEmpty())
return icuDefaultLocalString.get();
Modified: trunk/Source/_javascript_Core/runtime/IntlObject.h (261214 => 261215)
--- trunk/Source/_javascript_Core/runtime/IntlObject.h 2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/runtime/IntlObject.h 2020-05-06 06:01:07 UTC (rev 261215)
@@ -68,6 +68,8 @@
String intlStringOption(JSGlobalObject*, JSValue options, PropertyName, std::initializer_list<const char*> values, const char* notFound, const char* fallback);
unsigned intlNumberOption(JSGlobalObject*, JSValue options, PropertyName, unsigned minimum, unsigned maximum, unsigned fallback);
unsigned intlDefaultNumberOption(JSGlobalObject*, JSValue, PropertyName, unsigned minimum, unsigned maximum, unsigned fallback);
+Vector<char, 32> localeIDBufferForLanguageTag(const CString&);
+String languageTagForLocaleID(const char*, bool isImmortal = false);
Vector<String> canonicalizeLocaleList(JSGlobalObject*, JSValue locales);
HashMap<String, String> resolveLocale(JSGlobalObject*, const HashSet<String>& availableLocales, const Vector<String>& requestedLocales, const HashMap<String, String>& options, const char* const relevantExtensionKeys[], size_t relevantExtensionKeyCount, Vector<String> (*localeData)(const String&, size_t));
JSValue supportedLocales(JSGlobalObject*, const HashSet<String>& availableLocales, const Vector<String>& requestedLocales, JSValue options);
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (261214 => 261215)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2020-05-06 06:01:07 UTC (rev 261215)
@@ -81,6 +81,8 @@
#include "IntlCollatorPrototype.h"
#include "IntlDateTimeFormat.h"
#include "IntlDateTimeFormatPrototype.h"
+#include "IntlLocale.h"
+#include "IntlLocalePrototype.h"
#include "IntlNumberFormat.h"
#include "IntlNumberFormatPrototype.h"
#include "IntlObject.h"
@@ -943,6 +945,18 @@
IntlCollatorPrototype* collatorPrototype = IntlCollatorPrototype::create(init.vm, globalObject, IntlCollatorPrototype::createStructure(init.vm, globalObject, globalObject->objectPrototype()));
init.set(IntlCollator::createStructure(init.vm, globalObject, collatorPrototype));
});
+ m_dateTimeFormatStructure.initLater(
+ [] (const Initializer<Structure>& init) {
+ JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner);
+ IntlDateTimeFormatPrototype* dateTimeFormatPrototype = IntlDateTimeFormatPrototype::create(init.vm, globalObject, IntlDateTimeFormatPrototype::createStructure(init.vm, globalObject, globalObject->objectPrototype()));
+ init.set(IntlDateTimeFormat::createStructure(init.vm, globalObject, dateTimeFormatPrototype));
+ });
+ m_localeStructure.initLater(
+ [] (const Initializer<Structure>& init) {
+ JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner);
+ IntlLocalePrototype* localePrototype = IntlLocalePrototype::create(init.vm, IntlLocalePrototype::createStructure(init.vm, globalObject, globalObject->objectPrototype()));
+ init.set(IntlLocale::createStructure(init.vm, globalObject, localePrototype));
+ });
m_numberFormatStructure.initLater(
[] (const Initializer<Structure>& init) {
JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner);
@@ -949,12 +963,6 @@
IntlNumberFormatPrototype* numberFormatPrototype = IntlNumberFormatPrototype::create(init.vm, globalObject, IntlNumberFormatPrototype::createStructure(init.vm, globalObject, globalObject->objectPrototype()));
init.set(IntlNumberFormat::createStructure(init.vm, globalObject, numberFormatPrototype));
});
- m_dateTimeFormatStructure.initLater(
- [] (const Initializer<Structure>& init) {
- JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner);
- IntlDateTimeFormatPrototype* dateTimeFormatPrototype = IntlDateTimeFormatPrototype::create(init.vm, globalObject, IntlDateTimeFormatPrototype::createStructure(init.vm, globalObject, globalObject->objectPrototype()));
- init.set(IntlDateTimeFormat::createStructure(init.vm, globalObject, dateTimeFormatPrototype));
- });
m_pluralRulesStructure.initLater(
[] (const Initializer<Structure>& init) {
JSGlobalObject* globalObject = jsCast<JSGlobalObject*>(init.owner);
@@ -1775,8 +1783,9 @@
thisObject->m_defaultCollator.visit(visitor);
thisObject->m_collatorStructure.visit(visitor);
+ thisObject->m_dateTimeFormatStructure.visit(visitor);
thisObject->m_numberFormatStructure.visit(visitor);
- thisObject->m_dateTimeFormatStructure.visit(visitor);
+ thisObject->m_localeStructure.visit(visitor);
thisObject->m_pluralRulesStructure.visit(visitor);
thisObject->m_relativeTimeFormatStructure.visit(visitor);
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (261214 => 261215)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h 2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h 2020-05-06 06:01:07 UTC (rev 261215)
@@ -291,8 +291,9 @@
LazyProperty<JSGlobalObject, IntlCollator> m_defaultCollator;
LazyProperty<JSGlobalObject, Structure> m_collatorStructure;
+ LazyProperty<JSGlobalObject, Structure> m_dateTimeFormatStructure;
+ LazyProperty<JSGlobalObject, Structure> m_localeStructure;
LazyProperty<JSGlobalObject, Structure> m_numberFormatStructure;
- LazyProperty<JSGlobalObject, Structure> m_dateTimeFormatStructure;
LazyProperty<JSGlobalObject, Structure> m_pluralRulesStructure;
LazyProperty<JSGlobalObject, Structure> m_relativeTimeFormatStructure;
@@ -786,8 +787,9 @@
Structure* webAssemblyWrapperFunctionStructure() const { return m_webAssemblyWrapperFunctionStructure.get(this); }
#endif // ENABLE(WEBASSEMBLY)
Structure* collatorStructure() { return m_collatorStructure.get(this); }
+ Structure* dateTimeFormatStructure() { return m_dateTimeFormatStructure.get(this); }
Structure* numberFormatStructure() { return m_numberFormatStructure.get(this); }
- Structure* dateTimeFormatStructure() { return m_dateTimeFormatStructure.get(this); }
+ Structure* localeStructure() { return m_localeStructure.get(this); }
Structure* pluralRulesStructure() { return m_pluralRulesStructure.get(this); }
Structure* relativeTimeFormatStructure() { return m_relativeTimeFormatStructure.get(this); }
Modified: trunk/Source/_javascript_Core/runtime/OptionsList.h (261214 => 261215)
--- trunk/Source/_javascript_Core/runtime/OptionsList.h 2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/runtime/OptionsList.h 2020-05-06 06:01:07 UTC (rev 261215)
@@ -486,6 +486,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, useIntlLocale, false, Normal, "Expose the Intl.Locale constructor.") \
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.") \
Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (261214 => 261215)
--- trunk/Source/_javascript_Core/runtime/VM.cpp 2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp 2020-05-06 06:01:07 UTC (rev 261215)
@@ -75,6 +75,7 @@
#include "Interpreter.h"
#include "IntlCollator.h"
#include "IntlDateTimeFormat.h"
+#include "IntlLocale.h"
#include "IntlNumberFormat.h"
#include "IntlPluralRules.h"
#include "IntlRelativeTimeFormat.h"
@@ -339,6 +340,7 @@
#endif
, intlCollatorHeapCellType(IsoHeapCellType::create<IntlCollator>())
, intlDateTimeFormatHeapCellType(IsoHeapCellType::create<IntlDateTimeFormat>())
+ , intlLocaleHeapCellType(IsoHeapCellType::create<IntlLocale>())
, intlNumberFormatHeapCellType(IsoHeapCellType::create<IntlNumberFormat>())
, intlPluralRulesHeapCellType(IsoHeapCellType::create<IntlPluralRules>())
, intlRelativeTimeFormatHeapCellType(IsoHeapCellType::create<IntlRelativeTimeFormat>())
@@ -1510,6 +1512,7 @@
#endif
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlCollatorSpace, intlCollatorHeapCellType.get(), IntlCollator)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlDateTimeFormatSpace, intlDateTimeFormatHeapCellType.get(), IntlDateTimeFormat)
+DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER_SLOW(intlLocaleSpace, intlLocaleHeapCellType.get(), IntlLocale)
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)
Modified: trunk/Source/_javascript_Core/runtime/VM.h (261214 => 261215)
--- trunk/Source/_javascript_Core/runtime/VM.h 2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Source/_javascript_Core/runtime/VM.h 2020-05-06 06:01:07 UTC (rev 261215)
@@ -126,6 +126,7 @@
class Interpreter;
class IntlCollator;
class IntlDateTimeFormat;
+class IntlLocale;
class IntlNumberFormat;
class IntlPluralRules;
class IntlRelativeTimeFormat;
@@ -400,6 +401,7 @@
#endif
std::unique_ptr<IsoHeapCellType> intlCollatorHeapCellType;
std::unique_ptr<IsoHeapCellType> intlDateTimeFormatHeapCellType;
+ std::unique_ptr<IsoHeapCellType> intlLocaleHeapCellType;
std::unique_ptr<IsoHeapCellType> intlNumberFormatHeapCellType;
std::unique_ptr<IsoHeapCellType> intlPluralRulesHeapCellType;
std::unique_ptr<IsoHeapCellType> intlRelativeTimeFormatHeapCellType;
@@ -557,6 +559,7 @@
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(withScopeSpace)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlCollatorSpace)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlDateTimeFormatSpace)
+ DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlLocaleSpace)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlNumberFormatSpace)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlPluralRulesSpace)
DYNAMIC_ISO_SUBSPACE_DEFINE_MEMBER(intlRelativeTimeFormatSpace)
Modified: trunk/Tools/ChangeLog (261214 => 261215)
--- trunk/Tools/ChangeLog 2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Tools/ChangeLog 2020-05-06 06:01:07 UTC (rev 261215)
@@ -1,3 +1,13 @@
+2020-05-05 Ross Kirsling <ross.kirsl...@sony.com>
+
+ [ECMA-402] Implement Intl.Locale
+ https://bugs.webkit.org/show_bug.cgi?id=209772
+
+ Reviewed by Darin Adler and Saam Barati.
+
+ * Scripts/run-jsc-stress-tests:
+ Add runIntlLocaleEnabled.
+
2020-05-05 Saam Barati <sbar...@apple.com>
Don't use the DebugHeap for catalyst
Modified: trunk/Tools/Scripts/run-jsc-stress-tests (261214 => 261215)
--- trunk/Tools/Scripts/run-jsc-stress-tests 2020-05-06 05:55:00 UTC (rev 261214)
+++ trunk/Tools/Scripts/run-jsc-stress-tests 2020-05-06 06:01:07 UTC (rev 261215)
@@ -715,6 +715,10 @@
run("big-int-enabled-baseline", "--useBigInt=true", "--useDFGJIT=0", *optionalTestSpecificOptions)
end
+def runIntlLocaleEnabled(*optionalTestSpecificOptions)
+ run("intl-locale-enabled", "--useIntlLocale=true" , *(FTL_OPTIONS + optionalTestSpecificOptions))
+end
+
def runIntlRelativeTimeFormatEnabled(*optionalTestSpecificOptions)
run("intl-relativetimeformat-enabled", "--useIntlRelativeTimeFormat=true" , *(FTL_OPTIONS + optionalTestSpecificOptions))
end