diff options
Diffstat (limited to 'deps/v8/src/objects/js-relative-time-format.cc')
-rw-r--r-- | deps/v8/src/objects/js-relative-time-format.cc | 220 |
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 |