Commit 38c5394c authored by littledan's avatar littledan Committed by Commit bot

[intl] Fix NumberFormat options handling spec compliance issues

The goal of this patch was to refactor NumberFormat parameter handling
to be usable by a PluralRules implementation. Along the way, I found
and fixed a couple minor issues where options handling differed from
the specification, and removed some dead code. Regression tests are
added as test262 tests. With this change, the overall flow more closely
resembles the specification plus this editorial change which is out
for review: https://github.com/tc39/ecma402/pull/130/files

BUG=v8:6015,v8:6016
R=yangguo,jungshik

Review-Url: https://codereview.chromium.org/2717613005
Cr-Commit-Position: refs/heads/master@{#44571}
parent 7deb6821
......@@ -274,23 +274,6 @@ icu::DecimalFormat* CreateICUNumberFormat(
delete number_format;
return NULL;
}
UErrorCode status_digits = U_ZERO_ERROR;
#if U_ICU_VERSION_MAJOR_NUM >= 59
uint32_t fraction_digits = ucurr_getDefaultFractionDigits(
icu::toUCharPtr(currency.getTerminatedBuffer()), &status_digits);
#else
uint32_t fraction_digits = ucurr_getDefaultFractionDigits(
currency.getTerminatedBuffer(), &status_digits);
#endif
if (U_SUCCESS(status_digits)) {
number_format->setMinimumFractionDigits(fraction_digits);
number_format->setMaximumFractionDigits(fraction_digits);
} else {
// Set min & max to default values (previously in i18n.js)
number_format->setMinimumFractionDigits(0);
number_format->setMaximumFractionDigits(3);
}
} else if (style == UNICODE_STRING_SIMPLE("percent")) {
number_format = static_cast<icu::DecimalFormat*>(
icu::NumberFormat::createPercentInstance(icu_locale, status));
......
......@@ -32,6 +32,7 @@ var IntlFallbackSymbol = utils.ImportNow("intl_fallback_symbol");
var InstallFunctions = utils.InstallFunctions;
var InstallGetter = utils.InstallGetter;
var InternalArray = utils.InternalArray;
var MaxSimple;
var ObjectHasOwnProperty = utils.ImportNow("ObjectHasOwnProperty");
var OverrideFunction = utils.OverrideFunction;
var patternSymbol = utils.ImportNow("intl_pattern_symbol");
......@@ -43,6 +44,7 @@ var StringSubstring = GlobalString.prototype.substring;
utils.Import(function(from) {
ArrayJoin = from.ArrayJoin;
ArrayPush = from.ArrayPush;
MaxSimple = from.MaxSimple;
});
// Utilities for definitions
......@@ -934,16 +936,6 @@ function BuildLanguageTagREs() {
LANGUAGE_TAG_RE = new GlobalRegExp(languageTag, 'i');
}
var resolvedAccessor = {
get() {
%IncrementUseCounter(kIntlResolved);
return this[resolvedSymbol];
},
set(value) {
this[resolvedSymbol] = value;
}
};
// ECMA 402 section 8.2.1
InstallFunction(GlobalIntl, 'getCanonicalLocales', function(locales) {
return makeArray(canonicalizeLocaleList(locales));
......@@ -1137,7 +1129,6 @@ function defaultNumberOption(value, min, max, fallback, property) {
return fallback;
}
/**
* Returns the valid digit count for a property, or throws RangeError on
* a value out of the range.
......@@ -1147,15 +1138,35 @@ function getNumberOption(options, property, min, max, fallback) {
return defaultNumberOption(value, min, max, fallback, property);
}
var patternAccessor = {
get() {
%IncrementUseCounter(kIntlPattern);
return this[patternSymbol];
},
set(value) {
this[patternSymbol] = value;
// ECMA 402 #sec-setnfdigitoptions
// SetNumberFormatDigitOptions ( intlObj, options, mnfdDefault, mxfdDefault )
function SetNumberFormatDigitOptions(internalOptions, options,
mnfdDefault, mxfdDefault) {
// Digit ranges.
var mnid = getNumberOption(options, 'minimumIntegerDigits', 1, 21, 1);
defineWEProperty(internalOptions, 'minimumIntegerDigits', mnid);
var mnfd = getNumberOption(options, 'minimumFractionDigits', 0, 20,
mnfdDefault);
defineWEProperty(internalOptions, 'minimumFractionDigits', mnfd);
var mxfdActualDefault = MaxSimple(mnfd, mxfdDefault);
var mxfd = getNumberOption(options, 'maximumFractionDigits', mnfd, 20,
mxfdActualDefault);
defineWEProperty(internalOptions, 'maximumFractionDigits', mxfd);
var mnsd = options['minimumSignificantDigits'];
var mxsd = options['maximumSignificantDigits'];
if (!IS_UNDEFINED(mnsd) || !IS_UNDEFINED(mxsd)) {
mnsd = defaultNumberOption(mnsd, 1, 21, 1, 'minimumSignificantDigits');
defineWEProperty(internalOptions, 'minimumSignificantDigits', mnsd);
mxsd = defaultNumberOption(mxsd, mnsd, 21, 21, 'maximumSignificantDigits');
defineWEProperty(internalOptions, 'maximumSignificantDigits', mxsd);
}
};
}
/**
* Initializes the given object so it's a valid NumberFormat instance.
......@@ -1183,41 +1194,22 @@ function CreateNumberFormat(locales, options) {
throw %make_type_error(kCurrencyCode);
}
var mnfdDefault, mxfdDefault;
var currencyDisplay = getOption(
'currencyDisplay', 'string', ['code', 'symbol', 'name'], 'symbol');
if (internalOptions.style === 'currency') {
defineWEProperty(internalOptions, 'currency', %StringToUpperCaseI18N(currency));
defineWEProperty(internalOptions, 'currencyDisplay', currencyDisplay);
}
// Digit ranges.
var mnid = getNumberOption(options, 'minimumIntegerDigits', 1, 21, 1);
defineWEProperty(internalOptions, 'minimumIntegerDigits', mnid);
var mnfd = options['minimumFractionDigits'];
var mxfd = options['maximumFractionDigits'];
if (!IS_UNDEFINED(mnfd) || internalOptions.style !== 'currency') {
mnfd = getNumberOption(options, 'minimumFractionDigits', 0, 20, 0);
defineWEProperty(internalOptions, 'minimumFractionDigits', mnfd);
}
if (!IS_UNDEFINED(mxfd) || internalOptions.style !== 'currency') {
var min_mxfd = internalOptions.style === 'percent' ? 0 : 3;
mnfd = IS_UNDEFINED(mnfd) ? 0 : mnfd;
var fallback_limit = (mnfd > min_mxfd) ? mnfd : min_mxfd;
mxfd = getNumberOption(options, 'maximumFractionDigits', mnfd, 20, fallback_limit);
defineWEProperty(internalOptions, 'maximumFractionDigits', mxfd);
mnfdDefault = mxfdDefault = %CurrencyDigits(internalOptions.currency);
} else {
mnfdDefault = 0;
mxfdDefault = internalOptions.style === 'percent' ? 0 : 3;
}
var mnsd = options['minimumSignificantDigits'];
var mxsd = options['maximumSignificantDigits'];
if (!IS_UNDEFINED(mnsd) || !IS_UNDEFINED(mxsd)) {
mnsd = defaultNumberOption(mnsd, 1, 21, 1, 'minimumSignificantDigits');
defineWEProperty(internalOptions, 'minimumSignificantDigits', mnsd);
mxsd = defaultNumberOption(mxsd, mnsd, 21, 21, 'maximumSignificantDigits');
defineWEProperty(internalOptions, 'maximumSignificantDigits', mxsd);
}
SetNumberFormatDigitOptions(internalOptions, options, mnfdDefault,
mxfdDefault);
// Grouping.
defineWEProperty(internalOptions, 'useGrouping', getOption(
......
......@@ -532,6 +532,29 @@ RUNTIME_FUNCTION(Runtime_InternalNumberFormat) {
result.length())));
}
RUNTIME_FUNCTION(Runtime_CurrencyDigits) {
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(String, currency, 0);
// TODO(littledan): Avoid transcoding the string twice
v8::String::Utf8Value currency_string(v8::Utils::ToLocal(currency));
icu::UnicodeString currency_icu =
icu::UnicodeString::fromUTF8(*currency_string);
DisallowHeapAllocation no_gc;
UErrorCode status = U_ZERO_ERROR;
#if U_ICU_VERSION_MAJOR_NUM >= 59
uint32_t fraction_digits = ucurr_getDefaultFractionDigits(
icu::toUCharPtr(currency_icu.getTerminatedBuffer()), &status);
#else
uint32_t fraction_digits = ucurr_getDefaultFractionDigits(
currency_icu.getTerminatedBuffer(), &status);
#endif
// For missing currency codes, default to the most common, 2
if (!U_SUCCESS(status)) fraction_digits = 2;
return Smi::FromInt(fraction_digits);
}
RUNTIME_FUNCTION(Runtime_CreateCollator) {
HandleScope scope(isolate);
......
......@@ -265,6 +265,7 @@ namespace internal {
F(InternalDateFormatToParts, 2, 1) \
F(CreateNumberFormat, 3, 1) \
F(InternalNumberFormat, 2, 1) \
F(CurrencyDigits, 1, 1) \
F(CreateCollator, 3, 1) \
F(InternalCompare, 3, 1) \
F(CreateBreakIterator, 3, 1) \
......
......@@ -546,9 +546,6 @@
'built-ins/Object/internals/DefineOwnProperty/consistent-value-function-caller': [FAIL_SLOPPY],
'built-ins/Object/internals/DefineOwnProperty/consistent-value-function-arguments': [FAIL_SLOPPY],
# https://bugs.chromium.org/p/v8/issues/detail?id=6016
'intl402/NumberFormat/dft-currency-mnfd-range-check-mxfd': [FAIL],
######################## NEEDS INVESTIGATION ###########################
# These test failures are specific to the intl402 suite and need investigation
......@@ -568,8 +565,6 @@
'intl402/NumberFormat/11.2.3_b': [FAIL],
'intl402/NumberFormat/prototype/11.3_a': [FAIL],
'intl402/String/prototype/localeCompare/13.1.1_7': [PASS, FAIL],
'intl402/NumberFormat/default-currency-maximum-fraction-digits': [PASS, FAIL],
'intl402/NumberFormat/fraction-digit-options-read-once': [PASS, FAIL],
##################### DELIBERATE INCOMPATIBILITIES #####################
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment