Commit fe53fc04 authored by Frank Tang's avatar Frank Tang Committed by V8 LUCI CQ

[intl] Implement NumberFormat v8 string input handling

Design Document:
https://docs.google.com/document/d/14zxGub6Os6nARzH6XstOZX05w2537sZo_ZSSlGjGpBM/edit#


Bug: v8:10776
Change-Id: I506eadcf70f6855a79601a7cb1ce47849cfc066a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3594118Reviewed-by: 's avatarShu-yu Guo <syg@chromium.org>
Commit-Queue: Frank Tang <ftang@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81168}
parent b66d0824
......@@ -85,15 +85,7 @@ BUILTIN(NumberFormatPrototypeFormatToParts) {
Handle<Object> x;
if (args.length() >= 2) {
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));
}
x = args.at(1);
} else {
x = isolate->factory()->nan_value();
}
......@@ -505,25 +497,8 @@ BUILTIN(NumberFormatInternalFormatNumber) {
// 3. If value is not provided, let value be undefined.
Handle<Object> value = args.atOrUndefined(isolate, 1);
// 4. Let x be ? ToNumeric(value).
Handle<Object> numeric_obj;
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();
CHECK_NOT_NULL(icu_localized_number_formatter);
// Return FormatNumber(nf, x).
RETURN_RESULT_OR_FAILURE(
isolate, JSNumberFormat::FormatNumeric(
isolate, *icu_localized_number_formatter, numeric_obj));
RETURN_RESULT_OR_FAILURE(isolate, JSNumberFormat::NumberFormatFunction(
isolate, number_format, value));
}
// Common code for NumberFormatPrototypeFormtRange(|ToParts)
......@@ -553,19 +528,7 @@ V8_WARN_UNUSED_RESULT Object NumberFormatRange(BuiltinArguments args,
factory->NewStringFromStaticChars("end"), end));
}
// 4. Let x be ? ToIntlMathematicalValue(start).
Handle<Object> x;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, x,
Intl::ToIntlMathematicalValueAsNumberBigIntOrString(isolate, start));
// 5. Let y be ? ToIntlMathematicalValue(end).
Handle<Object> y;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, y,
Intl::ToIntlMathematicalValueAsNumberBigIntOrString(isolate, end));
RETURN_RESULT_OR_FAILURE(isolate, F(isolate, nf, x, y));
RETURN_RESULT_OR_FAILURE(isolate, F(isolate, nf, start, end));
}
BUILTIN(NumberFormatPrototypeFormatRange) {
......
......@@ -242,7 +242,8 @@ class BigInt : public BigIntBase {
Isolate* isolate, Handle<Object> number);
// ECMAScript's ToBigInt (throws for Number input)
static MaybeHandle<BigInt> FromObject(Isolate* isolate, Handle<Object> obj);
V8_EXPORT_PRIVATE static MaybeHandle<BigInt> FromObject(Isolate* isolate,
Handle<Object> obj);
class BodyDescriptor;
......
......@@ -2891,28 +2891,6 @@ int32_t Intl::GetTimeZoneIndex(Isolate* isolate, Handle<String> identifier) {
UNREACHABLE();
}
// #sec-tointlmathematicalvalue
MaybeHandle<Object> Intl::ToIntlMathematicalValueAsNumberBigIntOrString(
Isolate* isolate, Handle<Object> input) {
if (input->IsNumber() || input->IsBigInt()) return input; // Shortcut.
// TODO(ftang) revisit the following after the resolution of
// https://github.com/tc39/proposal-intl-numberformat-v3/pull/82
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(isolate, Handle<JSReceiver>::cast(input),
ToPrimitiveHint::kNumber),
Object);
if (input->IsString()) UNIMPLEMENTED();
return input;
}
Intl::FormatRangeSourceTracker::FormatRangeSourceTracker() {
start_[0] = start_[1] = limit_[0] = limit_[1] = 0;
}
......
......@@ -367,12 +367,6 @@ class Intl {
// 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
......
This diff is collapsed.
......@@ -23,11 +23,14 @@
#include "src/objects/object-macros.h"
namespace U_ICU_NAMESPACE {
class Formattable;
class UnicodeString;
namespace number {
class FormattedNumber;
class FormattedNumberRange;
class LocalizedNumberFormatter;
class UnlocalizedNumberFormatter;
class LocalizedNumberRangeFormatter;
class UnlocalizedNumberFormatter;
} // namespace number
} // namespace U_ICU_NAMESPACE
......@@ -48,6 +51,11 @@ class JSNumberFormat
V8_WARN_UNUSED_RESULT static MaybeHandle<JSNumberFormat> UnwrapNumberFormat(
Isolate* isolate, Handle<JSReceiver> format_holder);
// #sec-number-format-functions
V8_WARN_UNUSED_RESULT static MaybeHandle<String> NumberFormatFunction(
Isolate* isolate, Handle<JSNumberFormat> number_format,
Handle<Object> numeric_obj);
// ecma402/#sec-intl.numberformat.prototype.resolvedoptions
static Handle<JSObject> ResolvedOptions(Isolate* isolate,
Handle<JSNumberFormat> number_format);
......@@ -101,6 +109,49 @@ class JSNumberFormat
TQ_OBJECT_CONSTRUCTORS(JSNumberFormat)
};
// IntlMathematicalValue is designed only to be used as part of
// JSNumberFormat and can only be allocate on the stack. We place this class in
// the header so we can write unit test code for it. Please do NOT use this
// class outside JSNumberFormat implementation.
class V8_NODISCARD IntlMathematicalValue {
public:
IntlMathematicalValue() : approx_(0) {}
V8_EXPORT_PRIVATE bool IsNaN() const;
V8_EXPORT_PRIVATE bool IsMinusZero() const;
V8_EXPORT_PRIVATE bool IsNegative() const;
V8_EXPORT_PRIVATE bool IsNegativeInfinity() const {
return IsNegative() && IsInfinity();
}
V8_EXPORT_PRIVATE bool IsPositiveInfinity() const {
return !IsNegative() && IsInfinity();
}
V8_EXPORT_PRIVATE bool IsMathematicalValue() const {
return !(IsNaN() || IsMinusZero() || IsInfinity());
}
V8_EXPORT_PRIVATE bool IsLessThan(Isolate* isolate,
const IntlMathematicalValue& y) const;
V8_EXPORT_PRIVATE static Maybe<IntlMathematicalValue> From(
Isolate* isolate, Handle<Object> value);
static Maybe<icu::number::FormattedNumber> FormatNumeric(
Isolate* isolate,
const icu::number::LocalizedNumberFormatter& number_format,
const IntlMathematicalValue& x);
static Maybe<icu::number::FormattedNumberRange> FormatRange(
Isolate* isolate,
const icu::number::LocalizedNumberRangeFormatter& number_range_format,
const IntlMathematicalValue& x, const IntlMathematicalValue& y);
private:
double approx_;
Handle<Object> value_; // Number, BigInt or String
Maybe<icu::Formattable> ToFormattable(Isolate* isolate) const;
MaybeHandle<String> ToString(Isolate* isolate) const;
V8_EXPORT_PRIVATE bool IsInfinity() const;
};
} // namespace internal
} // namespace v8
......
......@@ -309,6 +309,197 @@ TEST(StringLocaleCompareFastPath) {
}
}
TEST(IntlMathematicalValueFromString) {
LocalContext env;
Isolate* isolate = CcTest::i_isolate();
HandleScope handle_scope(isolate);
struct TestCase {
bool is_nan;
bool is_minus_zero;
bool is_negative;
bool is_negative_infinity;
bool is_positive_infinity;
bool is_mathematical_value;
const char* string;
} cases[] = {
{false, false, false, false, false, true, "+1"},
{false, false, false, false, false, true,
"+1234567890123456789012345678901234567890"},
{false, false, false, false, true, false,
"+1234567890123456789012345678901234567890e987654321"},
{false, false, false, false, true, false,
" +1234567890123456789012345678901234567890e987654321 "},
{true, false, false, false, false, false,
" +12 345 67 "}, // space between digit is invalid
{true, false, false, false, false, false,
" -12 345 67 "}, // space between digit is invalid
{false, false, false, false, false, true,
"1234567890123456789012345678901234567890"},
{false, false, false, false, false, true,
"+.1234567890123456789012345678901234567890"},
{false, false, false, false, false, true,
".1234567890123456789012345678901234567890"},
{false, false, false, false, false, true, ".1234567890123456789e123"},
{false, false, false, false, false, true, ".1234567890123456789E123"},
{false, false, false, false, false, true, ".1234567890123456789e+123"},
{false, false, false, false, false, true, ".1234567890123456789E+123"},
{false, false, false, false, false, true, ".1234567890123456789e-0123"},
{false, false, false, false, false, true, ".1234567890123456789E-0123"},
{false, false, false, false, false, true,
"1234567890123456789012345678901234567.890"},
{false, false, false, false, false, true,
"1234567890123456789012345678901234567890."},
{true, false, false, false, false, false,
"1234567.90123456789012345678901234567.890"}, // two '.'
{true, false, false, false, false, false,
".1234567890123456789e12.3"}, // two '.'
{false, false, true, false, false, true, "-1"},
{false, false, true, false, false, true, "-1e33 "},
{false, false, true, false, false, true, " -0.21e33"},
{false, false, false, false, false, true, " 0.21e33"},
{false, true, false, false, false, false, "-0"},
{false, false, false, false, false, true, "1"},
{false, false, true, false, false, true, " -1234.567e-20 "},
{false, true, false, false, false, false, " -1234.567e-9876 "},
{false, false, false, false, true, false, " Infinity "},
{false, false, true, true, false, false, " -Infinity "},
{true, false, false, false, false, false, "yz"}, // not digits
{false, false, true, false, false, true,
" -12345678901234567890122345.6778901234567890e234 "},
{false, false, false, false, false, true,
" 12345678901234567890122345.6778901234567890e-234 "},
{false, false, false, false, false, true, " 0b01010001 "},
{false, false, false, false, false, true, " 0B01010001 "},
{true, false, false, false, false, false,
" -0b01010001 "}, // invalid binary becaues of -
{true, false, false, false, false, false,
" -0B01010001 "}, // invalid binary becaues of -
{true, false, false, false, false, false,
" 0b01010002 "}, // invalid binary becaues of 2
{true, false, false, false, false, false,
" 0B01010003 "}, // invalid binary becaues of 3
{false, false, false, false, false, true, " 0o01234567 "},
{false, false, false, false, false, true, " 0O76543210 "},
{true, false, false, false, false, false,
" -0o01234567 "}, // invalid oct becaues of -
{true, false, false, false, false, false,
" -0O76543210 "}, // invalid oct becaues of -
{true, false, false, false, false, false,
" 0o012345678 "}, // invalid oct becaues of 8
{true, false, false, false, false, false,
" 0O765432108 "}, // invalid oct becaues of 8
{false, false, false, false, false, true, " 0x123456789aBcDeF "},
{false, false, false, false, false, true, " 0X123456789AbCdEf "},
{true, false, false, false, false, false,
" -0x123456789aBcDeF "}, // invalid hex because of -
{true, false, false, false, false, false,
" -0X123456789AbCdEf "}, // invalid hex because of -
{true, false, false, false, false, false,
" 0x012345678xyz "}, // invalid hex because xyz
{true, false, false, false, false, false,
" 0X765432108xyz "}, // invalid hex because xyz
};
for (auto& cas : cases) {
IntlMathematicalValue x =
IntlMathematicalValue::From(
isolate, isolate->factory()->NewStringFromAsciiChecked(cas.string))
.ToChecked();
CHECK_EQ(x.IsNaN(), cas.is_nan);
CHECK_EQ(x.IsMinusZero(), cas.is_minus_zero);
CHECK_EQ(x.IsNegative(), cas.is_negative);
CHECK_EQ(x.IsNegativeInfinity(), cas.is_negative_infinity);
CHECK_EQ(x.IsPositiveInfinity(), cas.is_positive_infinity);
CHECK_EQ(x.IsMathematicalValue(), cas.is_mathematical_value);
}
}
TEST(IntlMathematicalValueFromBigInt) {
LocalContext env;
Isolate* isolate = CcTest::i_isolate();
HandleScope handle_scope(isolate);
struct TestCase {
bool is_negative;
const char* bigint_string;
} cases[] = {
{false, "12"},
{false, "12345678901234567890123456789012345678901234567890"},
{true, "-12345678901234567890123456789012345678901234567890"},
{false, "0"},
{true, "-20"},
};
for (auto& cas : cases) {
printf("%s\n", cas.bigint_string);
Handle<String> str =
isolate->factory()->NewStringFromAsciiChecked(cas.bigint_string);
IntlMathematicalValue x =
IntlMathematicalValue::From(
isolate, BigInt::FromObject(isolate, str).ToHandleChecked())
.ToChecked();
CHECK_EQ(x.IsNaN(), false);
CHECK_EQ(x.IsMinusZero(), false);
CHECK_EQ(x.IsNegative(), cas.is_negative);
CHECK_EQ(x.IsNegativeInfinity(), false);
CHECK_EQ(x.IsPositiveInfinity(), false);
CHECK_EQ(x.IsMathematicalValue(), true);
}
}
TEST(IntlMathematicalValueLessThanString) {
LocalContext env;
Isolate* isolate = CcTest::i_isolate();
HandleScope handle_scope(isolate);
struct TestCase {
const char* x;
const char* y;
bool is_x_less_than_y;
} cases[] = {
{" 1 ", " 2", true},
{" 1 ", " 2 ", true},
{" 1e-1 ", " 2 ", true},
{" 1e1 ", " 2 ", false},
{" 1 ", " 20e-3", false},
{" -1e10 ", " -1e9 ", true},
{" -1e-10 ", " -1e-9 ", false},
{" 123456789012345678901234567890 ", " 123456789012345678901234567890 ",
false},
{" .123456789012345678901234567890 ", " .123456789012345678901234567890 ",
false},
{" .123456789012345678901234567890000 ",
" .12345678901234567890123456789 ", false},
{" .12345678901234567890123456789 ",
" .123456789012345678901234567890000 ", false},
{" 123456789012345678901234567890 ", " 1234567890123456789012345678901 ",
true},
{" 1234567890123456789012345678902 ", " 1234567890123456789012345678901 ",
false},
{" 123456789012345.678901234567890e33 ",
" 12345678901234.5678901234567890e34 ", false},
{" 123456789012345.678901234567890e33 ",
" 12345678901234.5678901234567890e35 ", true},
{" 12345678901234.5678901234567890e34 ",
" 123456789012345.678901234567890e33 ", false},
{" 123456789012345678.901234567890e30 ",
" 12345678901234.5678901234567890e35 ", true},
{" .12345678901234567890123456789 ",
" .1234567890123456789012345678900000001 ", true},
{" -.1234567890123456789012345678900000001 ",
" -.123456789012345678901234567890000 ", true},
{" -.1234567890123456789012345678900000001 ",
" -0.00000123456789012345678901234567890000e5 ", true},
};
for (auto& cas : cases) {
IntlMathematicalValue x =
IntlMathematicalValue::From(
isolate, isolate->factory()->NewStringFromAsciiChecked(cas.x))
.ToChecked();
IntlMathematicalValue y =
IntlMathematicalValue::From(
isolate, isolate->factory()->NewStringFromAsciiChecked(cas.y))
.ToChecked();
CHECK_EQ(x.IsLessThan(isolate, y), cas.is_x_less_than_y);
}
}
} // namespace internal
} // namespace v8
......
// Copyright 2022 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 the throw in formatRange
let df = new Intl.NumberFormat();
// https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/diff.html#sec-partitionnumberrangepattern
// 2. If x is not-a-number or y is not-a-number, throw a RangeError exception.
assertThrows(() => { df.formatRange("xyz", "123") }, RangeError);
assertThrows(() => { df.formatRange("123", "xyz") }, RangeError);
assertThrows(() => { df.formatRange("1", "-0b1111") }, RangeError);
assertThrows(() => { df.formatRange("1", "-0o7654") }, RangeError);
assertThrows(() => { df.formatRange("1", "-0xabcde") }, RangeError);
// 2. If x is a mathematical value, then
// 2a. If y is a mathematical value and y < x, throw a RangeError exception.
assertThrows(() => { df.formatRange(
" +1234567890123456789012345678901234567890123456789012345678901 ",
" +123456789012345678901234567890123456789012345678901234567890 ") }, RangeError);
assertThrows(() => { df.formatRange(
" +123456789012345678901234567890.123456789012345678901234567890e25 ",
" +12345678901234567890.1234567890123456789012345678901234567890e25 ") }, RangeError);
assertThrows(() => { df.formatRange(
" +12345678901234567890.1234567890123456789012345678901234567890e35 ",
" +123456789012345678901234567890.123456789012345678901234567890e24 ") }, RangeError);
assertThrows(() => { df.formatRange(
" -123456789012345678901234567890123456789012345678901234567890 ",
" -1234567890123456789012345678901234567890123456789012345678901 ") }, RangeError);
assertThrows(() => { df.formatRange(
" -12345678901234567890.1234567890123456789012345678901234567890e25 ",
" -123456789012345678901234567890.123456789012345678901234567890e25 ") }, RangeError);
assertThrows(() => { df.formatRange(
" -123456789012345678901234567890.123456789012345678901234567890e24 ",
" -12345678901234567890.1234567890123456789012345678901234567890e35 ") }, RangeError);
assertThrows(() => { df.formatRange(
" +.1234567890123456789012345678901234567890123456789012345678901 ",
" +.123456789012345678901234567890123456789012345678901234567890 ") }, RangeError);
assertThrows(() => { df.formatRange(
" +.123456789012345678901234567890123456789012345678901234567890 ",
" -.1234567890123456789012345678901234567890123456789012345678901 ") }, RangeError);
assertThrows(() => { df.formatRange(
" +.12e3 ", " +.12e2 ") }, RangeError);
assertThrows(() => { df.formatRange(
" +123 ", " +.12e2 ") }, RangeError);
assertThrows(() => { df.formatRange(
" -123 ", " -.12e4 ") }, RangeError);
// 2b. Else if y is negative-infinity, throw a RangeError exception.
assertThrows(() => { df.formatRange( " 123 ", " -Infinity ") }, RangeError);
// 2c. Else if y is negative-zero and x ≥ 0, throw a RangeError exception.
assertThrows(() => { df.formatRange( " 123 ", " -0 ") }, RangeError);
// other case which won't throw under 2
assertDoesNotThrow(() => { df.formatRange( " 123 ", " Infinity ") })
assertEquals("123–∞", df.formatRange( " 123 ", " Infinity "));
assertDoesNotThrow(() => { df.formatRange(
" +.123456789012345678901234567890123456789012345678901234567890 ", " Infinity ") })
assertEquals("0.123–∞", df.formatRange(
" +.123456789012345678901234567890123456789012345678901234567890 ",
" Infinity "));
assertDoesNotThrow(() => { df.formatRange(
" +.123456789012345678901234567890123456789012345678901234567890 ",
" +.123456789012345678901234567890123456789012345678901234567890 ")})
assertDoesNotThrow(() => { df.formatRange(
" +.123456789012345678901234567890123456789012345678901234567890 ",
" +.1234567890123456789012345678901234567890123456789012345678901 ")})
assertDoesNotThrow(() => { df.formatRange(
" +12345678901234567890.123456789012345678901234567890123456789000000001e20 ",
" +1234567890.12345678901234567890123456789012345678901234567890e31 ")})
// 3. Else if x is positive-infinity, then
// 3a. If y is a mathematical value, throw a RangeError exception.
assertThrows(() => { df.formatRange( " Infinity ", " 123 ") }, RangeError);
assertThrows(() => { df.formatRange( " +Infinity ", " 123 ") }, RangeError);
// 3b. Else if y is negative-infinity, throw a RangeError exception.
assertThrows(() => { df.formatRange( " Infinity ", " -Infinity ") }, RangeError);
assertThrows(() => { df.formatRange( " +Infinity ", " -Infinity ") }, RangeError);
// 3c. Else if y is negative-zero, throw a RangeError exception.
assertThrows(() => { df.formatRange( " Infinity ", " -0 ") }, RangeError);
assertThrows(() => { df.formatRange( " +Infinity ", " -0 ") }, RangeError);
// other case which won't throw under 3
assertDoesNotThrow(() => { df.formatRange( " Infinity ", " Infinity ") })
assertEquals("~∞", df.formatRange(" Infinity ", " Infinity "));
// 4. Else if x is negative-zero, then
// 4a. If y is a mathematical value and y < 0, throw a RangeError exception.
assertThrows(() => { df.formatRange( " -0 ", " -1e-30 ") }, RangeError);
assertThrows(() => { df.formatRange( " -0.000e200 ", " -1e-30 ") }, RangeError);
// 4b. Else if y is negative-infinity, throw a RangeError exception.
assertThrows(() => { df.formatRange( " -0 ", " -Infinity ") }, RangeError);
// other case which won't throw under 4
assertDoesNotThrow(() => { df.formatRange( " -0 ", " Infinity ") })
assertEquals("-0 – ∞", df.formatRange(" -0 ", " Infinity "));
assertDoesNotThrow(() => { df.formatRange( " -0 ", " -0 ") })
assertDoesNotThrow(() => { df.formatRange( " -0 ", " 12345 ") })
assertDoesNotThrow(() => { df.formatRange( " -0 ", " 12345e-30 ") })
assertEquals("-0 – 0", df.formatRange(" -0 ", " 12345e-30 "));
assertDoesNotThrow(() => { df.formatRange( " -0 ", " .12345e-30 ") })
assertDoesNotThrow(() => { df.formatRange( " -0 ", " .12345e34 ") })
assertEquals("-0 – 12,345,000,000,000,000,000,000,000,000,000",
df.formatRange(" -0 ", " .12345e32 "));
// other cases which won't throw not under 2-4
assertDoesNotThrow(() => { df.formatRange( " -Infinity ", " -Infinity ") })
assertEquals("~-∞", df.formatRange(" -Infinity ", " -Infinity "));
assertDoesNotThrow(() => { df.formatRange( " -Infinity ", " -3e20 ") })
assertDoesNotThrow(() => { df.formatRange( " -Infinity ", " -3e20 ") })
assertDoesNotThrow(() => { df.formatRange( " -Infinity ", " -0 ") })
assertDoesNotThrow(() => { df.formatRange( " -Infinity ", " 0 ") })
assertDoesNotThrow(() => { df.formatRange( " -Infinity ", " .3e20 ") })
assertDoesNotThrow(() => { df.formatRange( " -Infinity ", " Infinity ") })
assertEquals("-∞ – ∞", df.formatRange(" -Infinity ", " Infinity "));
// Copyright 2022 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 nf = new Intl.NumberFormat("en");
// Basic case
assertEquals("123", nf.format("123"));
assertEquals("123.45", nf.format("123.45"));
assertEquals("123", nf.format("+123"));
assertEquals("123.45", nf.format("+123.45"));
assertEquals("-123", nf.format("-123"));
assertEquals("-123.45", nf.format("-123.45"));
// with _
assertEquals("NaN", nf.format("1_2_3_4"));
assertEquals("NaN", nf.format("1_2.3_4"));
assertEquals("NaN", nf.format("1_2.34"));
assertEquals("NaN", nf.format("12.3_4"));
assertEquals("NaN", nf.format(".1_2_3"));
assertEquals("NaN", nf.format("123e1_2"));
assertEquals("NaN", nf.format("123e-1_2"));
assertEquals("NaN", nf.format("1.23e1_2"));
assertEquals("NaN", nf.format("12.3e-1_2"));
assertEquals("NaN", nf.format("12.3e+1_2"));
let str_white_space = " \u0009\u000b\u000c\ufeff\u000a\u000d\u2028\u2029";
// With StrWhiteSpace_opt only
assertEquals("0", nf.format(str_white_space));
// With StrWhiteSpace_opt prefix/postfix
assertEquals("123", nf.format(str_white_space + "123" + str_white_space));
assertEquals("123.45", nf.format(str_white_space + "123.45" + str_white_space));
assertEquals("123", nf.format(str_white_space + "+123" + str_white_space));
assertEquals("123.45",
nf.format(str_white_space + "+123.45" + str_white_space));
assertEquals("-123", nf.format(str_white_space + "-123" + str_white_space));
assertEquals("-123.45",
nf.format(str_white_space + "-123.45" + str_white_space));
// NonDecimalIntegerLiteral
assertEquals("10", nf.format("0b1010"));
assertEquals("11", nf.format("0B1011"));
assertEquals("10", nf.format("0o12"));
assertEquals("11", nf.format("0O13"));
assertEquals("10", nf.format("0x000A"));
assertEquals("11", nf.format("0X00B"));
// With StrWhiteSpace_opt prefix/postfix
assertEquals("10", nf.format(str_white_space + "0b1010" + str_white_space));
assertEquals("11", nf.format(str_white_space + "0B1011" + str_white_space));
assertEquals("10", nf.format(str_white_space + "0o12" + str_white_space));
assertEquals("11", nf.format(str_white_space + "0O13" + str_white_space));
assertEquals("10", nf.format(str_white_space + "0x000A" + str_white_space));
assertEquals("11", nf.format(str_white_space + "0X00B" + str_white_space));
// Very large NonDecimalIntegerLiteral
assertEquals("1,208,925,819,614,629,174,706,175",
nf.format("0xFFFFFFFFFFFFFFFFFFFF"));
assertEquals("1,208,925,819,614,629,174,706,174",
nf.format("0XFFFFFFFFFFFFFFFFFFFE"));
// NaN
// Infinity
assertEquals("∞", nf.format("Infinity"));
assertEquals("∞", nf.format("+Infinity"));
assertEquals("-∞", nf.format("-Infinity"));
// With StrWhiteSpace_opt prefix/postfix
assertEquals("∞", nf.format(str_white_space + "Infinity" + str_white_space));
assertEquals("∞", nf.format(str_white_space + "+Infinity" + str_white_space));
assertEquals("-∞", nf.format(str_white_space + "-Infinity" + str_white_space));
// Extra SPACE
assertEquals("NaN", nf.format("+ Infinity"));
assertEquals("NaN", nf.format("- Infinity"));
// DecimalDigits . DecimalDigits_opt ExponentPart_opt
assertEquals("123.45", nf.format("12345e-2"));
assertEquals("123.45", nf.format("+12345e-2"));
assertEquals("-123.45", nf.format("-12345e-2"));
assertEquals("123.45", nf.format("1.2345e2"));
assertEquals("123.45", nf.format("1.2345e+2"));
assertEquals("-123.45", nf.format("-1.2345e2"));
assertEquals("-123.45", nf.format("-1.2345e+2"));
// With StrWhiteSpace_opt prefix/postfix
assertEquals("123.45",
nf.format(str_white_space + "12345e-2" + str_white_space));
assertEquals("123.45",
nf.format(str_white_space + "+12345e-2" + str_white_space));
assertEquals("-123.45",
nf.format(str_white_space + "-12345e-2" + str_white_space));
assertEquals("123.45",
nf.format(str_white_space + "1.2345e2" + str_white_space));
assertEquals("123.45",
nf.format(str_white_space + "1.2345e+2" + str_white_space));
assertEquals("-123.45", nf.format("-1.2345e2"));
assertEquals("-123.45", nf.format("-1.2345e+2"));
// . DecimalDigits ExponentPart_opt
assertEquals("123.45", nf.format(".12345e3"));
assertEquals("123.45", nf.format("+.12345e+3"));
assertEquals("-123.45", nf.format("-.12345e3"));
assertEquals("-123.45", nf.format("-.12345e+3"));
// With StrWhiteSpace_opt prefix/postfix
assertEquals("123.45",
nf.format(str_white_space + ".12345e3" + str_white_space));
assertEquals("123.45",
nf.format(str_white_space + "+.12345e+3" + str_white_space));
assertEquals("-123.45",
nf.format(str_white_space + "-.12345e3" + str_white_space));
assertEquals("-123.45",
nf.format(str_white_space + "-.12345e+3" + str_white_space));
assertEquals("1,234,567,890,123,456,789,012,345,678,901,234,567,890,123",
nf.format("1234567890123456789012345678901234567890123"));
assertEquals("-1,234,567,890,123,456,789,012,345,678,901,234,567,890,123",
nf.format("-1234567890123456789012345678901234567890123"));
assertEquals(
"1,234,567,890,123,456,789,012,345,678,901,234,567,890,123,000,000,000,000",
nf.format("1234567890123456789012345678901234567890123e12"));
// With StrWhiteSpace_opt prefix/postfix
assertEquals("1,234,567,890,123,456,789,012,345,678,901,234,567,890,123",
nf.format(str_white_space +
"1234567890123456789012345678901234567890123" + str_white_space));
assertEquals("-1,234,567,890,123,456,789,012,345,678,901,234,567,890,123",
nf.format(str_white_space +
"-1234567890123456789012345678901234567890123" + str_white_space));
assertEquals(
"1,234,567,890,123,456,789,012,345,678,901,234,567,890,123,000,000,000,000",
nf.format(str_white_space +
"1234567890123456789012345678901234567890123e12" + str_white_space));
......@@ -42,7 +42,8 @@ validRoundingIncrements.forEach(function(roundingIncrement) {
});
invalidRoundingIncrements.forEach(function(roundingIncrement) {
assertThrows(() => { let nf = new Intl.NumberFormat(undefined, {roundingIncrement,
minimumFractionDigits:3})},
assertThrows(() => {
let nf = new Intl.NumberFormat(undefined,
{roundingIncrement, minimumFractionDigits:3})},
RangeError);
});
......@@ -1940,42 +1940,7 @@
'harness/temporalHelpers-one-shift-time-zone': [SKIP],
# https://bugs.chromium.org/p/v8/issues/detail?id=10776
# NumberFormat.prototype.formatRange
'intl402/NumberFormat/prototype/formatRange/en-US': [FAIL],
'intl402/NumberFormat/prototype/formatRange/pt-PT': [FAIL],
'intl402/NumberFormat/prototype/format/format-max-min-fraction-significant-digits': [FAIL],
# String handling
'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-1': [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/prototype/format/value-decimal-string': [FAIL],
'intl402/NumberFormat/prototype/format/format-rounding-mode-ceil': [SKIP],
'intl402/NumberFormat/prototype/format/format-rounding-mode-expand': [SKIP],
'intl402/NumberFormat/prototype/format/format-rounding-mode-floor': [SKIP],
'intl402/NumberFormat/prototype/format/format-rounding-mode-half-ceil': [SKIP],
'intl402/NumberFormat/prototype/format/format-rounding-mode-half-even': [SKIP],
'intl402/NumberFormat/prototype/format/format-rounding-mode-half-expand': [SKIP],
'intl402/NumberFormat/prototype/format/format-rounding-mode-half-floor': [SKIP],
'intl402/NumberFormat/prototype/format/format-rounding-mode-half-trunc': [SKIP],
'intl402/NumberFormat/prototype/format/format-rounding-mode-trunc': [SKIP],
'intl402/NumberFormat/prototype/format/format-rounding-priority-auto': [SKIP],
'intl402/NumberFormat/prototype/format/format-rounding-priority-less-precision': [SKIP],
'intl402/NumberFormat/prototype/format/format-rounding-priority-more-precision': [SKIP],
'intl402/NumberFormat/test-option-roundingPriority-mixed-options': [SKIP],
'intl402/NumberFormat/test-option-roundingPriority-mixed-options': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=11660
'intl402/DurationFormat/prototype/prototype_attributes': [FAIL],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment