[intl] NumberFormat v3 Part 4 SelectRange
Implement the Intl.PluralRules.prototype.selectRange (start, end) of the spec See https://tc39.es/proposal-intl-numberformat-v3/out/pluralrules/diff.html https://chromestatus.com/guide/edit/5707621009981440 Design Doc: https://docs.google.com/document/d/19jAogPBb6W4Samt8NWGZKu47iv0_KoQhBvLgQH3xvr8/edit Bug: v8:10776 Change-Id: Ie9c56df7ce68199492281fdf2483c3d6f822cc9e Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3504421 Reviewed-by: Shu-yu Guo <syg@chromium.org> Commit-Queue: Frank Tang <ftang@chromium.org> Cr-Commit-Position: refs/heads/main@{#79495}
This commit is contained in:
parent
d782fd1da9
commit
09de56b06e
@ -1789,6 +1789,8 @@ namespace internal {
|
|||||||
CPP(PluralRulesPrototypeResolvedOptions) \
|
CPP(PluralRulesPrototypeResolvedOptions) \
|
||||||
/* ecma402 #sec-intl.pluralrules.prototype.select */ \
|
/* ecma402 #sec-intl.pluralrules.prototype.select */ \
|
||||||
CPP(PluralRulesPrototypeSelect) \
|
CPP(PluralRulesPrototypeSelect) \
|
||||||
|
/* ecma402 #sec-intl.pluralrules.prototype.selectrange */ \
|
||||||
|
CPP(PluralRulesPrototypeSelectRange) \
|
||||||
/* ecma402 #sec-intl.pluralrules.supportedlocalesof */ \
|
/* ecma402 #sec-intl.pluralrules.supportedlocalesof */ \
|
||||||
CPP(PluralRulesSupportedLocalesOf) \
|
CPP(PluralRulesSupportedLocalesOf) \
|
||||||
/* ecma402 #sec-intl.RelativeTimeFormat.constructor */ \
|
/* ecma402 #sec-intl.RelativeTimeFormat.constructor */ \
|
||||||
|
@ -987,6 +987,64 @@ BUILTIN(PluralRulesPrototypeSelect) {
|
|||||||
isolate, plural_rules, number_double));
|
isolate, plural_rules, number_double));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BUILTIN(PluralRulesPrototypeSelectRange) {
|
||||||
|
HandleScope scope(isolate);
|
||||||
|
|
||||||
|
// 1. Let pr be the this value.
|
||||||
|
// 2. Perform ? RequireInternalSlot(pr, [[InitializedPluralRules]]).
|
||||||
|
CHECK_RECEIVER(JSPluralRules, plural_rules,
|
||||||
|
"Intl.PluralRules.prototype.selectRange");
|
||||||
|
|
||||||
|
// 3. If start is undefined or end is undefined, throw a TypeError exception.
|
||||||
|
Handle<Object> start = args.atOrUndefined(isolate, 1);
|
||||||
|
Handle<Object> end = args.atOrUndefined(isolate, 2);
|
||||||
|
if (start->IsUndefined()) {
|
||||||
|
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||||
|
isolate, NewTypeError(MessageTemplate::kInvalid,
|
||||||
|
isolate->factory()->startRange_string(), start));
|
||||||
|
}
|
||||||
|
if (end->IsUndefined()) {
|
||||||
|
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||||
|
isolate, NewTypeError(MessageTemplate::kInvalid,
|
||||||
|
isolate->factory()->endRange_string(), end));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Let x be ? ToNumber(start).
|
||||||
|
Handle<Object> x;
|
||||||
|
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x,
|
||||||
|
Object::ToNumber(isolate, start));
|
||||||
|
|
||||||
|
// 5. Let y be ? ToNumber(end).
|
||||||
|
Handle<Object> y;
|
||||||
|
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, y,
|
||||||
|
Object::ToNumber(isolate, end));
|
||||||
|
|
||||||
|
// 6. Return ! ResolvePluralRange(pr, x, y).
|
||||||
|
// Inside ResolvePluralRange
|
||||||
|
// 5. If x is NaN or y is NaN, throw a RangeError exception.
|
||||||
|
if (x->IsNaN()) {
|
||||||
|
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||||
|
isolate, NewRangeError(MessageTemplate::kInvalid,
|
||||||
|
isolate->factory()->startRange_string(), x));
|
||||||
|
}
|
||||||
|
if (y->IsNaN()) {
|
||||||
|
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||||
|
isolate, NewRangeError(MessageTemplate::kInvalid,
|
||||||
|
isolate->factory()->endRange_string(), y));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. If x > y, throw a RangeError exception.
|
||||||
|
double x_double = x->Number();
|
||||||
|
double y_double = y->Number();
|
||||||
|
if (x_double > y_double) {
|
||||||
|
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||||
|
isolate, NewRangeError(MessageTemplate::kInvalid, x, y));
|
||||||
|
}
|
||||||
|
RETURN_RESULT_OR_FAILURE(
|
||||||
|
isolate, JSPluralRules::ResolvePluralRange(isolate, plural_rules,
|
||||||
|
x_double, y_double));
|
||||||
|
}
|
||||||
|
|
||||||
BUILTIN(PluralRulesSupportedLocalesOf) {
|
BUILTIN(PluralRulesSupportedLocalesOf) {
|
||||||
HandleScope scope(isolate);
|
HandleScope scope(isolate);
|
||||||
Handle<Object> locales = args.atOrUndefined(isolate, 1);
|
Handle<Object> locales = args.atOrUndefined(isolate, 1);
|
||||||
|
@ -5351,20 +5351,35 @@ void Genesis::InitializeGlobal_harmony_intl_number_format_v3() {
|
|||||||
factory()->InternalizeUtf8String("Intl"))
|
factory()->InternalizeUtf8String("Intl"))
|
||||||
.ToHandleChecked());
|
.ToHandleChecked());
|
||||||
|
|
||||||
Handle<JSFunction> number_format_constructor = Handle<JSFunction>::cast(
|
{
|
||||||
JSReceiver::GetProperty(
|
Handle<JSFunction> number_format_constructor = Handle<JSFunction>::cast(
|
||||||
isolate(), Handle<JSReceiver>(JSReceiver::cast(*intl), isolate()),
|
JSReceiver::GetProperty(
|
||||||
factory()->InternalizeUtf8String("NumberFormat"))
|
isolate(), Handle<JSReceiver>(JSReceiver::cast(*intl), isolate()),
|
||||||
.ToHandleChecked());
|
factory()->InternalizeUtf8String("NumberFormat"))
|
||||||
|
.ToHandleChecked());
|
||||||
|
|
||||||
Handle<JSObject> prototype(
|
Handle<JSObject> prototype(
|
||||||
JSObject::cast(number_format_constructor->prototype()), isolate());
|
JSObject::cast(number_format_constructor->prototype()), isolate());
|
||||||
|
|
||||||
SimpleInstallFunction(isolate(), prototype, "formatRange",
|
SimpleInstallFunction(isolate(), prototype, "formatRange",
|
||||||
Builtin::kNumberFormatPrototypeFormatRange, 2, false);
|
Builtin::kNumberFormatPrototypeFormatRange, 2, false);
|
||||||
SimpleInstallFunction(isolate(), prototype, "formatRangeToParts",
|
SimpleInstallFunction(isolate(), prototype, "formatRangeToParts",
|
||||||
Builtin::kNumberFormatPrototypeFormatRangeToParts, 2,
|
Builtin::kNumberFormatPrototypeFormatRangeToParts, 2,
|
||||||
false);
|
false);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Handle<JSFunction> plural_rules_constructor = Handle<JSFunction>::cast(
|
||||||
|
JSReceiver::GetProperty(
|
||||||
|
isolate(), Handle<JSReceiver>(JSReceiver::cast(*intl), isolate()),
|
||||||
|
factory()->InternalizeUtf8String("PluralRules"))
|
||||||
|
.ToHandleChecked());
|
||||||
|
|
||||||
|
Handle<JSObject> prototype(
|
||||||
|
JSObject::cast(plural_rules_constructor->prototype()), isolate());
|
||||||
|
|
||||||
|
SimpleInstallFunction(isolate(), prototype, "selectRange",
|
||||||
|
Builtin::kPluralRulesPrototypeSelectRange, 2, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // V8_INTL_SUPPORT
|
#endif // V8_INTL_SUPPORT
|
||||||
|
@ -28,6 +28,9 @@ ACCESSORS(JSPluralRules, icu_plural_rules, Managed<icu::PluralRules>,
|
|||||||
ACCESSORS(JSPluralRules, icu_number_formatter,
|
ACCESSORS(JSPluralRules, icu_number_formatter,
|
||||||
Managed<icu::number::LocalizedNumberFormatter>,
|
Managed<icu::number::LocalizedNumberFormatter>,
|
||||||
kIcuNumberFormatterOffset)
|
kIcuNumberFormatterOffset)
|
||||||
|
ACCESSORS(JSPluralRules, icu_number_range_formatter,
|
||||||
|
Managed<icu::number::LocalizedNumberRangeFormatter>,
|
||||||
|
kIcuNumberRangeFormatterOffset)
|
||||||
|
|
||||||
inline void JSPluralRules::set_type(Type type) {
|
inline void JSPluralRules::set_type(Type type) {
|
||||||
DCHECK_LE(type, TypeBit::kMax);
|
DCHECK_LE(type, TypeBit::kMax);
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "src/objects/option-utils.h"
|
#include "src/objects/option-utils.h"
|
||||||
#include "unicode/locid.h"
|
#include "unicode/locid.h"
|
||||||
#include "unicode/numberformatter.h"
|
#include "unicode/numberformatter.h"
|
||||||
|
#include "unicode/numberrangeformatter.h"
|
||||||
#include "unicode/plurrule.h"
|
#include "unicode/plurrule.h"
|
||||||
#include "unicode/unumberformatter.h"
|
#include "unicode/unumberformatter.h"
|
||||||
|
|
||||||
@ -145,6 +146,10 @@ MaybeHandle<JSPluralRules> JSPluralRules::New(Isolate* isolate, Handle<Map> map,
|
|||||||
|
|
||||||
icu::number::LocalizedNumberFormatter icu_number_formatter =
|
icu::number::LocalizedNumberFormatter icu_number_formatter =
|
||||||
settings.locale(icu_locale);
|
settings.locale(icu_locale);
|
||||||
|
icu::number::LocalizedNumberRangeFormatter icu_number_range_formatter =
|
||||||
|
icu::number::UnlocalizedNumberRangeFormatter()
|
||||||
|
.numberFormatterBoth(settings)
|
||||||
|
.locale(icu_locale);
|
||||||
|
|
||||||
Handle<Managed<icu::PluralRules>> managed_plural_rules =
|
Handle<Managed<icu::PluralRules>> managed_plural_rules =
|
||||||
Managed<icu::PluralRules>::FromUniquePtr(isolate, 0,
|
Managed<icu::PluralRules>::FromUniquePtr(isolate, 0,
|
||||||
@ -155,6 +160,12 @@ MaybeHandle<JSPluralRules> JSPluralRules::New(Isolate* isolate, Handle<Map> map,
|
|||||||
Managed<icu::number::LocalizedNumberFormatter>::FromRawPtr(
|
Managed<icu::number::LocalizedNumberFormatter>::FromRawPtr(
|
||||||
isolate, 0,
|
isolate, 0,
|
||||||
new icu::number::LocalizedNumberFormatter(icu_number_formatter));
|
new icu::number::LocalizedNumberFormatter(icu_number_formatter));
|
||||||
|
Handle<Managed<icu::number::LocalizedNumberRangeFormatter>>
|
||||||
|
managed_number_range_formatter =
|
||||||
|
Managed<icu::number::LocalizedNumberRangeFormatter>::FromRawPtr(
|
||||||
|
isolate, 0,
|
||||||
|
new icu::number::LocalizedNumberRangeFormatter(
|
||||||
|
icu_number_range_formatter));
|
||||||
|
|
||||||
// Now all properties are ready, so we can allocate the result object.
|
// Now all properties are ready, so we can allocate the result object.
|
||||||
Handle<JSPluralRules> plural_rules = Handle<JSPluralRules>::cast(
|
Handle<JSPluralRules> plural_rules = Handle<JSPluralRules>::cast(
|
||||||
@ -170,6 +181,7 @@ MaybeHandle<JSPluralRules> JSPluralRules::New(Isolate* isolate, Handle<Map> map,
|
|||||||
|
|
||||||
plural_rules->set_icu_plural_rules(*managed_plural_rules);
|
plural_rules->set_icu_plural_rules(*managed_plural_rules);
|
||||||
plural_rules->set_icu_number_formatter(*managed_number_formatter);
|
plural_rules->set_icu_number_formatter(*managed_number_formatter);
|
||||||
|
plural_rules->set_icu_number_range_formatter(*managed_number_range_formatter);
|
||||||
|
|
||||||
// 13. Return pluralRules.
|
// 13. Return pluralRules.
|
||||||
return plural_rules;
|
return plural_rules;
|
||||||
@ -196,6 +208,26 @@ MaybeHandle<String> JSPluralRules::ResolvePlural(
|
|||||||
return Intl::ToString(isolate, result);
|
return Intl::ToString(isolate, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeHandle<String> JSPluralRules::ResolvePluralRange(
|
||||||
|
Isolate* isolate, Handle<JSPluralRules> plural_rules, double x, double y) {
|
||||||
|
icu::PluralRules* icu_plural_rules = plural_rules->icu_plural_rules().raw();
|
||||||
|
DCHECK_NOT_NULL(icu_plural_rules);
|
||||||
|
|
||||||
|
icu::number::LocalizedNumberRangeFormatter* fmt =
|
||||||
|
plural_rules->icu_number_range_formatter().raw();
|
||||||
|
DCHECK_NOT_NULL(fmt);
|
||||||
|
|
||||||
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
|
icu::number::FormattedNumberRange formatted = fmt->formatFormattableRange(
|
||||||
|
icu::Formattable(x), icu::Formattable(y), status);
|
||||||
|
|
||||||
|
DCHECK(U_SUCCESS(status));
|
||||||
|
icu::UnicodeString result = icu_plural_rules->select(formatted, status);
|
||||||
|
DCHECK(U_SUCCESS(status));
|
||||||
|
|
||||||
|
return Intl::ToString(isolate, result);
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void CreateDataPropertyForOptions(Isolate* isolate, Handle<JSObject> options,
|
void CreateDataPropertyForOptions(Isolate* isolate, Handle<JSObject> options,
|
||||||
|
@ -26,6 +26,7 @@ namespace U_ICU_NAMESPACE {
|
|||||||
class PluralRules;
|
class PluralRules;
|
||||||
namespace number {
|
namespace number {
|
||||||
class LocalizedNumberFormatter;
|
class LocalizedNumberFormatter;
|
||||||
|
class LocalizedNumberRangeFormatter;
|
||||||
} // namespace number
|
} // namespace number
|
||||||
} // namespace U_ICU_NAMESPACE
|
} // namespace U_ICU_NAMESPACE
|
||||||
|
|
||||||
@ -47,6 +48,9 @@ class JSPluralRules
|
|||||||
V8_WARN_UNUSED_RESULT static MaybeHandle<String> ResolvePlural(
|
V8_WARN_UNUSED_RESULT static MaybeHandle<String> ResolvePlural(
|
||||||
Isolate* isolate, Handle<JSPluralRules> plural_rules, double number);
|
Isolate* isolate, Handle<JSPluralRules> plural_rules, double number);
|
||||||
|
|
||||||
|
V8_WARN_UNUSED_RESULT static MaybeHandle<String> ResolvePluralRange(
|
||||||
|
Isolate* isolate, Handle<JSPluralRules> plural_rules, double x, double y);
|
||||||
|
|
||||||
V8_EXPORT_PRIVATE static const std::set<std::string>& GetAvailableLocales();
|
V8_EXPORT_PRIVATE static const std::set<std::string>& GetAvailableLocales();
|
||||||
|
|
||||||
// [[Type]] is one of the values "cardinal" or "ordinal",
|
// [[Type]] is one of the values "cardinal" or "ordinal",
|
||||||
@ -68,6 +72,8 @@ class JSPluralRules
|
|||||||
DECL_ACCESSORS(icu_plural_rules, Managed<icu::PluralRules>)
|
DECL_ACCESSORS(icu_plural_rules, Managed<icu::PluralRules>)
|
||||||
DECL_ACCESSORS(icu_number_formatter,
|
DECL_ACCESSORS(icu_number_formatter,
|
||||||
Managed<icu::number::LocalizedNumberFormatter>)
|
Managed<icu::number::LocalizedNumberFormatter>)
|
||||||
|
DECL_ACCESSORS(icu_number_range_formatter,
|
||||||
|
Managed<icu::number::LocalizedNumberRangeFormatter>)
|
||||||
|
|
||||||
TQ_OBJECT_CONSTRUCTORS(JSPluralRules)
|
TQ_OBJECT_CONSTRUCTORS(JSPluralRules)
|
||||||
};
|
};
|
||||||
|
@ -15,4 +15,6 @@ extern class JSPluralRules extends JSObject {
|
|||||||
icu_plural_rules: Foreign; // Managed<icu::PluralRules>
|
icu_plural_rules: Foreign; // Managed<icu::PluralRules>
|
||||||
icu_number_formatter:
|
icu_number_formatter:
|
||||||
Foreign; // Managed<icu::number::LocalizedNumberFormatter>
|
Foreign; // Managed<icu::number::LocalizedNumberFormatter>
|
||||||
|
icu_number_range_formatter:
|
||||||
|
Foreign; // Managed<icu::number::LocalizedNumberRangeFormatter>
|
||||||
}
|
}
|
||||||
|
7
test/intl/plural-rules/select-range.js
Normal file
7
test/intl/plural-rules/select-range.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// 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
|
||||||
|
const pl = new Intl.PluralRules("sl");
|
||||||
|
assertEquals("few", pl.selectRange(102, 201));
|
@ -2776,15 +2776,6 @@
|
|||||||
'intl402/NumberFormat/prototype/formatRange/x-greater-than-y-throws': [FAIL],
|
'intl402/NumberFormat/prototype/formatRange/x-greater-than-y-throws': [FAIL],
|
||||||
'intl402/NumberFormat/prototype/formatRangeToParts/x-greater-than-y-throws': [FAIL],
|
'intl402/NumberFormat/prototype/formatRangeToParts/x-greater-than-y-throws': [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/prop-desc': [FAIL],
|
|
||||||
'intl402/PluralRules/prototype/selectRange/nan-arguments-throws': [FAIL],
|
|
||||||
'intl402/PluralRules/prototype/selectRange/x-greater-than-y-throws': [FAIL],
|
|
||||||
|
|
||||||
# String handling
|
# String handling
|
||||||
'intl402/NumberFormat/prototype/format/format-rounding-increment-1000': [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-100': [FAIL],
|
||||||
|
Loading…
Reference in New Issue
Block a user