Commit ccbe3d07 authored by Frank Tang's avatar Frank Tang Committed by Commit Bot

[Intl] Upgrade RelativeTimeFormat formatToParts

1. Add Intl::NumberFieldToType to support RelativeTimeFormat
by refactoring IcuNumberFieldIdToNumberType
2. Use formatNumericToValue / formatToValue to implement formatToParts

Bug: v8:8837
Change-Id: I4d8fab9c337ec02eeb3500b4c0f90547e48444e3
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1560661Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Commit-Queue: Frank Tang <ftang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60797}
parent af1988f1
......@@ -705,7 +705,7 @@ BUILTIN(RelativeTimeFormatPrototypeFormat) {
RETURN_RESULT_OR_FAILURE(
isolate, JSRelativeTimeFormat::Format(isolate, value_obj, unit_obj,
format_holder, "format", false));
format_holder));
}
BUILTIN(RelativeTimeFormatPrototypeFormatToParts) {
......@@ -718,9 +718,9 @@ BUILTIN(RelativeTimeFormatPrototypeFormatToParts) {
"Intl.RelativeTimeFormat.prototype.formatToParts");
Handle<Object> value_obj = args.atOrUndefined(isolate, 1);
Handle<Object> unit_obj = args.atOrUndefined(isolate, 2);
RETURN_RESULT_OR_FAILURE(isolate, JSRelativeTimeFormat::Format(
isolate, value_obj, unit_obj,
format_holder, "formatToParts", true));
RETURN_RESULT_OR_FAILURE(
isolate, JSRelativeTimeFormat::FormatToParts(isolate, value_obj, unit_obj,
format_holder));
}
// Locale getters.
......
......@@ -1878,5 +1878,61 @@ const std::set<std::string>& Intl::GetAvailableLocalesForDateFormat() {
return available_locales.Pointer()->Get();
}
Handle<String> Intl::NumberFieldToType(Isolate* isolate,
Handle<Object> numeric_obj,
int32_t field_id) {
DCHECK(numeric_obj->IsNumeric());
switch (static_cast<UNumberFormatFields>(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();
return isolate->factory()->infinity_string();
}
case UNUM_FRACTION_FIELD:
return isolate->factory()->fraction_string();
case UNUM_DECIMAL_SEPARATOR_FIELD:
return isolate->factory()->decimal_string();
case UNUM_GROUPING_SEPARATOR_FIELD:
return isolate->factory()->group_string();
case UNUM_CURRENCY_FIELD:
return isolate->factory()->currency_string();
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 number < 0 ? isolate->factory()->minusSign_string()
: isolate->factory()->plusSign_string();
}
case UNUM_EXPONENT_SYMBOL_FIELD:
case UNUM_EXPONENT_SIGN_FIELD:
case UNUM_EXPONENT_FIELD:
// We should never get these because we're not using any scientific
// formatter.
UNREACHABLE();
return Handle<String>();
case UNUM_PERMILL_FIELD:
// We're not creating any permill formatter, and it's not even clear how
// that would be possible with the ICU API.
UNREACHABLE();
return Handle<String>();
default:
UNREACHABLE();
return Handle<String>();
}
}
} // namespace internal
} // namespace v8
......@@ -20,7 +20,7 @@
#include "unicode/locid.h"
#include "unicode/uversion.h"
#define V8_MINIMUM_ICU_VERSION 63
#define V8_MINIMUM_ICU_VERSION 64
namespace U_ICU_NAMESPACE {
class BreakIterator;
......@@ -186,6 +186,11 @@ class Intl {
Isolate* isolate, const icu::UnicodeString& string, int32_t begin,
int32_t end);
// Helper function to convert number field id to type string.
static Handle<String> NumberFieldToType(Isolate* isolate,
Handle<Object> numeric_obj,
int32_t field_id);
// A helper function to implement formatToParts which add element to array as
// $array[$index] = { type: $field_type_string, value: $value }
static void AddElement(Isolate* isolate, Handle<JSArray> array, int index,
......
......@@ -559,64 +559,6 @@ bool cmp_NumberFormatSpan(const NumberFormatSpan& a,
return a.field_id < b.field_id;
}
// The list comes from third_party/icu/source/i18n/unicode/unum.h.
// They're mapped to NumberFormat part types mentioned throughout
// https://tc39.github.io/ecma402/#sec-partitionnumberpattern .
Handle<String> IcuNumberFieldIdToNumberType(int32_t field_id,
Handle<Object> numeric_obj,
Isolate* isolate) {
DCHECK(numeric_obj->IsNumeric());
switch (static_cast<UNumberFormatFields>(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();
return isolate->factory()->infinity_string();
}
case UNUM_FRACTION_FIELD:
return isolate->factory()->fraction_string();
case UNUM_DECIMAL_SEPARATOR_FIELD:
return isolate->factory()->decimal_string();
case UNUM_GROUPING_SEPARATOR_FIELD:
return isolate->factory()->group_string();
case UNUM_CURRENCY_FIELD:
return isolate->factory()->currency_string();
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 number < 0 ? isolate->factory()->minusSign_string()
: isolate->factory()->plusSign_string();
}
case UNUM_EXPONENT_SYMBOL_FIELD:
case UNUM_EXPONENT_SIGN_FIELD:
case UNUM_EXPONENT_FIELD:
// We should never get these because we're not using any scientific
// formatter.
UNREACHABLE();
return Handle<String>();
case UNUM_PERMILL_FIELD:
// We're not creating any permill formatter, and it's not even clear how
// that would be possible with the ICU API.
UNREACHABLE();
return Handle<String>();
default:
UNREACHABLE();
return Handle<String>();
}
}
} // namespace
// Flattens a list of possibly-overlapping "regions" to a list of
......@@ -748,7 +690,7 @@ Maybe<int> JSNumberFormat::FormatToParts(Isolate* isolate,
Handle<String> field_type_string =
part.field_id == -1
? isolate->factory()->literal_string()
: IcuNumberFieldIdToNumberType(part.field_id, numeric_obj, isolate);
: Intl::NumberFieldToType(isolate, numeric_obj, part.field_id);
Handle<String> substring;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, substring,
......
This diff is collapsed.
......@@ -44,11 +44,14 @@ class JSRelativeTimeFormat : public JSObject {
Handle<String> NumericAsString() const;
// ecma402/#sec-Intl.RelativeTimeFormat.prototype.format
V8_WARN_UNUSED_RESULT static MaybeHandle<String> Format(
Isolate* isolate, Handle<Object> value_obj, Handle<Object> unit_obj,
Handle<JSRelativeTimeFormat> format);
// ecma402/#sec-Intl.RelativeTimeFormat.prototype.formatToParts
V8_WARN_UNUSED_RESULT static MaybeHandle<Object> Format(
V8_WARN_UNUSED_RESULT static MaybeHandle<JSArray> FormatToParts(
Isolate* isolate, Handle<Object> value_obj, Handle<Object> unit_obj,
Handle<JSRelativeTimeFormat> format_holder, const char* func_name,
bool to_parts);
Handle<JSRelativeTimeFormat> format);
V8_EXPORT_PRIVATE static const std::set<std::string>& GetAvailableLocales();
......@@ -107,7 +110,6 @@ class JSRelativeTimeFormat : public JSObject {
// Layout description.
#define JS_RELATIVE_TIME_FORMAT_FIELDS(V) \
V(kJSRelativeTimeFormatOffset, kTaggedSize) \
V(kLocaleOffset, kTaggedSize) \
V(kICUFormatterOffset, kTaggedSize) \
V(kFlagsOffset, kTaggedSize) \
......
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