aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/objects/js-relative-time-format.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/objects/js-relative-time-format.cc')
-rw-r--r--deps/v8/src/objects/js-relative-time-format.cc220
1 files changed, 210 insertions, 10 deletions
diff --git a/deps/v8/src/objects/js-relative-time-format.cc b/deps/v8/src/objects/js-relative-time-format.cc
index 56130f7311..b3aa996d64 100644
--- a/deps/v8/src/objects/js-relative-time-format.cc
+++ b/deps/v8/src/objects/js-relative-time-format.cc
@@ -17,9 +17,9 @@
#include "src/objects-inl.h"
#include "src/objects/intl-objects.h"
#include "src/objects/js-relative-time-format-inl.h"
-#include "src/objects/managed.h"
#include "unicode/numfmt.h"
#include "unicode/reldatefmt.h"
+#include "unicode/uvernum.h" // for U_ICU_VERSION_MAJOR_NUM
namespace v8 {
namespace internal {
@@ -54,8 +54,7 @@ JSRelativeTimeFormat::Numeric JSRelativeTimeFormat::getNumeric(
UNREACHABLE();
}
-MaybeHandle<JSRelativeTimeFormat>
-JSRelativeTimeFormat::InitializeRelativeTimeFormat(
+MaybeHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::Initialize(
Isolate* isolate, Handle<JSRelativeTimeFormat> relative_time_format_holder,
Handle<Object> input_locales, Handle<Object> input_options) {
Factory* factory = isolate->factory();
@@ -161,7 +160,7 @@ JSRelativeTimeFormat::InitializeRelativeTimeFormat(
icu_formatter);
// 30. Set relativeTimeFormat.[[InitializedRelativeTimeFormat]] to true.
- relative_time_format_holder->set_formatter(*managed_formatter);
+ relative_time_format_holder->set_icu_formatter(*managed_formatter);
// 31. Return relativeTimeFormat.
return relative_time_format_holder;
}
@@ -180,12 +179,6 @@ Handle<JSObject> JSRelativeTimeFormat::ResolvedOptions(
return result;
}
-icu::RelativeDateTimeFormatter* JSRelativeTimeFormat::UnpackFormatter(
- Handle<JSRelativeTimeFormat> holder) {
- return Managed<icu::RelativeDateTimeFormatter>::cast(holder->formatter())
- ->raw();
-}
-
Handle<String> JSRelativeTimeFormat::StyleAsString() const {
switch (style()) {
case Style::LONG:
@@ -210,5 +203,212 @@ Handle<String> JSRelativeTimeFormat::NumericAsString() const {
}
}
+namespace {
+
+Handle<String> UnitAsString(Isolate* isolate, URelativeDateTimeUnit unit_enum) {
+ Factory* factory = isolate->factory();
+ switch (unit_enum) {
+ case UDAT_REL_UNIT_SECOND:
+ return factory->second_string();
+ case UDAT_REL_UNIT_MINUTE:
+ return factory->minute_string();
+ case UDAT_REL_UNIT_HOUR:
+ return factory->hour_string();
+ case UDAT_REL_UNIT_DAY:
+ return factory->day_string();
+ case UDAT_REL_UNIT_WEEK:
+ return factory->week_string();
+ case UDAT_REL_UNIT_MONTH:
+ return factory->month_string();
+ case UDAT_REL_UNIT_QUARTER:
+ return factory->quarter_string();
+ case UDAT_REL_UNIT_YEAR:
+ return factory->year_string();
+ default:
+ UNREACHABLE();
+ }
+}
+
+MaybeHandle<JSArray> GenerateRelativeTimeFormatParts(
+ Isolate* isolate, const icu::UnicodeString& formatted,
+ const icu::UnicodeString& integer_part, URelativeDateTimeUnit unit_enum) {
+ Factory* factory = isolate->factory();
+ Handle<JSArray> array = factory->NewJSArray(0);
+ int32_t found = formatted.indexOf(integer_part);
+
+ Handle<String> substring;
+ if (found < 0) {
+ // Cannot find the integer_part in the formatted.
+ // Return [{'type': 'literal', 'value': formatted}]
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, substring,
+ Intl::ToString(isolate, formatted), JSArray);
+ Intl::AddElement(isolate, array,
+ 0, // index
+ factory->literal_string(), // field_type_string
+ substring);
+ } else {
+ // Found the formatted integer in the result.
+ int index = 0;
+
+ // array.push({
+ // 'type': 'literal',
+ // 'value': formatted.substring(0, found)})
+ if (found > 0) {
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, substring,
+ Intl::ToString(isolate, formatted, 0, found),
+ JSArray);
+ Intl::AddElement(isolate, array, index++,
+ factory->literal_string(), // field_type_string
+ substring);
+ }
+
+ // array.push({
+ // 'type': 'integer',
+ // 'value': formatted.substring(found, found + integer_part.length),
+ // 'unit': unit})
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, substring,
+ Intl::ToString(isolate, formatted, found,
+ found + integer_part.length()),
+ JSArray);
+ Handle<String> unit = UnitAsString(isolate, unit_enum);
+ Intl::AddElement(isolate, array, index++,
+ factory->integer_string(), // field_type_string
+ substring, factory->unit_string(), unit);
+
+ // array.push({
+ // 'type': 'literal',
+ // 'value': formatted.substring(
+ // found + integer_part.length, formatted.length)})
+ if (found + integer_part.length() < formatted.length()) {
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, substring,
+ Intl::ToString(isolate, formatted, found + integer_part.length(),
+ formatted.length()),
+ JSArray);
+ Intl::AddElement(isolate, array, index,
+ factory->literal_string(), // field_type_string
+ substring);
+ }
+ }
+ return array;
+}
+
+bool GetURelativeDateTimeUnit(Handle<String> unit,
+ URelativeDateTimeUnit* unit_enum) {
+ std::unique_ptr<char[]> unit_str = unit->ToCString();
+ if ((strcmp("second", unit_str.get()) == 0) ||
+ (strcmp("seconds", unit_str.get()) == 0)) {
+ *unit_enum = UDAT_REL_UNIT_SECOND;
+ } else if ((strcmp("minute", unit_str.get()) == 0) ||
+ (strcmp("minutes", unit_str.get()) == 0)) {
+ *unit_enum = UDAT_REL_UNIT_MINUTE;
+ } else if ((strcmp("hour", unit_str.get()) == 0) ||
+ (strcmp("hours", unit_str.get()) == 0)) {
+ *unit_enum = UDAT_REL_UNIT_HOUR;
+ } else if ((strcmp("day", unit_str.get()) == 0) ||
+ (strcmp("days", unit_str.get()) == 0)) {
+ *unit_enum = UDAT_REL_UNIT_DAY;
+ } else if ((strcmp("week", unit_str.get()) == 0) ||
+ (strcmp("weeks", unit_str.get()) == 0)) {
+ *unit_enum = UDAT_REL_UNIT_WEEK;
+ } else if ((strcmp("month", unit_str.get()) == 0) ||
+ (strcmp("months", unit_str.get()) == 0)) {
+ *unit_enum = UDAT_REL_UNIT_MONTH;
+ } else if ((strcmp("quarter", unit_str.get()) == 0) ||
+ (strcmp("quarters", unit_str.get()) == 0)) {
+ *unit_enum = UDAT_REL_UNIT_QUARTER;
+ } else if ((strcmp("year", unit_str.get()) == 0) ||
+ (strcmp("years", unit_str.get()) == 0)) {
+ *unit_enum = UDAT_REL_UNIT_YEAR;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+MaybeHandle<Object> JSRelativeTimeFormat::Format(
+ Isolate* isolate, Handle<Object> value_obj, Handle<Object> unit_obj,
+ Handle<JSRelativeTimeFormat> format_holder, const char* func_name,
+ bool to_parts) {
+ Factory* factory = isolate->factory();
+
+ // 3. Let value be ? ToNumber(value).
+ Handle<Object> value;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
+ Object::ToNumber(isolate, value_obj), Object);
+ double number = value->Number();
+ // 4. Let unit be ? ToString(unit).
+ Handle<String> unit;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate, unit, Object::ToString(isolate, unit_obj),
+ Object);
+
+ // 4. If isFinite(value) is false, then throw a RangeError exception.
+ if (!std::isfinite(number)) {
+ THROW_NEW_ERROR(
+ isolate,
+ NewRangeError(MessageTemplate::kNotFiniteNumber,
+ isolate->factory()->NewStringFromAsciiChecked(func_name)),
+ Object);
+ }
+
+ icu::RelativeDateTimeFormatter* formatter =
+ format_holder->icu_formatter()->raw();
+ CHECK_NOT_NULL(formatter);
+
+ URelativeDateTimeUnit unit_enum;
+ if (!GetURelativeDateTimeUnit(unit, &unit_enum)) {
+ THROW_NEW_ERROR(
+ isolate,
+ NewRangeError(MessageTemplate::kInvalidUnit,
+ isolate->factory()->NewStringFromAsciiChecked(func_name),
+ unit),
+ Object);
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ icu::UnicodeString formatted;
+
+#if USE_CHROMIUM_ICU != 1 && U_ICU_VERSION_MAJOR_NUM < 63
+ if (unit_enum != UDAT_REL_UNIT_QUARTER) { // ICU did not implement
+ // UDAT_REL_UNIT_QUARTER < 63
+#endif // USE_CHROMIUM_ICU != 1 && U_ICU_VERSION_MAJOR_NUM < 63
+ if (format_holder->numeric() == JSRelativeTimeFormat::Numeric::ALWAYS) {
+ formatter->formatNumeric(number, unit_enum, formatted, status);
+ } else {
+ DCHECK_EQ(JSRelativeTimeFormat::Numeric::AUTO, format_holder->numeric());
+ formatter->format(number, unit_enum, formatted, status);
+ }
+#if USE_CHROMIUM_ICU != 1 && U_ICU_VERSION_MAJOR_NUM < 63
+ }
+#endif // USE_CHROMIUM_ICU != 1 && U_ICU_VERSION_MAJOR_NUM < 63
+
+ if (U_FAILURE(status)) {
+ THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError), Object);
+ }
+
+ if (to_parts) {
+ icu::UnicodeString integer;
+ icu::FieldPosition pos;
+ formatter->getNumberFormat().format(std::abs(number), integer, pos, status);
+ if (U_FAILURE(status)) {
+ THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError),
+ Object);
+ }
+
+ Handle<JSArray> elements;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, elements,
+ GenerateRelativeTimeFormatParts(isolate, formatted, integer, unit_enum),
+ Object);
+ return elements;
+ }
+
+ return factory->NewStringFromTwoByte(Vector<const uint16_t>(
+ reinterpret_cast<const uint16_t*>(formatted.getBuffer()),
+ formatted.length()));
+}
+
} // namespace internal
} // namespace v8