[Intl] Part 1 of NumberFormat v3
Implement ALL in NumberFormat v3 except: * Add PluralRules.prototype.selectRange * Add NumberFormat.prototype.formatRange(ToParts)? (which will be reviewed in later CLs) * Change NumberFormat.prototpe.resolvedOptions https://github.com/tc39/proposal-intl-numberformat-v3 https://chromestatus.com/guide/edit/5707621009981440 Design Doc: https://docs.google.com/document/d/19jAogPBb6W4Samt8NWGZKu47iv0_KoQhBvLgQH3xvr8/edit Bug: v8:10776 Change-Id: I1acf833ec25fb05437cb0b21c5510bb99d1c4583 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3405649 Reviewed-by: Shu-yu Guo <syg@chromium.org> Commit-Queue: Frank Tang <ftang@chromium.org> Cr-Commit-Position: refs/heads/main@{#78878}
This commit is contained in:
parent
cdb20294b4
commit
250b2e2972
@ -85,8 +85,15 @@ BUILTIN(NumberFormatPrototypeFormatToParts) {
|
||||
|
||||
Handle<Object> x;
|
||||
if (args.length() >= 2) {
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x,
|
||||
Object::ToNumeric(isolate, args.at(1)));
|
||||
Handle<Object> value = args.at(1);
|
||||
if (FLAG_harmony_intl_number_format_v3) {
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, x,
|
||||
Intl::ToIntlMathematicalValueAsNumberBigIntOrString(isolate, value));
|
||||
} else {
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x,
|
||||
Object::ToNumeric(isolate, value));
|
||||
}
|
||||
} else {
|
||||
x = isolate->factory()->nan_value();
|
||||
}
|
||||
@ -501,8 +508,14 @@ BUILTIN(NumberFormatInternalFormatNumber) {
|
||||
|
||||
// 4. Let x be ? ToNumeric(value).
|
||||
Handle<Object> numeric_obj;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, numeric_obj,
|
||||
Object::ToNumeric(isolate, value));
|
||||
if (FLAG_harmony_intl_number_format_v3) {
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, numeric_obj,
|
||||
Intl::ToIntlMathematicalValueAsNumberBigIntOrString(isolate, value));
|
||||
} else {
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, numeric_obj,
|
||||
Object::ToNumeric(isolate, value));
|
||||
}
|
||||
|
||||
icu::number::LocalizedNumberFormatter* icu_localized_number_formatter =
|
||||
number_format->icu_number_formatter().raw();
|
||||
@ -902,20 +915,18 @@ BUILTIN(PluralRulesPrototypeResolvedOptions) {
|
||||
BUILTIN(PluralRulesPrototypeSelect) {
|
||||
HandleScope scope(isolate);
|
||||
|
||||
// 1. Let pr be the this value.
|
||||
// 2. If Type(pr) is not Object, throw a TypeError exception.
|
||||
// 3. If pr does not have an [[InitializedPluralRules]] internal slot, throw a
|
||||
// TypeError exception.
|
||||
// 1. 1. Let pr be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(pr, [[InitializedPluralRules]]).
|
||||
CHECK_RECEIVER(JSPluralRules, plural_rules,
|
||||
"Intl.PluralRules.prototype.select");
|
||||
|
||||
// 4. Let n be ? ToNumber(value).
|
||||
// 3. Let n be ? ToNumber(value).
|
||||
Handle<Object> number = args.atOrUndefined(isolate, 1);
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number,
|
||||
Object::ToNumber(isolate, number));
|
||||
double number_double = number->Number();
|
||||
|
||||
// 5. Return ? ResolvePlural(pr, n).
|
||||
// 4. Return ! ResolvePlural(pr, n).
|
||||
RETURN_RESULT_OR_FAILURE(isolate, JSPluralRules::ResolvePlural(
|
||||
isolate, plural_rules, number_double));
|
||||
}
|
||||
|
@ -311,7 +311,9 @@ DEFINE_BOOL(harmony_shipping, true, "enable all shipped harmony features")
|
||||
V(harmony_array_grouping, "harmony array grouping")
|
||||
|
||||
#ifdef V8_INTL_SUPPORT
|
||||
#define HARMONY_INPROGRESS(V) HARMONY_INPROGRESS_BASE(V)
|
||||
#define HARMONY_INPROGRESS(V) \
|
||||
HARMONY_INPROGRESS_BASE(V) \
|
||||
V(harmony_intl_number_format_v3, "Intl.NumberFormat v3")
|
||||
#else
|
||||
#define HARMONY_INPROGRESS(V) HARMONY_INPROGRESS_BASE(V)
|
||||
#endif
|
||||
|
@ -4404,6 +4404,7 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_error_cause)
|
||||
|
||||
#ifdef V8_INTL_SUPPORT
|
||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_intl_best_fit_matcher)
|
||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_intl_number_format_v3)
|
||||
#endif // V8_INTL_SUPPORT
|
||||
|
||||
#undef EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE
|
||||
|
@ -78,6 +78,7 @@
|
||||
V(_, minusSign_string, "minusSign") \
|
||||
V(_, nan_string, "nan") \
|
||||
V(_, narrowSymbol_string, "narrowSymbol") \
|
||||
V(_, negative_string, "negative") \
|
||||
V(_, never_string, "never") \
|
||||
V(_, none_string, "none") \
|
||||
V(_, notation_string, "notation") \
|
||||
|
@ -1522,151 +1522,195 @@ Maybe<Intl::NumberFormatDigitOptions> Intl::SetNumberFormatDigitOptions(
|
||||
return Nothing<NumberFormatDigitOptions>();
|
||||
}
|
||||
|
||||
int mnfd = 0;
|
||||
int mxfd = 0;
|
||||
Handle<Object> mnfd_obj;
|
||||
Handle<Object> mxfd_obj;
|
||||
|
||||
// 6. Let mnfd be ? Get(options, "minimumFractionDigits").
|
||||
Handle<String> mnfd_str = factory->minimumFractionDigits_string();
|
||||
Handle<Object> mnfd_obj;
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
||||
isolate, mnfd_obj, JSReceiver::GetProperty(isolate, options, mnfd_str),
|
||||
isolate, mnfd_obj,
|
||||
JSReceiver::GetProperty(isolate, options,
|
||||
factory->minimumFractionDigits_string()),
|
||||
Nothing<NumberFormatDigitOptions>());
|
||||
|
||||
// 8. Let mxfd be ? Get(options, "maximumFractionDigits").
|
||||
Handle<String> mxfd_str = factory->maximumFractionDigits_string();
|
||||
// 7. Let mxfd be ? Get(options, "maximumFractionDigits").
|
||||
Handle<Object> mxfd_obj;
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
||||
isolate, mxfd_obj, JSReceiver::GetProperty(isolate, options, mxfd_str),
|
||||
isolate, mxfd_obj,
|
||||
JSReceiver::GetProperty(isolate, options,
|
||||
factory->maximumFractionDigits_string()),
|
||||
Nothing<NumberFormatDigitOptions>());
|
||||
|
||||
// 9. Let mnsd be ? Get(options, "minimumSignificantDigits").
|
||||
// 8. Let mnsd be ? Get(options, "minimumSignificantDigits").
|
||||
Handle<Object> mnsd_obj;
|
||||
Handle<String> mnsd_str = factory->minimumSignificantDigits_string();
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
||||
isolate, mnsd_obj, JSReceiver::GetProperty(isolate, options, mnsd_str),
|
||||
isolate, mnsd_obj,
|
||||
JSReceiver::GetProperty(isolate, options,
|
||||
factory->minimumSignificantDigits_string()),
|
||||
Nothing<NumberFormatDigitOptions>());
|
||||
|
||||
// 10. Let mxsd be ? Get(options, "maximumSignificantDigits").
|
||||
// 9. Let mxsd be ? Get(options, "maximumSignificantDigits").
|
||||
Handle<Object> mxsd_obj;
|
||||
Handle<String> mxsd_str = factory->maximumSignificantDigits_string();
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
||||
isolate, mxsd_obj, JSReceiver::GetProperty(isolate, options, mxsd_str),
|
||||
isolate, mxsd_obj,
|
||||
JSReceiver::GetProperty(isolate, options,
|
||||
factory->maximumSignificantDigits_string()),
|
||||
Nothing<NumberFormatDigitOptions>());
|
||||
|
||||
// 11. Set intlObj.[[MinimumIntegerDigits]] to mnid.
|
||||
digit_options.rounding_priority = RoundingPriority::kAuto;
|
||||
digit_options.minimum_significant_digits = 0;
|
||||
digit_options.maximum_significant_digits = 0;
|
||||
|
||||
// 10. Set intlObj.[[MinimumIntegerDigits]] to mnid.
|
||||
digit_options.minimum_integer_digits = mnid;
|
||||
|
||||
// 12. Set intlObj.[[MinimumFractionDigits]] to mnfd.
|
||||
digit_options.minimum_fraction_digits = mnfd;
|
||||
if (FLAG_harmony_intl_number_format_v3) {
|
||||
// 11. Let roundingPriority be ? GetOption(options, "roundingPriority",
|
||||
// "string", « "auto", "morePrecision", "lessPrecision" », "auto").
|
||||
|
||||
// 13. Set intlObj.[[MaximumFractionDigits]] to mxfd.
|
||||
digit_options.maximum_fraction_digits = mxfd;
|
||||
Maybe<RoundingPriority> maybe_rounding_priority =
|
||||
GetStringOption<RoundingPriority>(
|
||||
isolate, options, "roundingPriority", "SetNumberFormatDigitOptions",
|
||||
{"auto", "morePrecision", "lessPrecision"},
|
||||
{RoundingPriority::kAuto, RoundingPriority::kMorePrecision,
|
||||
RoundingPriority::kLessPrecision},
|
||||
RoundingPriority::kAuto);
|
||||
MAYBE_RETURN(maybe_rounding_priority, Nothing<NumberFormatDigitOptions>());
|
||||
digit_options.rounding_priority = maybe_rounding_priority.FromJust();
|
||||
}
|
||||
|
||||
// 14. If mnsd is not undefined or mxsd is not undefined, then
|
||||
if (!mnsd_obj->IsUndefined(isolate) || !mxsd_obj->IsUndefined(isolate)) {
|
||||
// 14. a. Let mnsd be ? DefaultNumberOption(mnsd, 1, 21, 1).
|
||||
int mnsd;
|
||||
if (!DefaultNumberOption(isolate, mnsd_obj, 1, 21, 1, mnsd_str).To(&mnsd)) {
|
||||
return Nothing<NumberFormatDigitOptions>();
|
||||
// 12. If mnsd is not undefined or mxsd is not undefined, then
|
||||
// a. Set hasSd to true.
|
||||
// 13. Else,
|
||||
// a. Set hasSd to false.
|
||||
bool has_sd =
|
||||
(!mnsd_obj->IsUndefined(isolate)) || (!mxsd_obj->IsUndefined(isolate));
|
||||
|
||||
// 14. If mnfd is not undefined or mxfd is not undefined, then
|
||||
// a. Set hasFd to true.
|
||||
// 15. Else,
|
||||
// a. Set hasFd to false.
|
||||
bool has_fd =
|
||||
(!mnfd_obj->IsUndefined(isolate)) || (!mxfd_obj->IsUndefined(isolate));
|
||||
|
||||
// 17. If hasSd or roundingPriority is not "auto", set needSd to true; else,
|
||||
// set needSd to false.
|
||||
bool need_sd =
|
||||
has_sd || (RoundingPriority::kAuto != digit_options.rounding_priority);
|
||||
|
||||
// 18. If ( not hasSd and (hasFd or notation is not "compact") ) or
|
||||
// roundingPriority is not "auto", then a. Set needFd to true.
|
||||
// 19. Else,
|
||||
// a. Set needFd to false.
|
||||
bool need_fd = ((!has_sd) && (has_fd || !notation_is_compact)) ||
|
||||
(RoundingPriority::kAuto != digit_options.rounding_priority);
|
||||
|
||||
// 20. If needSd, then
|
||||
if (need_sd) {
|
||||
// 20.b If hasSd, then
|
||||
if (has_sd) {
|
||||
// 20.b.i Let mnsd be ? DefaultNumberOption(mnsd, 1, 21, 1).
|
||||
int mnsd;
|
||||
if (!DefaultNumberOption(isolate, mnsd_obj, 1, 21, 1,
|
||||
factory->minimumSignificantDigits_string())
|
||||
.To(&mnsd)) {
|
||||
return Nothing<NumberFormatDigitOptions>();
|
||||
}
|
||||
// 20.b.ii Let mxsd be ? DefaultNumberOption(mxsd, mnsd, 21, 21).
|
||||
int mxsd;
|
||||
if (!DefaultNumberOption(isolate, mxsd_obj, mnsd, 21, 21,
|
||||
factory->maximumSignificantDigits_string())
|
||||
.To(&mxsd)) {
|
||||
return Nothing<NumberFormatDigitOptions>();
|
||||
}
|
||||
// 20.b.iii Set intlObj.[[MinimumSignificantDigits]] to mnsd.
|
||||
digit_options.minimum_significant_digits = mnsd;
|
||||
// 20.b.iv Set intlObj.[[MaximumSignificantDigits]] to mxsd.
|
||||
digit_options.maximum_significant_digits = mxsd;
|
||||
} else {
|
||||
// 20.c Else
|
||||
// 20.c.i Set intlObj.[[MinimumSignificantDigits]] to 1.
|
||||
digit_options.minimum_significant_digits = 1;
|
||||
// 20.c.ii Set intlObj.[[MaximumSignificantDigits]] to 21.
|
||||
digit_options.maximum_significant_digits = 21;
|
||||
}
|
||||
}
|
||||
|
||||
// 14. b. Let mxsd be ? DefaultNumberOption(mxsd, mnsd, 21, 21).
|
||||
int mxsd;
|
||||
if (!DefaultNumberOption(isolate, mxsd_obj, mnsd, 21, 21, mxsd_str)
|
||||
.To(&mxsd)) {
|
||||
return Nothing<NumberFormatDigitOptions>();
|
||||
}
|
||||
|
||||
// 14. c. Set intlObj.[[MinimumSignificantDigits]] to mnsd.
|
||||
digit_options.minimum_significant_digits = mnsd;
|
||||
|
||||
// 14. d. Set intlObj.[[MaximumSignificantDigits]] to mxsd.
|
||||
digit_options.maximum_significant_digits = mxsd;
|
||||
} else {
|
||||
digit_options.minimum_significant_digits = 0;
|
||||
digit_options.maximum_significant_digits = 0;
|
||||
|
||||
// 15. Else If mnfd is not undefined or mxfd is not undefined, then
|
||||
if (!mnfd_obj->IsUndefined(isolate) || !mxfd_obj->IsUndefined(isolate)) {
|
||||
int specified_mnfd;
|
||||
int specified_mxfd;
|
||||
|
||||
// a. Let _specifiedMnfd_ be ? DefaultNumberOption(_mnfd_, 0, 20,
|
||||
// *undefined*).
|
||||
// 21. If needFd, then
|
||||
if (need_fd) {
|
||||
// 21.a If hasFd, then
|
||||
if (has_fd) {
|
||||
Handle<String> mnfd_str = factory->minimumFractionDigits_string();
|
||||
Handle<String> mxfd_str = factory->maximumFractionDigits_string();
|
||||
// 21.a.i Let mnfd be ? DefaultNumberOption(mnfd, 0, 20, undefined).
|
||||
int mnfd;
|
||||
if (!DefaultNumberOption(isolate, mnfd_obj, 0, 20, -1, mnfd_str)
|
||||
.To(&specified_mnfd)) {
|
||||
return Nothing<NumberFormatDigitOptions>();
|
||||
}
|
||||
Handle<Object> specifiedMnfd_obj;
|
||||
if (specified_mnfd < 0) {
|
||||
specifiedMnfd_obj = factory->undefined_value();
|
||||
} else {
|
||||
specifiedMnfd_obj = handle(Smi::FromInt(specified_mnfd), isolate);
|
||||
}
|
||||
|
||||
// b. Let _specifiedMxfd_ be ? DefaultNumberOption(_mxfd_, 0, 20,
|
||||
// *undefined*).
|
||||
if (!DefaultNumberOption(isolate, mxfd_obj, 0, 20, -1, mxfd_str)
|
||||
.To(&specified_mxfd)) {
|
||||
return Nothing<NumberFormatDigitOptions>();
|
||||
}
|
||||
Handle<Object> specifiedMxfd_obj;
|
||||
if (specified_mxfd < 0) {
|
||||
specifiedMxfd_obj = factory->undefined_value();
|
||||
} else {
|
||||
specifiedMxfd_obj = handle(Smi::FromInt(specified_mxfd), isolate);
|
||||
}
|
||||
|
||||
// c. If _specifiedMxfd_ is not *undefined*, set _mnfdDefault_ to
|
||||
// min(_mnfdDefault_, _specifiedMxfd_).
|
||||
if (specified_mxfd >= 0) {
|
||||
mnfd_default = std::min(mnfd_default, specified_mxfd);
|
||||
}
|
||||
|
||||
// d. Set _mnfd_ to ! DefaultNumberOption(_specifiedMnfd_, 0, 20,
|
||||
// _mnfdDefault_).
|
||||
if (!DefaultNumberOption(isolate, specifiedMnfd_obj, 0, 20, mnfd_default,
|
||||
mnfd_str)
|
||||
.To(&mnfd)) {
|
||||
return Nothing<NumberFormatDigitOptions>();
|
||||
}
|
||||
|
||||
// e. Set _mxfd_ to ! DefaultNumberOption(_specifiedMxfd_, 0, 20,
|
||||
// max(_mxfdDefault_, _mnfd_)).
|
||||
if (!DefaultNumberOption(isolate, specifiedMxfd_obj, 0, 20,
|
||||
std::max(mxfd_default, mnfd), mxfd_str)
|
||||
// 21.a.ii Let mxfd be ? DefaultNumberOption(mxfd, 0, 20, undefined).
|
||||
int mxfd;
|
||||
if (!DefaultNumberOption(isolate, mxfd_obj, 0, 20, -1, mxfd_str)
|
||||
.To(&mxfd)) {
|
||||
return Nothing<NumberFormatDigitOptions>();
|
||||
}
|
||||
|
||||
// f. If _mnfd_ is greater than _mxfd_, throw a *RangeError* exception.
|
||||
if (mnfd > mxfd) {
|
||||
// 21.a.iii If mnfd is undefined, set mnfd to min(mnfdDefault, mxfd).
|
||||
if (mnfd_obj->IsUndefined(isolate)) {
|
||||
mnfd = std::min(mnfd_default, mxfd);
|
||||
} else if (mxfd_obj->IsUndefined(isolate)) {
|
||||
// 21.a.iv Else if mxfd is undefined, set mxfd to max(mxfdDefault,
|
||||
// mnfd).
|
||||
mxfd = std::max(mxfd_default, mnfd);
|
||||
} else if (mnfd > mxfd) {
|
||||
// 21.a.v Else if mnfd is greater than mxfd, throw a RangeError
|
||||
// exception.
|
||||
THROW_NEW_ERROR_RETURN_VALUE(
|
||||
isolate,
|
||||
NewRangeError(MessageTemplate::kPropertyValueOutOfRange, mxfd_str),
|
||||
Nothing<NumberFormatDigitOptions>());
|
||||
}
|
||||
|
||||
// g. Set intlObj.[[MinimumFractionDigits]] to mnfd.
|
||||
// 21.a.vi Set intlObj.[[MinimumFractionDigits]] to mnfd.
|
||||
digit_options.minimum_fraction_digits = mnfd;
|
||||
|
||||
// h. Set intlObj.[[MaximumFractionDigits]] to mxfd.
|
||||
// 21.a.vii Set intlObj.[[MaximumFractionDigits]] to mxfd.
|
||||
digit_options.maximum_fraction_digits = mxfd;
|
||||
// Else If intlObj.[[Notation]] is "compact", then
|
||||
} else if (notation_is_compact) {
|
||||
// a. Set intlObj.[[RoundingType]] to "compact-rounding".
|
||||
// Set minimum_significant_digits to -1 to represent roundingtype is
|
||||
// "compact-rounding".
|
||||
digit_options.minimum_significant_digits = -1;
|
||||
// 17. Else,
|
||||
} else {
|
||||
// 17. b. Set intlObj.[[MinimumFractionDigits]] to mnfdDefault.
|
||||
} else { // 17.b Else
|
||||
// 21.b.i Set intlObj.[[MinimumFractionDigits]] to mnfdDefault.
|
||||
digit_options.minimum_fraction_digits = mnfd_default;
|
||||
|
||||
// 17. c. Set intlObj.[[MaximumFractionDigits]] to mxfdDefault.
|
||||
// 21.b.ii Set intlObj.[[MaximumFractionDigits]] to mxfdDefault.
|
||||
digit_options.maximum_fraction_digits = mxfd_default;
|
||||
}
|
||||
}
|
||||
|
||||
// 22. If needSd or needFd, then
|
||||
if (need_sd || need_fd) {
|
||||
// a. If roundingPriority is "morePrecision", then
|
||||
if (digit_options.rounding_priority == RoundingPriority::kMorePrecision) {
|
||||
// i. Set intlObj.[[RoundingType]] to morePrecision.
|
||||
digit_options.rounding_type = RoundingType::kMorePrecision;
|
||||
// b. Else if roundingPriority is "lessPrecision", then
|
||||
} else if (digit_options.rounding_priority ==
|
||||
RoundingPriority::kLessPrecision) {
|
||||
// i. Set intlObj.[[RoundingType]] to lessPrecision.
|
||||
digit_options.rounding_type = RoundingType::kLessPrecision;
|
||||
// c. Else if hasSd, then
|
||||
} else if (has_sd) {
|
||||
// i. Set intlObj.[[RoundingType]] to significantDigits.
|
||||
digit_options.rounding_type = RoundingType::kSignificantDigits;
|
||||
// d. Else,
|
||||
} else {
|
||||
// i.Set intlObj.[[RoundingType]] to fractionDigits.
|
||||
digit_options.rounding_type = RoundingType::kFractionDigits;
|
||||
}
|
||||
// 23. Else
|
||||
} else {
|
||||
// a. Set intlObj.[[RoundingType]] to morePrecision.
|
||||
digit_options.rounding_type = RoundingType::kMorePrecision;
|
||||
// b. Set intlObj.[[MinimumFractionDigits]] to 0.
|
||||
digit_options.minimum_fraction_digits = 0;
|
||||
// c. Set intlObj.[[MaximumFractionDigits]] to 0.
|
||||
digit_options.maximum_fraction_digits = 0;
|
||||
// d. Set intlObj.[[MinimumSignificantDigits]] to 1.
|
||||
digit_options.minimum_significant_digits = 1;
|
||||
// e. Set intlObj.[[MaximumSignificantDigits]] to 2.
|
||||
digit_options.maximum_significant_digits = 2;
|
||||
}
|
||||
return Just(digit_options);
|
||||
}
|
||||
|
||||
@ -2644,22 +2688,22 @@ const std::set<std::string>& Intl::GetAvailableLocalesForDateFormat() {
|
||||
return available_locales.Pointer()->Get();
|
||||
}
|
||||
|
||||
constexpr uint16_t kInfinityChar = 0x221e;
|
||||
|
||||
Handle<String> Intl::NumberFieldToType(Isolate* isolate,
|
||||
Handle<Object> numeric_obj,
|
||||
int32_t field_id) {
|
||||
DCHECK(numeric_obj->IsNumeric());
|
||||
switch (static_cast<UNumberFormatFields>(field_id)) {
|
||||
const NumberFormatSpan& part,
|
||||
const icu::UnicodeString& text,
|
||||
bool is_nan) {
|
||||
switch (static_cast<UNumberFormatFields>(part.field_id)) {
|
||||
case UNUM_INTEGER_FIELD:
|
||||
if (numeric_obj->IsBigInt()) {
|
||||
// Neither NaN nor Infinite could be stored into BigInt
|
||||
// so just return integer.
|
||||
return isolate->factory()->integer_string();
|
||||
} else {
|
||||
double number = numeric_obj->Number();
|
||||
if (std::isfinite(number)) return isolate->factory()->integer_string();
|
||||
if (std::isnan(number)) return isolate->factory()->nan_string();
|
||||
if (is_nan) return isolate->factory()->nan_string();
|
||||
if (text.charAt(part.begin_pos) == kInfinityChar ||
|
||||
// en-US-POSIX output "INF" for Infinity
|
||||
(part.end_pos - part.begin_pos == 3 &&
|
||||
text.tempSubString(part.begin_pos, 3) == "INF")) {
|
||||
return isolate->factory()->infinity_string();
|
||||
}
|
||||
return isolate->factory()->integer_string();
|
||||
case UNUM_FRACTION_FIELD:
|
||||
return isolate->factory()->fraction_string();
|
||||
case UNUM_DECIMAL_SEPARATOR_FIELD:
|
||||
@ -2671,15 +2715,9 @@ Handle<String> Intl::NumberFieldToType(Isolate* isolate,
|
||||
case UNUM_PERCENT_FIELD:
|
||||
return isolate->factory()->percentSign_string();
|
||||
case UNUM_SIGN_FIELD:
|
||||
if (numeric_obj->IsBigInt()) {
|
||||
Handle<BigInt> big_int = Handle<BigInt>::cast(numeric_obj);
|
||||
return big_int->IsNegative() ? isolate->factory()->minusSign_string()
|
||||
: isolate->factory()->plusSign_string();
|
||||
} else {
|
||||
double number = numeric_obj->Number();
|
||||
return std::signbit(number) ? isolate->factory()->minusSign_string()
|
||||
: isolate->factory()->plusSign_string();
|
||||
}
|
||||
return (text.charAt(part.begin_pos) == '+')
|
||||
? isolate->factory()->plusSign_string()
|
||||
: isolate->factory()->minusSign_string();
|
||||
case UNUM_EXPONENT_SYMBOL_FIELD:
|
||||
return isolate->factory()->exponentSeparator_string();
|
||||
|
||||
@ -2856,5 +2894,29 @@ Maybe<bool> Intl::GetTimeZoneIndex(Isolate* isolate, Handle<String> identifier,
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
// #sec-tointlmathematicalvalue
|
||||
MaybeHandle<Object> Intl::ToIntlMathematicalValueAsNumberBigIntOrString(
|
||||
Isolate* isolate, Handle<Object> input) {
|
||||
// Strings are used to preserve arbitrary precision decimals, and are passed
|
||||
// through to ICU.
|
||||
if (input->IsNumber() || input->IsBigInt() || input->IsString())
|
||||
return input; // Shortcut.
|
||||
|
||||
// TODO(ftang) revisit the following later.
|
||||
if (input->IsOddball()) {
|
||||
return Oddball::ToNumber(isolate, Handle<Oddball>::cast(input));
|
||||
}
|
||||
if (input->IsSymbol()) {
|
||||
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kSymbolToNumber),
|
||||
Object);
|
||||
}
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
isolate, input,
|
||||
JSReceiver::ToPrimitive(Handle<JSReceiver>::cast(input),
|
||||
ToPrimitiveHint::kNumber),
|
||||
Object);
|
||||
return input;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -35,6 +35,19 @@ class UnicodeString;
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
struct NumberFormatSpan {
|
||||
int32_t field_id;
|
||||
int32_t begin_pos;
|
||||
int32_t end_pos;
|
||||
|
||||
NumberFormatSpan() = default;
|
||||
NumberFormatSpan(int32_t field_id, int32_t begin_pos, int32_t end_pos)
|
||||
: field_id(field_id), begin_pos(begin_pos), end_pos(end_pos) {}
|
||||
};
|
||||
|
||||
V8_EXPORT_PRIVATE std::vector<NumberFormatSpan> FlattenRegionsToParts(
|
||||
std::vector<NumberFormatSpan>* regions);
|
||||
|
||||
template <typename T>
|
||||
class Handle;
|
||||
class JSCollator;
|
||||
@ -115,6 +128,21 @@ class Intl {
|
||||
Isolate* isolate, Handle<Object> num, Handle<Object> locales,
|
||||
Handle<Object> options, const char* method_name);
|
||||
|
||||
// [[RoundingPriority]] is one of the String values "auto", "morePrecision",
|
||||
// or "lessPrecision", specifying the rounding priority for the number.
|
||||
enum class RoundingPriority {
|
||||
kAuto,
|
||||
kMorePrecision,
|
||||
kLessPrecision,
|
||||
};
|
||||
|
||||
enum class RoundingType {
|
||||
kFractionDigits,
|
||||
kSignificantDigits,
|
||||
kMorePrecision,
|
||||
kLessPrecision,
|
||||
};
|
||||
|
||||
// ecma402/#sec-setnfdigitoptions
|
||||
struct NumberFormatDigitOptions {
|
||||
int minimum_integer_digits;
|
||||
@ -122,6 +150,8 @@ class Intl {
|
||||
int maximum_fraction_digits;
|
||||
int minimum_significant_digits;
|
||||
int maximum_significant_digits;
|
||||
RoundingPriority rounding_priority;
|
||||
RoundingType rounding_type;
|
||||
};
|
||||
V8_WARN_UNUSED_RESULT static Maybe<NumberFormatDigitOptions>
|
||||
SetNumberFormatDigitOptions(Isolate* isolate, Handle<JSReceiver> options,
|
||||
@ -143,8 +173,9 @@ class Intl {
|
||||
|
||||
// Helper function to convert number field id to type string.
|
||||
static Handle<String> NumberFieldToType(Isolate* isolate,
|
||||
Handle<Object> numeric_obj,
|
||||
int32_t field_id);
|
||||
const NumberFormatSpan& part,
|
||||
const icu::UnicodeString& text,
|
||||
bool is_nan);
|
||||
|
||||
// A helper function to implement formatToParts which add element to array as
|
||||
// $array[$index] = { type: $field_type_string, value: $value }
|
||||
@ -312,6 +343,16 @@ class Intl {
|
||||
|
||||
V8_WARN_UNUSED_RESULT static MaybeHandle<String> CanonicalizeTimeZoneName(
|
||||
Isolate* isolate, Handle<String> identifier);
|
||||
|
||||
// ecma402/#sec-coerceoptionstoobject
|
||||
V8_WARN_UNUSED_RESULT static MaybeHandle<JSReceiver> CoerceOptionsToObject(
|
||||
Isolate* isolate, Handle<Object> options, const char* service);
|
||||
|
||||
// #sec-tointlmathematicalvalue
|
||||
// The implementation preserve the Object in String, BigInt or Number
|
||||
V8_WARN_UNUSED_RESULT static MaybeHandle<Object>
|
||||
ToIntlMathematicalValueAsNumberBigIntOrString(Isolate* isolate,
|
||||
Handle<Object> input);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -18,10 +18,8 @@
|
||||
#include "src/objects/objects-inl.h"
|
||||
#include "src/objects/option-utils.h"
|
||||
#include "unicode/currunit.h"
|
||||
#include "unicode/decimfmt.h"
|
||||
#include "unicode/locid.h"
|
||||
#include "unicode/numberformatter.h"
|
||||
#include "unicode/numfmt.h"
|
||||
#include "unicode/numsys.h"
|
||||
#include "unicode/ucurr.h"
|
||||
#include "unicode/uloc.h"
|
||||
@ -98,6 +96,38 @@ enum class SignDisplay {
|
||||
ALWAYS,
|
||||
NEVER,
|
||||
EXCEPT_ZERO,
|
||||
NEGATIVE,
|
||||
};
|
||||
|
||||
// [[RoundingMode]] is one of the String values "ceil", "floor", "expand",
|
||||
// "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", or "halfEven",
|
||||
// specifying the rounding strategy for the number.
|
||||
enum class RoundingMode {
|
||||
CEIL,
|
||||
FLOOR,
|
||||
EXPAND,
|
||||
TRUNC,
|
||||
HALF_CEIL,
|
||||
HALF_FLOOR,
|
||||
HALF_EXPAND,
|
||||
HALF_TRUNC,
|
||||
HALF_EVEN,
|
||||
};
|
||||
|
||||
// [[TrailingZeroDisplay]] is one of the String values "auto" or
|
||||
// "stripIfInteger", specifying the strategy for displaying trailing zeros on
|
||||
// whole number.
|
||||
enum class TrailingZeroDisplay {
|
||||
AUTO,
|
||||
STRIP_IF_INTEGER,
|
||||
};
|
||||
|
||||
// [[UseGrouping]] is ....
|
||||
enum class UseGrouping {
|
||||
OFF,
|
||||
MIN2,
|
||||
AUTO,
|
||||
ALWAYS,
|
||||
};
|
||||
|
||||
UNumberUnitWidth ToUNumberUnitWidth(CurrencyDisplay currency_display) {
|
||||
@ -147,6 +177,12 @@ UNumberSignDisplay ToUNumberSignDisplay(SignDisplay sign_display,
|
||||
}
|
||||
DCHECK(currency_sign == CurrencySign::STANDARD);
|
||||
return UNumberSignDisplay::UNUM_SIGN_EXCEPT_ZERO;
|
||||
case SignDisplay::NEGATIVE:
|
||||
if (currency_sign == CurrencySign::ACCOUNTING) {
|
||||
return UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_NEGATIVE;
|
||||
}
|
||||
DCHECK(currency_sign == CurrencySign::STANDARD);
|
||||
return UNumberSignDisplay::UNUM_SIGN_NEGATIVE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,6 +206,43 @@ icu::number::Notation ToICUNotation(Notation notation,
|
||||
}
|
||||
}
|
||||
|
||||
UNumberFormatRoundingMode ToUNumberFormatRoundingMode(
|
||||
RoundingMode rounding_mode) {
|
||||
switch (rounding_mode) {
|
||||
case RoundingMode::CEIL:
|
||||
return UNumberFormatRoundingMode::UNUM_ROUND_CEILING;
|
||||
case RoundingMode::FLOOR:
|
||||
return UNumberFormatRoundingMode::UNUM_ROUND_FLOOR;
|
||||
case RoundingMode::EXPAND:
|
||||
return UNumberFormatRoundingMode::UNUM_ROUND_UP;
|
||||
case RoundingMode::TRUNC:
|
||||
return UNumberFormatRoundingMode::UNUM_ROUND_DOWN;
|
||||
case RoundingMode::HALF_CEIL:
|
||||
return UNumberFormatRoundingMode::UNUM_ROUND_HALF_CEILING;
|
||||
case RoundingMode::HALF_FLOOR:
|
||||
return UNumberFormatRoundingMode::UNUM_ROUND_HALF_FLOOR;
|
||||
case RoundingMode::HALF_EXPAND:
|
||||
return UNumberFormatRoundingMode::UNUM_ROUND_HALFUP;
|
||||
case RoundingMode::HALF_TRUNC:
|
||||
return UNumberFormatRoundingMode::UNUM_ROUND_HALFDOWN;
|
||||
case RoundingMode::HALF_EVEN:
|
||||
return UNumberFormatRoundingMode::UNUM_ROUND_HALFEVEN;
|
||||
}
|
||||
}
|
||||
|
||||
UNumberGroupingStrategy ToUNumberGroupingStrategy(UseGrouping use_grouping) {
|
||||
switch (use_grouping) {
|
||||
case UseGrouping::OFF:
|
||||
return UNumberGroupingStrategy::UNUM_GROUPING_OFF;
|
||||
case UseGrouping::MIN2:
|
||||
return UNumberGroupingStrategy::UNUM_GROUPING_MIN2;
|
||||
case UseGrouping::AUTO:
|
||||
return UNumberGroupingStrategy::UNUM_GROUPING_AUTO;
|
||||
case UseGrouping::ALWAYS:
|
||||
return UNumberGroupingStrategy::UNUM_GROUPING_ON_ALIGNED;
|
||||
}
|
||||
}
|
||||
|
||||
std::map<const std::string, icu::MeasureUnit> CreateUnitMap() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
int32_t total = icu::MeasureUnit::getAvailable(nullptr, 0, status);
|
||||
@ -462,6 +535,13 @@ Handle<String> SignDisplayString(Isolate* isolate,
|
||||
skeleton.indexOf("sign-except-zero") >= 0) {
|
||||
return ReadOnlyRoots(isolate).exceptZero_string_handle();
|
||||
}
|
||||
// Ex: skeleton as
|
||||
// ".### rounding-mode-half-up sign-negative" or
|
||||
// "currency/TWD .00 rounding-mode-half-up sign-accounting-negative"
|
||||
if (skeleton.indexOf("sign-accounting-negative") >= 0 ||
|
||||
skeleton.indexOf("sign-negative") >= 0) {
|
||||
return ReadOnlyRoots(isolate).negative_string_handle();
|
||||
}
|
||||
return ReadOnlyRoots(isolate).auto_string_handle();
|
||||
}
|
||||
|
||||
@ -505,7 +585,7 @@ bool JSNumberFormat::FractionDigitsFromSkeleton(
|
||||
if (index < 0) return false;
|
||||
*minimum = 0;
|
||||
index++; // skip the '.'
|
||||
while (index < skeleton.length() && skeleton[index] == '0') {
|
||||
while (index < skeleton.length() && IsDecimalDigit(skeleton[index])) {
|
||||
(*minimum)++;
|
||||
index++;
|
||||
}
|
||||
@ -607,21 +687,16 @@ Style StyleFromSkeleton(const icu::UnicodeString& skeleton) {
|
||||
return Style::DECIMAL;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
icu::number::LocalizedNumberFormatter
|
||||
JSNumberFormat::SetDigitOptionsToFormatter(
|
||||
const icu::number::LocalizedNumberFormatter& icu_number_formatter,
|
||||
icu::number::UnlocalizedNumberFormatter SetDigitOptionsToFormatterV2(
|
||||
const icu::number::UnlocalizedNumberFormatter& settings,
|
||||
const Intl::NumberFormatDigitOptions& digit_options) {
|
||||
icu::number::LocalizedNumberFormatter result = icu_number_formatter;
|
||||
icu::number::UnlocalizedNumberFormatter result = settings;
|
||||
if (digit_options.minimum_integer_digits > 1) {
|
||||
result = result.integerWidth(icu::number::IntegerWidth::zeroFillTo(
|
||||
digit_options.minimum_integer_digits));
|
||||
}
|
||||
|
||||
// Value -1 of minimum_significant_digits represent the roundingtype is
|
||||
// "compact-rounding".
|
||||
if (digit_options.minimum_significant_digits < 0) {
|
||||
if (digit_options.rounding_type == Intl::RoundingType::kMorePrecision) {
|
||||
return result;
|
||||
}
|
||||
icu::number::Precision precision =
|
||||
@ -636,6 +711,70 @@ JSNumberFormat::SetDigitOptionsToFormatter(
|
||||
return result.precision(precision);
|
||||
}
|
||||
|
||||
icu::number::UnlocalizedNumberFormatter SetDigitOptionsToFormatterV3(
|
||||
const icu::number::UnlocalizedNumberFormatter& settings,
|
||||
const Intl::NumberFormatDigitOptions& digit_options, int rounding_increment,
|
||||
JSNumberFormat::ShowTrailingZeros trailing_zeros) {
|
||||
icu::number::UnlocalizedNumberFormatter result = settings;
|
||||
if (digit_options.minimum_integer_digits > 1) {
|
||||
result = result.integerWidth(icu::number::IntegerWidth::zeroFillTo(
|
||||
digit_options.minimum_integer_digits));
|
||||
}
|
||||
|
||||
icu::number::Precision precision = icu::number::Precision::unlimited();
|
||||
bool relaxed = false;
|
||||
switch (digit_options.rounding_type) {
|
||||
case Intl::RoundingType::kSignificantDigits:
|
||||
precision = icu::number::Precision::minMaxSignificantDigits(
|
||||
digit_options.minimum_significant_digits,
|
||||
digit_options.maximum_significant_digits);
|
||||
break;
|
||||
case Intl::RoundingType::kFractionDigits:
|
||||
precision = icu::number::Precision::minMaxFraction(
|
||||
digit_options.minimum_fraction_digits,
|
||||
digit_options.maximum_fraction_digits);
|
||||
break;
|
||||
case Intl::RoundingType::kMorePrecision:
|
||||
relaxed = true;
|
||||
V8_FALLTHROUGH;
|
||||
case Intl::RoundingType::kLessPrecision:
|
||||
precision =
|
||||
icu::number::Precision::minMaxFraction(
|
||||
digit_options.minimum_fraction_digits,
|
||||
digit_options.maximum_fraction_digits)
|
||||
.withSignificantDigits(digit_options.minimum_significant_digits,
|
||||
digit_options.maximum_significant_digits,
|
||||
relaxed ? UNUM_ROUNDING_PRIORITY_RELAXED
|
||||
: UNUM_ROUNDING_PRIORITY_STRICT);
|
||||
break;
|
||||
}
|
||||
if (rounding_increment != 1) {
|
||||
double icu_increment = rounding_increment *
|
||||
std::pow(10, -digit_options.maximum_fraction_digits);
|
||||
precision = ::icu::number::Precision::increment(icu_increment)
|
||||
.withMinFraction(digit_options.minimum_fraction_digits);
|
||||
}
|
||||
if (trailing_zeros == JSNumberFormat::ShowTrailingZeros::kHide) {
|
||||
precision = precision.trailingZeroDisplay(UNUM_TRAILING_ZERO_HIDE_IF_WHOLE);
|
||||
}
|
||||
return result.precision(precision);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
icu::number::UnlocalizedNumberFormatter
|
||||
JSNumberFormat::SetDigitOptionsToFormatter(
|
||||
const icu::number::UnlocalizedNumberFormatter& settings,
|
||||
const Intl::NumberFormatDigitOptions& digit_options, int rounding_increment,
|
||||
JSNumberFormat::ShowTrailingZeros trailing_zeros) {
|
||||
if (FLAG_harmony_intl_number_format_v3) {
|
||||
return SetDigitOptionsToFormatterV3(settings, digit_options,
|
||||
rounding_increment, trailing_zeros);
|
||||
} else {
|
||||
return SetDigitOptionsToFormatterV2(settings, digit_options);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
// ecma402 #sec-intl.numberformat.prototype.resolvedoptions
|
||||
Handle<JSObject> JSNumberFormat::ResolvedOptions(
|
||||
@ -662,12 +801,19 @@ Handle<JSObject> JSNumberFormat::ResolvedOptions(
|
||||
// [[Style]] "style"
|
||||
// [[Currency]] "currency"
|
||||
// [[CurrencyDisplay]] "currencyDisplay"
|
||||
// [[CurrencySign]] "currencySign"
|
||||
// [[Unit]] "unit"
|
||||
// [[UnitDisplay]] "unitDisplay"
|
||||
// [[MinimumIntegerDigits]] "minimumIntegerDigits"
|
||||
// [[MinimumFractionDigits]] "minimumFractionDigits"
|
||||
// [[MaximumFractionDigits]] "maximumFractionDigits"
|
||||
// [[MinimumSignificantDigits]] "minimumSignificantDigits"
|
||||
// [[MaximumSignificantDigits]] "maximumSignificantDigits"
|
||||
// [[UseGrouping]] "useGrouping"
|
||||
// [[Notation]] "notation"
|
||||
// [[CompactDisplay]] "compactDisplay"
|
||||
// [[SignDisplay]] "signDisplay"
|
||||
|
||||
CHECK(JSReceiver::CreateDataProperty(isolate, options,
|
||||
factory->locale_string(), locale,
|
||||
Just(kDontThrow))
|
||||
@ -752,6 +898,7 @@ Handle<JSObject> JSNumberFormat::ResolvedOptions(
|
||||
factory->ToBoolean(UseGroupingFromSkeleton(skeleton)),
|
||||
Just(kDontThrow))
|
||||
.FromJust());
|
||||
|
||||
Notation notation = NotationFromSkeleton(skeleton);
|
||||
CHECK(JSReceiver::CreateDataProperty(
|
||||
isolate, options, factory->notation_string(),
|
||||
@ -800,6 +947,14 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::UnwrapNumberFormat(
|
||||
return Handle<JSNumberFormat>::cast(object);
|
||||
}
|
||||
|
||||
// 22. is in « 1, 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 2500,
|
||||
// 5000 »
|
||||
bool IsValidRoundingIncrement(int value) {
|
||||
return value == 1 || value == 2 || value == 5 || value == 10 || value == 20 ||
|
||||
value == 25 || value == 50 || value == 100 || value == 200 ||
|
||||
value == 250 || value == 500 || value == 1000 || value == 2000 ||
|
||||
value == 2500 || value == 5000;
|
||||
}
|
||||
// static
|
||||
MaybeHandle<JSNumberFormat> JSNumberFormat::New(Isolate* isolate,
|
||||
Handle<Map> map,
|
||||
@ -821,28 +976,28 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::New(Isolate* isolate,
|
||||
isolate, options, CoerceOptionsToObject(isolate, options_obj, service),
|
||||
JSNumberFormat);
|
||||
|
||||
// 4. Let opt be a new Record.
|
||||
// 5. Let matcher be ? GetOption(options, "localeMatcher", "string", «
|
||||
// 3. Let opt be a new Record.
|
||||
// 4. Let matcher be ? GetOption(options, "localeMatcher", "string", «
|
||||
// "lookup", "best fit" », "best fit").
|
||||
// 6. Set opt.[[localeMatcher]] to matcher.
|
||||
// 5. Set opt.[[localeMatcher]] to matcher.
|
||||
Maybe<Intl::MatcherOption> maybe_locale_matcher =
|
||||
Intl::GetLocaleMatcher(isolate, options, service);
|
||||
MAYBE_RETURN(maybe_locale_matcher, MaybeHandle<JSNumberFormat>());
|
||||
Intl::MatcherOption matcher = maybe_locale_matcher.FromJust();
|
||||
|
||||
std::unique_ptr<char[]> numbering_system_str = nullptr;
|
||||
// 7. Let _numberingSystem_ be ? GetOption(_options_, `"numberingSystem"`,
|
||||
// 6. Let _numberingSystem_ be ? GetOption(_options_, `"numberingSystem"`,
|
||||
// `"string"`, *undefined*, *undefined*).
|
||||
Maybe<bool> maybe_numberingSystem = Intl::GetNumberingSystem(
|
||||
isolate, options, service, &numbering_system_str);
|
||||
// 8. If _numberingSystem_ is not *undefined*, then
|
||||
// a. If _numberingSystem_ does not match the
|
||||
// 7. If _numberingSystem_ is not *undefined*, then
|
||||
// 8. If _numberingSystem_ does not match the
|
||||
// `(3*8alphanum) *("-" (3*8alphanum))` sequence, throw a *RangeError*
|
||||
// exception.
|
||||
MAYBE_RETURN(maybe_numberingSystem, MaybeHandle<JSNumberFormat>());
|
||||
|
||||
// 7. Let localeData be %NumberFormat%.[[LocaleData]].
|
||||
// 8. Let r be ResolveLocale(%NumberFormat%.[[AvailableLocales]],
|
||||
// 9. Let localeData be %NumberFormat%.[[LocaleData]].
|
||||
// 10. Let r be ResolveLocale(%NumberFormat%.[[AvailableLocales]],
|
||||
// requestedLocales, opt, %NumberFormat%.[[RelevantExtensionKeys]],
|
||||
// localeData).
|
||||
std::set<std::string> relevant_extension_keys{"nu"};
|
||||
@ -882,21 +1037,20 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::New(Isolate* isolate,
|
||||
|
||||
// 11. Let dataLocale be r.[[dataLocale]].
|
||||
|
||||
icu::number::LocalizedNumberFormatter icu_number_formatter =
|
||||
icu::number::NumberFormatter::withLocale(icu_locale)
|
||||
.roundingMode(UNUM_ROUND_HALFUP);
|
||||
icu::number::UnlocalizedNumberFormatter settings =
|
||||
icu::number::UnlocalizedNumberFormatter().roundingMode(UNUM_ROUND_HALFUP);
|
||||
|
||||
// For 'latn' numbering system, skip the adoptSymbols which would cause
|
||||
// 10.1%-13.7% of regression of JSTests/Intl-NewIntlNumberFormat
|
||||
// See crbug/1052751 so we skip calling adoptSymbols and depending on the
|
||||
// default instead.
|
||||
if (!numbering_system.empty() && numbering_system != "latn") {
|
||||
icu_number_formatter = icu_number_formatter.adoptSymbols(
|
||||
icu::NumberingSystem::createInstanceByName(numbering_system.c_str(),
|
||||
status));
|
||||
settings = settings.adoptSymbols(icu::NumberingSystem::createInstanceByName(
|
||||
numbering_system.c_str(), status));
|
||||
CHECK(U_SUCCESS(status));
|
||||
}
|
||||
|
||||
// ==== Start SetNumberFormatUnitOptions ====
|
||||
// 3. Let style be ? GetOption(options, "style", "string", « "decimal",
|
||||
// "percent", "currency", "unit" », "decimal").
|
||||
|
||||
@ -1029,15 +1183,14 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::New(Isolate* isolate,
|
||||
Intl::ToString(isolate, currency_ustr),
|
||||
JSNumberFormat);
|
||||
|
||||
icu_number_formatter = icu_number_formatter.unit(
|
||||
icu::CurrencyUnit(currency_ustr.getBuffer(), status));
|
||||
settings =
|
||||
settings.unit(icu::CurrencyUnit(currency_ustr.getBuffer(), status));
|
||||
CHECK(U_SUCCESS(status));
|
||||
// 14.c Set intlObj.[[CurrencyDisplay]] to currencyDisplay.
|
||||
// The default unitWidth is SHORT in ICU and that mapped from
|
||||
// Symbol so we can skip the setting for optimization.
|
||||
if (currency_display != CurrencyDisplay::SYMBOL) {
|
||||
icu_number_formatter = icu_number_formatter.unitWidth(
|
||||
ToUNumberUnitWidth(currency_display));
|
||||
settings = settings.unitWidth(ToUNumberUnitWidth(currency_display));
|
||||
}
|
||||
CHECK(U_SUCCESS(status));
|
||||
}
|
||||
@ -1051,27 +1204,27 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::New(Isolate* isolate,
|
||||
icu::MeasureUnit none = icu::MeasureUnit();
|
||||
// 13.b Set intlObj.[[Unit]] to unit.
|
||||
if (unit_pair.first != none) {
|
||||
icu_number_formatter = icu_number_formatter.unit(unit_pair.first);
|
||||
settings = settings.unit(unit_pair.first);
|
||||
}
|
||||
if (unit_pair.second != none) {
|
||||
icu_number_formatter = icu_number_formatter.perUnit(unit_pair.second);
|
||||
settings = settings.perUnit(unit_pair.second);
|
||||
}
|
||||
|
||||
// The default unitWidth is SHORT in ICU and that mapped from
|
||||
// Symbol so we can skip the setting for optimization.
|
||||
if (unit_display != UnitDisplay::SHORT) {
|
||||
icu_number_formatter =
|
||||
icu_number_formatter.unitWidth(ToUNumberUnitWidth(unit_display));
|
||||
settings = settings.unitWidth(ToUNumberUnitWidth(unit_display));
|
||||
}
|
||||
}
|
||||
|
||||
// === End of SetNumberFormatUnitOptions
|
||||
|
||||
if (style == Style::PERCENT) {
|
||||
icu_number_formatter =
|
||||
icu_number_formatter.unit(icu::MeasureUnit::getPercent())
|
||||
.scale(icu::number::Scale::powerOfTen(2));
|
||||
settings = settings.unit(icu::MeasureUnit::getPercent())
|
||||
.scale(icu::number::Scale::powerOfTen(2));
|
||||
}
|
||||
|
||||
// 23. If style is "currency", then
|
||||
// 16. If style is "currency", then
|
||||
int mnfd_default, mxfd_default;
|
||||
if (style == Style::CURRENCY) {
|
||||
// b. Let cDigits be CurrencyDigits(currency).
|
||||
@ -1080,7 +1233,7 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::New(Isolate* isolate,
|
||||
// d. Let mxfdDefault be cDigits.
|
||||
mnfd_default = c_digits;
|
||||
mxfd_default = c_digits;
|
||||
// 24. Else,
|
||||
// 17. Else,
|
||||
} else {
|
||||
// a. Let mnfdDefault be 0.
|
||||
mnfd_default = 0;
|
||||
@ -1096,7 +1249,7 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::New(Isolate* isolate,
|
||||
}
|
||||
|
||||
Notation notation = Notation::STANDARD;
|
||||
// 25. Let notation be ? GetOption(options, "notation", "string", «
|
||||
// 18. Let notation be ? GetOption(options, "notation", "string", «
|
||||
// "standard", "scientific", "engineering", "compact" », "standard").
|
||||
Maybe<Notation> maybe_notation = GetStringOption<Notation>(
|
||||
isolate, options, "notation", service,
|
||||
@ -1105,9 +1258,10 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::New(Isolate* isolate,
|
||||
Notation::COMPACT},
|
||||
Notation::STANDARD);
|
||||
MAYBE_RETURN(maybe_notation, MaybeHandle<JSNumberFormat>());
|
||||
// 19. Set numberFormat.[[Notation]] to notation.
|
||||
notation = maybe_notation.FromJust();
|
||||
|
||||
// 27. Perform ? SetNumberFormatDigitOptions(numberFormat, options,
|
||||
// 20. Perform ? SetNumberFormatDigitOptions(numberFormat, options,
|
||||
// mnfdDefault, mxfdDefault).
|
||||
Maybe<Intl::NumberFormatDigitOptions> maybe_digit_options =
|
||||
Intl::SetNumberFormatDigitOptions(isolate, options, mnfd_default,
|
||||
@ -1115,10 +1269,58 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::New(Isolate* isolate,
|
||||
notation == Notation::COMPACT);
|
||||
MAYBE_RETURN(maybe_digit_options, Handle<JSNumberFormat>());
|
||||
Intl::NumberFormatDigitOptions digit_options = maybe_digit_options.FromJust();
|
||||
icu_number_formatter = JSNumberFormat::SetDigitOptionsToFormatter(
|
||||
icu_number_formatter, digit_options);
|
||||
|
||||
// 28. Let compactDisplay be ? GetOption(options, "compactDisplay",
|
||||
if (FLAG_harmony_intl_number_format_v3) {
|
||||
// 21. Let roundingIncrement be ? GetNumberOption(options,
|
||||
// "roundingIncrement,", 1, 5000, 1).
|
||||
int rounding_increment = 1;
|
||||
Maybe<int> maybe_rounding_increment = GetNumberOption(
|
||||
isolate, options, factory->roundingIncrement_string(), 1, 5000, 1);
|
||||
MAYBE_RETURN(maybe_rounding_increment, MaybeHandle<JSNumberFormat>());
|
||||
CHECK(maybe_rounding_increment.To(&rounding_increment));
|
||||
|
||||
// 22. If roundingIncrement is not in « 1, 2, 5, 10, 20, 25, 50, 100, 200,
|
||||
// 250, 500, 1000, 2000, 2500, 5000 », throw a RangeError exception.
|
||||
if (!IsValidRoundingIncrement(rounding_increment)) {
|
||||
THROW_NEW_ERROR(isolate,
|
||||
NewRangeError(MessageTemplate::kPropertyValueOutOfRange,
|
||||
factory->roundingIncrement_string()),
|
||||
JSNumberFormat);
|
||||
}
|
||||
// 23. If roundingIncrement is not 1 and numberFormat.[[RoundingType]] is
|
||||
// not fractionDigits, throw a RangeError exception.
|
||||
if (rounding_increment != 1 &&
|
||||
digit_options.rounding_type != Intl::RoundingType::kFractionDigits) {
|
||||
THROW_NEW_ERROR(isolate,
|
||||
NewRangeError(MessageTemplate::kPropertyValueOutOfRange,
|
||||
factory->roundingIncrement_string()),
|
||||
JSNumberFormat);
|
||||
}
|
||||
// 24. Set _numberFormat.[[RoundingIncrement]] to roundingIncrement.
|
||||
|
||||
// 25. Let trailingZeroDisplay be ? GetOption(options,
|
||||
// "trailingZeroDisplay", "string", « "auto", "stripIfInteger" », "auto").
|
||||
Maybe<TrailingZeroDisplay> maybe_trailing_zero_display =
|
||||
GetStringOption<TrailingZeroDisplay>(
|
||||
isolate, options, "trailingZeroDisplay", service,
|
||||
{"auto", "stripIfInteger"},
|
||||
{TrailingZeroDisplay::AUTO, TrailingZeroDisplay::STRIP_IF_INTEGER},
|
||||
TrailingZeroDisplay::AUTO);
|
||||
MAYBE_RETURN(maybe_trailing_zero_display, MaybeHandle<JSNumberFormat>());
|
||||
TrailingZeroDisplay trailing_zero_display =
|
||||
maybe_trailing_zero_display.FromJust();
|
||||
|
||||
// 26. Set numberFormat.[[TrailingZeroDisplay]] to trailingZeroDisplay.
|
||||
settings = SetDigitOptionsToFormatterV3(
|
||||
settings, digit_options, rounding_increment,
|
||||
trailing_zero_display == TrailingZeroDisplay::STRIP_IF_INTEGER
|
||||
? ShowTrailingZeros::kHide
|
||||
: ShowTrailingZeros::kShow);
|
||||
} else {
|
||||
settings = SetDigitOptionsToFormatterV2(settings, digit_options);
|
||||
}
|
||||
|
||||
// 27. Let compactDisplay be ? GetOption(options, "compactDisplay",
|
||||
// "string", « "short", "long" », "short").
|
||||
Maybe<CompactDisplay> maybe_compact_display = GetStringOption<CompactDisplay>(
|
||||
isolate, options, "compactDisplay", service, {"short", "long"},
|
||||
@ -1126,33 +1328,73 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::New(Isolate* isolate,
|
||||
MAYBE_RETURN(maybe_compact_display, MaybeHandle<JSNumberFormat>());
|
||||
CompactDisplay compact_display = maybe_compact_display.FromJust();
|
||||
|
||||
// 26. Set numberFormat.[[Notation]] to notation.
|
||||
// The default notation in ICU is Simple, which mapped from STANDARD
|
||||
// so we can skip setting it.
|
||||
if (notation != Notation::STANDARD) {
|
||||
icu_number_formatter =
|
||||
icu_number_formatter.notation(ToICUNotation(notation, compact_display));
|
||||
settings = settings.notation(ToICUNotation(notation, compact_display));
|
||||
}
|
||||
// 30. Let useGrouping be ? GetOption(options, "useGrouping", "boolean",
|
||||
// undefined, true).
|
||||
bool use_grouping = true;
|
||||
Maybe<bool> found_use_grouping =
|
||||
GetBoolOption(isolate, options, "useGrouping", service, &use_grouping);
|
||||
MAYBE_RETURN(found_use_grouping, MaybeHandle<JSNumberFormat>());
|
||||
// 31. Set numberFormat.[[UseGrouping]] to useGrouping.
|
||||
if (!use_grouping) {
|
||||
icu_number_formatter = icu_number_formatter.grouping(
|
||||
UNumberGroupingStrategy::UNUM_GROUPING_OFF);
|
||||
|
||||
if (!FLAG_harmony_intl_number_format_v3) {
|
||||
// 30. Let useGrouping be ? GetOption(options, "useGrouping", "boolean",
|
||||
// undefined, true).
|
||||
bool use_grouping = true;
|
||||
Maybe<bool> found_use_grouping =
|
||||
GetBoolOption(isolate, options, "useGrouping", service, &use_grouping);
|
||||
MAYBE_RETURN(found_use_grouping, MaybeHandle<JSNumberFormat>());
|
||||
// 31. Set numberFormat.[[UseGrouping]] to useGrouping.
|
||||
if (!use_grouping) {
|
||||
settings = settings.grouping(UNumberGroupingStrategy::UNUM_GROUPING_OFF);
|
||||
}
|
||||
settings = JSNumberFormat::SetDigitOptionsToFormatter(
|
||||
settings, digit_options, 1, ShowTrailingZeros::kShow);
|
||||
} else {
|
||||
// 28. Let defaultUseGrouping be "auto".
|
||||
UseGrouping default_use_grouping = UseGrouping::AUTO;
|
||||
|
||||
// 29. If notation is "compact", then
|
||||
if (notation == Notation::COMPACT) {
|
||||
// a. Set numberFormat.[[CompactDisplay]] to compactDisplay.
|
||||
// Done in above together
|
||||
// b. Set defaultUseGrouping to "min2".
|
||||
default_use_grouping = UseGrouping::MIN2;
|
||||
}
|
||||
|
||||
// 30. Let useGrouping be ? GetStringOrBooleanOption(options, "useGrouping",
|
||||
// « "min2", "auto", "always" », "always", false, defaultUseGrouping).
|
||||
Maybe<UseGrouping> maybe_use_grouping =
|
||||
GetStringOrBooleanOption<UseGrouping>(
|
||||
isolate, options, "useGrouping", service,
|
||||
{"min2", "auto", "always"},
|
||||
{UseGrouping::MIN2, UseGrouping::AUTO, UseGrouping::ALWAYS},
|
||||
UseGrouping::ALWAYS, // trueValue
|
||||
UseGrouping::OFF, // falseValue
|
||||
default_use_grouping); // fallbackValue
|
||||
MAYBE_RETURN(maybe_use_grouping, MaybeHandle<JSNumberFormat>());
|
||||
UseGrouping use_grouping = maybe_use_grouping.FromJust();
|
||||
// 31. Set numberFormat.[[UseGrouping]] to useGrouping.
|
||||
if (use_grouping != UseGrouping::AUTO) {
|
||||
settings = settings.grouping(ToUNumberGroupingStrategy(use_grouping));
|
||||
}
|
||||
}
|
||||
|
||||
// 32. Let signDisplay be ? GetOption(options, "signDisplay", "string", «
|
||||
// "auto", "never", "always", "exceptZero" », "auto").
|
||||
Maybe<SignDisplay> maybe_sign_display = GetStringOption<SignDisplay>(
|
||||
isolate, options, "signDisplay", service,
|
||||
{"auto", "never", "always", "exceptZero"},
|
||||
{SignDisplay::AUTO, SignDisplay::NEVER, SignDisplay::ALWAYS,
|
||||
SignDisplay::EXCEPT_ZERO},
|
||||
SignDisplay::AUTO);
|
||||
// "auto", "never", "always", "exceptZero", "negative" », "auto").
|
||||
Maybe<SignDisplay> maybe_sign_display = Nothing<SignDisplay>();
|
||||
if (FLAG_harmony_intl_number_format_v3) {
|
||||
maybe_sign_display = GetStringOption<SignDisplay>(
|
||||
isolate, options, "signDisplay", service,
|
||||
{"auto", "never", "always", "exceptZero", "negative"},
|
||||
{SignDisplay::AUTO, SignDisplay::NEVER, SignDisplay::ALWAYS,
|
||||
SignDisplay::EXCEPT_ZERO, SignDisplay::NEGATIVE},
|
||||
SignDisplay::AUTO);
|
||||
} else {
|
||||
maybe_sign_display = GetStringOption<SignDisplay>(
|
||||
isolate, options, "signDisplay", service,
|
||||
{"auto", "never", "always", "exceptZero"},
|
||||
{SignDisplay::AUTO, SignDisplay::NEVER, SignDisplay::ALWAYS,
|
||||
SignDisplay::EXCEPT_ZERO},
|
||||
SignDisplay::AUTO);
|
||||
}
|
||||
MAYBE_RETURN(maybe_sign_display, MaybeHandle<JSNumberFormat>());
|
||||
SignDisplay sign_display = maybe_sign_display.FromJust();
|
||||
|
||||
@ -1162,8 +1404,27 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::New(Isolate* isolate,
|
||||
// under that values for optimization.
|
||||
if (sign_display != SignDisplay::AUTO ||
|
||||
currency_sign != CurrencySign::STANDARD) {
|
||||
icu_number_formatter = icu_number_formatter.sign(
|
||||
ToUNumberSignDisplay(sign_display, currency_sign));
|
||||
settings = settings.sign(ToUNumberSignDisplay(sign_display, currency_sign));
|
||||
}
|
||||
|
||||
if (FLAG_harmony_intl_number_format_v3) {
|
||||
// X. Let roundingMode be ? GetOption(options, "roundingMode", "string",
|
||||
// « "ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor",
|
||||
// "halfExpand", "halfTrunc", "halfEven" »,
|
||||
// "halfExpand").
|
||||
Maybe<RoundingMode> maybe_rounding_mode = GetStringOption<RoundingMode>(
|
||||
isolate, options, "roundingMode", service,
|
||||
{"ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor",
|
||||
"halfExpand", "halfTrunc", "halfEven"},
|
||||
{RoundingMode::CEIL, RoundingMode::FLOOR, RoundingMode::EXPAND,
|
||||
RoundingMode::TRUNC, RoundingMode::HALF_CEIL, RoundingMode::HALF_FLOOR,
|
||||
RoundingMode::HALF_EXPAND, RoundingMode::HALF_TRUNC,
|
||||
RoundingMode::HALF_EVEN},
|
||||
RoundingMode::HALF_EXPAND);
|
||||
MAYBE_RETURN(maybe_rounding_mode, MaybeHandle<JSNumberFormat>());
|
||||
RoundingMode rounding_mode = maybe_rounding_mode.FromJust();
|
||||
settings =
|
||||
settings.roundingMode(ToUNumberFormatRoundingMode(rounding_mode));
|
||||
}
|
||||
|
||||
// 25. Let dataLocaleData be localeData.[[<dataLocale>]].
|
||||
@ -1180,6 +1441,9 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::New(Isolate* isolate,
|
||||
// 30. Set numberFormat.[[NegativePattern]] to
|
||||
// stylePatterns.[[negativePattern]].
|
||||
//
|
||||
icu::number::LocalizedNumberFormatter icu_number_formatter =
|
||||
settings.locale(icu_locale);
|
||||
|
||||
Handle<Managed<icu::number::LocalizedNumberFormatter>>
|
||||
managed_number_formatter =
|
||||
Managed<icu::number::LocalizedNumberFormatter>::FromRawPtr(
|
||||
@ -1200,6 +1464,7 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::New(Isolate* isolate,
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
Maybe<bool> IcuFormatNumber(
|
||||
Isolate* isolate,
|
||||
const icu::number::LocalizedNumberFormatter& number_format,
|
||||
@ -1212,13 +1477,40 @@ Maybe<bool> IcuFormatNumber(
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, big_int_string,
|
||||
BigInt::ToString(isolate, big_int),
|
||||
Nothing<bool>());
|
||||
*formatted = number_format.formatDecimal(
|
||||
{big_int_string->ToCString().get(), big_int_string->length()}, status);
|
||||
big_int_string = String::Flatten(isolate, big_int_string);
|
||||
DisallowGarbageCollection no_gc;
|
||||
const String::FlatContent& flat = big_int_string->GetFlatContent(no_gc);
|
||||
int32_t length = big_int_string->length();
|
||||
DCHECK(flat.IsOneByte());
|
||||
const char* char_buffer =
|
||||
reinterpret_cast<const char*>(flat.ToOneByteVector().begin());
|
||||
*formatted = number_format.formatDecimal({char_buffer, length}, status);
|
||||
} else {
|
||||
double number = numeric_obj->IsNaN()
|
||||
? std::numeric_limits<double>::quiet_NaN()
|
||||
: numeric_obj->Number();
|
||||
*formatted = number_format.formatDouble(number, status);
|
||||
if (FLAG_harmony_intl_number_format_v3 && numeric_obj->IsString()) {
|
||||
Handle<String> string =
|
||||
String::Flatten(isolate, Handle<String>::cast(numeric_obj));
|
||||
DisallowGarbageCollection no_gc;
|
||||
const String::FlatContent& flat = string->GetFlatContent(no_gc);
|
||||
int32_t length = string->length();
|
||||
if (flat.IsOneByte()) {
|
||||
const char* char_buffer =
|
||||
reinterpret_cast<const char*>(flat.ToOneByteVector().begin());
|
||||
*formatted = number_format.formatDecimal({char_buffer, length}, status);
|
||||
} else {
|
||||
// We may have two bytes string such as "漢 123456789".substring(2)
|
||||
// The value will be "123456789" only in ASCII range, but encoded
|
||||
// in two bytes string.
|
||||
// ICU accepts UTF8 string, so if the source is two-byte encoded,
|
||||
// copy into a UTF8 string via ToCString.
|
||||
*formatted = number_format.formatDecimal(
|
||||
{string->ToCString().get(), string->length()}, status);
|
||||
}
|
||||
} else {
|
||||
double number = numeric_obj->IsNaN()
|
||||
? std::numeric_limits<double>::quiet_NaN()
|
||||
: numeric_obj->Number();
|
||||
*formatted = number_format.formatDouble(number, status);
|
||||
}
|
||||
}
|
||||
if (U_FAILURE(status)) {
|
||||
// This happen because of icu data trimming trim out "unit".
|
||||
@ -1229,28 +1521,6 @@ Maybe<bool> IcuFormatNumber(
|
||||
return Just(true);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MaybeHandle<String> JSNumberFormat::FormatNumeric(
|
||||
Isolate* isolate,
|
||||
const icu::number::LocalizedNumberFormatter& number_format,
|
||||
Handle<Object> numeric_obj) {
|
||||
DCHECK(numeric_obj->IsNumeric());
|
||||
|
||||
icu::number::FormattedNumber formatted;
|
||||
Maybe<bool> maybe_format =
|
||||
IcuFormatNumber(isolate, number_format, numeric_obj, &formatted);
|
||||
MAYBE_RETURN(maybe_format, Handle<String>());
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
icu::UnicodeString result = formatted.toString(status);
|
||||
if (U_FAILURE(status)) {
|
||||
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), String);
|
||||
}
|
||||
return Intl::ToString(isolate, result);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool cmp_NumberFormatSpan(const NumberFormatSpan& a,
|
||||
const NumberFormatSpan& b) {
|
||||
// Regions that start earlier should be encountered earlier.
|
||||
@ -1359,17 +1629,15 @@ std::vector<NumberFormatSpan> FlattenRegionsToParts(
|
||||
}
|
||||
|
||||
namespace {
|
||||
Maybe<int> ConstructParts(Isolate* isolate,
|
||||
icu::number::FormattedNumber* formatted,
|
||||
Maybe<int> ConstructParts(Isolate* isolate, icu::FormattedValue* formatted,
|
||||
Handle<JSArray> result, int start_index,
|
||||
Handle<Object> numeric_obj, bool style_is_unit) {
|
||||
bool style_is_unit, bool is_nan) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
icu::UnicodeString formatted_text = formatted->toString(status);
|
||||
if (U_FAILURE(status)) {
|
||||
THROW_NEW_ERROR_RETURN_VALUE(
|
||||
isolate, NewTypeError(MessageTemplate::kIcuError), Nothing<int>());
|
||||
}
|
||||
DCHECK(numeric_obj->IsNumeric());
|
||||
int32_t length = formatted_text.length();
|
||||
int index = start_index;
|
||||
if (length == 0) return Just(index);
|
||||
@ -1380,7 +1648,6 @@ Maybe<int> ConstructParts(Isolate* isolate,
|
||||
// there's another field with exactly the same begin and end as this backdrop,
|
||||
// in which case the backdrop's field_id of -1 will give it lower priority.
|
||||
regions.push_back(NumberFormatSpan(-1, 0, formatted_text.length()));
|
||||
|
||||
{
|
||||
icu::ConstrainedFieldPosition cfp;
|
||||
cfp.constrainCategory(UFIELD_CATEGORY_NUMBER);
|
||||
@ -1402,7 +1669,7 @@ Maybe<int> ConstructParts(Isolate* isolate,
|
||||
field_type_string = isolate->factory()->unit_string();
|
||||
} else {
|
||||
field_type_string =
|
||||
Intl::NumberFieldToType(isolate, numeric_obj, part.field_id);
|
||||
Intl::NumberFieldToType(isolate, part, formatted_text, is_nan);
|
||||
}
|
||||
}
|
||||
Handle<String> substring;
|
||||
@ -1410,6 +1677,7 @@ Maybe<int> ConstructParts(Isolate* isolate,
|
||||
isolate, substring,
|
||||
Intl::ToString(isolate, formatted_text, part.begin_pos, part.end_pos),
|
||||
Nothing<int>());
|
||||
|
||||
Intl::AddElement(isolate, result, index, field_type_string, substring);
|
||||
++index;
|
||||
}
|
||||
@ -1417,13 +1685,54 @@ Maybe<int> ConstructParts(Isolate* isolate,
|
||||
return Just(index);
|
||||
}
|
||||
|
||||
MaybeHandle<String> FormatToString(Isolate* isolate,
|
||||
icu::FormattedValue* formatted,
|
||||
const icu::number::LocalizedNumberFormatter*,
|
||||
bool) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
icu::UnicodeString result = formatted->toString(status);
|
||||
if (U_FAILURE(status)) {
|
||||
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), String);
|
||||
}
|
||||
return Intl::ToString(isolate, result);
|
||||
}
|
||||
|
||||
MaybeHandle<JSArray> FormatToJSArray(
|
||||
Isolate* isolate, icu::FormattedValue* formatted,
|
||||
const icu::number::LocalizedNumberFormatter* nfmt, bool is_nan) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
bool is_unit = Style::UNIT == StyleFromSkeleton(nfmt->toSkeleton(status));
|
||||
CHECK(U_SUCCESS(status));
|
||||
|
||||
Factory* factory = isolate->factory();
|
||||
Handle<JSArray> result = factory->NewJSArray(0);
|
||||
Maybe<int> maybe_format_to_parts =
|
||||
ConstructParts(isolate, formatted, result, 0, is_unit, is_nan);
|
||||
MAYBE_RETURN(maybe_format_to_parts, Handle<JSArray>());
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MaybeHandle<String> JSNumberFormat::FormatNumeric(
|
||||
Isolate* isolate,
|
||||
const icu::number::LocalizedNumberFormatter& number_format,
|
||||
Handle<Object> numeric_obj) {
|
||||
DCHECK(numeric_obj->IsNumeric() || FLAG_harmony_intl_number_format_v3);
|
||||
|
||||
icu::number::FormattedNumber formatted;
|
||||
Maybe<bool> maybe_format =
|
||||
IcuFormatNumber(isolate, number_format, numeric_obj, &formatted);
|
||||
MAYBE_RETURN(maybe_format, Handle<String>());
|
||||
|
||||
return FormatToString(isolate, &formatted, &number_format,
|
||||
numeric_obj->IsNaN());
|
||||
}
|
||||
|
||||
MaybeHandle<JSArray> JSNumberFormat::FormatToParts(
|
||||
Isolate* isolate, Handle<JSNumberFormat> number_format,
|
||||
Handle<Object> numeric_obj) {
|
||||
CHECK(numeric_obj->IsNumeric());
|
||||
Factory* factory = isolate->factory();
|
||||
CHECK(numeric_obj->IsNumeric() || FLAG_harmony_intl_number_format_v3);
|
||||
icu::number::LocalizedNumberFormatter* fmt =
|
||||
number_format->icu_number_formatter().raw();
|
||||
CHECK_NOT_NULL(fmt);
|
||||
@ -1432,18 +1741,8 @@ MaybeHandle<JSArray> JSNumberFormat::FormatToParts(
|
||||
Maybe<bool> maybe_format =
|
||||
IcuFormatNumber(isolate, *fmt, numeric_obj, &formatted);
|
||||
MAYBE_RETURN(maybe_format, Handle<JSArray>());
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
bool style_is_unit =
|
||||
Style::UNIT == StyleFromSkeleton(fmt->toSkeleton(status));
|
||||
CHECK(U_SUCCESS(status));
|
||||
|
||||
Handle<JSArray> result = factory->NewJSArray(0);
|
||||
Maybe<int> maybe_format_to_parts = ConstructParts(
|
||||
isolate, &formatted, result, 0, numeric_obj, style_is_unit);
|
||||
MAYBE_RETURN(maybe_format_to_parts, Handle<JSArray>());
|
||||
|
||||
return result;
|
||||
return FormatToJSArray(isolate, &formatted, fmt, numeric_obj->IsNaN());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -26,8 +26,9 @@ namespace U_ICU_NAMESPACE {
|
||||
class UnicodeString;
|
||||
namespace number {
|
||||
class LocalizedNumberFormatter;
|
||||
} // namespace number
|
||||
} // namespace U_ICU_NAMESPACE
|
||||
class UnlocalizedNumberFormatter;
|
||||
} // namespace number
|
||||
} // namespace U_ICU_NAMESPACE
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -68,9 +69,13 @@ class JSNumberFormat
|
||||
int32_t* minimum, int32_t* maximum);
|
||||
static bool SignificantDigitsFromSkeleton(const icu::UnicodeString& skeleton,
|
||||
int32_t* minimum, int32_t* maximum);
|
||||
static icu::number::LocalizedNumberFormatter SetDigitOptionsToFormatter(
|
||||
const icu::number::LocalizedNumberFormatter& icu_number_formatter,
|
||||
const Intl::NumberFormatDigitOptions& digit_options);
|
||||
|
||||
enum class ShowTrailingZeros { kShow, kHide };
|
||||
|
||||
static icu::number::UnlocalizedNumberFormatter SetDigitOptionsToFormatter(
|
||||
const icu::number::UnlocalizedNumberFormatter& settings,
|
||||
const Intl::NumberFormatDigitOptions& digit_options,
|
||||
int rounding_increment, ShowTrailingZeros show);
|
||||
|
||||
DECL_PRINTER(JSNumberFormat)
|
||||
|
||||
@ -80,19 +85,6 @@ class JSNumberFormat
|
||||
TQ_OBJECT_CONSTRUCTORS(JSNumberFormat)
|
||||
};
|
||||
|
||||
struct NumberFormatSpan {
|
||||
int32_t field_id;
|
||||
int32_t begin_pos;
|
||||
int32_t end_pos;
|
||||
|
||||
NumberFormatSpan() = default;
|
||||
NumberFormatSpan(int32_t field_id, int32_t begin_pos, int32_t end_pos)
|
||||
: field_id(field_id), begin_pos(begin_pos), end_pos(end_pos) {}
|
||||
};
|
||||
|
||||
V8_EXPORT_PRIVATE std::vector<NumberFormatSpan> FlattenRegionsToParts(
|
||||
std::vector<NumberFormatSpan>* regions);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -115,21 +115,19 @@ MaybeHandle<JSPluralRules> JSPluralRules::New(Isolate* isolate, Handle<Map> map,
|
||||
Handle<String> locale_str =
|
||||
isolate->factory()->NewStringFromAsciiChecked(r.locale.c_str());
|
||||
|
||||
icu::number::LocalizedNumberFormatter icu_number_formatter =
|
||||
icu::number::NumberFormatter::withLocale(r.icu_locale)
|
||||
.roundingMode(UNUM_ROUND_HALFUP);
|
||||
icu::Locale icu_locale = r.icu_locale;
|
||||
icu::number::UnlocalizedNumberFormatter settings =
|
||||
icu::number::UnlocalizedNumberFormatter().roundingMode(UNUM_ROUND_HALFUP);
|
||||
|
||||
std::unique_ptr<icu::PluralRules> icu_plural_rules;
|
||||
bool success =
|
||||
CreateICUPluralRules(isolate, r.icu_locale, type, &icu_plural_rules);
|
||||
if (!success || icu_plural_rules.get() == nullptr) {
|
||||
// Remove extensions and try again.
|
||||
icu::Locale no_extension_locale(r.icu_locale.getBaseName());
|
||||
icu::Locale no_extension_locale(icu_locale.getBaseName());
|
||||
success = CreateICUPluralRules(isolate, no_extension_locale, type,
|
||||
&icu_plural_rules);
|
||||
icu_number_formatter =
|
||||
icu::number::NumberFormatter::withLocale(no_extension_locale)
|
||||
.roundingMode(UNUM_ROUND_HALFUP);
|
||||
icu_locale = no_extension_locale;
|
||||
|
||||
if (!success || icu_plural_rules.get() == nullptr) {
|
||||
THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError),
|
||||
@ -142,8 +140,11 @@ MaybeHandle<JSPluralRules> JSPluralRules::New(Isolate* isolate, Handle<Map> map,
|
||||
Intl::SetNumberFormatDigitOptions(isolate, options, 0, 3, false);
|
||||
MAYBE_RETURN(maybe_digit_options, MaybeHandle<JSPluralRules>());
|
||||
Intl::NumberFormatDigitOptions digit_options = maybe_digit_options.FromJust();
|
||||
icu_number_formatter = JSNumberFormat::SetDigitOptionsToFormatter(
|
||||
icu_number_formatter, digit_options);
|
||||
settings = JSNumberFormat::SetDigitOptionsToFormatter(
|
||||
settings, digit_options, 1, JSNumberFormat::ShowTrailingZeros::kShow);
|
||||
|
||||
icu::number::LocalizedNumberFormatter icu_number_formatter =
|
||||
settings.locale(icu_locale);
|
||||
|
||||
Handle<Managed<icu::PluralRules>> managed_plural_rules =
|
||||
Managed<icu::PluralRules>::FromUniquePtr(isolate, 0,
|
||||
|
@ -343,9 +343,9 @@ template <typename T>
|
||||
MaybeHandle<T> FormatCommon(
|
||||
Isolate* isolate, Handle<JSRelativeTimeFormat> format,
|
||||
Handle<Object> value_obj, Handle<Object> unit_obj, const char* func_name,
|
||||
const std::function<
|
||||
MaybeHandle<T>(Isolate*, const icu::FormattedRelativeDateTime&,
|
||||
Handle<Object>, Handle<String>)>& formatToResult) {
|
||||
MaybeHandle<T> (*formatToResult)(Isolate*,
|
||||
const icu::FormattedRelativeDateTime&,
|
||||
Handle<String>, bool)) {
|
||||
// 3. Let value be ? ToNumber(value).
|
||||
Handle<Object> value;
|
||||
ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
|
||||
@ -382,13 +382,13 @@ MaybeHandle<T> FormatCommon(
|
||||
if (U_FAILURE(status)) {
|
||||
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), T);
|
||||
}
|
||||
return formatToResult(isolate, formatted, value,
|
||||
UnitAsString(isolate, unit_enum));
|
||||
return formatToResult(isolate, formatted, UnitAsString(isolate, unit_enum),
|
||||
value->IsNaN());
|
||||
}
|
||||
|
||||
MaybeHandle<String> FormatToString(
|
||||
Isolate* isolate, const icu::FormattedRelativeDateTime& formatted,
|
||||
Handle<Object> value, Handle<String> unit) {
|
||||
Handle<String> unit, bool is_nan) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
icu::UnicodeString result = formatted.toString(status);
|
||||
if (U_FAILURE(status)) {
|
||||
@ -411,21 +411,22 @@ Maybe<bool> AddLiteral(Isolate* isolate, Handle<JSArray> array,
|
||||
|
||||
Maybe<bool> AddUnit(Isolate* isolate, Handle<JSArray> array,
|
||||
const icu::UnicodeString& string, int32_t index,
|
||||
int32_t start, int32_t limit, int32_t field_id,
|
||||
Handle<Object> value, Handle<String> unit) {
|
||||
const NumberFormatSpan& part, Handle<String> unit,
|
||||
bool is_nan) {
|
||||
Handle<String> substring;
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
||||
isolate, substring, Intl::ToString(isolate, string, start, limit),
|
||||
isolate, substring,
|
||||
Intl::ToString(isolate, string, part.begin_pos, part.end_pos),
|
||||
Nothing<bool>());
|
||||
Intl::AddElement(isolate, array, index,
|
||||
Intl::NumberFieldToType(isolate, value, field_id), substring,
|
||||
isolate->factory()->unit_string(), unit);
|
||||
Intl::NumberFieldToType(isolate, part, string, is_nan),
|
||||
substring, isolate->factory()->unit_string(), unit);
|
||||
return Just(true);
|
||||
}
|
||||
|
||||
MaybeHandle<JSArray> FormatToJSArray(
|
||||
Isolate* isolate, const icu::FormattedRelativeDateTime& formatted,
|
||||
Handle<Object> value, Handle<String> unit) {
|
||||
Handle<String> unit, bool is_nan) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
icu::UnicodeString string = formatted.toString(status);
|
||||
|
||||
@ -457,19 +458,23 @@ MaybeHandle<JSArray> FormatToJSArray(
|
||||
for (auto start_limit : groups) {
|
||||
if (start_limit.first > start) {
|
||||
Maybe<bool> maybe_added =
|
||||
AddUnit(isolate, array, string, index++, start,
|
||||
start_limit.first, field, value, unit);
|
||||
AddUnit(isolate, array, string, index++,
|
||||
NumberFormatSpan(field, start, start_limit.first), unit,
|
||||
is_nan);
|
||||
MAYBE_RETURN(maybe_added, Handle<JSArray>());
|
||||
maybe_added = AddUnit(isolate, array, string, index++,
|
||||
start_limit.first, start_limit.second,
|
||||
UNUM_GROUPING_SEPARATOR_FIELD, value, unit);
|
||||
maybe_added =
|
||||
AddUnit(isolate, array, string, index++,
|
||||
NumberFormatSpan(UNUM_GROUPING_SEPARATOR_FIELD,
|
||||
start_limit.first, start_limit.second),
|
||||
unit, is_nan);
|
||||
MAYBE_RETURN(maybe_added, Handle<JSArray>());
|
||||
start = start_limit.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
Maybe<bool> maybe_added = AddUnit(isolate, array, string, index++, start,
|
||||
limit, field, value, unit);
|
||||
Maybe<bool> maybe_added =
|
||||
AddUnit(isolate, array, string, index++,
|
||||
NumberFormatSpan(field, start, limit), unit, is_nan);
|
||||
MAYBE_RETURN(maybe_added, Handle<JSArray>());
|
||||
previous_end = limit;
|
||||
}
|
||||
|
@ -65,6 +65,75 @@ V8_WARN_UNUSED_RESULT static Maybe<T> GetStringOption(
|
||||
return Just(default_value);
|
||||
}
|
||||
|
||||
// A helper template to get string from option into a enum.
|
||||
// The enum in the enum_values is the corresponding value to the strings
|
||||
// in the str_values. If the option does not contains name,
|
||||
// default_value will be return.
|
||||
template <typename T>
|
||||
V8_WARN_UNUSED_RESULT static Maybe<T> GetStringOrBooleanOption(
|
||||
Isolate* isolate, Handle<JSReceiver> options, const char* property,
|
||||
const char* method, const std::vector<const char*>& str_values,
|
||||
const std::vector<T>& enum_values, T true_value, T false_value,
|
||||
T fallback_value) {
|
||||
DCHECK_EQ(str_values.size(), enum_values.size());
|
||||
Handle<String> property_str =
|
||||
isolate->factory()->NewStringFromAsciiChecked(property);
|
||||
|
||||
// 1. Let value be ? Get(options, property).
|
||||
Handle<Object> value;
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
||||
isolate, value,
|
||||
Object::GetPropertyOrElement(isolate, options, property_str),
|
||||
Nothing<T>());
|
||||
// 2. If value is undefined, then return fallback.
|
||||
if (value->IsUndefined(isolate)) {
|
||||
return Just(fallback_value);
|
||||
}
|
||||
// 3. If value is true, then return trueValue.
|
||||
if (value->IsTrue(isolate)) {
|
||||
return Just(true_value);
|
||||
}
|
||||
// 4. Let valueBoolean be ToBoolean(value).
|
||||
bool valueBoolean = value->BooleanValue(isolate);
|
||||
// 5. If valueBoolean is false, then return valueBoolean.
|
||||
if (!valueBoolean) {
|
||||
return Just(false_value);
|
||||
}
|
||||
|
||||
Handle<String> value_str;
|
||||
// 6. Let value be ? ToString(value).
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
||||
isolate, value_str, Object::ToString(isolate, value), Nothing<T>());
|
||||
// 7. If values does not contain an element equal to value, throw a
|
||||
// RangeError exception.
|
||||
// 8. Return value.
|
||||
value_str = String::Flatten(isolate, value_str);
|
||||
DisallowGarbageCollection no_gc;
|
||||
const String::FlatContent& flat = value_str->GetFlatContent(no_gc);
|
||||
int32_t length = value_str->length();
|
||||
for (size_t i = 0; i < str_values.size(); i++) {
|
||||
if (static_cast<int32_t>(strlen(str_values.at(i))) == length) {
|
||||
if (flat.IsOneByte()) {
|
||||
if (CompareCharsEqual(str_values.at(i), flat.ToOneByteVector().begin(),
|
||||
length)) {
|
||||
return Just(enum_values[i]);
|
||||
}
|
||||
} else {
|
||||
if (CompareCharsEqual(str_values.at(i), flat.ToUC16Vector().begin(),
|
||||
length)) {
|
||||
return Just(enum_values[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
THROW_NEW_ERROR_RETURN_VALUE(
|
||||
isolate,
|
||||
NewRangeError(MessageTemplate::kValueOutOfRange, value,
|
||||
isolate->factory()->NewStringFromAsciiChecked(method),
|
||||
property_str),
|
||||
Nothing<T>());
|
||||
}
|
||||
|
||||
// ECMA402 9.2.10. GetOption( options, property, type, values, fallback)
|
||||
// ecma402/#sec-getoption
|
||||
//
|
||||
|
@ -30,6 +30,7 @@
|
||||
[ALWAYS, {
|
||||
# TODO(ftang,jshin): The following test is flaky.
|
||||
'overrides/caching': [PASS, FAIL],
|
||||
'number-format/rounding-increment-resolved-match-v3': [FAIL],
|
||||
}], # ALWAYS
|
||||
|
||||
################################################################################
|
||||
|
@ -0,0 +1,13 @@
|
||||
// Copyright 2021 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --harmony-intl-number-format-v3
|
||||
|
||||
let validRoundingIncrements = [
|
||||
1, 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 2500, 5000];
|
||||
|
||||
validRoundingIncrements.forEach(function(roundingIncrement) {
|
||||
let nf = new Intl.NumberFormat(undefined, {roundingIncrement});
|
||||
assertEquals(roundingIncrement, nf.resolvedOptions().roundingIncrement);
|
||||
});
|
23
test/intl/number-format/rounding-increment-v3.js
Normal file
23
test/intl/number-format/rounding-increment-v3.js
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2021 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --harmony-intl-number-format-v3
|
||||
|
||||
let validRoundingIncrements = [
|
||||
1, 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 2500, 5000];
|
||||
|
||||
let invalidRoundingIncrements = [
|
||||
-1, -5, 0, 3, 1001, 1100, 5500, 10000, 20000, 25000, 100000, 200000, 500005, 10000000
|
||||
];
|
||||
|
||||
validRoundingIncrements.forEach(function(roundingIncrement) {
|
||||
assertDoesNotThrow(() => {
|
||||
new Intl.NumberFormat(undefined, {roundingIncrement})});
|
||||
});
|
||||
|
||||
invalidRoundingIncrements.forEach(function(roundingIncrement) {
|
||||
assertThrows(() => {
|
||||
let nf = new Intl.NumberFormat(undefined, {roundingIncrement})},
|
||||
RangeError);
|
||||
});
|
23
test/intl/number-format/rounding-increment-value-v3.js
Normal file
23
test/intl/number-format/rounding-increment-value-v3.js
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2021 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --harmony-intl-number-format-v3
|
||||
|
||||
let penny = new Intl.NumberFormat(
|
||||
"en", { minimumFractionDigits: 2, maximumFractionDigits: 2, roundingIncrement: 1 });
|
||||
let nickel = new Intl.NumberFormat(
|
||||
"en", { minimumFractionDigits: 2, maximumFractionDigits: 2, roundingIncrement: 5 });
|
||||
let dime = new Intl.NumberFormat(
|
||||
"en", { minimumFractionDigits: 2, maximumFractionDigits: 2, roundingIncrement: 10 });
|
||||
|
||||
// https://necs.com/knowledgebase/sysprefs_prc_mod_roundmeth.htm
|
||||
assertEquals("10.15", penny.format(10.154));
|
||||
assertEquals("10.16", penny.format(10.155));
|
||||
assertEquals("10.10", nickel.format(10.124));
|
||||
assertEquals("10.15", nickel.format(10.125));
|
||||
assertEquals("10.40", dime.format(10.444));
|
||||
// mistake in the above page, the result should be 10.40 not 10.50
|
||||
// assertEquals("10.50", dime.format(10.445));
|
||||
assertEquals("10.40", dime.format(10.445));
|
||||
assertEquals("10.50", dime.format(10.45));
|
29
test/intl/number-format/sign-display-v3.js
Normal file
29
test/intl/number-format/sign-display-v3.js
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2021 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Flags: --harmony-intl-number-format-v3
|
||||
|
||||
// Test default.
|
||||
let nf = new Intl.NumberFormat();
|
||||
assertEquals("auto", nf.resolvedOptions().signDisplay);
|
||||
|
||||
nf = new Intl.NumberFormat("en");
|
||||
assertEquals("auto", nf.resolvedOptions().signDisplay);
|
||||
|
||||
const testData = [
|
||||
["auto", "-123", "-0", "0", "123"],
|
||||
["always", "-123", "-0", "+0", "+123"],
|
||||
["never", "123", "0", "0", "123"],
|
||||
["exceptZero", "-123", "0", "0", "+123"],
|
||||
["negative", "-123", "0", "0", "123"],
|
||||
];
|
||||
|
||||
for (const [signDisplay, neg, negZero, zero, pos] of testData) {
|
||||
nf = new Intl.NumberFormat("en", {signDisplay});
|
||||
assertEquals(signDisplay, nf.resolvedOptions().signDisplay);
|
||||
assertEquals(neg, nf.format(-123));
|
||||
assertEquals(negZero, nf.format(-0));
|
||||
assertEquals(zero, nf.format(0));
|
||||
assertEquals(pos, nf.format(123));
|
||||
}
|
24
test/intl/number-format/trailing-zero-display-v3.js
Normal file
24
test/intl/number-format/trailing-zero-display-v3.js
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2021 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --harmony-intl-number-format-v3
|
||||
|
||||
let defaultFmt = new Intl.NumberFormat("en",
|
||||
{ minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||||
let autoFmt = new Intl.NumberFormat("en",
|
||||
{ minimumFractionDigits: 2, maximumFractionDigits: 2,
|
||||
trailingZeroDisplay: 'auto'});
|
||||
let stripIfIntegerFmt = new Intl.NumberFormat("en",
|
||||
{ minimumFractionDigits: 2, maximumFractionDigits: 2,
|
||||
trailingZeroDisplay: 'stripIfInteger'});
|
||||
|
||||
assertEquals("3.14", defaultFmt.format(3.1411));
|
||||
assertEquals("3.14", autoFmt.format(3.1411));
|
||||
assertEquals("3.14", stripIfIntegerFmt.format(3.1411));
|
||||
assertEquals("3.00", defaultFmt.format(3.001411));
|
||||
assertEquals("3.00", autoFmt.format(3.001411));
|
||||
assertEquals("3", stripIfIntegerFmt.format(3.001411));
|
||||
assertEquals("3.00", defaultFmt.format(2.999411));
|
||||
assertEquals("3.00", autoFmt.format(2.999411));
|
||||
assertEquals("3", stripIfIntegerFmt.format(2.999411));
|
@ -2578,66 +2578,11 @@
|
||||
|
||||
|
||||
# https://bugs.chromium.org/p/v8/issues/detail?id=10776
|
||||
'intl402/NumberFormat/constructor-options-roundingMode-invalid': [FAIL],
|
||||
'intl402/NumberFormat/constructor-options-throwing-getters-rounding-mode': [FAIL],
|
||||
'intl402/NumberFormat/constructor-signDisplay-negative': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-mode-ceil': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-mode-expand': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-mode-floor': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-mode-half-ceil': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-mode-half-even': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-mode-half-floor': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-mode-half-trunc': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-mode-trunc': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/signDisplay-negative-currency-de-DE': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/signDisplay-negative-currency-en-US': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/signDisplay-negative-currency-ja-JP': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/signDisplay-negative-currency-ko-KR': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/signDisplay-negative-currency-zh-TW': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/signDisplay-negative-de-DE': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/signDisplay-negative-en-US': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/signDisplay-negative-ja-JP': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/signDisplay-negative-ko-KR': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/signDisplay-negative-zh-TW': [FAIL],
|
||||
'intl402/NumberFormat/prototype/formatToParts/signDisplay-negative-currency-de-DE': [FAIL],
|
||||
'intl402/NumberFormat/prototype/formatToParts/signDisplay-negative-currency-en-US': [FAIL],
|
||||
'intl402/NumberFormat/prototype/formatToParts/signDisplay-negative-currency-ja-JP': [FAIL],
|
||||
'intl402/NumberFormat/prototype/formatToParts/signDisplay-negative-currency-ko-KR': [FAIL],
|
||||
'intl402/NumberFormat/prototype/formatToParts/signDisplay-negative-currency-zh-TW': [FAIL],
|
||||
'intl402/NumberFormat/prototype/formatToParts/signDisplay-negative-de-DE': [FAIL],
|
||||
'intl402/NumberFormat/prototype/formatToParts/signDisplay-negative-en-US': [FAIL],
|
||||
'intl402/NumberFormat/prototype/formatToParts/signDisplay-negative-ja-JP': [FAIL],
|
||||
'intl402/NumberFormat/prototype/formatToParts/signDisplay-negative-ko-KR': [FAIL],
|
||||
'intl402/NumberFormat/prototype/formatToParts/signDisplay-negative-zh-TW': [FAIL],
|
||||
'intl402/NumberFormat/prototype/resolvedOptions/roundingMode': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/useGrouping-extended-de-DE': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/useGrouping-extended-en-IN': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/useGrouping-extended-en-US': [FAIL],
|
||||
'intl402/NumberFormat/test-option-useGrouping-extended': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/value-decimal-string': [FAIL],
|
||||
'intl402/NumberFormat/constructor-options-throwing-getters-rounding-increment': [FAIL],
|
||||
'intl402/NumberFormat/constructor-options-throwing-getters-rounding-priority': [FAIL],
|
||||
'intl402/NumberFormat/constructor-options-throwing-getters-trailing-zero-display': [FAIL],
|
||||
'intl402/NumberFormat/constructor-roundingIncrement': [FAIL],
|
||||
'intl402/NumberFormat/constructor-roundingIncrement-invalid': [FAIL],
|
||||
'intl402/NumberFormat/constructor-trailingZeroDisplay': [FAIL],
|
||||
'intl402/NumberFormat/constructor-trailingZeroDisplay-invalid': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-increment-1000': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-increment-100': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-increment-10': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-increment-2000': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-increment-200': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-increment-20': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-increment-2500': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-increment-250': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-increment-25': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-increment-2': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-increment-5000': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-increment-500': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-increment-50': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-increment-5': [FAIL],
|
||||
'intl402/NumberFormat/test-option-roundingPriority': [FAIL],
|
||||
# NumberFormat.prototype.format
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-priority-less-precision': [FAIL],
|
||||
'intl402/NumberFormat/prototype/format/format-rounding-priority-more-precision': [FAIL],
|
||||
# NumberFormat.prototype.formatRange
|
||||
'intl402/NumberFormat/prototype/formatRange/builtin': [FAIL],
|
||||
'intl402/NumberFormat/prototype/formatRange/en-US': [FAIL],
|
||||
'intl402/NumberFormat/prototype/formatRange/invoked-as-func': [FAIL],
|
||||
@ -2646,6 +2591,8 @@
|
||||
'intl402/NumberFormat/prototype/formatRange/nan-arguments-throws': [FAIL],
|
||||
'intl402/NumberFormat/prototype/formatRange/prop-desc': [FAIL],
|
||||
'intl402/NumberFormat/prototype/formatRange/pt-PT': [FAIL],
|
||||
'intl402/NumberFormat/prototype/formatRange/x-greater-than-y-throws': [FAIL],
|
||||
# NumberFormat.prototype.formatRangeToParts
|
||||
'intl402/NumberFormat/prototype/formatRangeToParts/builtin': [FAIL],
|
||||
'intl402/NumberFormat/prototype/formatRangeToParts/en-US': [FAIL],
|
||||
'intl402/NumberFormat/prototype/formatRangeToParts/invoked-as-func': [FAIL],
|
||||
@ -2654,19 +2601,22 @@
|
||||
'intl402/NumberFormat/prototype/formatRangeToParts/nan-arguments-throws': [FAIL],
|
||||
'intl402/NumberFormat/prototype/formatRangeToParts/prop-desc': [FAIL],
|
||||
'intl402/NumberFormat/prototype/formatRangeToParts/x-greater-than-y-throws': [FAIL],
|
||||
'intl402/NumberFormat/prototype/formatRange/x-greater-than-y-throws': [FAIL],
|
||||
|
||||
# NumberFormat.prototype.resolvedOptions
|
||||
'intl402/NumberFormat/constructor-trailingZeroDisplay': [FAIL],
|
||||
'intl402/NumberFormat/prototype/resolvedOptions/basic': [FAIL],
|
||||
'intl402/NumberFormat/test-option-roundingPriority': [FAIL],
|
||||
'intl402/NumberFormat/prototype/resolvedOptions/roundingMode': [FAIL],
|
||||
'intl402/NumberFormat/test-option-useGrouping': [FAIL],
|
||||
'intl402/NumberFormat/test-option-useGrouping-extended': [FAIL],
|
||||
# PluralRules.prototype.selectRange
|
||||
'intl402/PluralRules/prototype/selectRange/default-en-us': [FAIL],
|
||||
'intl402/PluralRules/prototype/selectRange/invoked-as-func': [FAIL],
|
||||
'intl402/PluralRules/prototype/selectRange/length': [FAIL],
|
||||
'intl402/PluralRules/prototype/selectRange/name': [FAIL],
|
||||
'intl402/PluralRules/prototype/selectRange/nan-arguments-throws': [FAIL],
|
||||
'intl402/PluralRules/prototype/selectRange/prop-desc': [FAIL],
|
||||
'intl402/PluralRules/prototype/selectRange/nan-arguments-throws': [FAIL],
|
||||
'intl402/PluralRules/prototype/selectRange/x-greater-than-y-throws': [FAIL],
|
||||
|
||||
|
||||
# https://bugs.chromium.org/p/v8/issues/detail?id=11660
|
||||
'intl402/DurationFormat/prototype/prototype_attributes': [FAIL],
|
||||
'intl402/DurationFormat/prototype/toStringTag': [FAIL],
|
||||
|
@ -46,6 +46,7 @@ from testrunner.outproc import test262
|
||||
FEATURE_FLAGS = {
|
||||
'Intl.Locale-info': '--harmony_intl_locale_info',
|
||||
'Intl-enumeration': '--harmony_intl_enumeration',
|
||||
'Intl.NumberFormat-v3': '--harmony_intl_number_format_v3',
|
||||
'Symbol.prototype.description': '--harmony-symbol-description',
|
||||
'FinalizationRegistry': '--harmony-weak-refs-with-cleanup-some',
|
||||
'WeakRef': '--harmony-weak-refs-with-cleanup-some',
|
||||
|
@ -371,76 +371,76 @@ KNOWN_MAPS = {
|
||||
("read_only_space", 0x033d9): (131, "BasicBlockCountersMarkerMap"),
|
||||
("read_only_space", 0x0341d): (147, "ArrayBoilerplateDescriptionMap"),
|
||||
("read_only_space", 0x0351d): (161, "InterceptorInfoMap"),
|
||||
("read_only_space", 0x05e25): (132, "PromiseFulfillReactionJobTaskMap"),
|
||||
("read_only_space", 0x05e4d): (133, "PromiseRejectReactionJobTaskMap"),
|
||||
("read_only_space", 0x05e75): (134, "CallableTaskMap"),
|
||||
("read_only_space", 0x05e9d): (135, "CallbackTaskMap"),
|
||||
("read_only_space", 0x05ec5): (136, "PromiseResolveThenableJobTaskMap"),
|
||||
("read_only_space", 0x05eed): (139, "FunctionTemplateInfoMap"),
|
||||
("read_only_space", 0x05f15): (140, "ObjectTemplateInfoMap"),
|
||||
("read_only_space", 0x05f3d): (141, "AccessCheckInfoMap"),
|
||||
("read_only_space", 0x05f65): (142, "AccessorInfoMap"),
|
||||
("read_only_space", 0x05f8d): (143, "AccessorPairMap"),
|
||||
("read_only_space", 0x05fb5): (144, "AliasedArgumentsEntryMap"),
|
||||
("read_only_space", 0x05fdd): (145, "AllocationMementoMap"),
|
||||
("read_only_space", 0x06005): (148, "AsmWasmDataMap"),
|
||||
("read_only_space", 0x0602d): (149, "AsyncGeneratorRequestMap"),
|
||||
("read_only_space", 0x06055): (150, "BreakPointMap"),
|
||||
("read_only_space", 0x0607d): (151, "BreakPointInfoMap"),
|
||||
("read_only_space", 0x060a5): (152, "CachedTemplateObjectMap"),
|
||||
("read_only_space", 0x060cd): (154, "CallSiteInfoMap"),
|
||||
("read_only_space", 0x060f5): (155, "ClassPositionsMap"),
|
||||
("read_only_space", 0x0611d): (156, "DebugInfoMap"),
|
||||
("read_only_space", 0x06145): (158, "ErrorStackDataMap"),
|
||||
("read_only_space", 0x0616d): (160, "FunctionTemplateRareDataMap"),
|
||||
("read_only_space", 0x06195): (162, "InterpreterDataMap"),
|
||||
("read_only_space", 0x061bd): (163, "ModuleRequestMap"),
|
||||
("read_only_space", 0x061e5): (164, "PromiseCapabilityMap"),
|
||||
("read_only_space", 0x0620d): (165, "PromiseReactionMap"),
|
||||
("read_only_space", 0x06235): (166, "PropertyDescriptorObjectMap"),
|
||||
("read_only_space", 0x0625d): (167, "PrototypeInfoMap"),
|
||||
("read_only_space", 0x06285): (168, "RegExpBoilerplateDescriptionMap"),
|
||||
("read_only_space", 0x062ad): (169, "ScriptMap"),
|
||||
("read_only_space", 0x062d5): (170, "ScriptOrModuleMap"),
|
||||
("read_only_space", 0x062fd): (171, "SourceTextModuleInfoEntryMap"),
|
||||
("read_only_space", 0x06325): (172, "StackFrameInfoMap"),
|
||||
("read_only_space", 0x0634d): (173, "TemplateObjectDescriptionMap"),
|
||||
("read_only_space", 0x06375): (174, "Tuple2Map"),
|
||||
("read_only_space", 0x0639d): (175, "WasmContinuationObjectMap"),
|
||||
("read_only_space", 0x063c5): (176, "WasmExceptionTagMap"),
|
||||
("read_only_space", 0x063ed): (177, "WasmIndirectFunctionTableMap"),
|
||||
("read_only_space", 0x06415): (196, "SloppyArgumentsElementsMap"),
|
||||
("read_only_space", 0x0643d): (231, "DescriptorArrayMap"),
|
||||
("read_only_space", 0x06465): (219, "UncompiledDataWithoutPreparseDataMap"),
|
||||
("read_only_space", 0x0648d): (217, "UncompiledDataWithPreparseDataMap"),
|
||||
("read_only_space", 0x064b5): (220, "UncompiledDataWithoutPreparseDataWithJobMap"),
|
||||
("read_only_space", 0x064dd): (218, "UncompiledDataWithPreparseDataAndJobMap"),
|
||||
("read_only_space", 0x06505): (250, "OnHeapBasicBlockProfilerDataMap"),
|
||||
("read_only_space", 0x0652d): (197, "TurbofanBitsetTypeMap"),
|
||||
("read_only_space", 0x06555): (201, "TurbofanUnionTypeMap"),
|
||||
("read_only_space", 0x0657d): (200, "TurbofanRangeTypeMap"),
|
||||
("read_only_space", 0x065a5): (198, "TurbofanHeapConstantTypeMap"),
|
||||
("read_only_space", 0x065cd): (199, "TurbofanOtherNumberConstantTypeMap"),
|
||||
("read_only_space", 0x065f5): (246, "InternalClassMap"),
|
||||
("read_only_space", 0x0661d): (257, "SmiPairMap"),
|
||||
("read_only_space", 0x06645): (256, "SmiBoxMap"),
|
||||
("read_only_space", 0x0666d): (225, "ExportedSubClassBaseMap"),
|
||||
("read_only_space", 0x06695): (226, "ExportedSubClassMap"),
|
||||
("read_only_space", 0x066bd): (202, "AbstractInternalClassSubclass1Map"),
|
||||
("read_only_space", 0x066e5): (203, "AbstractInternalClassSubclass2Map"),
|
||||
("read_only_space", 0x0670d): (195, "InternalClassWithSmiElementsMap"),
|
||||
("read_only_space", 0x06735): (247, "InternalClassWithStructElementsMap"),
|
||||
("read_only_space", 0x0675d): (227, "ExportedSubClass2Map"),
|
||||
("read_only_space", 0x06785): (258, "SortStateMap"),
|
||||
("read_only_space", 0x067ad): (146, "AllocationSiteWithWeakNextMap"),
|
||||
("read_only_space", 0x067d5): (146, "AllocationSiteWithoutWeakNextMap"),
|
||||
("read_only_space", 0x067fd): (137, "LoadHandler1Map"),
|
||||
("read_only_space", 0x06825): (137, "LoadHandler2Map"),
|
||||
("read_only_space", 0x0684d): (137, "LoadHandler3Map"),
|
||||
("read_only_space", 0x06875): (138, "StoreHandler0Map"),
|
||||
("read_only_space", 0x0689d): (138, "StoreHandler1Map"),
|
||||
("read_only_space", 0x068c5): (138, "StoreHandler2Map"),
|
||||
("read_only_space", 0x068ed): (138, "StoreHandler3Map"),
|
||||
("read_only_space", 0x05e39): (132, "PromiseFulfillReactionJobTaskMap"),
|
||||
("read_only_space", 0x05e61): (133, "PromiseRejectReactionJobTaskMap"),
|
||||
("read_only_space", 0x05e89): (134, "CallableTaskMap"),
|
||||
("read_only_space", 0x05eb1): (135, "CallbackTaskMap"),
|
||||
("read_only_space", 0x05ed9): (136, "PromiseResolveThenableJobTaskMap"),
|
||||
("read_only_space", 0x05f01): (139, "FunctionTemplateInfoMap"),
|
||||
("read_only_space", 0x05f29): (140, "ObjectTemplateInfoMap"),
|
||||
("read_only_space", 0x05f51): (141, "AccessCheckInfoMap"),
|
||||
("read_only_space", 0x05f79): (142, "AccessorInfoMap"),
|
||||
("read_only_space", 0x05fa1): (143, "AccessorPairMap"),
|
||||
("read_only_space", 0x05fc9): (144, "AliasedArgumentsEntryMap"),
|
||||
("read_only_space", 0x05ff1): (145, "AllocationMementoMap"),
|
||||
("read_only_space", 0x06019): (148, "AsmWasmDataMap"),
|
||||
("read_only_space", 0x06041): (149, "AsyncGeneratorRequestMap"),
|
||||
("read_only_space", 0x06069): (150, "BreakPointMap"),
|
||||
("read_only_space", 0x06091): (151, "BreakPointInfoMap"),
|
||||
("read_only_space", 0x060b9): (152, "CachedTemplateObjectMap"),
|
||||
("read_only_space", 0x060e1): (154, "CallSiteInfoMap"),
|
||||
("read_only_space", 0x06109): (155, "ClassPositionsMap"),
|
||||
("read_only_space", 0x06131): (156, "DebugInfoMap"),
|
||||
("read_only_space", 0x06159): (158, "ErrorStackDataMap"),
|
||||
("read_only_space", 0x06181): (160, "FunctionTemplateRareDataMap"),
|
||||
("read_only_space", 0x061a9): (162, "InterpreterDataMap"),
|
||||
("read_only_space", 0x061d1): (163, "ModuleRequestMap"),
|
||||
("read_only_space", 0x061f9): (164, "PromiseCapabilityMap"),
|
||||
("read_only_space", 0x06221): (165, "PromiseReactionMap"),
|
||||
("read_only_space", 0x06249): (166, "PropertyDescriptorObjectMap"),
|
||||
("read_only_space", 0x06271): (167, "PrototypeInfoMap"),
|
||||
("read_only_space", 0x06299): (168, "RegExpBoilerplateDescriptionMap"),
|
||||
("read_only_space", 0x062c1): (169, "ScriptMap"),
|
||||
("read_only_space", 0x062e9): (170, "ScriptOrModuleMap"),
|
||||
("read_only_space", 0x06311): (171, "SourceTextModuleInfoEntryMap"),
|
||||
("read_only_space", 0x06339): (172, "StackFrameInfoMap"),
|
||||
("read_only_space", 0x06361): (173, "TemplateObjectDescriptionMap"),
|
||||
("read_only_space", 0x06389): (174, "Tuple2Map"),
|
||||
("read_only_space", 0x063b1): (175, "WasmContinuationObjectMap"),
|
||||
("read_only_space", 0x063d9): (176, "WasmExceptionTagMap"),
|
||||
("read_only_space", 0x06401): (177, "WasmIndirectFunctionTableMap"),
|
||||
("read_only_space", 0x06429): (196, "SloppyArgumentsElementsMap"),
|
||||
("read_only_space", 0x06451): (231, "DescriptorArrayMap"),
|
||||
("read_only_space", 0x06479): (219, "UncompiledDataWithoutPreparseDataMap"),
|
||||
("read_only_space", 0x064a1): (217, "UncompiledDataWithPreparseDataMap"),
|
||||
("read_only_space", 0x064c9): (220, "UncompiledDataWithoutPreparseDataWithJobMap"),
|
||||
("read_only_space", 0x064f1): (218, "UncompiledDataWithPreparseDataAndJobMap"),
|
||||
("read_only_space", 0x06519): (250, "OnHeapBasicBlockProfilerDataMap"),
|
||||
("read_only_space", 0x06541): (197, "TurbofanBitsetTypeMap"),
|
||||
("read_only_space", 0x06569): (201, "TurbofanUnionTypeMap"),
|
||||
("read_only_space", 0x06591): (200, "TurbofanRangeTypeMap"),
|
||||
("read_only_space", 0x065b9): (198, "TurbofanHeapConstantTypeMap"),
|
||||
("read_only_space", 0x065e1): (199, "TurbofanOtherNumberConstantTypeMap"),
|
||||
("read_only_space", 0x06609): (246, "InternalClassMap"),
|
||||
("read_only_space", 0x06631): (257, "SmiPairMap"),
|
||||
("read_only_space", 0x06659): (256, "SmiBoxMap"),
|
||||
("read_only_space", 0x06681): (225, "ExportedSubClassBaseMap"),
|
||||
("read_only_space", 0x066a9): (226, "ExportedSubClassMap"),
|
||||
("read_only_space", 0x066d1): (202, "AbstractInternalClassSubclass1Map"),
|
||||
("read_only_space", 0x066f9): (203, "AbstractInternalClassSubclass2Map"),
|
||||
("read_only_space", 0x06721): (195, "InternalClassWithSmiElementsMap"),
|
||||
("read_only_space", 0x06749): (247, "InternalClassWithStructElementsMap"),
|
||||
("read_only_space", 0x06771): (227, "ExportedSubClass2Map"),
|
||||
("read_only_space", 0x06799): (258, "SortStateMap"),
|
||||
("read_only_space", 0x067c1): (146, "AllocationSiteWithWeakNextMap"),
|
||||
("read_only_space", 0x067e9): (146, "AllocationSiteWithoutWeakNextMap"),
|
||||
("read_only_space", 0x06811): (137, "LoadHandler1Map"),
|
||||
("read_only_space", 0x06839): (137, "LoadHandler2Map"),
|
||||
("read_only_space", 0x06861): (137, "LoadHandler3Map"),
|
||||
("read_only_space", 0x06889): (138, "StoreHandler0Map"),
|
||||
("read_only_space", 0x068b1): (138, "StoreHandler1Map"),
|
||||
("read_only_space", 0x068d9): (138, "StoreHandler2Map"),
|
||||
("read_only_space", 0x06901): (138, "StoreHandler3Map"),
|
||||
("map_space", 0x02149): (1057, "ExternalMap"),
|
||||
("map_space", 0x02171): (2114, "JSMessageObjectMap"),
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user