Skip to content

Commit af312b9

Browse files
catamorphismptomato
authored andcommitted
[Temporal] Implement toPlainDate method for PlainYearMonth
https://bugs.webkit.org/show_bug.cgi?id=303947 Reviewed by Yusuke Suzuki. Implement this method. * JSTests/stress/temporal-plainyearmonth.js: (shouldBe): * JSTests/test262/config.yaml: * Source/JavaScriptCore/runtime/TemporalPlainDate.cpp: (JSC::TemporalPlainDate::toDay): * Source/JavaScriptCore/runtime/TemporalPlainDate.h: * Source/JavaScriptCore/runtime/TemporalPlainYearMonthPrototype.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): Canonical link: https://commits.webkit.org/304376@main
1 parent aa0a2f6 commit af312b9

File tree

5 files changed

+87
-24
lines changed

5 files changed

+87
-24
lines changed

JSTests/stress/temporal-plainyearmonth.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,13 @@ shouldBe(Temporal.PlainYearMonth.prototype.with.length, 1);
119119
shouldBe(yearMonth.with({ month: 13 }).toString(), '2025-12');
120120
shouldThrow(() => { yearMonth.with({ month: 13 }, { overflow: 'reject' }); }, RangeError);
121121
}
122+
123+
shouldBe(Temporal.PlainYearMonth.prototype.toPlainDate.length, 1);
124+
{
125+
shouldBe(yearMonth.toPlainDate({ day: 29 }).toString(), "2025-04-29");
126+
shouldThrow(() => yearMonth.toPlainDate({ notYear: 'whatever' }), TypeError);
127+
const leapYear = new Temporal.PlainYearMonth(2024, 2);
128+
shouldBe(leapYear.toPlainDate({ day: 29 }).toString(), "2024-02-29");
129+
const commonYear = new Temporal.PlainYearMonth(2025, 2);
130+
shouldBe(commonYear.toPlainDate({ day: 29 }).toString(), "2025-02-28");
131+
}

JSTests/test262/config.yaml

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -237,17 +237,6 @@ skip:
237237
- test/built-ins/Temporal/PlainYearMonth/prototype/subtract/subclassing-ignored.js
238238
- test/built-ins/Temporal/PlainYearMonth/prototype/subtract/subtract-from-last-representable-month.js
239239
- test/built-ins/Temporal/PlainYearMonth/prototype/subtract/throws-if-year-outside-valid-iso-range.js
240-
- test/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/argument-not-object.js
241-
- test/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/basic.js
242-
- test/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/branding.js
243-
- test/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/builtin.js
244-
- test/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/default-overflow-behaviour.js
245-
- test/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/infinity-throws-rangeerror.js
246-
- test/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/length.js
247-
- test/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/limits.js
248-
- test/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/name.js
249-
- test/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/not-a-constructor.js
250-
- test/built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/prop-desc.js
251240
- test/built-ins/Temporal/PlainYearMonth/prototype/until/argument-casting.js
252241
- test/built-ins/Temporal/PlainYearMonth/prototype/until/argument-number.js
253242
- test/built-ins/Temporal/PlainYearMonth/prototype/until/argument-propertybag-calendar-invalid-iso-string.js

Source/JavaScriptCore/runtime/TemporalPlainDate.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,32 @@ TemporalPlainDate::mergeDateFields(JSGlobalObject* globalObject, JSObject* tempo
325325
return { yearToUse, monthToUse, dayToUse, otherMonth, overflow, any };
326326
}
327327

328+
std::optional<int32_t> TemporalPlainDate::toDay(JSGlobalObject* globalObject, JSObject* temporalDateLike)
329+
{
330+
VM& vm = globalObject->vm();
331+
auto scope = DECLARE_THROW_SCOPE(vm);
332+
333+
std::optional<int32_t> day;
334+
JSValue dayProperty = temporalDateLike->get(globalObject, vm.propertyNames->day);
335+
RETURN_IF_EXCEPTION(scope, { });
336+
if (!dayProperty.isUndefined()) {
337+
double doubleDay = dayProperty.toIntegerOrInfinity(globalObject);
338+
RETURN_IF_EXCEPTION(scope, { });
339+
340+
if (!std::isfinite(doubleDay)) [[unlikely]] {
341+
throwRangeError(globalObject, scope, "day property must be finite"_s);
342+
return { };
343+
}
344+
345+
if (!isInBounds<int32_t>(doubleDay))[[unlikely]] {
346+
// Later checks will report error
347+
day = ISO8601::outOfRangeYear;
348+
} else
349+
day = static_cast<int32_t>(doubleDay);
350+
}
351+
return day;
352+
}
353+
328354
std::optional<int32_t> TemporalPlainDate::toYear(JSGlobalObject* globalObject, JSObject* temporalDateLike)
329355
{
330356
VM& vm = globalObject->vm();
@@ -387,6 +413,7 @@ TemporalPlainDate::toYearMonth(JSGlobalObject* globalObject, JSObject* temporalD
387413

388414
scope.release();
389415
auto year = toYear(globalObject, temporalDateLike);
416+
RETURN_IF_EXCEPTION(scope, { });
390417

391418
return { month, monthCode, year };
392419
}

Source/JavaScriptCore/runtime/TemporalPlainDate.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class TemporalPlainDate final : public JSNonFinalObject {
5151
static ISO8601::PlainDate toPlainDate(JSGlobalObject*, const ISO8601::Duration&);
5252
static std::tuple<int32_t, unsigned, unsigned, std::optional<ParsedMonthCode>, TemporalOverflow, TemporalAnyProperties>
5353
mergeDateFields(JSGlobalObject*, JSObject*, JSValue, int32_t, unsigned, unsigned);
54+
static std::optional<int32_t> toDay(JSGlobalObject*, JSObject*);
5455
static std::optional<int32_t> toYear(JSGlobalObject*, JSObject*);
5556
std::tuple<std::optional<int32_t>, std::optional<ParsedMonthCode>, std::optional<int32_t>> static toYearMonth(JSGlobalObject*, JSObject*);
5657
static TemporalPlainDate* from(JSGlobalObject*, JSValue, Variant<JSObject*, TemporalOverflow>);

Source/JavaScriptCore/runtime/TemporalPlainYearMonthPrototype.cpp

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838

3939
namespace JSC {
4040

41+
static JSC_DECLARE_HOST_FUNCTION(temporalPlainYearMonthPrototypeFuncToPlainDate);
4142
static JSC_DECLARE_HOST_FUNCTION(temporalPlainYearMonthPrototypeFuncToString);
4243
static JSC_DECLARE_HOST_FUNCTION(temporalPlainYearMonthPrototypeFuncToJSON);
4344
static JSC_DECLARE_HOST_FUNCTION(temporalPlainYearMonthPrototypeFuncToLocaleString);
@@ -63,6 +64,7 @@ const ClassInfo TemporalPlainYearMonthPrototype::s_info = { "Temporal.PlainYearM
6364

6465
/* Source for TemporalPlainYearMonthPrototype.lut.h
6566
@begin plainYearMonthPrototypeTable
67+
toPlainDate temporalPlainYearMonthPrototypeFuncToPlainDate DontEnum|Function 1
6668
toString temporalPlainYearMonthPrototypeFuncToString DontEnum|Function 0
6769
toJSON temporalPlainYearMonthPrototypeFuncToJSON DontEnum|Function 0
6870
toLocaleString temporalPlainYearMonthPrototypeFuncToLocaleString DontEnum|Function 0
@@ -104,19 +106,6 @@ void TemporalPlainYearMonthPrototype::finishCreation(VM& vm, JSGlobalObject*)
104106
JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
105107
}
106108

107-
// https://tc39.es/proposal-temporal/#sec-temporal.plainyearmonth.prototype.tostring
108-
JSC_DEFINE_HOST_FUNCTION(temporalPlainYearMonthPrototypeFuncToString, (JSGlobalObject* globalObject, CallFrame* callFrame))
109-
{
110-
VM& vm = globalObject->vm();
111-
auto scope = DECLARE_THROW_SCOPE(vm);
112-
113-
auto* yearMonth = jsDynamicCast<TemporalPlainYearMonth*>(callFrame->thisValue());
114-
if (!yearMonth) [[unlikely]]
115-
return throwVMTypeError(globalObject, scope, "Temporal.PlainYearMonth.prototype.toString called on value that's not a PlainYearMonth"_s);
116-
117-
RELEASE_AND_RETURN(scope, JSValue::encode(jsString(vm, yearMonth->toString(globalObject, callFrame->argument(0)))));
118-
}
119-
120109
// https://tc39.es/proposal-temporal/#sec-temporal.plainyearmonth.prototype.with
121110
JSC_DEFINE_HOST_FUNCTION(temporalPlainYearMonthPrototypeFuncWith, (JSGlobalObject* globalObject, CallFrame* callFrame))
122111
{
@@ -156,6 +145,53 @@ JSC_DEFINE_HOST_FUNCTION(temporalPlainYearMonthPrototypeFuncEquals, (JSGlobalObj
156145
return JSValue::encode(jsBoolean(true));
157146
}
158147

148+
// https://tc39.es/proposal-temporal/#sec-temporal.plaindate.prototype.toplaindatetime
149+
JSC_DEFINE_HOST_FUNCTION(temporalPlainYearMonthPrototypeFuncToPlainDate, (JSGlobalObject* globalObject, CallFrame* callFrame))
150+
{
151+
VM& vm = globalObject->vm();
152+
auto scope = DECLARE_THROW_SCOPE(vm);
153+
154+
auto* yearMonth = jsDynamicCast<TemporalPlainYearMonth*>(callFrame->thisValue());
155+
if (!yearMonth) [[unlikely]]
156+
return throwVMTypeError(globalObject, scope, "Temporal.PlainYearMonth.prototype.toPlainDate called on value that's not a PlainYearMonth"_s);
157+
158+
JSValue itemValue = callFrame->argument(0);
159+
if (!itemValue.isObject()) [[unlikely]]
160+
return throwVMTypeError(globalObject, scope, "Temporal.PlainYearMonth.prototype.toPlainDate: item is not an object"_s);
161+
162+
auto thisYear = yearMonth->year();
163+
auto thisMonth = yearMonth->month();
164+
auto itemDay = TemporalPlainDate::toDay(globalObject, asObject(itemValue));
165+
RETURN_IF_EXCEPTION(scope, { });
166+
167+
if (!itemDay) [[unlikely]] {
168+
throwTypeError(globalObject, scope, "Temporal.PlainYearMonth.prototype.toPlainDate: item does not have a day field"_s);
169+
return { };
170+
}
171+
172+
auto plainDateOptional =
173+
TemporalDuration::regulateISODate(thisYear, thisMonth, itemDay.value(), TemporalOverflow::Constrain);
174+
if (!plainDateOptional) [[unlikely]] {
175+
throwRangeError(globalObject, scope, "Temporal.PlainYearMonth.prototype.toPlainDate: date is invalid"_s);
176+
return { };
177+
}
178+
179+
RELEASE_AND_RETURN(scope, JSValue::encode(TemporalPlainDate::tryCreateIfValid(globalObject, globalObject->plainDateStructure(), WTFMove(plainDateOptional.value()))));
180+
}
181+
182+
// https://tc39.es/proposal-temporal/#sec-temporal.plainyearmonth.prototype.tostring
183+
JSC_DEFINE_HOST_FUNCTION(temporalPlainYearMonthPrototypeFuncToString, (JSGlobalObject* globalObject, CallFrame* callFrame))
184+
{
185+
VM& vm = globalObject->vm();
186+
auto scope = DECLARE_THROW_SCOPE(vm);
187+
188+
auto* yearMonth = jsDynamicCast<TemporalPlainYearMonth*>(callFrame->thisValue());
189+
if (!yearMonth) [[unlikely]]
190+
return throwVMTypeError(globalObject, scope, "Temporal.PlainYearMonth.prototype.toString called on value that's not a PlainYearMonth"_s);
191+
192+
RELEASE_AND_RETURN(scope, JSValue::encode(jsString(vm, yearMonth->toString(globalObject, callFrame->argument(0)))));
193+
}
194+
159195
// https://tc39.es/proposal-temporal/#sec-temporal.plainyearmonth.prototype.tojson
160196
JSC_DEFINE_HOST_FUNCTION(temporalPlainYearMonthPrototypeFuncToJSON, (JSGlobalObject* globalObject, CallFrame* callFrame))
161197
{

0 commit comments

Comments
 (0)