Skip to content

Commit

Permalink
Normative: Look up calendar methods only once
Browse files Browse the repository at this point in the history
Introduce a new spec type, Calendar Record, which stores a calendar
object's dateAdd, dateFromFields, and dateUntil methods once they have
been observably looked up. The record is passed around into abstract
operations instead of the calendar object itself.

These three are the only methods that are called more than once within
the same API call. Others are called only once and can be looked up as
needed.

This is a large commit but most of it is mechanical replacement of
Temporal.Calendar variables with Calendar Record variables.
  • Loading branch information
ptomato committed Apr 26, 2023
1 parent 1eee9e6 commit 5e0c619
Show file tree
Hide file tree
Showing 9 changed files with 606 additions and 349 deletions.
81 changes: 71 additions & 10 deletions polyfill/lib/duration.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import * as ES from './ecmascript.mjs';
import { MakeIntrinsicClass } from './intrinsicclass.mjs';
import { MethodRecord } from './methodrecord.mjs';
import {
YEARS,
MONTHS,
Expand Down Expand Up @@ -308,13 +309,40 @@ export class Duration {
plainRelativeTo = ES.TemporalDateTimeToDate(dt);
}

let calendar, calendarRec;
if (zonedRelativeTo) {
calendar = GetSlot(zonedRelativeTo, CALENDAR);
} else if (plainRelativeTo) {
calendar = GetSlot(plainRelativeTo, CALENDAR);
}
if (calendar) {
calendarRec = new MethodRecord(calendar);
if (
years !== 0 ||
months !== 0 ||
weeks !== 0 ||
largestUnit === 'year' ||
largestUnit === 'month' ||
largestUnit === 'week' ||
smallestUnit === 'year' ||
smallestUnit === 'month' ||
smallestUnit === 'week'
) {
calendarRec.lookup('dateAdd');
}
if (largestUnit === 'year' || (largestUnit === 'month' && years !== 0) || smallestUnit === 'year') {
calendarRec.lookup('dateUntil');
}
}

({ years, months, weeks, days } = ES.UnbalanceDurationRelative(
years,
months,
weeks,
days,
largestUnit,
plainRelativeTo
plainRelativeTo,
calendarRec
));
({ years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } =
ES.RoundDuration(
Expand All @@ -332,6 +360,7 @@ export class Duration {
smallestUnit,
roundingMode,
plainRelativeTo,
calendarRec,
zonedRelativeTo,
timeZoneRec
));
Expand All @@ -352,6 +381,7 @@ export class Duration {
smallestUnit,
roundingMode,
zonedRelativeTo,
calendarRec,
timeZoneRec
));
}
Expand All @@ -373,7 +403,8 @@ export class Duration {
weeks,
days,
largestUnit,
plainRelativeTo
plainRelativeTo,
calendarRec
));

return new Duration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds);
Expand Down Expand Up @@ -417,12 +448,36 @@ export class Duration {
plainRelativeTo = ES.TemporalDateTimeToDate(dt);
}

let calendar, calendarRec;
if (zonedRelativeTo) {
calendar = GetSlot(zonedRelativeTo, CALENDAR);
} else if (plainRelativeTo) {
calendar = GetSlot(plainRelativeTo, CALENDAR);
}
if (calendar) {
calendarRec = new MethodRecord(calendar);
if (years !== 0 || months !== 0 || weeks !== 0 || unit === 'year' || unit === 'month' || unit === 'week') {
calendarRec.lookup('dateAdd');
}
if (unit === 'year' || (unit === 'month' && years !== 0)) {
calendarRec.lookup('dateUntil');
}
}

// Convert larger units down to days
({ years, months, weeks, days } = ES.UnbalanceDurationRelative(years, months, weeks, days, unit, plainRelativeTo));
({ years, months, weeks, days } = ES.UnbalanceDurationRelative(
years,
months,
weeks,
days,
unit,
plainRelativeTo,
calendarRec
));
// If the unit we're totalling is smaller than `days`, convert days down to that unit.
let intermediate;
if (zonedRelativeTo) {
intermediate = ES.MoveRelativeZonedDateTime(zonedRelativeTo, timeZoneRec, years, months, weeks, 0);
intermediate = ES.MoveRelativeZonedDateTime(zonedRelativeTo, calendarRec, timeZoneRec, years, months, weeks, 0);
}
let balanceResult = ES.BalancePossiblyInfiniteDuration(
days,
Expand Down Expand Up @@ -458,6 +513,7 @@ export class Duration {
unit,
'trunc',
plainRelativeTo,
calendarRec,
zonedRelativeTo,
timeZoneRec
);
Expand Down Expand Up @@ -550,15 +606,20 @@ export class Duration {

const calendarUnitsPresent = y1 !== 0 || y2 !== 0 || mon1 !== 0 || mon2 !== 0 || w1 !== 0 || w2 !== 0;

let calendarRec;
if (relativeTo) {
calendarRec = new MethodRecord(GetSlot(relativeTo, CALENDAR));
if (calendarUnitsPresent) calendarRec.lookup('dateAdd');
}

if (ES.IsTemporalZonedDateTime(relativeTo) && (calendarUnitsPresent || d1 != 0 || d2 !== 0)) {
const instant = GetSlot(relativeTo, INSTANT);
const calendar = GetSlot(relativeTo, CALENDAR);
const precalculatedDateTime = ES.GetPlainDateTimeFor(timeZoneRec, instant, calendar);
const precalculatedDateTime = ES.GetPlainDateTimeFor(timeZoneRec, instant, calendarRec.receiver);

const after1 = ES.AddZonedDateTime(
instant,
timeZoneRec,
calendar,
calendarRec,
y1,
mon1,
w1,
Expand All @@ -574,7 +635,7 @@ export class Duration {
const after2 = ES.AddZonedDateTime(
instant,
timeZoneRec,
calendar,
calendarRec,
y2,
mon2,
w2,
Expand All @@ -592,8 +653,8 @@ export class Duration {

if (calendarUnitsPresent) {
// relativeTo is PlainDate or undefined
({ days: d1 } = ES.UnbalanceDurationRelative(y1, mon1, w1, d1, 'day', relativeTo));
({ days: d2 } = ES.UnbalanceDurationRelative(y2, mon2, w2, d2, 'day', relativeTo));
({ days: d1 } = ES.UnbalanceDurationRelative(y1, mon1, w1, d1, 'day', relativeTo, calendarRec));
({ days: d2 } = ES.UnbalanceDurationRelative(y2, mon2, w2, d2, 'day', relativeTo, calendarRec));
}
ns1 = ES.TotalDurationNanoseconds(d1, h1, min1, s1, ms1, µs1, ns1);
ns2 = ES.TotalDurationNanoseconds(d2, h2, min2, s2, ms2, µs2, ns2);
Expand Down
Loading

0 comments on commit 5e0c619

Please sign in to comment.