Commit afe71f39 authored by Frank Tang's avatar Frank Tang Committed by V8 LUCI CQ

[Temporal] Add Temporal.PlainDate.from

Bug: v8:11544
Change-Id: I781119561db5ec05b12b9bca31c98403355e35ac
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3378882Reviewed-by: 's avatarShu-yu Guo <syg@chromium.org>
Commit-Queue: Frank Tang <ftang@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79396}
parent e7b7a3df
......@@ -1661,6 +1661,7 @@ namespace internal {
CPP(TemporalCalendarPrototypeToJSON) \
\
/* "Private" (created but not exposed) Bulitins needed by Temporal */ \
TFJ(StringFixedArrayFromIterable, kJSArgcReceiverSlots, kIterable) \
TFJ(TemporalInstantFixedArrayFromIterable, kJSArgcReceiverSlots, kIterable)
#define BUILTIN_LIST_BASE(CPP, TFJ, TFC, TFS, TFH, ASM) \
......
......@@ -218,7 +218,7 @@ TF_BUILTIN(IterableToFixedArrayForWasm, IteratorBuiltinsAssembler) {
}
#endif // V8_ENABLE_WEBASSEMBLY
TNode<JSArray> IteratorBuiltinsAssembler::StringListFromIterable(
TNode<FixedArray> IteratorBuiltinsAssembler::StringListFromIterable(
TNode<Context> context, TNode<Object> iterable) {
Label done(this);
GrowableFixedArray list(state());
......@@ -279,7 +279,7 @@ TNode<JSArray> IteratorBuiltinsAssembler::StringListFromIterable(
BIND(&done);
// 6. Return list.
return list.ToJSArray(context);
return list.ToFixedArray();
}
TF_BUILTIN(StringListFromIterable, IteratorBuiltinsAssembler) {
......@@ -289,6 +289,13 @@ TF_BUILTIN(StringListFromIterable, IteratorBuiltinsAssembler) {
Return(StringListFromIterable(context, iterable));
}
TF_BUILTIN(StringFixedArrayFromIterable, IteratorBuiltinsAssembler) {
auto context = Parameter<Context>(Descriptor::kContext);
auto iterable = Parameter<Object>(Descriptor::kIterable);
Return(StringListFromIterable(context, iterable));
}
// This builtin always returns a new JSArray and is thus safe to use even in the
// presence of code that may call back into user-JS. This builtin will take the
// fast path if the iterable is a fast array and the Array prototype and the
......
......@@ -67,8 +67,8 @@ class IteratorBuiltinsAssembler : public CodeStubAssembler {
// Currently at https://tc39.github.io/proposal-intl-list-format/
// #sec-createstringlistfromiterable
TNode<JSArray> StringListFromIterable(TNode<Context> context,
TNode<Object> iterable);
TNode<FixedArray> StringListFromIterable(TNode<Context> context,
TNode<Object> iterable);
void FastIterableToList(TNode<Context> context, TNode<Object> iterable,
TVariable<JSArray>* var_result, Label* slow);
......
......@@ -38,8 +38,6 @@ namespace internal {
JSTemporal##T::NowISO(isolate, args.atOrUndefined(isolate, 1))); \
}
/* Temporal #sec-temporal.plaindate.from */
TO_BE_IMPLEMENTED(TemporalPlainDateFrom)
/* Temporal #sec-temporal.plaindate.compare */
TO_BE_IMPLEMENTED(TemporalPlainDateCompare)
/* Temporal #sec-temporal.plaindate.prototype.toplainyearmonth */
......@@ -454,6 +452,15 @@ TO_BE_IMPLEMENTED(TemporalZonedDateTimePrototypeToLocaleString)
args.atOrUndefined(isolate, 3))); \
}
#define TEMPORAL_METHOD2(T, METHOD) \
BUILTIN(Temporal##T##METHOD) { \
HandleScope scope(isolate); \
RETURN_RESULT_OR_FAILURE( \
isolate, \
JSTemporal##T ::METHOD(isolate, args.atOrUndefined(isolate, 1), \
args.atOrUndefined(isolate, 2))); \
}
#define TEMPORAL_VALUE_OF(T) \
BUILTIN(Temporal##T##PrototypeValueOf) { \
HandleScope scope(isolate); \
......@@ -561,6 +568,7 @@ BUILTIN(TemporalPlainDateConstructor) {
args.atOrUndefined(isolate, 3), // iso_day
args.atOrUndefined(isolate, 4))); // calendar_like
}
TEMPORAL_METHOD2(PlainDate, From)
TEMPORAL_GET(PlainDate, Calendar, calendar)
TEMPORAL_GET_BY_FORWARD_CALENDAR(PlainDate, Year, year)
TEMPORAL_GET_BY_FORWARD_CALENDAR(PlainDate, Month, month)
......
......@@ -5298,6 +5298,15 @@ void Genesis::InitializeGlobal_harmony_temporal() {
#undef INSTALL_TEMPORAL_CTOR_AND_PROTOTYPE
#undef INSTALL_TEMPORAL_FUNC
// The StringListFromIterable functions is created but not
// exposed, as it is used internally by CalendarFields.
{
Handle<JSFunction> func = SimpleCreateFunction(
isolate_,
factory()->InternalizeUtf8String("StringFixedArrayFromIterable"),
Builtin::kStringFixedArrayFromIterable, 1, false);
native_context()->set_string_fixed_array_from_iterable(*func);
}
// The TemporalInsantFixedArrayFromIterable functions is created but not
// exposed, as it is used internally by GetPossibleInstantsFor.
{
......
......@@ -31,8 +31,6 @@
V(_, direction_string, "direction") \
V(_, endRange_string, "endRange") \
V(_, engineering_string, "engineering") \
V(_, era_string, "era") \
V(_, eraYear_string, "eraYear") \
V(_, exceptZero_string, "exceptZero") \
V(_, expand_string, "expand") \
V(_, exponentInteger_string, "exponentInteger") \
......@@ -228,6 +226,8 @@
V(_, epochMilliseconds_string, "epochMilliseconds") \
V(_, epochNanoseconds_string, "epochNanoseconds") \
V(_, epochSeconds_string, "epochSeconds") \
V(_, era_string, "era") \
V(_, eraYear_string, "eraYear") \
V(_, errors_string, "errors") \
V(_, error_to_string, "[object Error]") \
V(_, eval_string, "eval") \
......
......@@ -210,6 +210,8 @@ enum ContextLookupFlags {
temporal_zoned_date_time_function) \
V(TEMPORAL_INSTANT_FIXED_ARRAY_FROM_ITERABLE_FUNCTION_INDEX, JSFunction, \
temporal_instant_fixed_array_from_iterable) \
V(STRING_FIXED_ARRAY_FROM_ITERABLE_FUNCTION_INDEX, JSFunction, \
string_fixed_array_from_iterable) \
/* Context maps */ \
V(NATIVE_CONTEXT_MAP_INDEX, Map, native_context_map) \
V(FUNCTION_CONTEXT_MAP_INDEX, Map, function_context_map) \
......
......@@ -197,19 +197,13 @@ Handle<String> JSListFormat::TypeAsString() const {
namespace {
// Extract String from JSArray into array of UnicodeString
// Extract String from FixedArray into array of UnicodeString
Maybe<std::vector<icu::UnicodeString>> ToUnicodeStringArray(
Isolate* isolate, Handle<JSArray> array) {
// Thanks to iterable-to-list preprocessing, we never see dictionary-mode
// arrays here, so the loop below can construct an entry from the index.
DCHECK(array->HasFastElements(isolate));
auto* accessor = array->GetElementsAccessor();
size_t length = accessor->NumberOfElements(*array);
Isolate* isolate, Handle<FixedArray> array) {
int length = array->length();
std::vector<icu::UnicodeString> result;
for (InternalIndex entry : InternalIndex::Range(length)) {
DCHECK(accessor->HasEntry(*array, entry));
Handle<Object> item = accessor->Get(array, entry);
for (int i = 0; i < length; i++) {
Handle<Object> item = FixedArray::get(*array, i, isolate);
DCHECK(item->IsString());
Handle<String> item_str = Handle<String>::cast(item);
if (!item_str->IsFlat()) item_str = String::Flatten(isolate, item_str);
......@@ -220,7 +214,7 @@ Maybe<std::vector<icu::UnicodeString>> ToUnicodeStringArray(
template <typename T>
MaybeHandle<T> FormatListCommon(
Isolate* isolate, Handle<JSListFormat> format, Handle<JSArray> list,
Isolate* isolate, Handle<JSListFormat> format, Handle<FixedArray> list,
const std::function<MaybeHandle<T>(Isolate*, const icu::FormattedValue&)>&
formatToResult) {
DCHECK(!list->IsUndefined());
......@@ -283,14 +277,14 @@ MaybeHandle<JSArray> FormattedListToJSArray(
// ecma402 #sec-formatlist
MaybeHandle<String> JSListFormat::FormatList(Isolate* isolate,
Handle<JSListFormat> format,
Handle<JSArray> list) {
Handle<FixedArray> list) {
return FormatListCommon<String>(isolate, format, list,
Intl::FormattedToString);
}
// ecma42 #sec-formatlisttoparts
MaybeHandle<JSArray> JSListFormat::FormatListToParts(
Isolate* isolate, Handle<JSListFormat> format, Handle<JSArray> list) {
Isolate* isolate, Handle<JSListFormat> format, Handle<FixedArray> list) {
return FormatListCommon<JSArray>(isolate, format, list,
FormattedListToJSArray);
}
......
......@@ -46,12 +46,12 @@ class JSListFormat
// ecma402 #sec-formatlist
V8_WARN_UNUSED_RESULT static MaybeHandle<String> FormatList(
Isolate* isolate, Handle<JSListFormat> format_holder,
Handle<JSArray> list);
Handle<FixedArray> list);
// ecma42 #sec-formatlisttoparts
V8_WARN_UNUSED_RESULT static MaybeHandle<JSArray> FormatListToParts(
Isolate* isolate, Handle<JSListFormat> format_holder,
Handle<JSArray> list);
Handle<FixedArray> list);
V8_EXPORT_PRIVATE static const std::set<std::string>& GetAvailableLocales();
......
......@@ -69,6 +69,17 @@ struct DateTimeRecordCommon {
int32_t nanosecond;
};
struct DateRecord {
int32_t year;
int32_t month;
int32_t day;
Handle<String> calendar;
};
struct DateTimeRecord : public DateTimeRecordCommon {
Handle<String> calendar;
};
struct DurationRecord {
int64_t years;
int64_t months;
......@@ -95,12 +106,19 @@ V8_WARN_UNUSED_RESULT Handle<String> UnitToString(Isolate* isolate, Unit unit);
// #sec-temporal-totemporaldisambiguation
enum class Disambiguation { kCompatible, kEarlier, kLater, kReject };
// #sec-temporal-totemporaloverflow
enum class ShowOverflow { kConstrain, kReject };
// ISO8601 String Parsing
// #sec-temporal-parsetemporalcalendarstring
V8_WARN_UNUSED_RESULT MaybeHandle<String> ParseTemporalCalendarString(
Isolate* isolate, Handle<String> iso_string);
// #sec-temporal-parsetemporaldatestring
V8_WARN_UNUSED_RESULT Maybe<DateRecord> ParseTemporalDateString(
Isolate* isolate, Handle<String> iso_string);
// #sec-temporal-parsetemporaltimezone
V8_WARN_UNUSED_RESULT MaybeHandle<String> ParseTemporalTimeZone(
Isolate* isolate, Handle<String> string);
......@@ -229,19 +247,32 @@ int64_t TotalDurationNanoseconds(Isolate* isolate, int64_t days, int64_t hours,
// Calendar Operations
// #sec-temporal-calendardateadd
V8_WARN_UNUSED_RESULT MaybeHandle<JSTemporalPlainDate> CalendarDateAdd(
Isolate* isolate, Handle<JSReceiver> calendar, Handle<Object> date,
Handle<Object> durations, Handle<Object> options, Handle<Object> date_add);
// #sec-temporal-calendardateuntil
V8_WARN_UNUSED_RESULT MaybeHandle<JSTemporalDuration> CalendarDateUntil(
Isolate* isolate, Handle<JSReceiver> calendar, Handle<Object> one,
Handle<Object> two, Handle<Object> options, Handle<Object> date_until);
// #sec-temporal-calendarfields
MaybeHandle<FixedArray> CalendarFields(Isolate* isolate,
Handle<JSReceiver> calendar,
Handle<FixedArray> field_names);
// #sec-temporal-getoffsetnanosecondsfor
V8_WARN_UNUSED_RESULT Maybe<int64_t> GetOffsetNanosecondsFor(
Isolate* isolate, Handle<JSReceiver> time_zone, Handle<Object> instant,
const char* method_name);
// #sec-temporal-totemporalcalendarwithisodefault
MaybeHandle<JSReceiver> ToTemporalCalendarWithISODefault(
Isolate* isolate, Handle<Object> temporal_calendar_like,
const char* method_name);
// #sec-temporal-isbuiltincalendar
bool IsBuiltinCalendar(Isolate* isolate, Handle<String> id);
// Internal Helper Function
......@@ -254,6 +285,14 @@ bool IsValidTimeZoneName(Isolate* isolate, Handle<String> time_zone);
V8_WARN_UNUSED_RESULT MaybeHandle<String> CanonicalizeTimeZoneName(
Isolate* isolate, Handle<String> identifier);
// #sec-temporal-tointegerthrowoninfinity
MaybeHandle<Object> ToIntegerThrowOnInfinity(Isolate* isolate,
Handle<Object> argument);
// #sec-temporal-topositiveinteger
MaybeHandle<Object> ToPositiveInteger(Isolate* isolate,
Handle<Object> argument);
inline int64_t floor_divide(int64_t a, int64_t b) {
return (((a) / (b)) + ((((a) < 0) && (((a) % (b)) != 0)) ? -1 : 0));
}
......@@ -1241,7 +1280,7 @@ MaybeHandle<JSTemporalInstant> DisambiguatePossibleInstants(
date_time->iso_day(), date_time->iso_hour(), date_time->iso_minute(),
date_time->iso_second(), date_time->iso_millisecond(),
date_time->iso_microsecond(), date_time->iso_nanosecond(),
Handle<JSReceiver>(date_time->calendar(), isolate),
handle(date_time->calendar(), isolate),
{0, 0, 0, 0, 0, 0, 0, 0, 0, -nanoseconds},
isolate->factory()->undefined_value());
MAYBE_RETURN(maybe_earlier, Handle<JSTemporalInstant>());
......@@ -1259,7 +1298,7 @@ MaybeHandle<JSTemporalInstant> DisambiguatePossibleInstants(
isolate, earlier.year, earlier.month, earlier.day, earlier.hour,
earlier.minute, earlier.second, earlier.millisecond,
earlier.microsecond, earlier.nanosecond,
Handle<JSReceiver>(date_time->calendar(), isolate)),
handle(date_time->calendar(), isolate)),
JSTemporalInstant);
// c. Set possibleInstants to ? GetPossibleInstantsFor(timeZone,
......@@ -1292,7 +1331,7 @@ MaybeHandle<JSTemporalInstant> DisambiguatePossibleInstants(
date_time->iso_day(), date_time->iso_hour(), date_time->iso_minute(),
date_time->iso_second(), date_time->iso_millisecond(),
date_time->iso_microsecond(), date_time->iso_nanosecond(),
Handle<JSReceiver>(date_time->calendar(), isolate),
handle(date_time->calendar(), isolate),
{0, 0, 0, 0, 0, 0, 0, 0, 0, nanoseconds},
isolate->factory()->undefined_value());
MAYBE_RETURN(maybe_later, Handle<JSTemporalInstant>());
......@@ -1310,7 +1349,7 @@ MaybeHandle<JSTemporalInstant> DisambiguatePossibleInstants(
temporal::CreateTemporalDateTime(
isolate, later.year, later.month, later.day, later.hour, later.minute,
later.second, later.millisecond, later.microsecond, later.nanosecond,
Handle<JSReceiver>(date_time->calendar(), isolate)),
handle(date_time->calendar(), isolate)),
JSTemporalInstant);
// 17. Set possibleInstants to ? GetPossibleInstantsFor(timeZone,
// laterDateTime).
......@@ -1331,6 +1370,215 @@ MaybeHandle<JSTemporalInstant> DisambiguatePossibleInstants(
return Handle<JSTemporalInstant>::cast(ret_obj);
}
// #sec-temporal-gettemporalcalendarwithisodefault
MaybeHandle<JSReceiver> GetTemporalCalendarWithISODefault(
Isolate* isolate, Handle<JSReceiver> item, const char* method_name) {
TEMPORAL_ENTER_FUNC();
Factory* factory = isolate->factory();
// 1. If item has an [[InitializedTemporalDate]],
// [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]],
// [[InitializedTemporalTime]], [[InitializedTemporalYearMonth]], or
// [[InitializedTemporalZonedDateTime]] internal slot, then a. Return
// item.[[Calendar]].
if (item->IsJSTemporalPlainDate()) {
return handle(Handle<JSTemporalPlainDate>::cast(item)->calendar(), isolate);
}
if (item->IsJSTemporalPlainDateTime()) {
return handle(Handle<JSTemporalPlainDateTime>::cast(item)->calendar(),
isolate);
}
if (item->IsJSTemporalPlainMonthDay()) {
return handle(Handle<JSTemporalPlainMonthDay>::cast(item)->calendar(),
isolate);
}
if (item->IsJSTemporalPlainTime()) {
return handle(Handle<JSTemporalPlainTime>::cast(item)->calendar(), isolate);
}
if (item->IsJSTemporalPlainYearMonth()) {
return handle(Handle<JSTemporalPlainYearMonth>::cast(item)->calendar(),
isolate);
}
if (item->IsJSTemporalZonedDateTime()) {
return handle(Handle<JSTemporalZonedDateTime>::cast(item)->calendar(),
isolate);
}
// 2. Let calendar be ? Get(item, "calendar").
Handle<Object> calendar;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, calendar,
JSReceiver::GetProperty(isolate, item, factory->calendar_string()),
JSReceiver);
// 3. Return ? ToTemporalCalendarWithISODefault(calendar).
return ToTemporalCalendarWithISODefault(isolate, calendar, method_name);
}
enum class RequiredFields { kNone, kTimeZone, kTimeZoneAndOffset, kDay };
// The common part of PrepareTemporalFields and PreparePartialTemporalFields
// #sec-temporal-preparetemporalfields
// #sec-temporal-preparepartialtemporalfields
V8_WARN_UNUSED_RESULT MaybeHandle<JSObject> PrepareTemporalFieldsOrPartial(
Isolate* isolate, Handle<JSReceiver> fields, Handle<FixedArray> field_names,
RequiredFields required, bool partial) {
TEMPORAL_ENTER_FUNC();
Factory* factory = isolate->factory();
// 1. Assert: Type(fields) is Object.
// 2. Let result be ! OrdinaryObjectCreate(%Object.prototype%).
Handle<JSObject> result =
isolate->factory()->NewJSObject(isolate->object_function());
// 3. For each value property of fieldNames, do
int length = field_names->length();
bool any = false;
for (int i = 0; i < length; i++) {
Handle<Object> property_obj = Handle<Object>(field_names->get(i), isolate);
Handle<String> property = Handle<String>::cast(property_obj);
// a. Let value be ? Get(fields, property).
Handle<Object> value;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, value, JSReceiver::GetProperty(isolate, fields, property),
JSObject);
// b. If value is undefined, then
if (value->IsUndefined()) {
// This part is only for PrepareTemporalFields
// Skip for the case of PreparePartialTemporalFields.
if (partial) continue;
// i. If requiredFields contains property, then
if ((required == RequiredFields::kDay &&
String::Equals(isolate, property, factory->day_string())) ||
((required == RequiredFields::kTimeZone ||
required == RequiredFields::kTimeZoneAndOffset) &&
String::Equals(isolate, property, factory->timeZone_string())) ||
(required == RequiredFields::kTimeZoneAndOffset &&
String::Equals(isolate, property, factory->offset_string()))) {
// 1. Throw a TypeError exception.
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_TYPE_ERROR(),
JSObject);
}
// ii. Else,
// 1. If property is in the Property column of Table 13, then
// a. Set value to the corresponding Default value of the same row.
if (String::Equals(isolate, property, factory->hour_string()) ||
String::Equals(isolate, property, factory->minute_string()) ||
String::Equals(isolate, property, factory->second_string()) ||
String::Equals(isolate, property, factory->millisecond_string()) ||
String::Equals(isolate, property, factory->microsecond_string()) ||
String::Equals(isolate, property, factory->nanosecond_string())) {
value = Handle<Object>(Smi::zero(), isolate);
}
} else {
// For both PrepareTemporalFields and PreparePartialTemporalFields
any = partial;
// c. Else,
// i. If property is in the Property column of Table 13 and there is a
// Conversion value in the same row, then
// 1. Let Conversion represent the abstract operation named by the
// Conversion value of the same row.
// 2. Set value to ? Conversion(value).
if (String::Equals(isolate, property, factory->month_string()) ||
String::Equals(isolate, property, factory->day_string())) {
ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
ToPositiveInteger(isolate, value), JSObject);
} else if (String::Equals(isolate, property, factory->year_string()) ||
String::Equals(isolate, property, factory->hour_string()) ||
String::Equals(isolate, property, factory->minute_string()) ||
String::Equals(isolate, property, factory->second_string()) ||
String::Equals(isolate, property,
factory->millisecond_string()) ||
String::Equals(isolate, property,
factory->microsecond_string()) ||
String::Equals(isolate, property,
factory->nanosecond_string()) ||
String::Equals(isolate, property, factory->eraYear_string())) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, value, ToIntegerThrowOnInfinity(isolate, value), JSObject);
} else if (String::Equals(isolate, property,
factory->monthCode_string()) ||
String::Equals(isolate, property, factory->offset_string()) ||
String::Equals(isolate, property, factory->era_string())) {
ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
Object::ToString(isolate, value), JSObject);
}
}
// d. Perform ! CreateDataPropertyOrThrow(result, property, value).
CHECK(JSReceiver::CreateDataProperty(isolate, result, property, value,
Just(kThrowOnError))
.FromJust());
}
// Only for PreparePartialTemporalFields
if (partial) {
// 5. If any is false, then
if (!any) {
// a. Throw a TypeError exception.
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_TYPE_ERROR(), JSObject);
}
}
// 4. Return result.
return result;
}
// #sec-temporal-preparetemporalfields
V8_WARN_UNUSED_RESULT MaybeHandle<JSObject> PrepareTemporalFields(
Isolate* isolate, Handle<JSReceiver> fields, Handle<FixedArray> field_names,
RequiredFields required) {
TEMPORAL_ENTER_FUNC();
return PrepareTemporalFieldsOrPartial(isolate, fields, field_names, required,
false);
}
// Template for DateFromFields, YearMonthFromFields, and MonthDayFromFields
template <typename T>
MaybeHandle<T> FromFields(Isolate* isolate, Handle<JSReceiver> calendar,
Handle<JSReceiver> fields, Handle<Object> options,
Handle<String> property, InstanceType type) {
Handle<Object> function;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, function, Object::GetProperty(isolate, calendar, property), T);
if (!function->IsCallable()) {
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kCalledNonCallable, property),
T);
}
Handle<Object> argv[] = {fields, options};
Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result, Execution::Call(isolate, function, calendar, 2, argv),
T);
if ((!result->IsHeapObject()) ||
HeapObject::cast(*result).map().instance_type() != type) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_INVALD_ARG_TYPE_ERROR(), T);
}
return Handle<T>::cast(result);
}
MaybeHandle<JSTemporalPlainDate> DateFromFields(Isolate* isolate,
Handle<JSReceiver> calendar,
Handle<JSReceiver> fields,
Handle<Object> options) {
return FromFields<JSTemporalPlainDate>(
isolate, calendar, fields, options,
isolate->factory()->dateFromFields_string(), JS_TEMPORAL_PLAIN_DATE_TYPE);
}
// IMPL_FROM_FIELDS_ABSTRACT_OPERATION(Date, date, JS_TEMPORAL_PLAIN_DATE_TYPE)
#undef IMPL_FROM_FIELDS_ABSTRACT_OPERATION
// #sec-temporal-totemporaloverflow
Maybe<ShowOverflow> ToTemporalOverflow(Isolate* isolate,
Handle<JSReceiver> options,
const char* method_name) {
return GetStringOption<ShowOverflow>(
isolate, options, "overflow", method_name, {"constrain", "reject"},
{ShowOverflow::kConstrain, ShowOverflow::kReject},
ShowOverflow::kConstrain);
}
// #sec-temporal-builtintimezonegetinstantfor
MaybeHandle<JSTemporalInstant> BuiltinTimeZoneGetInstantFor(
Isolate* isolate, Handle<JSReceiver> time_zone,
......@@ -1365,10 +1613,9 @@ MaybeHandle<JSReceiver> ToTemporalCalendar(
// [[InitializedTemporalZonedDateTime]] internal slot, then i. Return
// temporalCalendarLike.[[Calendar]].
#define EXTRACT_CALENDAR(T, obj) \
if (obj->IsJSTemporal##T()) { \
return Handle<JSReceiver>(Handle<JSTemporal##T>::cast(obj)->calendar(), \
isolate); \
#define EXTRACT_CALENDAR(T, obj) \
if (obj->IsJSTemporal##T()) { \
return handle(Handle<JSTemporal##T>::cast(obj)->calendar(), isolate); \
}
EXTRACT_CALENDAR(PlainDate, temporal_calendar_like)
......@@ -1444,9 +1691,133 @@ MaybeHandle<JSReceiver> ToTemporalCalendarWithISODefault(
method_name);
}
// #sec-temporal-totemporaldate
MaybeHandle<JSTemporalPlainDate> ToTemporalDate(Isolate* isolate,
Handle<Object> item_obj,
Handle<JSReceiver> options,
const char* method_name) {
TEMPORAL_ENTER_FUNC();
Factory* factory = isolate->factory();
// 2. Assert: Type(options) is Object.
// 3. If Type(item) is Object, then
if (item_obj->IsJSReceiver()) {
Handle<JSReceiver> item = Handle<JSReceiver>::cast(item_obj);
// a. If item has an [[InitializedTemporalDate]] internal slot, then
// i. Return item.
if (item->IsJSTemporalPlainDate()) {
return Handle<JSTemporalPlainDate>::cast(item);
}
// b. If item has an [[InitializedTemporalZonedDateTime]] internal slot,
// then
if (item->IsJSTemporalZonedDateTime()) {
// i. Let instant be ! CreateTemporalInstant(item.[[Nanoseconds]]).
Handle<JSTemporalZonedDateTime> zoned_date_time =
Handle<JSTemporalZonedDateTime>::cast(item);
Handle<JSTemporalInstant> instant;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, instant,
temporal::CreateTemporalInstant(
isolate, Handle<BigInt>(zoned_date_time->nanoseconds(), isolate)),
JSTemporalPlainDate);
// ii. Let plainDateTime be ?
// BuiltinTimeZoneGetPlainDateTimeFor(item.[[TimeZone]],
// instant, item.[[Calendar]]).
Handle<JSTemporalPlainDateTime> plain_date_time;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, plain_date_time,
temporal::BuiltinTimeZoneGetPlainDateTimeFor(
isolate,
Handle<JSReceiver>(zoned_date_time->time_zone(), isolate),
instant, Handle<JSReceiver>(zoned_date_time->calendar(), isolate),
method_name),
JSTemporalPlainDate);
// iii. Return ! CreateTemporalDate(plainDateTime.[[ISOYear]],
// plainDateTime.[[ISOMonth]], plainDateTime.[[ISODay]],
// plainDateTime.[[Calendar]]).
return CreateTemporalDate(
isolate, plain_date_time->iso_year(), plain_date_time->iso_month(),
plain_date_time->iso_day(),
Handle<JSReceiver>(plain_date_time->calendar(), isolate));
}
// c. If item has an [[InitializedTemporalDateTime]] internal slot, then
// i. Return ! CreateTemporalDate(item.[[ISOYear]], item.[[ISOMonth]],
// item.[[ISODay]], item.[[Calendar]]).
if (item->IsJSTemporalPlainDateTime()) {
Handle<JSTemporalPlainDateTime> date_time =
Handle<JSTemporalPlainDateTime>::cast(item);
return CreateTemporalDate(isolate, date_time->iso_year(),
date_time->iso_month(), date_time->iso_day(),
handle(date_time->calendar(), isolate));
}
// d. Let calendar be ? GetTemporalCalendarWithISODefault(item).
Handle<JSReceiver> calendar;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, calendar,
GetTemporalCalendarWithISODefault(isolate, item, method_name),
JSTemporalPlainDate);
// e. Let fieldNames be ? CalendarFields(calendar, « "day", "month",
// "monthCode", "year" »).
Handle<FixedArray> field_names = factory->NewFixedArray(4);
field_names->set(0, *(factory->day_string()));
field_names->set(1, *(factory->month_string()));
field_names->set(2, *(factory->monthCode_string()));
field_names->set(3, *(factory->year_string()));
ASSIGN_RETURN_ON_EXCEPTION(isolate, field_names,
CalendarFields(isolate, calendar, field_names),
JSTemporalPlainDate);
// f. Let fields be ? PrepareTemporalFields(item,
// fieldNames, «»).
Handle<JSReceiver> fields;
ASSIGN_RETURN_ON_EXCEPTION(isolate, fields,
PrepareTemporalFields(isolate, item, field_names,
RequiredFields::kNone),
JSTemporalPlainDate);
// g. Return ? DateFromFields(calendar, fields, options).
return DateFromFields(isolate, calendar, fields, options);
}
// 4. Perform ? ToTemporalOverflow(options).
Maybe<ShowOverflow> maybe_overflow =
ToTemporalOverflow(isolate, options, method_name);
MAYBE_RETURN(maybe_overflow, Handle<JSTemporalPlainDate>());
// 5. Let string be ? ToString(item).
Handle<String> string;
ASSIGN_RETURN_ON_EXCEPTION(isolate, string,
Object::ToString(isolate, item_obj),
JSTemporalPlainDate);
// 6. Let result be ? ParseTemporalDateString(string).
Maybe<DateRecord> maybe_result = ParseTemporalDateString(isolate, string);
MAYBE_RETURN(maybe_result, MaybeHandle<JSTemporalPlainDate>());
DateRecord result = maybe_result.FromJust();
// 7. Assert: ! IsValidISODate(result.[[Year]], result.[[Month]],
// result.[[Day]]) is true.
DCHECK(IsValidISODate(isolate, result.year, result.month, result.day));
// 8. Let calendar be ? ToTemporalCalendarWithISODefault(result.[[Calendar]]).
Handle<Object> calendar_string;
if (result.calendar->length() == 0) {
calendar_string = factory->undefined_value();
} else {
calendar_string = result.calendar;
}
Handle<JSReceiver> calendar;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, calendar,
ToTemporalCalendarWithISODefault(isolate, calendar_string, method_name),
JSTemporalPlainDate);
// 9. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]],
// result.[[Day]], calendar).
return CreateTemporalDate(isolate, result.year, result.month, result.day,
calendar);
}
} // namespace
namespace temporal {
// #sec-temporal-totemporaltimezone
MaybeHandle<JSReceiver> ToTemporalTimeZone(
Isolate* isolate, Handle<Object> temporal_time_zone_like,
......@@ -1462,7 +1833,7 @@ MaybeHandle<JSReceiver> ToTemporalTimeZone(
// i. Return temporalTimeZoneLike.[[TimeZone]].
Handle<JSTemporalZonedDateTime> zoned_date_time =
Handle<JSTemporalZonedDateTime>::cast(temporal_time_zone_like);
return Handle<JSReceiver>(zoned_date_time->time_zone(), isolate);
return handle(zoned_date_time->time_zone(), isolate);
}
Handle<JSReceiver> obj = Handle<JSReceiver>::cast(temporal_time_zone_like);
// b. If ? HasProperty(temporalTimeZoneLike, "timeZone") is false,
......@@ -1658,6 +2029,130 @@ MaybeHandle<String> BuiltinTimeZoneGetOffsetStringFor(
return FormatTimeZoneOffsetString(isolate, offset_nanoseconds);
}
// #sec-temporal-parseisodatetime
Maybe<DateTimeRecord> ParseISODateTime(Isolate* isolate,
Handle<String> iso_string,
const ParsedISO8601Result& parsed) {
TEMPORAL_ENTER_FUNC();
DateTimeRecord result;
// 5. Set year to ! ToIntegerOrInfinity(year).
result.year = parsed.date_year;
// 6. If month is undefined, then
if (parsed.date_month_is_undefined()) {
// a. Set month to 1.
result.month = 1;
// 7. Else,
} else {
// a. Set month to ! ToIntegerOrInfinity(month).
result.month = parsed.date_month;
}
// 8. If day is undefined, then
if (parsed.date_day_is_undefined()) {
// a. Set day to 1.
result.day = 1;
// 9. Else,
} else {
// a. Set day to ! ToIntegerOrInfinity(day).
result.day = parsed.date_day;
}
// 10. Set hour to ! ToIntegerOrInfinity(hour).
result.hour = parsed.time_hour_is_undefined() ? 0 : parsed.time_hour;
// 11. Set minute to ! ToIntegerOrInfinity(minute).
result.minute = parsed.time_minute_is_undefined() ? 0 : parsed.time_minute;
// 12. Set second to ! ToIntegerOrInfinity(second).
result.second = parsed.time_second_is_undefined() ? 0 : parsed.time_second;
// 13. If second is 60, then
if (result.second == 60) {
// a. Set second to 59.
result.second = 59;
}
// 14. If fraction is not undefined, then
if (!parsed.time_nanosecond_is_undefined()) {
// a. Set fraction to the string-concatenation of the previous value of
// fraction and the string "000000000".
// b. Let millisecond be the String value equal to the substring of fraction
// from 0 to 3. c. Set millisecond to ! ToIntegerOrInfinity(millisecond).
result.millisecond = parsed.time_nanosecond / 1000000;
// d. Let microsecond be the String value equal to the substring of fraction
// from 3 to 6. e. Set microsecond to ! ToIntegerOrInfinity(microsecond).
result.microsecond = (parsed.time_nanosecond / 1000) % 1000;
// f. Let nanosecond be the String value equal to the substring of fraction
// from 6 to 9. g. Set nanosecond to ! ToIntegerOrInfinity(nanosecond).
result.nanosecond = (parsed.time_nanosecond % 1000);
// 15. Else,
} else {
// a. Let millisecond be 0.
result.millisecond = 0;
// b. Let microsecond be 0.
result.microsecond = 0;
// c. Let nanosecond be 0.
result.nanosecond = 0;
}
// 16. If ! IsValidISODate(year, month, day) is false, throw a RangeError
// exception.
if (!IsValidISODate(isolate, result.year, result.month, result.day)) {
THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
Nothing<DateTimeRecord>());
}
// 17. If ! IsValidTime(hour, minute, second, millisecond, microsecond,
// nanosecond) is false, throw a RangeError exception.
if (!IsValidTime(isolate, result.hour, result.minute, result.second,
result.millisecond, result.microsecond, result.nanosecond)) {
THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
Nothing<DateTimeRecord>());
}
// 18. Return the Record { [[Year]]: year, [[Month]]: month, [[Day]]: day,
// [[Hour]]: hour, [[Minute]]: minute, [[Second]]: second, [[Millisecond]]:
// millisecond, [[Microsecond]]: microsecond, [[Nanosecond]]: nanosecond,
// [[Calendar]]: calendar }.
if (parsed.calendar_name_length == 0) {
result.calendar = isolate->factory()->empty_string();
} else {
result.calendar = isolate->factory()->NewSubString(
iso_string, parsed.calendar_name_start,
parsed.calendar_name_start + parsed.calendar_name_length);
}
return Just(result);
}
// #sec-temporal-parsetemporaldatestring
Maybe<DateRecord> ParseTemporalDateString(Isolate* isolate,
Handle<String> iso_string) {
TEMPORAL_ENTER_FUNC();
// 1. Assert: Type(isoString) is String.
// 2. If isoString does not satisfy the syntax of a TemporalDateString
// (see 13.33), then
Maybe<ParsedISO8601Result> maybe_parsed =
TemporalParser::ParseTemporalDateString(isolate, iso_string);
if (maybe_parsed.IsNothing()) {
// a. Throw a *RangeError* exception.
THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
Nothing<DateRecord>());
}
MAYBE_RETURN(maybe_parsed, Nothing<DateRecord>());
ParsedISO8601Result parsed = maybe_parsed.FromJust();
// 3. If _isoString_ contains a |UTCDesignator|, then
if (parsed.utc_designator) {
// a. Throw a *RangeError* exception.
THROW_NEW_ERROR_RETURN_VALUE(isolate, NEW_TEMPORAL_INVALD_ARG_RANGE_ERROR(),
Nothing<DateRecord>());
}
// 3. Let result be ? ParseISODateTime(isoString).
Maybe<DateTimeRecord> maybe_result =
ParseISODateTime(isolate, iso_string, parsed);
MAYBE_RETURN(maybe_result, Nothing<DateRecord>());
DateTimeRecord result = maybe_result.FromJust();
// 4. Return the Record { [[Year]]: result.[[Year]], [[Month]]:
// result.[[Month]], [[Day]]: result.[[Day]], [[Calendar]]:
// result.[[Calendar]] }.
DateRecord ret = {result.year, result.month, result.day, result.calendar};
return Just(ret);
}
// #sec-temporal-parsetemporaltimezonestring
Maybe<TimeZoneRecord> ParseTemporalTimeZoneString(Isolate* isolate,
Handle<String> iso_string) {
......@@ -1903,6 +2398,39 @@ MaybeHandle<String> ParseTemporalCalendarString(Isolate* isolate,
return id;
}
// #sec-temporal-calendarfields
MaybeHandle<FixedArray> CalendarFields(Isolate* isolate,
Handle<JSReceiver> calendar,
Handle<FixedArray> field_names) {
// 1. Let fields be ? GetMethod(calendar, "fields").
Handle<Object> fields;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, fields,
Object::GetMethod(calendar, isolate->factory()->fields_string()),
FixedArray);
// 2. Let fieldsArray be ! CreateArrayFromList(fieldNames).
Handle<Object> fields_array =
isolate->factory()->NewJSArrayWithElements(field_names);
// 3. If fields is not undefined, then
if (!fields->IsUndefined()) {
// a. Set fieldsArray to ? Call(fields, calendar, « fieldsArray »).
Handle<Object> argv[] = {fields_array};
ASSIGN_RETURN_ON_EXCEPTION(
isolate, fields_array,
Execution::Call(isolate, fields, calendar, 1, argv), FixedArray);
}
// 4. Return ? IterableToListOfType(fieldsArray, « String »).
Handle<Object> argv[] = {fields_array};
ASSIGN_RETURN_ON_EXCEPTION(
isolate, fields_array,
Execution::CallBuiltin(isolate,
isolate->string_fixed_array_from_iterable(),
fields_array, 1, argv),
FixedArray);
DCHECK(fields_array->IsFixedArray());
return Handle<FixedArray>::cast(fields_array);
}
MaybeHandle<JSTemporalPlainDate> CalendarDateAdd(Isolate* isolate,
Handle<JSReceiver> calendar,
Handle<Object> date,
......@@ -2033,9 +2561,7 @@ Maybe<int64_t> GetOffsetNanosecondsFor(Isolate* isolate,
return Just(offset_nanoseconds_int);
}
MaybeHandle<Object> ToIntegerThrowOnInfinity(Isolate* isolate,
Handle<Object> argument);
// #sec-temporal-topositiveinteger
MaybeHandle<Object> ToPositiveInteger(Isolate* isolate,
Handle<Object> argument) {
TEMPORAL_ENTER_FUNC();
......@@ -2315,6 +2841,7 @@ MaybeHandle<JSObject> MergeLargestUnitOption(Isolate* isolate,
return merged;
}
// #sec-temporal-tointegerthrowoninfinity
MaybeHandle<Object> ToIntegerThrowOnInfinity(Isolate* isolate,
Handle<Object> argument) {
TEMPORAL_ENTER_FUNC();
......@@ -2330,6 +2857,7 @@ MaybeHandle<Object> ToIntegerThrowOnInfinity(Isolate* isolate,
return argument;
}
// #sec-temporal-largeroftwotemporalunits
Unit LargerOfTwoTemporalUnits(Isolate* isolate, Unit u1, Unit u2) {
// 1. If either u1 or u2 is "year", return "year".
if (u1 == Unit::kYear || u2 == Unit::kYear) return Unit::kYear;
......@@ -3977,6 +4505,33 @@ MaybeHandle<JSTemporalPlainDate> JSTemporalPlainDate::NowISO(
Handle<JSReceiver>(date_time->calendar(), isolate));
}
// #sec-temporal.plaindate.from
MaybeHandle<JSTemporalPlainDate> JSTemporalPlainDate::From(
Isolate* isolate, Handle<Object> item, Handle<Object> options_obj) {
const char* method_name = "Temporal.PlainDate.from";
// 1. Set options to ? GetOptionsObject(options).
Handle<JSReceiver> options;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, options, GetOptionsObject(isolate, options_obj, method_name),
JSTemporalPlainDate);
// 2. If Type(item) is Object and item has an [[InitializedTemporalDate]]
// internal slot, then
if (item->IsJSTemporalPlainDate()) {
// a. Perform ? ToTemporalOverflow(options).
Maybe<ShowOverflow> maybe_overflow =
ToTemporalOverflow(isolate, options, method_name);
MAYBE_RETURN(maybe_overflow, Handle<JSTemporalPlainDate>());
// b. Return ? CreateTemporalDate(item.[[ISOYear]], item.[[ISOMonth]],
// item.[[ISODay]], item.[[Calendar]]).
Handle<JSTemporalPlainDate> date = Handle<JSTemporalPlainDate>::cast(item);
return CreateTemporalDate(isolate, date->iso_year(), date->iso_month(),
date->iso_day(),
Handle<JSReceiver>(date->calendar(), isolate));
}
// 3. Return ? ToTemporalDate(item, options).
return ToTemporalDate(isolate, item, options, method_name);
}
#define DEFINE_INT_FIELD(obj, str, field, item) \
CHECK(JSReceiver::CreateDataProperty( \
isolate, obj, factory->str##_string(), \
......
......@@ -123,6 +123,10 @@ class JSTemporalPlainDate
Isolate* isolate, Handle<JSTemporalPlainDate> plain_date,
Handle<Object> calendar_like);
// #sec-temporal.plaindate.from
V8_WARN_UNUSED_RESULT static MaybeHandle<JSTemporalPlainDate> From(
Isolate* isolate, Handle<Object> item, Handle<Object> options);
// #sec-temporal.plaindate.prototype.getisofields
V8_WARN_UNUSED_RESULT static MaybeHandle<JSReceiver> GetISOFields(
Isolate* isolate, Handle<JSTemporalPlainDate> plain_date);
......
......@@ -37,7 +37,7 @@ RUNTIME_FUNCTION(Runtime_FormatList) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSListFormat, list_format, 0);
CONVERT_ARG_HANDLE_CHECKED(JSArray, list, 1);
CONVERT_ARG_HANDLE_CHECKED(FixedArray, list, 1);
RETURN_RESULT_OR_FAILURE(
isolate, JSListFormat::FormatList(isolate, list_format, list));
}
......@@ -47,7 +47,7 @@ RUNTIME_FUNCTION(Runtime_FormatListToParts) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSListFormat, list_format, 0);
CONVERT_ARG_HANDLE_CHECKED(JSArray, list, 1);
CONVERT_ARG_HANDLE_CHECKED(FixedArray, list, 1);
RETURN_RESULT_OR_FAILURE(
isolate, JSListFormat::FormatListToParts(isolate, list_format, list));
}
......
......@@ -986,17 +986,10 @@
'built-ins/Temporal/PlainDate/from/argument-plaindate': [FAIL],
'built-ins/Temporal/PlainDate/from/argument-plaindatetime': [FAIL],
'built-ins/Temporal/PlainDate/from/argument-string': [FAIL],
'built-ins/Temporal/PlainDate/from/argument-string-invalid': [FAIL],
'built-ins/Temporal/PlainDate/from/argument-string-with-utc-designator': [FAIL],
'built-ins/Temporal/PlainDate/from/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer': [FAIL],
'built-ins/Temporal/PlainDate/from/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable': [FAIL],
'built-ins/Temporal/PlainDate/from/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range': [FAIL],
'built-ins/Temporal/PlainDate/from/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type': [FAIL],
'built-ins/Temporal/PlainDate/from/calendar-fields-iterable': [FAIL],
'built-ins/Temporal/PlainDate/from/calendar-temporal-object': [FAIL],
'built-ins/Temporal/PlainDate/from/infinity-throws-rangeerror': [FAIL],
'built-ins/Temporal/PlainDate/from/limits': [FAIL],
'built-ins/Temporal/PlainDate/from/options-invalid': [FAIL],
'built-ins/Temporal/PlainDate/from/options-undefined': [FAIL],
'built-ins/Temporal/PlainDate/from/order-of-operations': [FAIL],
'built-ins/Temporal/PlainDate/from/overflow-invalid-string': [FAIL],
......@@ -1175,7 +1168,6 @@
'built-ins/Temporal/PlainDate/prototype/until/smallestunit-undefined': [FAIL],
'built-ins/Temporal/PlainDate/prototype/until/smallestunit-wrong-type': [FAIL],
'built-ins/Temporal/PlainDate/prototype/until/weeks-months': [FAIL],
'built-ins/Temporal/PlainDate/prototype/valueOf/basic': [FAIL],
'built-ins/Temporal/PlainDate/prototype/weekOfYear/basic': [FAIL],
'built-ins/Temporal/PlainDate/prototype/with/basic': [FAIL],
'built-ins/Temporal/PlainDate/prototype/with/branding': [FAIL],
......@@ -2492,7 +2484,6 @@
'built-ins/Temporal/PlainDate/from/argument-object-invalid': [FAIL],
'built-ins/Temporal/PlainDate/from/argument-object-valid': [FAIL],
'built-ins/Temporal/PlainDate/from/argument-string-overflow': [FAIL],
'built-ins/Temporal/PlainDate/from/argument-string-trailing-junk': [FAIL],
'built-ins/Temporal/PlainDate/from/year-zero': [FAIL],
'built-ins/Temporal/PlainDate/prototype/add/argument-invalid-duration': [FAIL],
'built-ins/Temporal/PlainDate/prototype/add/argument-missing-properties': [FAIL],
......
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