PlainMonthDay.cpp (22246B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "builtin/temporal/PlainMonthDay.h" 8 9 #include "mozilla/Assertions.h" 10 11 #include "jspubtd.h" 12 #include "NamespaceImports.h" 13 14 #include "builtin/intl/DateTimeFormat.h" 15 #include "builtin/temporal/Calendar.h" 16 #include "builtin/temporal/CalendarFields.h" 17 #include "builtin/temporal/PlainDate.h" 18 #include "builtin/temporal/PlainDateTime.h" 19 #include "builtin/temporal/PlainYearMonth.h" 20 #include "builtin/temporal/Temporal.h" 21 #include "builtin/temporal/TemporalParser.h" 22 #include "builtin/temporal/TemporalTypes.h" 23 #include "builtin/temporal/ToString.h" 24 #include "gc/AllocKind.h" 25 #include "gc/Barrier.h" 26 #include "gc/GCEnum.h" 27 #include "js/CallArgs.h" 28 #include "js/CallNonGenericMethod.h" 29 #include "js/Class.h" 30 #include "js/ErrorReport.h" 31 #include "js/friend/ErrorMessages.h" 32 #include "js/PropertyDescriptor.h" 33 #include "js/PropertySpec.h" 34 #include "js/RootingAPI.h" 35 #include "js/TypeDecls.h" 36 #include "js/Value.h" 37 #include "vm/BytecodeUtil.h" 38 #include "vm/GlobalObject.h" 39 #include "vm/JSAtomState.h" 40 #include "vm/JSContext.h" 41 #include "vm/JSObject.h" 42 #include "vm/PlainObject.h" 43 #include "vm/StringType.h" 44 45 #include "vm/JSObject-inl.h" 46 #include "vm/NativeObject-inl.h" 47 48 using namespace js; 49 using namespace js::temporal; 50 51 static inline bool IsPlainMonthDay(Handle<Value> v) { 52 return v.isObject() && v.toObject().is<PlainMonthDayObject>(); 53 } 54 55 /** 56 * CreateTemporalMonthDay ( isoDate, calendar [ , newTarget ] ) 57 */ 58 static PlainMonthDayObject* CreateTemporalMonthDay( 59 JSContext* cx, const CallArgs& args, const ISODate& isoDate, 60 Handle<CalendarValue> calendar) { 61 // Step 1. 62 if (!ISODateWithinLimits(isoDate)) { 63 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 64 JSMSG_TEMPORAL_PLAIN_MONTH_DAY_INVALID); 65 return nullptr; 66 } 67 68 // Steps 2-3. 69 Rooted<JSObject*> proto(cx); 70 if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_PlainMonthDay, 71 &proto)) { 72 return nullptr; 73 } 74 75 auto* object = NewObjectWithClassProto<PlainMonthDayObject>(cx, proto); 76 if (!object) { 77 return nullptr; 78 } 79 80 // Step 4. 81 auto packedDate = PackedDate::pack(isoDate); 82 object->initFixedSlot(PlainMonthDayObject::PACKED_DATE_SLOT, 83 PrivateUint32Value(packedDate.value)); 84 85 // Step 5. 86 object->initFixedSlot(PlainMonthDayObject::CALENDAR_SLOT, 87 calendar.toSlotValue()); 88 89 // Step 6. 90 return object; 91 } 92 93 /** 94 * CreateTemporalMonthDay ( isoDate, calendar [ , newTarget ] ) 95 */ 96 PlainMonthDayObject* js::temporal::CreateTemporalMonthDay( 97 JSContext* cx, Handle<PlainMonthDay> monthDay) { 98 MOZ_ASSERT(IsValidISODate(monthDay)); 99 100 // Step 1. 101 MOZ_ASSERT(ISODateWithinLimits(monthDay)); 102 103 // Steps 2-3. 104 auto* object = NewBuiltinClassInstance<PlainMonthDayObject>(cx); 105 if (!object) { 106 return nullptr; 107 } 108 109 // Step 4. 110 auto packedDate = PackedDate::pack(monthDay); 111 object->initFixedSlot(PlainMonthDayObject::PACKED_DATE_SLOT, 112 PrivateUint32Value(packedDate.value)); 113 114 // Step 5. 115 object->initFixedSlot(PlainMonthDayObject::CALENDAR_SLOT, 116 monthDay.calendar().toSlotValue()); 117 118 // Step 6. 119 return object; 120 } 121 122 /** 123 * CreateTemporalMonthDay ( isoDate, calendar [ , newTarget ] ) 124 */ 125 bool js::temporal::CreateTemporalMonthDay(JSContext* cx, const ISODate& isoDate, 126 Handle<CalendarValue> calendar, 127 MutableHandle<PlainMonthDay> result) { 128 MOZ_ASSERT(IsValidISODate(isoDate)); 129 130 // Step 1. 131 if (!ISODateWithinLimits(isoDate)) { 132 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 133 JSMSG_TEMPORAL_PLAIN_MONTH_DAY_INVALID); 134 return false; 135 } 136 137 // Steps 2-6. 138 result.set(PlainMonthDay{isoDate, calendar}); 139 return true; 140 } 141 142 struct MonthDayOptions { 143 TemporalOverflow overflow = TemporalOverflow::Constrain; 144 }; 145 146 /** 147 * ToTemporalMonthDay ( item [ , options ] ) 148 */ 149 static bool ToTemporalMonthDayOptions(JSContext* cx, Handle<Value> options, 150 MonthDayOptions* result) { 151 if (options.isUndefined()) { 152 *result = {}; 153 return true; 154 } 155 156 // NOTE: |options| are only passed from `Temporal.PlainMonthDay.from`. 157 158 Rooted<JSObject*> resolvedOptions( 159 cx, RequireObjectArg(cx, "options", "from", options)); 160 if (!resolvedOptions) { 161 return false; 162 } 163 164 auto overflow = TemporalOverflow::Constrain; 165 if (!GetTemporalOverflowOption(cx, resolvedOptions, &overflow)) { 166 return false; 167 } 168 169 *result = {overflow}; 170 return true; 171 } 172 173 /** 174 * ToTemporalMonthDay ( item [ , options ] ) 175 */ 176 static bool ToTemporalMonthDay(JSContext* cx, Handle<JSObject*> item, 177 Handle<Value> options, 178 MutableHandle<PlainMonthDay> result) { 179 // Step 2.a. 180 if (auto* plainMonthDay = item->maybeUnwrapIf<PlainMonthDayObject>()) { 181 auto date = plainMonthDay->date(); 182 Rooted<CalendarValue> calendar(cx, plainMonthDay->calendar()); 183 if (!calendar.wrap(cx)) { 184 return false; 185 } 186 187 // Steps 2.a.i-ii. 188 MonthDayOptions ignoredOptions; 189 if (!ToTemporalMonthDayOptions(cx, options, &ignoredOptions)) { 190 return false; 191 } 192 193 // Step 2.a.iii. 194 result.set(PlainMonthDay{date, calendar}); 195 return true; 196 } 197 198 // Step 2.b. 199 Rooted<CalendarValue> calendar(cx); 200 if (!GetTemporalCalendarWithISODefault(cx, item, &calendar)) { 201 return false; 202 } 203 204 // Step 2.c. 205 Rooted<CalendarFields> fields(cx); 206 if (!PrepareCalendarFields(cx, calendar, item, 207 { 208 CalendarField::Year, 209 CalendarField::Month, 210 CalendarField::MonthCode, 211 CalendarField::Day, 212 }, 213 &fields)) { 214 return false; 215 } 216 217 // Steps 2.d-e. 218 MonthDayOptions resolvedOptions; 219 if (!ToTemporalMonthDayOptions(cx, options, &resolvedOptions)) { 220 return false; 221 } 222 auto [overflow] = resolvedOptions; 223 224 // Step 2.f. 225 return CalendarMonthDayFromFields(cx, calendar, fields, overflow, result); 226 } 227 228 /** 229 * ToTemporalMonthDay ( item [ , options ] ) 230 */ 231 static bool ToTemporalMonthDay(JSContext* cx, Handle<Value> item, 232 Handle<Value> options, 233 MutableHandle<PlainMonthDay> result) { 234 // Step 1. (Not applicable in our implementation.) 235 236 // Step 2. 237 if (item.isObject()) { 238 Rooted<JSObject*> itemObj(cx, &item.toObject()); 239 return ToTemporalMonthDay(cx, itemObj, options, result); 240 } 241 242 // Step 3. 243 if (!item.isString()) { 244 ReportValueError(cx, JSMSG_UNEXPECTED_TYPE, JSDVG_IGNORE_STACK, item, 245 nullptr, "not a string"); 246 return false; 247 } 248 Rooted<JSString*> string(cx, item.toString()); 249 250 // Step 4. 251 ISODate date; 252 bool hasYear; 253 Rooted<JSString*> calendarString(cx); 254 if (!ParseTemporalMonthDayString(cx, string, &date, &hasYear, 255 &calendarString)) { 256 return false; 257 } 258 259 // Steps 5-7. 260 Rooted<CalendarValue> calendar(cx, CalendarValue(CalendarId::ISO8601)); 261 if (calendarString) { 262 if (!CanonicalizeCalendar(cx, calendarString, &calendar)) { 263 return false; 264 } 265 } 266 267 // Steps 8-9. 268 MonthDayOptions ignoredOptions; 269 if (!ToTemporalMonthDayOptions(cx, options, &ignoredOptions)) { 270 return false; 271 } 272 273 // Step 10. 274 if (calendar.identifier() == CalendarId::ISO8601) { 275 // Step 10.a. 276 constexpr int32_t referenceISOYear = 1972; 277 278 // Step 10.b. 279 auto isoDate = ISODate{referenceISOYear, date.month, date.day}; 280 281 // Step 10.c. 282 return CreateTemporalMonthDay(cx, isoDate, calendar, result); 283 } 284 285 // Steps 11-12. 286 Rooted<PlainMonthDay> monthDay(cx); 287 if (!CreateTemporalMonthDay(cx, date, calendar, &monthDay)) { 288 return false; 289 } 290 291 // Step 13. 292 Rooted<CalendarFields> fields(cx); 293 if (!ISODateToFields(cx, monthDay, &fields)) { 294 return false; 295 } 296 297 // Steps 14-15. 298 return CalendarMonthDayFromFields(cx, calendar, fields, 299 TemporalOverflow::Constrain, result); 300 } 301 302 /** 303 * ToTemporalMonthDay ( item [ , options ] ) 304 */ 305 static bool ToTemporalMonthDay(JSContext* cx, Handle<Value> item, 306 MutableHandle<PlainMonthDay> result) { 307 return ToTemporalMonthDay(cx, item, UndefinedHandleValue, result); 308 } 309 310 /** 311 * Temporal.PlainMonthDay ( isoMonth, isoDay [ , calendar [ , referenceISOYear ] 312 * ] ) 313 */ 314 static bool PlainMonthDayConstructor(JSContext* cx, unsigned argc, Value* vp) { 315 CallArgs args = CallArgsFromVp(argc, vp); 316 317 // Step 1. 318 if (!ThrowIfNotConstructing(cx, args, "Temporal.PlainMonthDay")) { 319 return false; 320 } 321 322 // Step 3. 323 double isoMonth; 324 if (!ToIntegerWithTruncation(cx, args.get(0), "month", &isoMonth)) { 325 return false; 326 } 327 328 // Step 4. 329 double isoDay; 330 if (!ToIntegerWithTruncation(cx, args.get(1), "day", &isoDay)) { 331 return false; 332 } 333 334 // Steps 5-7. 335 Rooted<CalendarValue> calendar(cx, CalendarValue(CalendarId::ISO8601)); 336 if (args.hasDefined(2)) { 337 // Step 6. 338 if (!args[2].isString()) { 339 ReportValueError(cx, JSMSG_UNEXPECTED_TYPE, JSDVG_IGNORE_STACK, args[2], 340 nullptr, "not a string"); 341 return false; 342 } 343 344 // Step 7. 345 Rooted<JSString*> calendarString(cx, args[2].toString()); 346 if (!CanonicalizeCalendar(cx, calendarString, &calendar)) { 347 return false; 348 } 349 } 350 351 // Steps 2 and 8. 352 double isoYear = 1972; 353 if (args.hasDefined(3)) { 354 if (!ToIntegerWithTruncation(cx, args[3], "year", &isoYear)) { 355 return false; 356 } 357 } 358 359 // Step 9. 360 if (!ThrowIfInvalidISODate(cx, isoYear, isoMonth, isoDay)) { 361 return false; 362 } 363 364 // Step 10. 365 auto isoDate = ISODate{int32_t(isoYear), int32_t(isoMonth), int32_t(isoDay)}; 366 367 // Step 9. 368 auto* monthDay = CreateTemporalMonthDay(cx, args, isoDate, calendar); 369 if (!monthDay) { 370 return false; 371 } 372 373 args.rval().setObject(*monthDay); 374 return true; 375 } 376 377 /** 378 * Temporal.PlainMonthDay.from ( item [ , options ] ) 379 */ 380 static bool PlainMonthDay_from(JSContext* cx, unsigned argc, Value* vp) { 381 CallArgs args = CallArgsFromVp(argc, vp); 382 383 // Step 1. 384 Rooted<PlainMonthDay> monthDay(cx); 385 if (!ToTemporalMonthDay(cx, args.get(0), args.get(1), &monthDay)) { 386 return false; 387 } 388 389 auto* result = CreateTemporalMonthDay(cx, monthDay); 390 if (!result) { 391 return false; 392 } 393 394 args.rval().setObject(*result); 395 return true; 396 } 397 398 /** 399 * get Temporal.PlainMonthDay.prototype.calendarId 400 */ 401 static bool PlainMonthDay_calendarId(JSContext* cx, const CallArgs& args) { 402 auto* monthDay = &args.thisv().toObject().as<PlainMonthDayObject>(); 403 404 // Step 3. 405 auto* str = 406 NewStringCopy<CanGC>(cx, CalendarIdentifier(monthDay->calendar())); 407 if (!str) { 408 return false; 409 } 410 411 args.rval().setString(str); 412 return true; 413 } 414 415 /** 416 * get Temporal.PlainMonthDay.prototype.calendarId 417 */ 418 static bool PlainMonthDay_calendarId(JSContext* cx, unsigned argc, Value* vp) { 419 // Steps 1-2. 420 CallArgs args = CallArgsFromVp(argc, vp); 421 return CallNonGenericMethod<IsPlainMonthDay, PlainMonthDay_calendarId>(cx, 422 args); 423 } 424 425 /** 426 * get Temporal.PlainMonthDay.prototype.monthCode 427 */ 428 static bool PlainMonthDay_monthCode(JSContext* cx, const CallArgs& args) { 429 auto* monthDay = &args.thisv().toObject().as<PlainMonthDayObject>(); 430 Rooted<CalendarValue> calendar(cx, monthDay->calendar()); 431 432 // Step 3. 433 return CalendarMonthCode(cx, calendar, monthDay->date(), args.rval()); 434 } 435 436 /** 437 * get Temporal.PlainMonthDay.prototype.monthCode 438 */ 439 static bool PlainMonthDay_monthCode(JSContext* cx, unsigned argc, Value* vp) { 440 // Steps 1-2. 441 CallArgs args = CallArgsFromVp(argc, vp); 442 return CallNonGenericMethod<IsPlainMonthDay, PlainMonthDay_monthCode>(cx, 443 args); 444 } 445 446 /** 447 * get Temporal.PlainMonthDay.prototype.day 448 */ 449 static bool PlainMonthDay_day(JSContext* cx, const CallArgs& args) { 450 auto* monthDay = &args.thisv().toObject().as<PlainMonthDayObject>(); 451 Rooted<CalendarValue> calendar(cx, monthDay->calendar()); 452 453 // Step 3. 454 return CalendarDay(cx, calendar, monthDay->date(), args.rval()); 455 } 456 457 /** 458 * get Temporal.PlainMonthDay.prototype.day 459 */ 460 static bool PlainMonthDay_day(JSContext* cx, unsigned argc, Value* vp) { 461 // Steps 1-2. 462 CallArgs args = CallArgsFromVp(argc, vp); 463 return CallNonGenericMethod<IsPlainMonthDay, PlainMonthDay_day>(cx, args); 464 } 465 466 /** 467 * Temporal.PlainMonthDay.prototype.with ( temporalMonthDayLike [ , options ] ) 468 */ 469 static bool PlainMonthDay_with(JSContext* cx, const CallArgs& args) { 470 Rooted<PlainMonthDay> monthDay( 471 cx, &args.thisv().toObject().as<PlainMonthDayObject>()); 472 473 // Step 3. 474 Rooted<JSObject*> temporalMonthDayLike( 475 cx, RequireObjectArg(cx, "temporalMonthDayLike", "with", args.get(0))); 476 if (!temporalMonthDayLike) { 477 return false; 478 } 479 if (!ThrowIfTemporalLikeObject(cx, temporalMonthDayLike)) { 480 return false; 481 } 482 483 // Step 4. 484 auto calendar = monthDay.calendar(); 485 486 // Step 5. 487 Rooted<CalendarFields> fields(cx); 488 if (!ISODateToFields(cx, monthDay, &fields)) { 489 return false; 490 } 491 492 // Step 6. 493 Rooted<CalendarFields> partialMonthDay(cx); 494 if (!PreparePartialCalendarFields(cx, calendar, temporalMonthDayLike, 495 { 496 CalendarField::Year, 497 CalendarField::Month, 498 CalendarField::MonthCode, 499 CalendarField::Day, 500 }, 501 &partialMonthDay)) { 502 return false; 503 } 504 MOZ_ASSERT(!partialMonthDay.keys().isEmpty()); 505 506 // Step 7. 507 fields = CalendarMergeFields(calendar, fields, partialMonthDay); 508 509 // Steps 8-9. 510 auto overflow = TemporalOverflow::Constrain; 511 if (args.hasDefined(1)) { 512 // Step 8. 513 Rooted<JSObject*> options(cx, 514 RequireObjectArg(cx, "options", "with", args[1])); 515 if (!options) { 516 return false; 517 } 518 519 // Step 9. 520 if (!GetTemporalOverflowOption(cx, options, &overflow)) { 521 return false; 522 } 523 } 524 525 // Step 10. 526 Rooted<PlainMonthDay> result(cx); 527 if (!CalendarMonthDayFromFields(cx, calendar, fields, overflow, &result)) { 528 return false; 529 } 530 MOZ_ASSERT(ISODateWithinLimits(result)); 531 532 // Step 11. 533 auto* obj = CreateTemporalMonthDay(cx, result); 534 if (!obj) { 535 return false; 536 } 537 538 args.rval().setObject(*obj); 539 return true; 540 } 541 542 /** 543 * Temporal.PlainMonthDay.prototype.with ( temporalMonthDayLike [ , options ] ) 544 */ 545 static bool PlainMonthDay_with(JSContext* cx, unsigned argc, Value* vp) { 546 // Steps 1-2. 547 CallArgs args = CallArgsFromVp(argc, vp); 548 return CallNonGenericMethod<IsPlainMonthDay, PlainMonthDay_with>(cx, args); 549 } 550 551 /** 552 * Temporal.PlainMonthDay.prototype.equals ( other ) 553 */ 554 static bool PlainMonthDay_equals(JSContext* cx, const CallArgs& args) { 555 auto* monthDay = &args.thisv().toObject().as<PlainMonthDayObject>(); 556 auto date = monthDay->date(); 557 Rooted<CalendarValue> calendar(cx, monthDay->calendar()); 558 559 // Step 3. 560 Rooted<PlainMonthDay> other(cx); 561 if (!ToTemporalMonthDay(cx, args.get(0), &other)) { 562 return false; 563 } 564 565 // Steps 4-7. 566 bool equals = 567 date == other.date() && CalendarEquals(calendar, other.calendar()); 568 569 args.rval().setBoolean(equals); 570 return true; 571 } 572 573 /** 574 * Temporal.PlainMonthDay.prototype.equals ( other ) 575 */ 576 static bool PlainMonthDay_equals(JSContext* cx, unsigned argc, Value* vp) { 577 // Steps 1-2. 578 CallArgs args = CallArgsFromVp(argc, vp); 579 return CallNonGenericMethod<IsPlainMonthDay, PlainMonthDay_equals>(cx, args); 580 } 581 582 /** 583 * Temporal.PlainMonthDay.prototype.toString ( [ options ] ) 584 */ 585 static bool PlainMonthDay_toString(JSContext* cx, const CallArgs& args) { 586 Rooted<PlainMonthDayObject*> monthDay( 587 cx, &args.thisv().toObject().as<PlainMonthDayObject>()); 588 589 auto showCalendar = ShowCalendar::Auto; 590 if (args.hasDefined(0)) { 591 // Step 3. 592 Rooted<JSObject*> options( 593 cx, RequireObjectArg(cx, "options", "toString", args[0])); 594 if (!options) { 595 return false; 596 } 597 598 // Step 4. 599 if (!GetTemporalShowCalendarNameOption(cx, options, &showCalendar)) { 600 return false; 601 } 602 } 603 604 // Step 5. 605 JSString* str = TemporalMonthDayToString(cx, monthDay, showCalendar); 606 if (!str) { 607 return false; 608 } 609 610 args.rval().setString(str); 611 return true; 612 } 613 614 /** 615 * Temporal.PlainMonthDay.prototype.toString ( [ options ] ) 616 */ 617 static bool PlainMonthDay_toString(JSContext* cx, unsigned argc, Value* vp) { 618 // Steps 1-2. 619 CallArgs args = CallArgsFromVp(argc, vp); 620 return CallNonGenericMethod<IsPlainMonthDay, PlainMonthDay_toString>(cx, 621 args); 622 } 623 624 /** 625 * Temporal.PlainMonthDay.prototype.toLocaleString ( [ locales [ , options ] ] ) 626 */ 627 static bool PlainMonthDay_toLocaleString(JSContext* cx, const CallArgs& args) { 628 // Steps 3-4. 629 return intl::TemporalObjectToLocaleString(cx, args, 630 intl::DateTimeFormatKind::Date); 631 } 632 633 /** 634 * Temporal.PlainMonthDay.prototype.toLocaleString ( [ locales [ , options ] ] ) 635 */ 636 static bool PlainMonthDay_toLocaleString(JSContext* cx, unsigned argc, 637 Value* vp) { 638 // Steps 1-2. 639 CallArgs args = CallArgsFromVp(argc, vp); 640 return CallNonGenericMethod<IsPlainMonthDay, PlainMonthDay_toLocaleString>( 641 cx, args); 642 } 643 644 /** 645 * Temporal.PlainMonthDay.prototype.toJSON ( ) 646 */ 647 static bool PlainMonthDay_toJSON(JSContext* cx, const CallArgs& args) { 648 Rooted<PlainMonthDayObject*> monthDay( 649 cx, &args.thisv().toObject().as<PlainMonthDayObject>()); 650 651 // Step 3. 652 JSString* str = TemporalMonthDayToString(cx, monthDay, ShowCalendar::Auto); 653 if (!str) { 654 return false; 655 } 656 657 args.rval().setString(str); 658 return true; 659 } 660 661 /** 662 * Temporal.PlainMonthDay.prototype.toJSON ( ) 663 */ 664 static bool PlainMonthDay_toJSON(JSContext* cx, unsigned argc, Value* vp) { 665 // Steps 1-2. 666 CallArgs args = CallArgsFromVp(argc, vp); 667 return CallNonGenericMethod<IsPlainMonthDay, PlainMonthDay_toJSON>(cx, args); 668 } 669 670 /** 671 * Temporal.PlainMonthDay.prototype.valueOf ( ) 672 */ 673 static bool PlainMonthDay_valueOf(JSContext* cx, unsigned argc, Value* vp) { 674 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CONVERT_TO, 675 "PlainMonthDay", "primitive type"); 676 return false; 677 } 678 679 /** 680 * Temporal.PlainMonthDay.prototype.toPlainDate ( item ) 681 */ 682 static bool PlainMonthDay_toPlainDate(JSContext* cx, const CallArgs& args) { 683 Rooted<PlainMonthDay> monthDay( 684 cx, &args.thisv().toObject().as<PlainMonthDayObject>()); 685 686 // Step 3. 687 Rooted<JSObject*> item( 688 cx, RequireObjectArg(cx, "item", "toPlainDate", args.get(0))); 689 if (!item) { 690 return false; 691 } 692 693 // Step 4. 694 auto calendar = monthDay.calendar(); 695 696 // Step 5. 697 Rooted<CalendarFields> fields(cx); 698 if (!ISODateToFields(cx, monthDay, &fields)) { 699 return false; 700 } 701 702 // Step 6. 703 Rooted<CalendarFields> inputFields(cx); 704 if (!PrepareCalendarFields(cx, calendar, item, 705 { 706 CalendarField::Year, 707 }, 708 &inputFields)) { 709 return false; 710 } 711 712 // Step 7. 713 fields = CalendarMergeFields(calendar, fields, inputFields); 714 715 // Step 8. 716 Rooted<PlainDate> date(cx); 717 if (!CalendarDateFromFields(cx, calendar, fields, TemporalOverflow::Constrain, 718 &date)) { 719 return false; 720 } 721 MOZ_ASSERT(ISODateWithinLimits(date)); 722 723 // Step 9. 724 auto* obj = CreateTemporalDate(cx, date); 725 if (!obj) { 726 return false; 727 } 728 729 args.rval().setObject(*obj); 730 return true; 731 } 732 733 /** 734 * Temporal.PlainMonthDay.prototype.toPlainDate ( item ) 735 */ 736 static bool PlainMonthDay_toPlainDate(JSContext* cx, unsigned argc, Value* vp) { 737 // Steps 1-2. 738 CallArgs args = CallArgsFromVp(argc, vp); 739 return CallNonGenericMethod<IsPlainMonthDay, PlainMonthDay_toPlainDate>(cx, 740 args); 741 } 742 743 const JSClass PlainMonthDayObject::class_ = { 744 "Temporal.PlainMonthDay", 745 JSCLASS_HAS_RESERVED_SLOTS(PlainMonthDayObject::SLOT_COUNT) | 746 JSCLASS_HAS_CACHED_PROTO(JSProto_PlainMonthDay), 747 JS_NULL_CLASS_OPS, 748 &PlainMonthDayObject::classSpec_, 749 }; 750 751 const JSClass& PlainMonthDayObject::protoClass_ = PlainObject::class_; 752 753 static const JSFunctionSpec PlainMonthDay_methods[] = { 754 JS_FN("from", PlainMonthDay_from, 1, 0), 755 JS_FS_END, 756 }; 757 758 static const JSFunctionSpec PlainMonthDay_prototype_methods[] = { 759 JS_FN("with", PlainMonthDay_with, 1, 0), 760 JS_FN("equals", PlainMonthDay_equals, 1, 0), 761 JS_FN("toString", PlainMonthDay_toString, 0, 0), 762 JS_FN("toLocaleString", PlainMonthDay_toLocaleString, 0, 0), 763 JS_FN("toJSON", PlainMonthDay_toJSON, 0, 0), 764 JS_FN("valueOf", PlainMonthDay_valueOf, 0, 0), 765 JS_FN("toPlainDate", PlainMonthDay_toPlainDate, 1, 0), 766 JS_FS_END, 767 }; 768 769 static const JSPropertySpec PlainMonthDay_prototype_properties[] = { 770 JS_PSG("calendarId", PlainMonthDay_calendarId, 0), 771 JS_PSG("monthCode", PlainMonthDay_monthCode, 0), 772 JS_PSG("day", PlainMonthDay_day, 0), 773 JS_STRING_SYM_PS(toStringTag, "Temporal.PlainMonthDay", JSPROP_READONLY), 774 JS_PS_END, 775 }; 776 777 const ClassSpec PlainMonthDayObject::classSpec_ = { 778 GenericCreateConstructor<PlainMonthDayConstructor, 2, 779 gc::AllocKind::FUNCTION>, 780 GenericCreatePrototype<PlainMonthDayObject>, 781 PlainMonthDay_methods, 782 nullptr, 783 PlainMonthDay_prototype_methods, 784 PlainMonthDay_prototype_properties, 785 nullptr, 786 ClassSpec::DontDefineConstructor, 787 };