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 Mar 11, 2023
1 parent f1a2c69 commit a2f79ba
Show file tree
Hide file tree
Showing 9 changed files with 651 additions and 286 deletions.
89 changes: 78 additions & 11 deletions polyfill/lib/duration.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { ES } from './ecmascript.mjs';
import { MakeIntrinsicClass } from './intrinsicclass.mjs';
import { MethodRecord } from './methodrecord.mjs';
import {
YEARS,
MONTHS,
Expand Down Expand Up @@ -308,13 +309,38 @@ 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 +358,7 @@ export class Duration {
smallestUnit,
roundingMode,
plainRelativeTo,
calendarRec,
zonedRelativeTo,
timeZoneRec
));
Expand All @@ -352,6 +379,7 @@ export class Duration {
smallestUnit,
roundingMode,
zonedRelativeTo,
calendarRec,
timeZoneRec
));
}
Expand All @@ -361,10 +389,19 @@ export class Duration {
weeks,
days,
largestUnit,
plainRelativeTo
plainRelativeTo,
calendarRec
));
if (zonedRelativeTo) {
zonedRelativeTo = ES.MoveRelativeZonedDateTime(zonedRelativeTo, timeZoneRec, years, months, weeks, 0);
zonedRelativeTo = ES.MoveRelativeZonedDateTime(
zonedRelativeTo,
calendarRec,
timeZoneRec,
years,
months,
weeks,
0
);
}
({ days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = ES.BalanceDuration(
days,
Expand Down Expand Up @@ -420,12 +457,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 @@ -461,6 +522,7 @@ export class Duration {
unit,
'trunc',
plainRelativeTo,
calendarRec,
zonedRelativeTo,
timeZoneRec
);
Expand Down Expand Up @@ -553,15 +615,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 @@ -577,7 +644,7 @@ export class Duration {
const after2 = ES.AddZonedDateTime(
instant,
timeZoneRec,
calendar,
calendarRec,
y2,
mon2,
w2,
Expand All @@ -595,8 +662,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 a2f79ba

Please sign in to comment.