Changeset 196434 in webkit
- Timestamp:
- Feb 11, 2016 1:24:52 PM (8 years ago)
- Location:
- trunk
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r196431 r196434 1 2016-02-11 Sukolsak Sakshuwong <sukolsak@gmail.com> 2 3 [INTL] Implement Intl.NumberFormat.prototype.resolvedOptions () 4 https://bugs.webkit.org/show_bug.cgi?id=147602 5 6 Reviewed by Darin Adler. 7 8 * js/intl-numberformat-expected.txt: 9 * js/script-tests/intl-numberformat.js: 10 (testNumberFormat): 11 1 12 2016-02-11 Ryan Haddad <ryanhaddad@apple.com> 2 13 -
trunk/LayoutTests/js/intl-numberformat-expected.txt
r189811 r196434 13 13 PASS class DerivedNumberFormat extends Intl.NumberFormat {};Object.getPrototypeOf(new DerivedNumberFormat) === DerivedNumberFormat.prototype is true 14 14 PASS class DerivedNumberFormat extends Intl.NumberFormat {};Object.getPrototypeOf(Object.getPrototypeOf(new DerivedNumberFormat)) === Intl.NumberFormat.prototype is true 15 PASS testNumberFormat(Intl.NumberFormat('en'), [{locale: 'en'}]) is true 16 PASS testNumberFormat(Intl.NumberFormat('eN-uS'), [{locale: 'en-US'}]) is true 17 PASS testNumberFormat(Intl.NumberFormat(['en', 'de']), [{locale: 'en'}]) is true 18 PASS testNumberFormat(Intl.NumberFormat('de'), [{locale: 'de'}]) is true 19 PASS testNumberFormat(Intl.NumberFormat('zh-Hans-CN-u-nu-hanidec'), [{locale: 'zh-Hans-CN-u-nu-hanidec', numberingSystem: 'hanidec'}]) is true 20 PASS testNumberFormat(Intl.NumberFormat('ZH-hans-cn-U-Nu-Hanidec'), [{locale: 'zh-Hans-CN-u-nu-hanidec', numberingSystem: 'hanidec'}]) is true 21 PASS testNumberFormat(Intl.NumberFormat('en-u-nu-abcd'), [{locale: 'en'}]) is true 22 PASS testNumberFormat(Intl.NumberFormat('zh-Hans-CN-u-aa-aaaa-co-pinyin-nu-hanidec-bb-bbbb'), [{locale: 'zh-Hans-CN-u-nu-hanidec', numberingSystem: 'hanidec'}]) is true 23 PASS testNumberFormat(Intl.NumberFormat('en', {localeMatcher: 'lookup'}), [{locale: 'en'}]) is true 24 PASS testNumberFormat(Intl.NumberFormat('en', {localeMatcher: 'best fit'}), [{locale: 'en'}]) is true 25 PASS Intl.NumberFormat('en', {localeMatcher: 'LookUp'}) threw exception RangeError: localeMatcher must be either "lookup" or "best fit". 26 PASS Intl.NumberFormat('en', { get localeMatcher() { throw 42; } }) threw exception 42. 27 PASS Intl.NumberFormat('en', {localeMatcher: {toString() { throw 42; }}}) threw exception 42. 28 PASS testNumberFormat(Intl.NumberFormat('en', {style: 'decimal'}), [{locale: 'en', style: 'decimal'}]) is true 29 PASS Intl.NumberFormat('en', {style: 'currency'}) threw exception TypeError: currency must be a string. 30 PASS testNumberFormat(Intl.NumberFormat('en', {style: 'percent'}), [{locale: 'en', style: 'percent', maximumFractionDigits: 0}]) is true 31 PASS Intl.NumberFormat('en', {style: 'Decimal'}) threw exception RangeError: style must be either "decimal", "percent", or "currency". 32 PASS Intl.NumberFormat('en', { get style() { throw 42; } }) threw exception 42. 33 PASS testNumberFormat(Intl.NumberFormat('en', {style: 'currency', currency: 'USD'}), [{locale: 'en', style: 'currency', currency: 'USD', currencyDisplay: 'symbol', minimumFractionDigits: 2, maximumFractionDigits: 2}]) is true 34 PASS testNumberFormat(Intl.NumberFormat('en', {style: 'currency', currency: 'UsD'}), [{locale: 'en', style: 'currency', currency: 'USD', currencyDisplay: 'symbol', minimumFractionDigits: 2, maximumFractionDigits: 2}]) is true 35 PASS testNumberFormat(Intl.NumberFormat('en', {style: 'currency', currency: 'CLF'}), [{locale: 'en', style: 'currency', currency: 'CLF', currencyDisplay: 'symbol', minimumFractionDigits: 4, maximumFractionDigits: 4}]) is true 36 PASS testNumberFormat(Intl.NumberFormat('en', {style: 'currency', currency: 'cLf'}), [{locale: 'en', style: 'currency', currency: 'CLF', currencyDisplay: 'symbol', minimumFractionDigits: 4, maximumFractionDigits: 4}]) is true 37 PASS testNumberFormat(Intl.NumberFormat('en', {style: 'currency', currency: 'XXX'}), [{locale: 'en', style: 'currency', currency: 'XXX', currencyDisplay: 'symbol', minimumFractionDigits: 2, maximumFractionDigits: 2}]) is true 38 PASS Intl.NumberFormat('en', {style: 'currency', currency: 'US$'}) threw exception RangeError: currency is not a well-formed currency code. 39 PASS Intl.NumberFormat('en', {style: 'currency', currency: 'US'}) threw exception RangeError: currency is not a well-formed currency code. 40 PASS Intl.NumberFormat('en', {style: 'currency', currency: 'US Dollar'}) threw exception RangeError: currency is not a well-formed currency code. 41 PASS Intl.NumberFormat('en', {style: 'currency', get currency() { throw 42; }}) threw exception 42. 42 PASS testNumberFormat(Intl.NumberFormat('en', {style: 'decimal', currency: 'USD'}), [{locale: 'en', style: 'decimal'}]) is true 43 PASS testNumberFormat(Intl.NumberFormat('en', {style: 'currency', currency: 'USD', currencyDisplay: 'code'}), [{locale: 'en', style: 'currency', currency: 'USD', currencyDisplay: 'code', minimumFractionDigits: 2, maximumFractionDigits: 2}]) is true 44 PASS testNumberFormat(Intl.NumberFormat('en', {style: 'currency', currency: 'USD', currencyDisplay: 'symbol'}), [{locale: 'en', style: 'currency', currency: 'USD', currencyDisplay: 'symbol', minimumFractionDigits: 2, maximumFractionDigits: 2}]) is true 45 PASS testNumberFormat(Intl.NumberFormat('en', {style: 'currency', currency: 'USD', currencyDisplay: 'name'}), [{locale: 'en', style: 'currency', currency: 'USD', currencyDisplay: 'name', minimumFractionDigits: 2, maximumFractionDigits: 2}]) is true 46 PASS Intl.NumberFormat('en', {style: 'currency', currency: 'USD', currencyDisplay: 'Code'}) threw exception RangeError: currencyDisplay must be either "code", "symbol", or "name". 47 PASS Intl.NumberFormat('en', {style: 'currency', currency: 'USD', get currencyDisplay() { throw 42; }}) threw exception 42. 48 PASS testNumberFormat(Intl.NumberFormat('en', {style: 'decimal', currencyDisplay: 'code'}), [{locale: 'en', style: 'decimal'}]) is true 49 PASS testNumberFormat(Intl.NumberFormat('en', {minimumIntegerDigits: 1}), [{locale: 'en', minimumIntegerDigits: 1}]) is true 50 PASS testNumberFormat(Intl.NumberFormat('en', {minimumIntegerDigits: '2'}), [{locale: 'en', minimumIntegerDigits: 2}]) is true 51 PASS testNumberFormat(Intl.NumberFormat('en', {minimumIntegerDigits: {valueOf() { return 3; }}}), [{locale: 'en', minimumIntegerDigits: 3}]) is true 52 PASS testNumberFormat(Intl.NumberFormat('en', {minimumIntegerDigits: 4.9}), [{locale: 'en', minimumIntegerDigits: 4}]) is true 53 PASS testNumberFormat(Intl.NumberFormat('en', {minimumIntegerDigits: 21}), [{locale: 'en', minimumIntegerDigits: 21}]) is true 54 PASS Intl.NumberFormat('en', {minimumIntegerDigits: 0}) threw exception RangeError: minimumIntegerDigits is out of range. 55 PASS Intl.NumberFormat('en', {minimumIntegerDigits: 22}) threw exception RangeError: minimumIntegerDigits is out of range. 56 PASS Intl.NumberFormat('en', {minimumIntegerDigits: 0.9}) threw exception RangeError: minimumIntegerDigits is out of range. 57 PASS Intl.NumberFormat('en', {minimumIntegerDigits: 21.1}) threw exception RangeError: minimumIntegerDigits is out of range. 58 PASS Intl.NumberFormat('en', {minimumIntegerDigits: NaN}) threw exception RangeError: minimumIntegerDigits is out of range. 59 PASS Intl.NumberFormat('en', {minimumIntegerDigits: Infinity}) threw exception RangeError: minimumIntegerDigits is out of range. 60 PASS Intl.NumberFormat('en', { get minimumIntegerDigits() { throw 42; } }) threw exception 42. 61 PASS Intl.NumberFormat('en', {minimumIntegerDigits: {valueOf() { throw 42; }}}) threw exception 42. 62 PASS testNumberFormat(Intl.NumberFormat('en', {minimumFractionDigits: 0}), [{locale: 'en', minimumFractionDigits: 0, maximumFractionDigits: 3}]) is true 63 PASS testNumberFormat(Intl.NumberFormat('en', {style: 'percent', minimumFractionDigits: 0}), [{locale: 'en', style: 'percent', minimumFractionDigits: 0, maximumFractionDigits: 0}]) is true 64 PASS testNumberFormat(Intl.NumberFormat('en', {minimumFractionDigits: 6}), [{locale: 'en', minimumFractionDigits: 6, maximumFractionDigits: 6}]) is true 65 PASS Intl.NumberFormat('en', {minimumFractionDigits: -1}) threw exception RangeError: minimumFractionDigits is out of range. 66 PASS Intl.NumberFormat('en', {minimumFractionDigits: 21}) threw exception RangeError: minimumFractionDigits is out of range. 67 PASS testNumberFormat(Intl.NumberFormat('en', {maximumFractionDigits: 6}), [{locale: 'en', maximumFractionDigits: 6}]) is true 68 PASS Intl.NumberFormat('en', {minimumFractionDigits: 7, maximumFractionDigits: 6}) threw exception RangeError: maximumFractionDigits is out of range. 69 PASS Intl.NumberFormat('en', {maximumFractionDigits: -1}) threw exception RangeError: maximumFractionDigits is out of range. 70 PASS Intl.NumberFormat('en', {maximumFractionDigits: 21}) threw exception RangeError: maximumFractionDigits is out of range. 71 PASS testNumberFormat(Intl.NumberFormat('en', {minimumSignificantDigits: 6}), [{locale: 'en', minimumSignificantDigits: 6, maximumSignificantDigits: 21}]) is true 72 PASS Intl.NumberFormat('en', {minimumSignificantDigits: 0}) threw exception RangeError: minimumSignificantDigits is out of range. 73 PASS Intl.NumberFormat('en', {minimumSignificantDigits: 22}) threw exception RangeError: minimumSignificantDigits is out of range. 74 PASS testNumberFormat(Intl.NumberFormat('en', {maximumSignificantDigits: 6}), [{locale: 'en', minimumSignificantDigits: 1, maximumSignificantDigits: 6}]) is true 75 PASS Intl.NumberFormat('en', {minimumSignificantDigits: 7, maximumSignificantDigits: 6}) threw exception RangeError: maximumSignificantDigits is out of range. 76 PASS Intl.NumberFormat('en', {maximumSignificantDigits: 0}) threw exception RangeError: maximumSignificantDigits is out of range. 77 PASS Intl.NumberFormat('en', {maximumSignificantDigits: 22}) threw exception RangeError: maximumSignificantDigits is out of range. 78 PASS testNumberFormat(Intl.NumberFormat('en', {useGrouping: true}), [{locale: 'en', useGrouping: true}]) is true 79 PASS testNumberFormat(Intl.NumberFormat('en', {useGrouping: false}), [{locale: 'en', useGrouping: false}]) is true 80 PASS testNumberFormat(Intl.NumberFormat('en', {useGrouping: 'false'}), [{locale: 'en', useGrouping: true}]) is true 81 PASS Intl.NumberFormat('en', { get useGrouping() { throw 42; } }) threw exception 42. 15 82 PASS Intl.NumberFormat.length is 0 16 83 PASS Object.getOwnPropertyDescriptor(Intl.NumberFormat, 'prototype').writable is false … … 65 132 PASS Intl.NumberFormat.prototype.resolvedOptions() === Intl.NumberFormat.prototype.resolvedOptions() is false 66 133 PASS Intl.NumberFormat.prototype.resolvedOptions.call(5) threw exception TypeError: Intl.NumberFormat.prototype.resolvedOptions called on value that's not an object initialized as a NumberFormat. 134 PASS var options = Intl.NumberFormat.prototype.resolvedOptions(); delete options['locale']; JSON.stringify(options) is '{"numberingSystem":"latn","style":"decimal","minimumIntegerDigits":1,"minimumFractionDigits":0,"maximumFractionDigits":3,"useGrouping":true}' 67 135 PASS successfullyParsed is true 68 136 -
trunk/LayoutTests/js/script-tests/intl-numberformat.js
r189811 r196434 18 18 shouldBeTrue(classPrefix + "Object.getPrototypeOf(new DerivedNumberFormat) === DerivedNumberFormat.prototype"); 19 19 shouldBeTrue(classPrefix + "Object.getPrototypeOf(Object.getPrototypeOf(new DerivedNumberFormat)) === Intl.NumberFormat.prototype"); 20 21 function testNumberFormat(numberFormat, possibleDifferences) { 22 var possibleOptions = possibleDifferences.map(function(difference) { 23 var defaultOptions = { 24 locale: undefined, 25 numberingSystem: "latn", 26 style: "decimal", 27 currency: undefined, 28 currencyDisplay: undefined, 29 minimumIntegerDigits: 1, 30 minimumFractionDigits: 0, 31 maximumFractionDigits: 3, 32 minimumSignificantDigits: undefined, 33 maximumSignificantDigits: undefined, 34 useGrouping: true 35 } 36 Object.assign(defaultOptions, difference); 37 return JSON.stringify(defaultOptions); 38 }); 39 var actualOptions = JSON.stringify(numberFormat.resolvedOptions()) 40 return possibleOptions.includes(actualOptions); 41 } 42 43 // Locale is processed correctly. 44 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en'), [{locale: 'en'}])"); 45 shouldBeTrue("testNumberFormat(Intl.NumberFormat('eN-uS'), [{locale: 'en-US'}])"); 46 shouldBeTrue("testNumberFormat(Intl.NumberFormat(['en', 'de']), [{locale: 'en'}])"); 47 shouldBeTrue("testNumberFormat(Intl.NumberFormat('de'), [{locale: 'de'}])"); 48 49 // The "nu" key is processed correctly. 50 shouldBeTrue("testNumberFormat(Intl.NumberFormat('zh-Hans-CN-u-nu-hanidec'), [{locale: 'zh-Hans-CN-u-nu-hanidec', numberingSystem: 'hanidec'}])"); 51 shouldBeTrue("testNumberFormat(Intl.NumberFormat('ZH-hans-cn-U-Nu-Hanidec'), [{locale: 'zh-Hans-CN-u-nu-hanidec', numberingSystem: 'hanidec'}])"); 52 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en-u-nu-abcd'), [{locale: 'en'}])"); 53 54 // Ignores irrelevant extension keys. 55 shouldBeTrue("testNumberFormat(Intl.NumberFormat('zh-Hans-CN-u-aa-aaaa-co-pinyin-nu-hanidec-bb-bbbb'), [{locale: 'zh-Hans-CN-u-nu-hanidec', numberingSystem: 'hanidec'}])"); 56 57 // The option localeMatcher is processed correctly. 58 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {localeMatcher: 'lookup'}), [{locale: 'en'}])"); 59 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {localeMatcher: 'best fit'}), [{locale: 'en'}])"); 60 shouldThrow("Intl.NumberFormat('en', {localeMatcher: 'LookUp'})", '\'RangeError: localeMatcher must be either "lookup" or "best fit"\''); 61 shouldThrow("Intl.NumberFormat('en', { get localeMatcher() { throw 42; } })", "'42'"); 62 shouldThrow("Intl.NumberFormat('en', {localeMatcher: {toString() { throw 42; }}})", "'42'"); 63 64 // The option style is processed correctly. 65 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {style: 'decimal'}), [{locale: 'en', style: 'decimal'}])"); 66 shouldThrow("Intl.NumberFormat('en', {style: 'currency'})", "'TypeError: currency must be a string'"); 67 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {style: 'percent'}), [{locale: 'en', style: 'percent', maximumFractionDigits: 0}])"); 68 shouldThrow("Intl.NumberFormat('en', {style: 'Decimal'})", '\'RangeError: style must be either "decimal", "percent", or "currency"\''); 69 shouldThrow("Intl.NumberFormat('en', { get style() { throw 42; } })", "'42'"); 70 71 // The option currency is processed correctly. 72 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {style: 'currency', currency: 'USD'}), [{locale: 'en', style: 'currency', currency: 'USD', currencyDisplay: 'symbol', minimumFractionDigits: 2, maximumFractionDigits: 2}])"); 73 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {style: 'currency', currency: 'UsD'}), [{locale: 'en', style: 'currency', currency: 'USD', currencyDisplay: 'symbol', minimumFractionDigits: 2, maximumFractionDigits: 2}])"); 74 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {style: 'currency', currency: 'CLF'}), [{locale: 'en', style: 'currency', currency: 'CLF', currencyDisplay: 'symbol', minimumFractionDigits: 4, maximumFractionDigits: 4}])"); 75 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {style: 'currency', currency: 'cLf'}), [{locale: 'en', style: 'currency', currency: 'CLF', currencyDisplay: 'symbol', minimumFractionDigits: 4, maximumFractionDigits: 4}])"); 76 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {style: 'currency', currency: 'XXX'}), [{locale: 'en', style: 'currency', currency: 'XXX', currencyDisplay: 'symbol', minimumFractionDigits: 2, maximumFractionDigits: 2}])"); 77 shouldThrow("Intl.NumberFormat('en', {style: 'currency', currency: 'US$'})", "'RangeError: currency is not a well-formed currency code'"); 78 shouldThrow("Intl.NumberFormat('en', {style: 'currency', currency: 'US'})", "'RangeError: currency is not a well-formed currency code'"); 79 shouldThrow("Intl.NumberFormat('en', {style: 'currency', currency: 'US Dollar'})", "'RangeError: currency is not a well-formed currency code'"); 80 shouldThrow("Intl.NumberFormat('en', {style: 'currency', get currency() { throw 42; }})", "'42'"); 81 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {style: 'decimal', currency: 'USD'}), [{locale: 'en', style: 'decimal'}])"); 82 83 // The option currencyDisplay is processed correctly. 84 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {style: 'currency', currency: 'USD', currencyDisplay: 'code'}), [{locale: 'en', style: 'currency', currency: 'USD', currencyDisplay: 'code', minimumFractionDigits: 2, maximumFractionDigits: 2}])"); 85 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {style: 'currency', currency: 'USD', currencyDisplay: 'symbol'}), [{locale: 'en', style: 'currency', currency: 'USD', currencyDisplay: 'symbol', minimumFractionDigits: 2, maximumFractionDigits: 2}])"); 86 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {style: 'currency', currency: 'USD', currencyDisplay: 'name'}), [{locale: 'en', style: 'currency', currency: 'USD', currencyDisplay: 'name', minimumFractionDigits: 2, maximumFractionDigits: 2}])"); 87 shouldThrow("Intl.NumberFormat('en', {style: 'currency', currency: 'USD', currencyDisplay: 'Code'})", '\'RangeError: currencyDisplay must be either "code", "symbol", or "name"\''); 88 shouldThrow("Intl.NumberFormat('en', {style: 'currency', currency: 'USD', get currencyDisplay() { throw 42; }})", "'42'"); 89 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {style: 'decimal', currencyDisplay: 'code'}), [{locale: 'en', style: 'decimal'}])"); 90 91 // The option minimumIntegerDigits is processed correctly. 92 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {minimumIntegerDigits: 1}), [{locale: 'en', minimumIntegerDigits: 1}])"); 93 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {minimumIntegerDigits: '2'}), [{locale: 'en', minimumIntegerDigits: 2}])"); 94 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {minimumIntegerDigits: {valueOf() { return 3; }}}), [{locale: 'en', minimumIntegerDigits: 3}])"); 95 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {minimumIntegerDigits: 4.9}), [{locale: 'en', minimumIntegerDigits: 4}])"); 96 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {minimumIntegerDigits: 21}), [{locale: 'en', minimumIntegerDigits: 21}])"); 97 shouldThrow("Intl.NumberFormat('en', {minimumIntegerDigits: 0})", "'RangeError: minimumIntegerDigits is out of range'"); 98 shouldThrow("Intl.NumberFormat('en', {minimumIntegerDigits: 22})", "'RangeError: minimumIntegerDigits is out of range'"); 99 shouldThrow("Intl.NumberFormat('en', {minimumIntegerDigits: 0.9})", "'RangeError: minimumIntegerDigits is out of range'"); 100 shouldThrow("Intl.NumberFormat('en', {minimumIntegerDigits: 21.1})", "'RangeError: minimumIntegerDigits is out of range'"); 101 shouldThrow("Intl.NumberFormat('en', {minimumIntegerDigits: NaN})", "'RangeError: minimumIntegerDigits is out of range'"); 102 shouldThrow("Intl.NumberFormat('en', {minimumIntegerDigits: Infinity})", "'RangeError: minimumIntegerDigits is out of range'"); 103 shouldThrow("Intl.NumberFormat('en', { get minimumIntegerDigits() { throw 42; } })", "'42'"); 104 shouldThrow("Intl.NumberFormat('en', {minimumIntegerDigits: {valueOf() { throw 42; }}})", "'42'"); 105 106 // The option minimumFractionDigits is processed correctly. 107 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {minimumFractionDigits: 0}), [{locale: 'en', minimumFractionDigits: 0, maximumFractionDigits: 3}])"); 108 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {style: 'percent', minimumFractionDigits: 0}), [{locale: 'en', style: 'percent', minimumFractionDigits: 0, maximumFractionDigits: 0}])"); 109 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {minimumFractionDigits: 6}), [{locale: 'en', minimumFractionDigits: 6, maximumFractionDigits: 6}])"); 110 shouldThrow("Intl.NumberFormat('en', {minimumFractionDigits: -1})", "'RangeError: minimumFractionDigits is out of range'"); 111 shouldThrow("Intl.NumberFormat('en', {minimumFractionDigits: 21})", "'RangeError: minimumFractionDigits is out of range'"); 112 113 // The option maximumFractionDigits is processed correctly. 114 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {maximumFractionDigits: 6}), [{locale: 'en', maximumFractionDigits: 6}])"); 115 shouldThrow("Intl.NumberFormat('en', {minimumFractionDigits: 7, maximumFractionDigits: 6})", "'RangeError: maximumFractionDigits is out of range'"); 116 shouldThrow("Intl.NumberFormat('en', {maximumFractionDigits: -1})", "'RangeError: maximumFractionDigits is out of range'"); 117 shouldThrow("Intl.NumberFormat('en', {maximumFractionDigits: 21})", "'RangeError: maximumFractionDigits is out of range'"); 118 119 // The option minimumSignificantDigits is processed correctly. 120 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {minimumSignificantDigits: 6}), [{locale: 'en', minimumSignificantDigits: 6, maximumSignificantDigits: 21}])"); 121 shouldThrow("Intl.NumberFormat('en', {minimumSignificantDigits: 0})", "'RangeError: minimumSignificantDigits is out of range'"); 122 shouldThrow("Intl.NumberFormat('en', {minimumSignificantDigits: 22})", "'RangeError: minimumSignificantDigits is out of range'"); 123 124 // The option maximumSignificantDigits is processed correctly. 125 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {maximumSignificantDigits: 6}), [{locale: 'en', minimumSignificantDigits: 1, maximumSignificantDigits: 6}])"); 126 shouldThrow("Intl.NumberFormat('en', {minimumSignificantDigits: 7, maximumSignificantDigits: 6})", "'RangeError: maximumSignificantDigits is out of range'"); 127 shouldThrow("Intl.NumberFormat('en', {maximumSignificantDigits: 0})", "'RangeError: maximumSignificantDigits is out of range'"); 128 shouldThrow("Intl.NumberFormat('en', {maximumSignificantDigits: 22})", "'RangeError: maximumSignificantDigits is out of range'"); 129 130 // The option useGrouping is processed correctly. 131 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {useGrouping: true}), [{locale: 'en', useGrouping: true}])"); 132 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {useGrouping: false}), [{locale: 'en', useGrouping: false}])"); 133 shouldBeTrue("testNumberFormat(Intl.NumberFormat('en', {useGrouping: 'false'}), [{locale: 'en', useGrouping: true}])"); 134 shouldThrow("Intl.NumberFormat('en', { get useGrouping() { throw 42; } })", "'42'"); 20 135 21 136 // 11.2 Properties of the Intl.NumberFormat Constructor … … 136 251 shouldThrow("Intl.NumberFormat.prototype.resolvedOptions.call(5)", "'TypeError: Intl.NumberFormat.prototype.resolvedOptions called on value that\\'s not an object initialized as a NumberFormat'"); 137 252 253 // Returns the default options. 254 shouldBe("var options = Intl.NumberFormat.prototype.resolvedOptions(); delete options['locale']; JSON.stringify(options)", '\'{"numberingSystem":"latn","style":"decimal","minimumIntegerDigits":1,"minimumFractionDigits":0,"maximumFractionDigits":3,"useGrouping":true}\''); -
trunk/Source/JavaScriptCore/ChangeLog
r196433 r196434 1 2016-02-11 Sukolsak Sakshuwong <sukolsak@gmail.com> 2 3 [INTL] Implement Intl.NumberFormat.prototype.resolvedOptions () 4 https://bugs.webkit.org/show_bug.cgi?id=147602 5 6 Reviewed by Darin Adler. 7 8 This patch implements Intl.NumberFormat.prototype.resolvedOptions() according 9 to the ECMAScript 2015 Internationalization API spec (ECMA-402 2nd edition.) 10 11 * runtime/IntlDateTimeFormat.cpp: 12 (JSC::localeData): 13 * runtime/IntlNumberFormat.cpp: 14 (JSC::localeData): 15 (JSC::computeCurrencySortKey): 16 (JSC::extractCurrencySortKey): 17 (JSC::computeCurrencyDigits): 18 (JSC::IntlNumberFormat::initializeNumberFormat): 19 (JSC::IntlNumberFormat::styleString): 20 (JSC::IntlNumberFormat::currencyDisplayString): 21 (JSC::IntlNumberFormat::resolvedOptions): 22 (JSC::IntlNumberFormat::setBoundFormat): 23 * runtime/IntlNumberFormat.h: 24 * runtime/IntlNumberFormatConstructor.cpp: 25 (JSC::constructIntlNumberFormat): 26 (JSC::callIntlNumberFormat): 27 * runtime/IntlNumberFormatPrototype.cpp: 28 (JSC::IntlNumberFormatPrototypeFuncResolvedOptions): 29 * runtime/IntlObject.cpp: 30 (JSC::intlNumberOption): 31 (JSC::numberingSystemsForLocale): 32 (JSC::getNumberingSystemsForLocale): Deleted. 33 * runtime/IntlObject.h: 34 1 35 2016-02-11 Filip Pizlo <fpizlo@apple.com> 2 36 -
trunk/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp
r195138 r196434 211 211 } 212 212 case indexOfExtensionKeyNu: 213 keyLocaleData = getNumberingSystemsForLocale(locale);213 keyLocaleData = numberingSystemsForLocale(locale); 214 214 break; 215 215 default: -
trunk/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp
r192831 r196434 1 1 /* 2 2 * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com) 3 * Copyright (C) 2016 Sukolsak Sakshuwong (sukolsak@gmail.com) 3 4 * 4 5 * Redistribution and use in source and binary forms, with or without … … 30 31 31 32 #include "Error.h" 33 #include "IdentifierInlines.h" 32 34 #include "IntlNumberFormatConstructor.h" 33 35 #include "IntlObject.h" … … 35 37 #include "JSCJSValueInlines.h" 36 38 #include "JSCellInlines.h" 39 #include "ObjectConstructor.h" 37 40 #include "SlotVisitorInlines.h" 38 41 #include "StructureInlines.h" … … 41 44 42 45 const ClassInfo IntlNumberFormat::s_info = { "Object", &Base::s_info, 0, CREATE_METHOD_TABLE(IntlNumberFormat) }; 46 47 static const char* const relevantExtensionKeys[1] = { "nu" }; 43 48 44 49 IntlNumberFormat* IntlNumberFormat::create(VM& vm, IntlNumberFormatConstructor* constructor) … … 80 85 } 81 86 82 void IntlNumberFormat::setBoundFormat(VM& vm, JSBoundFunction* format) 83 { 84 m_boundFormat.set(vm, this, format); 87 static Vector<String> localeData(const String& locale, size_t keyIndex) 88 { 89 // 9.1 Internal slots of Service Constructors & 11.2.3 Internal slots (ECMA-402 2.0) 90 ASSERT_UNUSED(keyIndex, !keyIndex); // The index of the extension key "nu" in relevantExtensionKeys is 0. 91 return numberingSystemsForLocale(locale); 92 } 93 94 static inline unsigned computeCurrencySortKey(const String& currency) 95 { 96 ASSERT(currency.length() == 3); 97 ASSERT(currency.isAllSpecialCharacters<isASCIIUpper>()); 98 return (currency[0] << 16) + (currency[1] << 8) + currency[2]; 99 } 100 101 static inline unsigned computeCurrencySortKey(const char* currency) 102 { 103 ASSERT(strlen(currency) == 3); 104 ASSERT(isAllSpecialCharacters<isASCIIUpper>(currency, 3)); 105 return (currency[0] << 16) + (currency[1] << 8) + currency[2]; 106 } 107 108 static unsigned extractCurrencySortKey(std::pair<const char*, unsigned>* currencyMinorUnit) 109 { 110 return computeCurrencySortKey(currencyMinorUnit->first); 111 } 112 113 static unsigned computeCurrencyDigits(const String& currency) 114 { 115 // 11.1.1 The abstract operation CurrencyDigits (currency) 116 // "If the ISO 4217 currency and funds code list contains currency as an alphabetic code, 117 // then return the minor unit value corresponding to the currency from the list; else return 2. 118 std::pair<const char*, unsigned> currencyMinorUnits[] = { 119 { "BHD", 3 }, 120 { "BIF", 0 }, 121 { "BYR", 0 }, 122 { "CLF", 4 }, 123 { "CLP", 0 }, 124 { "DJF", 0 }, 125 { "GNF", 0 }, 126 { "IQD", 3 }, 127 { "ISK", 0 }, 128 { "JOD", 3 }, 129 { "JPY", 0 }, 130 { "KMF", 0 }, 131 { "KRW", 0 }, 132 { "KWD", 3 }, 133 { "LYD", 3 }, 134 { "OMR", 3 }, 135 { "PYG", 0 }, 136 { "RWF", 0 }, 137 { "TND", 3 }, 138 { "UGX", 0 }, 139 { "UYI", 0 }, 140 { "VND", 0 }, 141 { "VUV", 0 }, 142 { "XAF", 0 }, 143 { "XOF", 0 }, 144 { "XPF", 0 } 145 }; 146 auto* currencyMinorUnit = tryBinarySearch<std::pair<const char*, unsigned>>(currencyMinorUnits, WTF_ARRAY_LENGTH(currencyMinorUnits), computeCurrencySortKey(currency), extractCurrencySortKey); 147 if (currencyMinorUnit) 148 return currencyMinorUnit->second; 149 return 2; 150 } 151 152 void IntlNumberFormat::initializeNumberFormat(ExecState& state, JSValue locales, JSValue optionsValue) 153 { 154 // 11.1.1 InitializeNumberFormat (numberFormat, locales, options) (ECMA-402 2.0) 155 VM& vm = state.vm(); 156 157 // 1. If numberFormat has an [[initializedIntlObject]] internal slot with value true, throw a TypeError exception. 158 // 2. Set numberFormat.[[initializedIntlObject]] to true. 159 160 // 3. Let requestedLocales be CanonicalizeLocaleList(locales). 161 auto requestedLocales = canonicalizeLocaleList(state, locales); 162 // 4. ReturnIfAbrupt(requestedLocales). 163 if (state.hadException()) 164 return; 165 166 // 5. If options is undefined, then 167 JSObject* options; 168 if (optionsValue.isUndefined()) { 169 // a. Let options be ObjectCreate(%ObjectPrototype%). 170 options = constructEmptyObject(&state); 171 } else { // 6. Else 172 // a. Let options be ToObject(options). 173 options = optionsValue.toObject(&state); 174 // b. ReturnIfAbrupt(options). 175 if (state.hadException()) 176 return; 177 } 178 179 // 7. Let opt be a new Record. 180 HashMap<String, String> opt; 181 182 // 8. Let matcher be GetOption(options, "localeMatcher", "string", «"lookup", "best fit"», "best fit"). 183 String matcher = intlStringOption(state, options, state.vm().propertyNames->localeMatcher, { "lookup", "best fit" }, "localeMatcher must be either \"lookup\" or \"best fit\"", "best fit"); 184 // 9. ReturnIfAbrupt(matcher). 185 if (state.hadException()) 186 return; 187 // 10. Set opt.[[localeMatcher]] to matcher. 188 opt.add(ASCIILiteral("localeMatcher"), matcher); 189 190 // 11. Let localeData be %NumberFormat%.[[localeData]]. 191 // 12. Let r be ResolveLocale(%NumberFormat%.[[availableLocales]], requestedLocales, opt, %NumberFormat%.[[relevantExtensionKeys]], localeData). 192 auto& availableLocales = state.callee()->globalObject()->intlNumberFormatAvailableLocales(); 193 auto result = resolveLocale(availableLocales, requestedLocales, opt, relevantExtensionKeys, WTF_ARRAY_LENGTH(relevantExtensionKeys), localeData); 194 195 // 13. Set numberFormat.[[locale]] to the value of r.[[locale]]. 196 m_locale = result.get(ASCIILiteral("locale")); 197 198 // 14. Set numberFormat.[[numberingSystem]] to the value of r.[[nu]]. 199 m_numberingSystem = result.get(ASCIILiteral("nu")); 200 201 // 15. Let dataLocale be r.[[dataLocale]]. 202 203 // 16. Let s be GetOption(options, "style", "string", « "decimal", "percent", "currency"», "decimal"). 204 String styleString = intlStringOption(state, options, Identifier::fromString(&vm, "style"), { "decimal", "percent", "currency" }, "style must be either \"decimal\", \"percent\", or \"currency\"", "decimal"); 205 // 17. ReturnIfAbrupt(s). 206 if (state.hadException()) 207 return; 208 // 18. Set numberFormat.[[style]] to s. 209 if (styleString == "decimal") 210 m_style = Style::Decimal; 211 else if (styleString == "percent") 212 m_style = Style::Percent; 213 else if (styleString == "currency") 214 m_style = Style::Currency; 215 else 216 ASSERT_NOT_REACHED(); 217 218 // 19. Let c be GetOption(options, "currency", "string", undefined, undefined). 219 String currency = intlStringOption(state, options, Identifier::fromString(&vm, "currency"), { }, nullptr, nullptr); 220 // 20. ReturnIfAbrupt(c). 221 if (state.hadException()) 222 return; 223 // 21. If c is not undefined, then 224 if (!currency.isNull()) { 225 // a. If the result of IsWellFormedCurrencyCode(c), is false, then throw a RangeError exception. 226 if (currency.length() != 3 || !currency.isAllSpecialCharacters<isASCIIAlpha>()) { 227 state.vm().throwException(&state, createRangeError(&state, ASCIILiteral("currency is not a well-formed currency code"))); 228 return; 229 } 230 } 231 232 unsigned currencyDigits; 233 if (m_style == Style::Currency) { 234 // 22. If s is "currency" and c is undefined, throw a TypeError exception. 235 if (currency.isNull()) { 236 throwTypeError(&state, ASCIILiteral("currency must be a string")); 237 return; 238 } 239 240 // 23. If s is "currency", then 241 // a. Let c be converting c to upper case as specified in 6.1. 242 currency = currency.convertToASCIIUppercase(); 243 // b. Set numberFormat.[[currency]] to c. 244 m_currency = currency; 245 // c. Let cDigits be CurrencyDigits(c) 246 currencyDigits = computeCurrencyDigits(currency); 247 } 248 249 // 24. Let cd be GetOption(options, "currencyDisplay", "string", «"code", "symbol", "name"», "symbol"). 250 String currencyDisplayString = intlStringOption(state, options, Identifier::fromString(&vm, "currencyDisplay"), { "code", "symbol", "name" }, "currencyDisplay must be either \"code\", \"symbol\", or \"name\"", "symbol"); 251 // 25. ReturnIfAbrupt(cd). 252 if (state.hadException()) 253 return; 254 // 26. If s is "currency", set numberFormat.[[currencyDisplay]] to cd. 255 if (m_style == Style::Currency) { 256 if (currencyDisplayString == "code") 257 m_currencyDisplay = CurrencyDisplay::Code; 258 else if (currencyDisplayString == "symbol") 259 m_currencyDisplay = CurrencyDisplay::Symbol; 260 else if (currencyDisplayString == "name") 261 m_currencyDisplay = CurrencyDisplay::Name; 262 else 263 ASSERT_NOT_REACHED(); 264 } 265 266 // 27. Let mnid be GetNumberOption(options, "minimumIntegerDigits", 1, 21, 1). 267 // 28. ReturnIfAbrupt(mnid). 268 // 29. Set numberFormat.[[minimumIntegerDigits]] to mnid. 269 unsigned minimumIntegerDigits = intlNumberOption(state, options, Identifier::fromString(&vm, "minimumIntegerDigits"), 1, 21, 1); 270 if (state.hadException()) 271 return; 272 m_minimumIntegerDigits = minimumIntegerDigits; 273 274 // 30. If s is "currency", let mnfdDefault be cDigits; else let mnfdDefault be 0. 275 unsigned minimumFractionDigitsDefault = (m_style == Style::Currency) ? currencyDigits : 0; 276 277 // 31. Let mnfd be GetNumberOption(options, "minimumFractionDigits", 0, 20, mnfdDefault). 278 // 32. ReturnIfAbrupt(mnfd). 279 // 33. Set numberFormat.[[minimumFractionDigits]] to mnfd. 280 unsigned minimumFractionDigits = intlNumberOption(state, options, Identifier::fromString(&vm, "minimumFractionDigits"), 0, 20, minimumFractionDigitsDefault); 281 if (state.hadException()) 282 return; 283 m_minimumFractionDigits = minimumFractionDigits; 284 285 // 34. If s is "currency", let mxfdDefault be max(mnfd, cDigits); 286 unsigned maximumFractionDigitsDefault; 287 if (m_style == Style::Currency) 288 maximumFractionDigitsDefault = std::max(minimumFractionDigits, currencyDigits); 289 else if (m_style == Style::Percent) // else if s is "percent", let mxfdDefault be max(mnfd, 0); 290 maximumFractionDigitsDefault = minimumFractionDigits; 291 else // else let mxfdDefault be max(mnfd, 3). 292 maximumFractionDigitsDefault = std::max(minimumFractionDigits, 3u); 293 294 // 35. Let mxfd be GetNumberOption(options, "maximumFractionDigits", mnfd, 20, mxfdDefault). 295 // 36. ReturnIfAbrupt(mxfd). 296 // 37. Set numberFormat.[[maximumFractionDigits]] to mxfd. 297 unsigned maximumFractionDigits = intlNumberOption(state, options, Identifier::fromString(&vm, "maximumFractionDigits"), minimumFractionDigits, 20, maximumFractionDigitsDefault); 298 if (state.hadException()) 299 return; 300 m_maximumFractionDigits = maximumFractionDigits; 301 302 // 38. Let mnsd be Get(options, "minimumSignificantDigits"). 303 JSValue minimumSignificantDigitsValue = options->get(&state, Identifier::fromString(&vm, "minimumSignificantDigits")); 304 // 39. ReturnIfAbrupt(mnsd). 305 if (state.hadException()) 306 return; 307 308 // 40. Let mxsd be Get(options, "maximumSignificantDigits"). 309 JSValue maximumSignificantDigitsValue = options->get(&state, Identifier::fromString(&vm, "maximumSignificantDigits")); 310 // 41. ReturnIfAbrupt(mxsd). 311 if (state.hadException()) 312 return; 313 314 // 42. If mnsd is not undefined or mxsd is not undefined, then 315 if (!minimumSignificantDigitsValue.isUndefined() || !maximumSignificantDigitsValue.isUndefined()) { 316 // a. Let mnsd be GetNumberOption(options, "minimumSignificantDigits", 1, 21, 1). 317 unsigned minimumSignificantDigits = intlNumberOption(state, options, Identifier::fromString(&vm, "minimumSignificantDigits"), 1, 21, 1); 318 // b. ReturnIfAbrupt(mnsd). 319 if (state.hadException()) 320 return; 321 // c. Let mxsd be GetNumberOption(options, "maximumSignificantDigits", mnsd, 21, 21). 322 unsigned maximumSignificantDigits = intlNumberOption(state, options, Identifier::fromString(&vm, "maximumSignificantDigits"), minimumSignificantDigits, 21, 21); 323 // d. ReturnIfAbrupt(mxsd). 324 if (state.hadException()) 325 return; 326 // e. Set numberFormat.[[minimumSignificantDigits]] to mnsd. 327 m_minimumSignificantDigits = minimumSignificantDigits; 328 // f. Set numberFormat.[[maximumSignificantDigits]] to mxsd. 329 m_maximumSignificantDigits = maximumSignificantDigits; 330 } 331 332 // 43. Let g be GetOption(options, "useGrouping", "boolean", undefined, true). 333 bool usesFallback; 334 bool useGrouping = intlBooleanOption(state, options, Identifier::fromString(&vm, "useGrouping"), usesFallback); 335 if (usesFallback) 336 useGrouping = true; 337 // 44. ReturnIfAbrupt(g). 338 if (state.hadException()) 339 return; 340 // 45. Set numberFormat.[[useGrouping]] to g. 341 m_useGrouping = useGrouping; 342 343 // FIXME: Implement Steps 46 - 51. 344 // 46. Let dataLocaleData be Get(localeData, dataLocale). 345 // 47. Let patterns be Get(dataLocaleData, "patterns"). 346 // 48. Assert: patterns is an object (see 11.2.3). 347 // 49. Let stylePatterns be Get(patterns, s). 348 // 50. Set numberFormat.[[positivePattern]] to Get(stylePatterns, "positivePattern"). 349 // 51. Set numberFormat.[[negativePattern]] to Get(stylePatterns, "negativePattern"). 350 351 // 52. Set numberFormat.[[boundFormat]] to undefined. 352 // 53. Set numberFormat.[[initializedNumberFormat]] to true. 353 m_initializedNumberFormat = true; 354 355 // 54. Return numberFormat. 85 356 } 86 357 … … 109 380 } 110 381 382 const char* IntlNumberFormat::styleString(Style style) 383 { 384 switch (style) { 385 case Style::Decimal: 386 return "decimal"; 387 case Style::Percent: 388 return "percent"; 389 case Style::Currency: 390 return "currency"; 391 } 392 ASSERT_NOT_REACHED(); 393 return nullptr; 394 } 395 396 const char* IntlNumberFormat::currencyDisplayString(CurrencyDisplay currencyDisplay) 397 { 398 switch (currencyDisplay) { 399 case CurrencyDisplay::Code: 400 return "code"; 401 case CurrencyDisplay::Symbol: 402 return "symbol"; 403 case CurrencyDisplay::Name: 404 return "name"; 405 } 406 ASSERT_NOT_REACHED(); 407 return nullptr; 408 } 409 410 JSObject* IntlNumberFormat::resolvedOptions(ExecState& state) 411 { 412 // 11.3.5 Intl.NumberFormat.prototype.resolvedOptions() (ECMA-402 2.0) 413 // The function returns a new object whose properties and attributes are set as if 414 // constructed by an object literal assigning to each of the following properties the 415 // value of the corresponding internal slot of this NumberFormat object (see 11.4): 416 // locale, numberingSystem, style, currency, currencyDisplay, minimumIntegerDigits, 417 // minimumFractionDigits, maximumFractionDigits, minimumSignificantDigits, 418 // maximumSignificantDigits, and useGrouping. Properties whose corresponding internal 419 // slots are not present are not assigned. 420 421 if (!m_initializedNumberFormat) { 422 initializeNumberFormat(state, jsUndefined(), jsUndefined()); 423 ASSERT(!state.hadException()); 424 } 425 426 VM& vm = state.vm(); 427 JSObject* options = constructEmptyObject(&state); 428 options->putDirect(vm, vm.propertyNames->locale, jsString(&state, m_locale)); 429 options->putDirect(vm, Identifier::fromString(&vm, "numberingSystem"), jsString(&state, m_numberingSystem)); 430 options->putDirect(vm, Identifier::fromString(&vm, "style"), jsNontrivialString(&state, ASCIILiteral(styleString(m_style)))); 431 if (m_style == Style::Currency) { 432 options->putDirect(vm, Identifier::fromString(&vm, "currency"), jsNontrivialString(&state, m_currency)); 433 options->putDirect(vm, Identifier::fromString(&vm, "currencyDisplay"), jsNontrivialString(&state, ASCIILiteral(currencyDisplayString(m_currencyDisplay)))); 434 } 435 options->putDirect(vm, Identifier::fromString(&vm, "minimumIntegerDigits"), jsNumber(m_minimumIntegerDigits)); 436 options->putDirect(vm, Identifier::fromString(&vm, "minimumFractionDigits"), jsNumber(m_minimumFractionDigits)); 437 options->putDirect(vm, Identifier::fromString(&vm, "maximumFractionDigits"), jsNumber(m_maximumFractionDigits)); 438 if (m_minimumSignificantDigits) { 439 ASSERT(m_maximumSignificantDigits); 440 options->putDirect(vm, Identifier::fromString(&vm, "minimumSignificantDigits"), jsNumber(m_minimumSignificantDigits)); 441 options->putDirect(vm, Identifier::fromString(&vm, "maximumSignificantDigits"), jsNumber(m_maximumSignificantDigits)); 442 } 443 options->putDirect(vm, Identifier::fromString(&vm, "useGrouping"), jsBoolean(m_useGrouping)); 444 return options; 445 } 446 447 void IntlNumberFormat::setBoundFormat(VM& vm, JSBoundFunction* format) 448 { 449 m_boundFormat.set(vm, this, format); 450 } 451 111 452 } // namespace JSC 112 453 -
trunk/Source/JavaScriptCore/runtime/IntlNumberFormat.h
r187575 r196434 45 45 DECLARE_INFO; 46 46 47 void initializeNumberFormat(ExecState&, JSValue locales, JSValue optionsValue); 48 JSObject* resolvedOptions(ExecState&); 49 47 50 JSBoundFunction* boundFormat() const { return m_boundFormat.get(); } 48 51 void setBoundFormat(VM&, JSBoundFunction*); … … 54 57 static void visitChildren(JSCell*, SlotVisitor&); 55 58 59 private: 60 enum class Style { Decimal, Percent, Currency }; 61 enum class CurrencyDisplay { Code, Symbol, Name }; 62 63 const char* styleString(Style); 64 const char* currencyDisplayString(CurrencyDisplay); 65 66 String m_locale; 67 String m_numberingSystem; 68 Style m_style { Style::Decimal }; 69 String m_currency; 70 CurrencyDisplay m_currencyDisplay; 71 unsigned m_minimumIntegerDigits { 1 }; 72 unsigned m_minimumFractionDigits { 0 }; 73 unsigned m_maximumFractionDigits { 3 }; 74 unsigned m_minimumSignificantDigits { 0 }; 75 unsigned m_maximumSignificantDigits { 0 }; 56 76 WriteBarrier<JSBoundFunction> m_boundFormat; 77 bool m_useGrouping { true }; 78 bool m_initializedNumberFormat { false }; 57 79 }; 58 80 -
trunk/Source/JavaScriptCore/runtime/IntlNumberFormatConstructor.cpp
r192831 r196434 105 105 106 106 // 4. Return InitializeNumberFormat(numberFormat, locales, options). 107 // FIXME: return JSValue::encode(InitializeNumberFormat(numberFormat, locales, options)); 108 107 JSValue locales = state->argument(0); 108 JSValue options = state->argument(1); 109 numberFormat->initializeNumberFormat(*state, locales, options); 109 110 return JSValue::encode(numberFormat); 110 111 } … … 124 125 125 126 // 4. Return InitializeNumberFormat(numberFormat, locales, options). 126 // FIXME: return JSValue::encode(InitializeNumberFormat(numberFormat, locales, options)); 127 127 JSValue locales = state->argument(0); 128 JSValue options = state->argument(1); 129 numberFormat->initializeNumberFormat(*state, locales, options); 128 130 return JSValue::encode(numberFormat); 129 131 } -
trunk/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp
r192831 r196434 35 35 #include "JSCellInlines.h" 36 36 #include "JSObject.h" 37 #include "ObjectConstructor.h"38 37 #include "StructureInlines.h" 39 38 40 39 namespace JSC { 41 42 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IntlNumberFormatPrototype);43 40 44 41 static EncodedJSValue JSC_HOST_CALL IntlNumberFormatPrototypeGetterFormat(ExecState*); … … 119 116 { 120 117 // 11.3.5 Intl.NumberFormat.prototype.resolvedOptions() (ECMA-402 2.0) 121 IntlNumberFormat* n f= jsDynamicCast<IntlNumberFormat*>(state->thisValue());122 if (!n f)118 IntlNumberFormat* numberFormat = jsDynamicCast<IntlNumberFormat*>(state->thisValue()); 119 if (!numberFormat) 123 120 return JSValue::encode(throwTypeError(state, ASCIILiteral("Intl.NumberFormat.prototype.resolvedOptions called on value that's not an object initialized as a NumberFormat"))); 124 121 125 // The function returns a new object whose properties and attributes are set as if constructed by an object literal assigning to each of the following properties the value of the corresponding internal slot of this NumberFormat object (see 11.4): locale, numberingSystem, style, currency, currencyDisplay, minimumIntegerDigits, minimumFractionDigits, maximumFractionDigits, minimumSignificantDigits, maximumSignificantDigits, and useGrouping. Properties whose corresponding internal slots are not present are not assigned. 126 127 JSObject* options = constructEmptyObject(state); 128 129 // FIXME: Populate object from internal slots. 130 131 return JSValue::encode(options); 122 return JSValue::encode(numberFormat->resolvedOptions(*state)); 132 123 } 133 124 -
trunk/Source/JavaScriptCore/runtime/IntlObject.cpp
r196223 r196434 208 208 // e. Return value. 209 209 return stringValue; 210 } 211 212 // 6. Else return fallback. 213 return fallback; 214 } 215 216 unsigned intlNumberOption(ExecState& state, JSValue options, PropertyName property, unsigned minimum, unsigned maximum, unsigned fallback) 217 { 218 // 9.2.9 GetNumberOption (options, property, minimum, maximum, fallback) (ECMA-402 2.0) 219 // 1. Let opts be ToObject(options). 220 JSObject* opts = options.toObject(&state); 221 222 // 2. ReturnIfAbrupt(opts). 223 if (state.hadException()) 224 return 0; 225 226 // 3. Let value be Get(opts, property). 227 JSValue value = opts->get(&state, property); 228 229 // 4. ReturnIfAbrupt(value). 230 if (state.hadException()) 231 return 0; 232 233 // 5. If value is not undefined, then 234 if (!value.isUndefined()) { 235 // a. Let value be ToNumber(value). 236 double doubleValue = value.toNumber(&state); 237 // b. ReturnIfAbrupt(value). 238 if (state.hadException()) 239 return 0; 240 // 1. If value is NaN or less than minimum or greater than maximum, throw a RangeError exception. 241 if (!(doubleValue >= minimum && doubleValue <= maximum)) { 242 state.vm().throwException(&state, createRangeError(&state, *property.publicName() + " is out of range")); 243 return 0; 244 } 245 246 // c. Return floor(value). 247 return static_cast<unsigned>(doubleValue); 210 248 } 211 249 … … 925 963 } 926 964 927 Vector<String> getNumberingSystemsForLocale(const String& locale)965 Vector<String> numberingSystemsForLocale(const String& locale) 928 966 { 929 967 static NeverDestroyed<Vector<String>> cachedNumberingSystems; -
trunk/Source/JavaScriptCore/runtime/IntlObject.h
r194387 r196434 62 62 bool intlBooleanOption(ExecState&, JSValue options, PropertyName, bool& usesFallback); 63 63 String intlStringOption(ExecState&, JSValue options, PropertyName, std::initializer_list<const char*> values, const char* notFound, const char* fallback); 64 unsigned intlNumberOption(ExecState&, JSValue options, PropertyName, unsigned minimum, unsigned maximum, unsigned fallback); 64 65 Vector<String> canonicalizeLocaleList(ExecState&, JSValue locales); 65 66 HashMap<String, String> resolveLocale(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)); … … 67 68 String removeUnicodeLocaleExtension(const String& locale); 68 69 String bestAvailableLocale(const HashSet<String>& availableLocales, const String& requestedLocale); 69 Vector<String> getNumberingSystemsForLocale(const String& locale);70 Vector<String> numberingSystemsForLocale(const String& locale); 70 71 71 72 } // namespace JSC
Note: See TracChangeset
for help on using the changeset viewer.