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

[Intl] Move code into src/objects/js-relative-time-format*

Bug: v8:7869
Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng
Change-Id: Idaa9ff1c5c46051aacaa2691e539484295622b8d
Reviewed-on: https://chromium-review.googlesource.com/1195076Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Commit-Queue: Frank Tang <ftang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55505}
parent 660514b0
......@@ -32,12 +32,10 @@
#include "unicode/listformatter.h"
#include "unicode/normalizer2.h"
#include "unicode/numfmt.h"
#include "unicode/reldatefmt.h"
#include "unicode/smpdtfmt.h"
#include "unicode/udat.h"
#include "unicode/ufieldpositer.h"
#include "unicode/unistr.h"
#include "unicode/ureldatefmt.h"
#include "unicode/ustring.h"
namespace v8 {
......@@ -834,186 +832,6 @@ BUILTIN(LocalePrototypeMinimize) {
isolate->factory()->NewJSObjectWithNullProto()));
}
namespace {
MaybeHandle<JSArray> GenerateRelativeTimeFormatParts(
Isolate* isolate, icu::UnicodeString formatted,
icu::UnicodeString integer_part, Handle<String> unit) {
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);
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;
}
MaybeHandle<Object> RelativeTimeFormatPrototypeFormatCommon(
BuiltinArguments args, Isolate* isolate,
Handle<JSRelativeTimeFormat> format_holder, const char* func_name,
bool to_parts) {
Factory* factory = isolate->factory();
Handle<Object> value_obj = args.atOrUndefined(isolate, 1);
Handle<Object> unit_obj = args.atOrUndefined(isolate, 2);
// 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 =
JSRelativeTimeFormat::UnpackFormatter(format_holder);
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 (unit_enum == UDAT_REL_UNIT_QUARTER) {
// ICU have not yet implement UDAT_REL_UNIT_QUARTER.
} else {
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 (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),
Object);
return elements;
}
return factory->NewStringFromTwoByte(Vector<const uint16_t>(
reinterpret_cast<const uint16_t*>(formatted.getBuffer()),
formatted.length()));
}
} // namespace
BUILTIN(RelativeTimeFormatSupportedLocalesOf) {
HandleScope scope(isolate);
RETURN_RESULT_OR_FAILURE(
......@@ -1028,9 +846,12 @@ BUILTIN(RelativeTimeFormatPrototypeFormat) {
// true, throw a TypeError exception.
CHECK_RECEIVER(JSRelativeTimeFormat, format_holder,
"Intl.RelativeTimeFormat.prototype.format");
RETURN_RESULT_OR_FAILURE(isolate,
RelativeTimeFormatPrototypeFormatCommon(
args, isolate, format_holder, "format", false));
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, "format", false));
}
BUILTIN(RelativeTimeFormatPrototypeFormatToParts) {
......@@ -1041,9 +862,11 @@ BUILTIN(RelativeTimeFormatPrototypeFormatToParts) {
// true, throw a TypeError exception.
CHECK_RECEIVER(JSRelativeTimeFormat, format_holder,
"Intl.RelativeTimeFormat.prototype.formatToParts");
RETURN_RESULT_OR_FAILURE(
isolate, RelativeTimeFormatPrototypeFormatCommon(
args, isolate, format_holder, "formatToParts", true));
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));
}
// Locale getters.
......
......@@ -210,5 +210,183 @@ Handle<String> JSRelativeTimeFormat::NumericAsString() const {
}
}
namespace {
MaybeHandle<JSArray> GenerateRelativeTimeFormatParts(
Isolate* isolate, icu::UnicodeString formatted,
icu::UnicodeString integer_part, Handle<String> unit) {
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);
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 =
JSRelativeTimeFormat::UnpackFormatter(format_holder);
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 (unit_enum == UDAT_REL_UNIT_QUARTER) {
// ICU have not yet implement UDAT_REL_UNIT_QUARTER.
} else {
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 (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),
Object);
return elements;
}
return factory->NewStringFromTwoByte(Vector<const uint16_t>(
reinterpret_cast<const uint16_t*>(formatted.getBuffer()),
formatted.length()));
}
} // namespace internal
} // namespace v8
......@@ -28,20 +28,29 @@ class JSRelativeTimeFormat : public JSObject {
public:
// Initializes relative time format object with properties derived from input
// locales and options.
static MaybeHandle<JSRelativeTimeFormat> InitializeRelativeTimeFormat(
V8_WARN_UNUSED_RESULT static MaybeHandle<JSRelativeTimeFormat>
InitializeRelativeTimeFormat(
Isolate* isolate,
Handle<JSRelativeTimeFormat> relative_time_format_holder,
Handle<Object> locales, Handle<Object> options);
static Handle<JSObject> ResolvedOptions(
V8_WARN_UNUSED_RESULT static Handle<JSObject> ResolvedOptions(
Isolate* isolate, Handle<JSRelativeTimeFormat> format_holder);
// Unpacks formatter object from corresponding JavaScript object.
static icu::RelativeDateTimeFormatter* UnpackFormatter(
V8_WARN_UNUSED_RESULT static icu::RelativeDateTimeFormatter* UnpackFormatter(
Handle<JSRelativeTimeFormat> relative_time_format_holder);
Handle<String> StyleAsString() const;
Handle<String> NumericAsString() const;
// ecma402/#sec-Intl.RelativeTimeFormat.prototype.format
// ecma402/#sec-Intl.RelativeTimeFormat.prototype.formatToParts
V8_WARN_UNUSED_RESULT static MaybeHandle<Object> Format(
Isolate* isolate, Handle<Object> value_obj, Handle<Object> unit_obj,
Handle<JSRelativeTimeFormat> format_holder, const char* func_name,
bool to_parts);
DECL_CAST(JSRelativeTimeFormat)
// RelativeTimeFormat accessors.
......
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