Bug 1342647 - Remove redundant IntlCurrency system and use ICU, r?Waldo
Intl.NumberFormat refers to a CurrencyDigits() algorithm which
finds the default number of digits to format a currency in.
SpiderMonkey implemented this by a table off to the side, based
on information scraped from a website. However, ICU has this
information already, accessible by the
ucurr_getDefaultFractionDigits function. This patch calls out
to that function.
MozReview-Commit-ID: GU3VZWVNVgr
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -1363,16 +1363,41 @@ js::intl_CompareStrings(JSContext* cx, u
}
// Use the UCollator to actually compare the strings.
RootedString str1(cx, args[1].toString());
RootedString str2(cx, args[2].toString());
return intl_CompareStrings(cx, coll, str1, str2, args.rval());
}
+bool
+js::intl_CurrencyDigits(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isString());
+
+ RootedString str(cx, args[0].toString());
+ AutoStableStringChars stableChars(cx);
+ if (!stableChars.initTwoByte(cx, str))
+ return false;
+ mozilla::Range<const char16_t> chars = stableChars.twoByteRange();
+ // This might not be null-terminated, but ICU only ever looks
+ // at the first three UChars, since an ISO currency code always has a
+ // length of three
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t digits = ucurr_getDefaultFractionDigits(Char16ToUChar(chars.begin().get()), &status);
+ if (U_FAILURE(status)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
+ return false;
+ }
+ args.rval().setInt32(digits);
+ return true;
+}
+
/******************** NumberFormat ********************/
const ClassOps NumberFormatObject::classOps_ = {
nullptr, /* addProperty */
nullptr, /* delProperty */
nullptr, /* getProperty */
nullptr, /* setProperty */
--- a/js/src/builtin/Intl.h
+++ b/js/src/builtin/Intl.h
@@ -241,16 +241,26 @@ intl_availableCollations(JSContext* cx,
*
* Spec: ECMAScript Internationalization API Specification, 10.3.2.
*
* Usage: result = intl_CompareStrings(collator, x, y)
*/
extern MOZ_MUST_USE bool
intl_CompareStrings(JSContext* cx, unsigned argc, Value* vp);
+/**
+ * Finds the default number of decimal digits for a currency code
+ *
+ * Spec: https://tc39.github.io/ecma402/#sec-currencydigits
+ *
+ * Usage: result = intl_CurrencyDigits(currency)
+ */
+extern MOZ_MUST_USE bool
+intl_CurrencyDigits(JSContext* cx, unsigned argc, Value* vp);
+
/******************** NumberFormat ********************/
class NumberFormatObject : public NativeObject
{
public:
static const Class class_;
--- a/js/src/builtin/Intl.js
+++ b/js/src/builtin/Intl.js
@@ -9,16 +9,17 @@
JSMSG_INVALID_OPTION_VALUE: false, JSMSG_INVALID_DIGITS_VALUE: false,
JSMSG_INVALID_CURRENCY_CODE: false,
JSMSG_UNDEFINED_CURRENCY: false, JSMSG_INVALID_TIME_ZONE: false,
JSMSG_DATE_NOT_FINITE: false, JSMSG_INVALID_KEYS_TYPE: false,
JSMSG_INVALID_KEY: false,
intl_Collator_availableLocales: false,
intl_availableCollations: false,
intl_CompareStrings: false,
+ intl_CurrencyDigits: false,
intl_NumberFormat_availableLocales: false,
intl_numberingSystem: false,
intl_FormatNumber: false,
intl_DateTimeFormat_availableLocales: false,
intl_availableCalendars: false,
intl_patternForSkeleton: false,
intl_FormatDateTime: false,
intl_SelectPluralRule: false,
@@ -2008,19 +2009,17 @@ function InitializeNumberFormat(numberFo
function getCurrencyDigitsRE() {
return internalIntlRegExps.currencyDigitsRE ||
(internalIntlRegExps.currencyDigitsRE = RegExpCreate("^[A-Z]{3}$"));
}
function CurrencyDigits(currency) {
assert(typeof currency === "string", "CurrencyDigits");
assert(regexp_test_no_statics(getCurrencyDigitsRE(), currency), "CurrencyDigits");
- if (callFunction(std_Object_hasOwnProperty, currencyDigits, currency))
- return currencyDigits[currency];
- return 2;
+ return intl_CurrencyDigits(currency);
}
/**
* Returns the subset of the given locale list for which this locale list has a
* matching (possibly fallback) locale. Locales appear in the same order in the
* returned list as in the input list.
*
deleted file mode 100644
--- a/js/src/builtin/IntlCurrency.js
+++ /dev/null
@@ -1,76 +0,0 @@
-// Generated by make_intl_data.py. DO NOT EDIT.
-// Version: 2017-01-01
-
-/**
- * Mapping from currency codes to the number of decimal digits used for them.
- * Default is 2 digits.
- *
- * Spec: ISO 4217 Currency and Funds Code List.
- * http://www.currency-iso.org/en/home/tables/table-a1.html
- */
-var currencyDigits = {
- // Bahraini Dinar (BAHRAIN)
- BHD: 3,
- // Burundi Franc (BURUNDI)
- BIF: 0,
- // Unidad de Fomento (CHILE)
- CLF: 4,
- // Chilean Peso (CHILE)
- CLP: 0,
- // Djibouti Franc (DJIBOUTI)
- DJF: 0,
- // Guinea Franc (GUINEA)
- GNF: 0,
- // Iraqi Dinar (IRAQ)
- IQD: 3,
- // Iceland Krona (ICELAND)
- ISK: 0,
- // Jordanian Dinar (JORDAN)
- JOD: 3,
- // Yen (JAPAN)
- JPY: 0,
- // Comoro Franc (COMOROS (THE))
- KMF: 0,
- // Won (KOREA (THE REPUBLIC OF))
- KRW: 0,
- // Kuwaiti Dinar (KUWAIT)
- KWD: 3,
- // Libyan Dinar (LIBYA)
- LYD: 3,
- // Rial Omani (OMAN)
- OMR: 3,
- // Guarani (PARAGUAY)
- PYG: 0,
- // Rwanda Franc (RWANDA)
- RWF: 0,
- // Tunisian Dinar (TUNISIA)
- TND: 3,
- // Uganda Shilling (UGANDA)
- UGX: 0,
- // Uruguay Peso en Unidades Indexadas (URUIURUI) (URUGUAY)
- UYI: 0,
- // Dong (VIET NAM)
- VND: 0,
- // Vatu (VANUATU)
- VUV: 0,
- // CFA Franc BEAC (CAMEROON)
- // CFA Franc BEAC (CENTRAL AFRICAN REPUBLIC (THE))
- // CFA Franc BEAC (CHAD)
- // CFA Franc BEAC (CONGO (THE))
- // CFA Franc BEAC (EQUATORIAL GUINEA)
- // CFA Franc BEAC (GABON)
- XAF: 0,
- // CFA Franc BCEAO (BENIN)
- // CFA Franc BCEAO (BURKINA FASO)
- // CFA Franc BCEAO (CÔTE D'IVOIRE)
- // CFA Franc BCEAO (GUINEA-BISSAU)
- // CFA Franc BCEAO (MALI)
- // CFA Franc BCEAO (NIGER (THE))
- // CFA Franc BCEAO (SENEGAL)
- // CFA Franc BCEAO (TOGO)
- XOF: 0,
- // CFP Franc (FRENCH POLYNESIA)
- // CFP Franc (NEW CALEDONIA)
- // CFP Franc (WALLIS AND FUTUNA)
- XPF: 0,
-};
--- a/js/src/builtin/make_intl_data.py
+++ b/js/src/builtin/make_intl_data.py
@@ -964,57 +964,16 @@ def writeCurrencyFile(published, currenc
*/""")
println(u"var currencyDigits = {")
for (currency, entries) in groupby(sorted(currencies, key=itemgetter(0)), itemgetter(0)):
for (_, minorUnits, currencyName, countryName) in entries:
println(u" // {} ({})".format(currencyName, countryName))
println(u" {}: {},".format(currency, minorUnits))
println(u"};")
-def updateCurrency(topsrcdir, args):
- """ Update the IntlCurrency.js file. """
- import xml.etree.ElementTree as ET
- from random import randint
-
- url = args.url
- out = args.out
- filename = args.file
-
- print("Arguments:")
- print("\tDownload url: %s" % url)
- print("\tLocal currency file: %s" % filename)
- print("\tOutput file: %s" % out)
- print("")
-
- def updateFrom(currencyFile):
- print("Processing currency code list file...")
- tree = ET.parse(currencyFile)
- published = tree.getroot().attrib["Pblshd"]
- currencies = readCurrencyFile(tree)
-
- print("Writing IntlCurrency file...")
- writeCurrencyFile(published, currencies, out)
-
- if filename is not None:
- print("Always make sure you have the newest currency code list file!")
- updateFrom(filename)
- else:
- print("Downloading currency & funds code list...")
- request = urllib2.Request(url)
- # Fake a random user agent string to circumvent the bot detection from
- # currency-iso.org...
- request.add_header("User-agent", "Mozilla/5.0 (Mobile; rv:{0}.0) Gecko/{0}.0 Firefox/{0}.0".format(randint(1, 999)))
- with closing(urllib2.urlopen(request)) as currencyFile:
- fname = urlparse.urlsplit(currencyFile.geturl()).path.split("/")[-1]
- with tempfile.NamedTemporaryFile(suffix=fname) as currencyTmpFile:
- print("File stored in %s" % currencyTmpFile.name)
- currencyTmpFile.write(currencyFile.read())
- currencyTmpFile.flush()
- updateFrom(currencyTmpFile.name)
-
if __name__ == "__main__":
import argparse
# This script must reside in js/src/builtin to work correctly.
(thisDir, thisFile) = os.path.split(os.path.abspath(sys.argv[0]))
dirPaths = os.path.normpath(thisDir).split(os.sep)
if "/".join(dirPaths[-3:]) != "js/src/builtin":
raise RuntimeError("%s must reside in js/src/builtin" % sys.argv[0])
@@ -1070,12 +1029,11 @@ if __name__ == "__main__":
help="Download url for the currency & funds code list (default: "
"%(default)s)")
parser_currency.add_argument("--out",
default="IntlCurrency.js",
help="Output file (default: %(default)s)")
parser_currency.add_argument("file",
nargs="?",
help="Local currency code list file, if omitted uses <URL>")
- parser_currency.set_defaults(func=partial(updateCurrency, topsrcdir))
args = parser.parse_args()
args.func(args)
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -762,17 +762,16 @@ selfhosted.inputs = [
'builtin/Utilities.js',
'builtin/Array.js',
'builtin/Classes.js',
'builtin/Date.js',
'builtin/Error.js',
'builtin/Function.js',
'builtin/Generator.js',
'builtin/Intl.js',
- 'builtin/IntlCurrency.js',
'builtin/IntlData.js',
'builtin/Iterator.js',
'builtin/Map.js',
'builtin/Module.js',
'builtin/Number.js',
'builtin/Object.js',
'builtin/Promise.js',
'builtin/Reflect.js',
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -2603,16 +2603,17 @@ static const JSFunctionSpec intrinsic_fu
// See builtin/Intl.h for descriptions of the intl_* functions.
JS_FN("intl_availableCalendars", intl_availableCalendars, 1,0),
JS_FN("intl_availableCollations", intl_availableCollations, 1,0),
JS_FN("intl_canonicalizeTimeZone", intl_canonicalizeTimeZone, 1,0),
JS_FN("intl_Collator", intl_Collator, 2,0),
JS_FN("intl_Collator_availableLocales", intl_Collator_availableLocales, 0,0),
JS_FN("intl_CompareStrings", intl_CompareStrings, 3,0),
+ JS_FN("intl_CurrencyDigits", intl_CurrencyDigits, 1,0),
JS_FN("intl_DateTimeFormat", intl_DateTimeFormat, 2,0),
JS_FN("intl_DateTimeFormat_availableLocales", intl_DateTimeFormat_availableLocales, 0,0),
JS_FN("intl_defaultTimeZone", intl_defaultTimeZone, 0,0),
JS_FN("intl_defaultTimeZoneOffset", intl_defaultTimeZoneOffset, 0,0),
JS_FN("intl_FormatDateTime", intl_FormatDateTime, 2,0),
JS_FN("intl_FormatNumber", intl_FormatNumber, 2,0),
JS_FN("intl_GetCalendarInfo", intl_GetCalendarInfo, 1,0),
JS_FN("intl_ComputeDisplayNames", intl_ComputeDisplayNames, 3,0),