Commit 41db90b0 authored by Frank Tang's avatar Frank Tang Committed by Commit Bot

[Intl] Move most functions from DateFormat to JSDateTimeFormat

Move Unwrap,FormatDateTime,DateTimeFormat,ToDateTimeOptions,ToLocaleDateTime to JSDateTimeFormat

Bug: v8:8066
Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng;luci.chromium.try:linux_chromium_rel_ng
Change-Id: I4d83cc96ea280ab8f77df5a431b877b76b05f1ac
Reviewed-on: https://chromium-review.googlesource.com/1198142
Commit-Queue: Frank Tang <ftang@chromium.org>
Reviewed-by: 's avatarJungshik Shin <jshin@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55626}
parent d7ae63e6
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "src/objects-inl.h" #include "src/objects-inl.h"
#ifdef V8_INTL_SUPPORT #ifdef V8_INTL_SUPPORT
#include "src/objects/intl-objects.h" #include "src/objects/intl-objects.h"
#include "src/objects/js-date-time-format.h"
#endif #endif
namespace v8 { namespace v8 {
...@@ -843,45 +844,45 @@ BUILTIN(DatePrototypeToTimeString) { ...@@ -843,45 +844,45 @@ BUILTIN(DatePrototypeToTimeString) {
BUILTIN(DatePrototypeToLocaleDateString) { BUILTIN(DatePrototypeToLocaleDateString) {
HandleScope scope(isolate); HandleScope scope(isolate);
CHECK_RECEIVER(JSDate, date, "Date.prototype.toLocaleDateString"); CHECK_RECEIVER(JSDate, date, "Date.prototype.toLocaleDateString");
RETURN_RESULT_OR_FAILURE( RETURN_RESULT_OR_FAILURE(isolate,
isolate, JSDateTimeFormat::ToLocaleDateTime(
DateFormat::ToLocaleDateTime(isolate, isolate,
date, // date date, // date
args.atOrUndefined(isolate, 1), // locales args.atOrUndefined(isolate, 1), // locales
args.atOrUndefined(isolate, 2), // options args.atOrUndefined(isolate, 2), // options
"date", // required "date", // required
"date", // defaults "date", // defaults
"dateformatdate")); // service "dateformatdate")); // service
} }
// ecma402 #sup-date.prototype.tolocalestring // ecma402 #sup-date.prototype.tolocalestring
BUILTIN(DatePrototypeToLocaleString) { BUILTIN(DatePrototypeToLocaleString) {
HandleScope scope(isolate); HandleScope scope(isolate);
CHECK_RECEIVER(JSDate, date, "Date.prototype.toLocaleString"); CHECK_RECEIVER(JSDate, date, "Date.prototype.toLocaleString");
RETURN_RESULT_OR_FAILURE( RETURN_RESULT_OR_FAILURE(isolate,
isolate, JSDateTimeFormat::ToLocaleDateTime(
DateFormat::ToLocaleDateTime(isolate, isolate,
date, // date date, // date
args.atOrUndefined(isolate, 1), // locales args.atOrUndefined(isolate, 1), // locales
args.atOrUndefined(isolate, 2), // options args.atOrUndefined(isolate, 2), // options
"any", // required "any", // required
"all", // defaults "all", // defaults
"dateformatall")); // service "dateformatall")); // service
} }
// ecma402 #sup-date.prototype.tolocaletimestring // ecma402 #sup-date.prototype.tolocaletimestring
BUILTIN(DatePrototypeToLocaleTimeString) { BUILTIN(DatePrototypeToLocaleTimeString) {
HandleScope scope(isolate); HandleScope scope(isolate);
CHECK_RECEIVER(JSDate, date, "Date.prototype.toLocaleTimeString"); CHECK_RECEIVER(JSDate, date, "Date.prototype.toLocaleTimeString");
RETURN_RESULT_OR_FAILURE( RETURN_RESULT_OR_FAILURE(isolate,
isolate, JSDateTimeFormat::ToLocaleDateTime(
DateFormat::ToLocaleDateTime(isolate, isolate,
date, // date date, // date
args.atOrUndefined(isolate, 1), // locales args.atOrUndefined(isolate, 1), // locales
args.atOrUndefined(isolate, 2), // options args.atOrUndefined(isolate, 2), // options
"time", // required "time", // required
"time", // defaults "time", // defaults
"dateformattime")); // service "dateformattime")); // service
} }
#endif // V8_INTL_SUPPORT #endif // V8_INTL_SUPPORT
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "src/objects/intl-objects.h" #include "src/objects/intl-objects.h"
#include "src/objects/js-array-inl.h" #include "src/objects/js-array-inl.h"
#include "src/objects/js-collator-inl.h" #include "src/objects/js-collator-inl.h"
#include "src/objects/js-date-time-format-inl.h"
#include "src/objects/js-list-format-inl.h" #include "src/objects/js-list-format-inl.h"
#include "src/objects/js-locale-inl.h" #include "src/objects/js-locale-inl.h"
#include "src/objects/js-number-format-inl.h" #include "src/objects/js-number-format-inl.h"
...@@ -725,7 +726,7 @@ BUILTIN(DateTimeFormatPrototypeFormat) { ...@@ -725,7 +726,7 @@ BUILTIN(DateTimeFormatPrototypeFormat) {
Handle<JSObject> date_format_holder; Handle<JSObject> date_format_holder;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION( ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, date_format_holder, isolate, date_format_holder,
DateFormat::Unwrap(isolate, receiver, method)); JSDateTimeFormat::Unwrap(isolate, receiver, method));
DCHECK(Intl::IsObjectOfType(isolate, date_format_holder, DCHECK(Intl::IsObjectOfType(isolate, date_format_holder,
Intl::Type::kDateTimeFormat)); Intl::Type::kDateTimeFormat));
...@@ -768,8 +769,8 @@ BUILTIN(DateTimeFormatInternalFormat) { ...@@ -768,8 +769,8 @@ BUILTIN(DateTimeFormatInternalFormat) {
Handle<Object> date = args.atOrUndefined(isolate, 1); Handle<Object> date = args.atOrUndefined(isolate, 1);
RETURN_RESULT_OR_FAILURE( RETURN_RESULT_OR_FAILURE(isolate, JSDateTimeFormat::DateTimeFormat(
isolate, DateFormat::DateTimeFormat(isolate, date_format_holder, date)); isolate, date_format_holder, date));
} }
BUILTIN(ListFormatConstructor) { BUILTIN(ListFormatConstructor) {
......
...@@ -277,11 +277,11 @@ void SetResolvedBreakIteratorSettings(Isolate* isolate, ...@@ -277,11 +277,11 @@ void SetResolvedBreakIteratorSettings(Isolate* isolate,
} }
} }
MaybeHandle<JSObject> CachedOrNewService(Isolate* isolate, } // namespace
Handle<String> service,
Handle<Object> locales, MaybeHandle<JSObject> Intl::CachedOrNewService(
Handle<Object> options, Isolate* isolate, Handle<String> service, Handle<Object> locales,
Handle<Object> internal_options) { Handle<Object> options, Handle<Object> internal_options) {
Handle<Object> result; Handle<Object> result;
Handle<Object> undefined_value(ReadOnlyRoots(isolate).undefined_value(), Handle<Object> undefined_value(ReadOnlyRoots(isolate).undefined_value(),
isolate); isolate);
...@@ -294,8 +294,6 @@ MaybeHandle<JSObject> CachedOrNewService(Isolate* isolate, ...@@ -294,8 +294,6 @@ MaybeHandle<JSObject> CachedOrNewService(Isolate* isolate,
return Handle<JSObject>::cast(result); return Handle<JSObject>::cast(result);
} }
} // namespace
icu::Locale Intl::CreateICULocale(Isolate* isolate, icu::Locale Intl::CreateICULocale(Isolate* isolate,
Handle<String> bcp47_locale_str) { Handle<String> bcp47_locale_str) {
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
...@@ -380,110 +378,6 @@ void DateFormat::DeleteDateFormat(const v8::WeakCallbackInfo<void>& data) { ...@@ -380,110 +378,6 @@ void DateFormat::DeleteDateFormat(const v8::WeakCallbackInfo<void>& data) {
GlobalHandles::Destroy(reinterpret_cast<Object**>(data.GetParameter())); GlobalHandles::Destroy(reinterpret_cast<Object**>(data.GetParameter()));
} }
MaybeHandle<JSObject> DateFormat::Unwrap(Isolate* isolate,
Handle<JSReceiver> receiver,
const char* method_name) {
Handle<Context> native_context =
Handle<Context>(isolate->context()->native_context(), isolate);
Handle<JSFunction> constructor = Handle<JSFunction>(
JSFunction::cast(native_context->intl_date_time_format_function()),
isolate);
Handle<String> method_name_str =
isolate->factory()->NewStringFromAsciiChecked(method_name);
return Intl::UnwrapReceiver(isolate, receiver, constructor,
Intl::Type::kDateTimeFormat, method_name_str,
true);
}
// ecma402/#sec-formatdatetime
// FormatDateTime( dateTimeFormat, x )
MaybeHandle<String> DateFormat::FormatDateTime(
Isolate* isolate, Handle<JSObject> date_time_format_holder, double x) {
double date_value = DateCache::TimeClip(x);
if (std::isnan(date_value)) {
THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidTimeValue),
String);
}
CHECK(Intl::IsObjectOfType(isolate, date_time_format_holder,
Intl::Type::kDateTimeFormat));
icu::SimpleDateFormat* date_format =
DateFormat::UnpackDateFormat(date_time_format_holder);
CHECK_NOT_NULL(date_format);
icu::UnicodeString result;
date_format->format(date_value, result);
return isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>(
reinterpret_cast<const uint16_t*>(result.getBuffer()), result.length()));
}
// ecma402/#sec-datetime-format-functions
// DateTime Format Functions
MaybeHandle<String> DateFormat::DateTimeFormat(
Isolate* isolate, Handle<JSObject> date_time_format_holder,
Handle<Object> date) {
// 2. Assert: Type(dtf) is Object and dtf has an [[InitializedDateTimeFormat]]
// internal slot.
DCHECK(Intl::IsObjectOfType(isolate, date_time_format_holder,
Intl::Type::kDateTimeFormat));
// 3. If date is not provided or is undefined, then
double x;
if (date->IsUndefined()) {
// 3.a Let x be Call(%Date_now%, undefined).
x = JSDate::CurrentTimeValue(isolate);
} else {
// 4. Else,
// a. Let x be ? ToNumber(date).
ASSIGN_RETURN_ON_EXCEPTION(isolate, date, Object::ToNumber(isolate, date),
String);
CHECK(date->IsNumber());
x = date->Number();
}
// 5. Return FormatDateTime(dtf, x).
return DateFormat::FormatDateTime(isolate, date_time_format_holder, x);
}
MaybeHandle<String> DateFormat::ToLocaleDateTime(
Isolate* isolate, Handle<Object> date, Handle<Object> locales,
Handle<Object> options, const char* required, const char* defaults,
const char* service) {
Factory* factory = isolate->factory();
// 1. Let x be ? thisTimeValue(this value);
if (!date->IsJSDate()) {
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
factory->NewStringFromStaticChars("Date")),
String);
}
double const x = Handle<JSDate>::cast(date)->value()->Number();
// 2. If x is NaN, return "Invalid Date"
if (std::isnan(x)) {
return factory->NewStringFromStaticChars("Invalid Date");
}
// 3. Let options be ? ToDateTimeOptions(options, required, defaults).
Handle<JSObject> internal_options;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, internal_options,
DateFormat::ToDateTimeOptions(isolate, options, required, defaults),
String);
// 4. Let dateFormat be ? Construct(%DateTimeFormat%, « locales, options »).
Handle<JSObject> date_format;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, date_format,
CachedOrNewService(isolate, factory->NewStringFromAsciiChecked(service),
locales, options, internal_options),
String);
// 5. Return FormatDateTime(dateFormat, x).
return DateFormat::FormatDateTime(isolate, date_format, x);
}
icu::BreakIterator* V8BreakIterator::InitializeBreakIterator( icu::BreakIterator* V8BreakIterator::InitializeBreakIterator(
Isolate* isolate, Handle<String> locale, Handle<JSObject> options, Isolate* isolate, Handle<String> locale, Handle<JSObject> options,
Handle<JSObject> resolved) { Handle<JSObject> resolved) {
...@@ -622,110 +516,6 @@ bool Intl::RemoveLocaleScriptTag(const std::string& icu_locale, ...@@ -622,110 +516,6 @@ bool Intl::RemoveLocaleScriptTag(const std::string& icu_locale,
return true; return true;
} }
namespace {
Maybe<bool> IsPropertyUndefined(Isolate* isolate, Handle<JSObject> options,
const char* property) {
Factory* factory = isolate->factory();
// i. Let prop be the property name.
// ii. Let value be ? Get(options, prop).
Handle<Object> value;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, value,
Object::GetPropertyOrElement(
isolate, options, factory->NewStringFromAsciiChecked(property)),
Nothing<bool>());
return Just(value->IsUndefined(isolate));
}
} // namespace
// ecma-402/#sec-todatetimeoptions
MaybeHandle<JSObject> DateFormat::ToDateTimeOptions(
Isolate* isolate, Handle<Object> input_options, const char* required,
const char* defaults) {
Factory* factory = isolate->factory();
// 1. If options is undefined, let options be null; otherwise let options be ?
// ToObject(options).
Handle<JSObject> options;
if (input_options->IsUndefined(isolate)) {
options = factory->NewJSObjectWithNullProto();
} else {
Handle<JSReceiver> options_obj;
ASSIGN_RETURN_ON_EXCEPTION(isolate, options_obj,
Object::ToObject(isolate, input_options),
JSObject);
// 2. Let options be ObjectCreate(options).
ASSIGN_RETURN_ON_EXCEPTION(isolate, options,
JSObject::ObjectCreate(isolate, options_obj),
JSObject);
}
// 3. Let needDefaults be true.
bool needs_default = true;
bool required_is_any = strcmp(required, "any") == 0;
// 4. If required is "date" or "any", then
if (required_is_any || (strcmp(required, "date") == 0)) {
// a. For each of the property names "weekday", "year", "month", "day", do
for (auto& prop : {"weekday", "year", "month", "day"}) {
// i. Let prop be the property name.
// ii. Let value be ? Get(options, prop)
Maybe<bool> maybe_undefined = IsPropertyUndefined(isolate, options, prop);
MAYBE_RETURN(maybe_undefined, Handle<JSObject>());
// iii. If value is not undefined, let needDefaults be false.
if (!maybe_undefined.FromJust()) {
needs_default = false;
}
}
}
// 5. If required is "time" or "any", then
if (required_is_any || (strcmp(required, "time") == 0)) {
// a. For each of the property names "hour", "minute", "second", do
for (auto& prop : {"hour", "minute", "second"}) {
// i. Let prop be the property name.
// ii. Let value be ? Get(options, prop)
Maybe<bool> maybe_undefined = IsPropertyUndefined(isolate, options, prop);
MAYBE_RETURN(maybe_undefined, Handle<JSObject>());
// iii. If value is not undefined, let needDefaults be false.
if (!maybe_undefined.FromJust()) {
needs_default = false;
}
}
}
// 6. If needDefaults is true and defaults is either "date" or "all", then
if (needs_default) {
bool default_is_all = strcmp(defaults, "all") == 0;
if (default_is_all || (strcmp(defaults, "date") == 0)) {
// a. For each of the property names "year", "month", "day", do
// i. Perform ? CreateDataPropertyOrThrow(options, prop, "numeric").
for (auto& prop : {"year", "month", "day"}) {
MAYBE_RETURN(
JSReceiver::CreateDataProperty(
isolate, options, factory->NewStringFromAsciiChecked(prop),
factory->numeric_string(), kThrowOnError),
Handle<JSObject>());
}
}
// 7. If needDefaults is true and defaults is either "time" or "all", then
if (default_is_all || (strcmp(defaults, "time") == 0)) {
// a. For each of the property names "hour", "minute", "second", do
// i. Perform ? CreateDataPropertyOrThrow(options, prop, "numeric").
for (auto& prop : {"hour", "minute", "second"}) {
MAYBE_RETURN(
JSReceiver::CreateDataProperty(
isolate, options, factory->NewStringFromAsciiChecked(prop),
factory->numeric_string(), kThrowOnError),
Handle<JSObject>());
}
}
}
// 8. Return options.
return options;
}
std::set<std::string> Intl::GetAvailableLocales(const IcuService& service) { std::set<std::string> Intl::GetAvailableLocales(const IcuService& service) {
const icu::Locale* icu_available_locales = nullptr; const icu::Locale* icu_available_locales = nullptr;
int32_t count = 0; int32_t count = 0;
......
...@@ -47,36 +47,7 @@ class DateFormat { ...@@ -47,36 +47,7 @@ class DateFormat {
// holds the pointer gets garbage collected. // holds the pointer gets garbage collected.
static void DeleteDateFormat(const v8::WeakCallbackInfo<void>& data); static void DeleteDateFormat(const v8::WeakCallbackInfo<void>& data);
// ecma402/#sec-formatdatetime // Layout description.
// FormatDateTime( dateTimeFormat, x )
V8_WARN_UNUSED_RESULT static MaybeHandle<String> FormatDateTime(
Isolate* isolate, Handle<JSObject> date_time_format_holder, double x);
// ecma402/#sec-datetime-format-functions
// DateTime Format Functions
V8_WARN_UNUSED_RESULT static MaybeHandle<String> DateTimeFormat(
Isolate* isolate, Handle<JSObject> date_time_format_holder,
Handle<Object> date);
// The UnwrapDateTimeFormat abstract operation gets the underlying
// DateTimeFormat operation for various methods which implement ECMA-402 v1
// semantics for supporting initializing existing Intl objects.
//
// ecma402/#sec-unwrapdatetimeformat
V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> Unwrap(
Isolate* isolate, Handle<JSReceiver> receiver, const char* method_name);
// ecma-402/#sec-todatetimeoptions
V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> ToDateTimeOptions(
Isolate* isolate, Handle<Object> input_options, const char* required,
const char* defaults);
V8_WARN_UNUSED_RESULT static MaybeHandle<String> ToLocaleDateTime(
Isolate* isolate, Handle<Object> date, Handle<Object> locales,
Handle<Object> options, const char* required, const char* defaults,
const char* service);
// Layout description.
#define DATE_FORMAT_FIELDS(V) \ #define DATE_FORMAT_FIELDS(V) \
V(kSimpleDateFormat, kPointerSize) \ V(kSimpleDateFormat, kPointerSize) \
V(kBoundFormat, kPointerSize) \ V(kBoundFormat, kPointerSize) \
...@@ -383,6 +354,11 @@ class Intl { ...@@ -383,6 +354,11 @@ class Intl {
V8_WARN_UNUSED_RESULT static MaybeHandle<Object> LegacyUnwrapReceiver( V8_WARN_UNUSED_RESULT static MaybeHandle<Object> LegacyUnwrapReceiver(
Isolate* isolate, Handle<JSReceiver> receiver, Isolate* isolate, Handle<JSReceiver> receiver,
Handle<JSFunction> constructor, bool has_initialized_slot); Handle<JSFunction> constructor, bool has_initialized_slot);
// A factory method to got cached objects.
V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> CachedOrNewService(
Isolate* isolate, Handle<String> service, Handle<Object> locales,
Handle<Object> options, Handle<Object> internal_options);
}; };
} // namespace internal } // namespace internal
......
...@@ -448,5 +448,225 @@ Maybe<std::string> JSDateTimeFormat::OptionsToSkeleton( ...@@ -448,5 +448,225 @@ Maybe<std::string> JSDateTimeFormat::OptionsToSkeleton(
return Just(result); return Just(result);
} }
namespace {
// ecma402/#sec-formatdatetime
// FormatDateTime( dateTimeFormat, x )
MaybeHandle<String> FormatDateTime(Isolate* isolate,
Handle<JSObject> date_time_format_holder,
double x) {
double date_value = DateCache::TimeClip(x);
if (std::isnan(date_value)) {
THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidTimeValue),
String);
}
CHECK(Intl::IsObjectOfType(isolate, date_time_format_holder,
Intl::Type::kDateTimeFormat));
icu::SimpleDateFormat* date_format =
DateFormat::UnpackDateFormat(date_time_format_holder);
CHECK_NOT_NULL(date_format);
icu::UnicodeString result;
date_format->format(date_value, result);
return isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>(
reinterpret_cast<const uint16_t*>(result.getBuffer()), result.length()));
}
} // namespace
// ecma402/#sec-datetime-format-functions
// DateTime Format Functions
MaybeHandle<String> JSDateTimeFormat::DateTimeFormat(
Isolate* isolate, Handle<JSObject> date_time_format_holder,
Handle<Object> date) {
// 2. Assert: Type(dtf) is Object and dtf has an [[InitializedDateTimeFormat]]
// internal slot.
DCHECK(Intl::IsObjectOfType(isolate, date_time_format_holder,
Intl::Type::kDateTimeFormat));
// 3. If date is not provided or is undefined, then
double x;
if (date->IsUndefined()) {
// 3.a Let x be Call(%Date_now%, undefined).
x = JSDate::CurrentTimeValue(isolate);
} else {
// 4. Else,
// a. Let x be ? ToNumber(date).
ASSIGN_RETURN_ON_EXCEPTION(isolate, date, Object::ToNumber(isolate, date),
String);
CHECK(date->IsNumber());
x = date->Number();
}
// 5. Return FormatDateTime(dtf, x).
return FormatDateTime(isolate, date_time_format_holder, x);
}
MaybeHandle<String> JSDateTimeFormat::ToLocaleDateTime(
Isolate* isolate, Handle<Object> date, Handle<Object> locales,
Handle<Object> options, const char* required, const char* defaults,
const char* service) {
Factory* factory = isolate->factory();
// 1. Let x be ? thisTimeValue(this value);
if (!date->IsJSDate()) {
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
factory->NewStringFromStaticChars("Date")),
String);
}
double const x = Handle<JSDate>::cast(date)->value()->Number();
// 2. If x is NaN, return "Invalid Date"
if (std::isnan(x)) {
return factory->NewStringFromStaticChars("Invalid Date");
}
// 3. Let options be ? ToDateTimeOptions(options, required, defaults).
Handle<JSObject> internal_options;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, internal_options,
ToDateTimeOptions(isolate, options, required, defaults), String);
// 4. Let dateFormat be ? Construct(%DateTimeFormat%, « locales, options »).
Handle<JSObject> date_format;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, date_format,
Intl::CachedOrNewService(isolate,
factory->NewStringFromAsciiChecked(service),
locales, options, internal_options),
String);
// 5. Return FormatDateTime(dateFormat, x).
return FormatDateTime(isolate, date_format, x);
}
namespace {
Maybe<bool> IsPropertyUndefined(Isolate* isolate, Handle<JSObject> options,
const char* property) {
Factory* factory = isolate->factory();
// i. Let prop be the property name.
// ii. Let value be ? Get(options, prop).
Handle<Object> value;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, value,
Object::GetPropertyOrElement(
isolate, options, factory->NewStringFromAsciiChecked(property)),
Nothing<bool>());
return Just(value->IsUndefined(isolate));
}
Maybe<bool> NeedsDefault(Isolate* isolate, Handle<JSObject> options,
const std::vector<std::string>& props) {
bool needs_default = true;
for (const auto& prop : props) {
// i. Let prop be the property name.
// ii. Let value be ? Get(options, prop)
Maybe<bool> maybe_undefined =
IsPropertyUndefined(isolate, options, prop.c_str());
MAYBE_RETURN(maybe_undefined, Nothing<bool>());
// iii. If value is not undefined, let needDefaults be false.
if (!maybe_undefined.FromJust()) {
needs_default = false;
}
}
return Just(needs_default);
}
Maybe<bool> CreateDefault(Isolate* isolate, Handle<JSObject> options,
const std::vector<std::string>& props) {
Factory* factory = isolate->factory();
// i. Perform ? CreateDataPropertyOrThrow(options, prop, "numeric").
for (const auto& prop : props) {
MAYBE_RETURN(
JSReceiver::CreateDataProperty(
isolate, options, factory->NewStringFromAsciiChecked(prop.c_str()),
factory->numeric_string(), kThrowOnError),
Nothing<bool>());
}
return Just(true);
}
} // namespace
// ecma-402/#sec-todatetimeoptions
MaybeHandle<JSObject> JSDateTimeFormat::ToDateTimeOptions(
Isolate* isolate, Handle<Object> input_options, const char* required,
const char* defaults) {
Factory* factory = isolate->factory();
// 1. If options is undefined, let options be null; otherwise let options be ?
// ToObject(options).
Handle<JSObject> options;
if (input_options->IsUndefined(isolate)) {
options = factory->NewJSObjectWithNullProto();
} else {
Handle<JSReceiver> options_obj;
ASSIGN_RETURN_ON_EXCEPTION(isolate, options_obj,
Object::ToObject(isolate, input_options),
JSObject);
// 2. Let options be ObjectCreate(options).
ASSIGN_RETURN_ON_EXCEPTION(isolate, options,
JSObject::ObjectCreate(isolate, options_obj),
JSObject);
}
// 3. Let needDefaults be true.
bool needs_default = true;
bool required_is_any = strcmp(required, "any") == 0;
// 4. If required is "date" or "any", then
if (required_is_any || (strcmp(required, "date") == 0)) {
// a. For each of the property names "weekday", "year", "month", "day", do
const std::vector<std::string> list({"weekday", "year", "month", "day"});
Maybe<bool> maybe_needs_default = NeedsDefault(isolate, options, list);
MAYBE_RETURN(maybe_needs_default, Handle<JSObject>());
needs_default = maybe_needs_default.FromJust();
}
// 5. If required is "time" or "any", then
if (required_is_any || (strcmp(required, "time") == 0)) {
// a. For each of the property names "hour", "minute", "second", do
const std::vector<std::string> list({"hour", "minute", "second"});
Maybe<bool> maybe_needs_default = NeedsDefault(isolate, options, list);
MAYBE_RETURN(maybe_needs_default, Handle<JSObject>());
needs_default &= maybe_needs_default.FromJust();
}
// 6. If needDefaults is true and defaults is either "date" or "all", then
if (needs_default) {
bool default_is_all = strcmp(defaults, "all") == 0;
if (default_is_all || (strcmp(defaults, "date") == 0)) {
// a. For each of the property names "year", "month", "day", do)
const std::vector<std::string> list({"year", "month", "day"});
MAYBE_RETURN(CreateDefault(isolate, options, list), Handle<JSObject>());
}
// 7. If needDefaults is true and defaults is either "time" or "all", then
if (default_is_all || (strcmp(defaults, "time") == 0)) {
// a. For each of the property names "hour", "minute", "second", do
const std::vector<std::string> list({"hour", "minute", "second"});
MAYBE_RETURN(CreateDefault(isolate, options, list), Handle<JSObject>());
}
}
// 8. Return options.
return options;
}
MaybeHandle<JSObject> JSDateTimeFormat::Unwrap(Isolate* isolate,
Handle<JSReceiver> receiver,
const char* method_name) {
Handle<Context> native_context =
Handle<Context>(isolate->context()->native_context(), isolate);
Handle<JSFunction> constructor = Handle<JSFunction>(
JSFunction::cast(native_context->intl_date_time_format_function()),
isolate);
Handle<String> method_name_str =
isolate->factory()->NewStringFromAsciiChecked(method_name);
return Intl::UnwrapReceiver(isolate, receiver, constructor,
Intl::Type::kDateTimeFormat, method_name_str,
true);
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -26,6 +26,14 @@ class JSDateTimeFormat : public JSObject { ...@@ -26,6 +26,14 @@ class JSDateTimeFormat : public JSObject {
V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> ResolvedOptions( V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> ResolvedOptions(
Isolate* isolate, Handle<JSReceiver> date_time_holder); Isolate* isolate, Handle<JSReceiver> date_time_holder);
// The UnwrapDateTimeFormat abstract operation gets the underlying
// DateTimeFormat operation for various methods which implement ECMA-402 v1
// semantics for supporting initializing existing Intl objects.
//
// ecma402/#sec-unwrapdatetimeformat
V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> Unwrap(
Isolate* isolate, Handle<JSReceiver> receiver, const char* method_name);
// Convert the options to ICU DateTimePatternGenerator skeleton. // Convert the options to ICU DateTimePatternGenerator skeleton.
static Maybe<std::string> OptionsToSkeleton(Isolate* isolate, static Maybe<std::string> OptionsToSkeleton(Isolate* isolate,
Handle<JSReceiver> options); Handle<JSReceiver> options);
...@@ -35,6 +43,22 @@ class JSDateTimeFormat : public JSObject { ...@@ -35,6 +43,22 @@ class JSDateTimeFormat : public JSObject {
static std::string CanonicalizeTimeZoneID(Isolate* isolate, static std::string CanonicalizeTimeZoneID(Isolate* isolate,
const std::string& input); const std::string& input);
// ecma402/#sec-datetime-format-functions
// DateTime Format Functions
V8_WARN_UNUSED_RESULT static MaybeHandle<String> DateTimeFormat(
Isolate* isolate, Handle<JSObject> date_time_format_holder,
Handle<Object> date);
// ecma-402/#sec-todatetimeoptions
V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> ToDateTimeOptions(
Isolate* isolate, Handle<Object> input_options, const char* required,
const char* defaults);
V8_WARN_UNUSED_RESULT static MaybeHandle<String> ToLocaleDateTime(
Isolate* isolate, Handle<Object> date, Handle<Object> locales,
Handle<Object> options, const char* required, const char* defaults,
const char* service);
DECL_CAST(JSDateTimeFormat) DECL_CAST(JSDateTimeFormat)
// Layout description. // Layout description.
......
...@@ -368,10 +368,10 @@ RUNTIME_FUNCTION(Runtime_ToDateTimeOptions) { ...@@ -368,10 +368,10 @@ RUNTIME_FUNCTION(Runtime_ToDateTimeOptions) {
CONVERT_ARG_HANDLE_CHECKED(Object, options, 0); CONVERT_ARG_HANDLE_CHECKED(Object, options, 0);
CONVERT_ARG_HANDLE_CHECKED(String, required, 1); CONVERT_ARG_HANDLE_CHECKED(String, required, 1);
CONVERT_ARG_HANDLE_CHECKED(String, defaults, 2); CONVERT_ARG_HANDLE_CHECKED(String, defaults, 2);
RETURN_RESULT_OR_FAILURE( RETURN_RESULT_OR_FAILURE(isolate,
isolate, DateFormat::ToDateTimeOptions(isolate, options, JSDateTimeFormat::ToDateTimeOptions(
required->ToCString().get(), isolate, options, required->ToCString().get(),
defaults->ToCString().get())); defaults->ToCString().get()));
} }
RUNTIME_FUNCTION(Runtime_StringToLowerCaseIntl) { RUNTIME_FUNCTION(Runtime_StringToLowerCaseIntl) {
......
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