Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Temporal: Initial PlainTime build out #3621

Merged
merged 1 commit into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/engine/src/builtins/temporal/calendar/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ impl Calendar {

// 5. Set duration to ? ToTemporalDuration(duration).
let duration_like = args.get_or_undefined(1);
let duration = temporal::duration::to_temporal_duration(duration_like)?;
let duration = temporal::duration::to_temporal_duration(duration_like, context)?;

// 6. Set options to ? GetOptionsObject(options).
let options = args.get_or_undefined(2);
Expand Down
62 changes: 51 additions & 11 deletions core/engine/src/builtins/temporal/duration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,16 +584,15 @@ impl Duration {
JsNativeError::typ().with_message("this value must be a Duration object.")
})?;

let round_to = args.get_or_undefined(0);
let round_to = match round_to {
let round_to = match args.first() {
// 3. If roundTo is undefined, then
JsValue::Undefined => {
None | Some(JsValue::Undefined) => {
return Err(JsNativeError::typ()
.with_message("roundTo cannot be undefined.")
.into())
}
// 4. If Type(roundTo) is String, then
JsValue::String(rt) => {
Some(JsValue::String(rt)) => {
// a. Let paramString be roundTo.
let param_string = rt.clone();
// b. Set roundTo to OrdinaryObjectCreate(null).
Expand All @@ -607,7 +606,7 @@ impl Duration {
new_round_to
}
// 5. Else,
_ => {
Some(round_to) => {
// a. Set roundTo to ? GetOptionsObject(roundTo).
get_options_object(round_to)?
}
Expand Down Expand Up @@ -876,7 +875,10 @@ impl Duration {
// -- Duration Abstract Operations --

/// 7.5.8 `ToTemporalDuration ( item )`
pub(crate) fn to_temporal_duration(item: &JsValue) -> JsResult<InnerDuration> {
pub(crate) fn to_temporal_duration(
item: &JsValue,
context: &mut Context,
) -> JsResult<InnerDuration> {
// 1a. If Type(item) is Object
// 1b. and item has an [[InitializedTemporalDuration]] internal slot, then
if let Some(duration) = item
Expand All @@ -887,18 +889,56 @@ pub(crate) fn to_temporal_duration(item: &JsValue) -> JsResult<InnerDuration> {
}

// 2. Let result be ? ToTemporalDurationRecord(item).
let result = to_temporal_duration_record(item)?;
let result = to_temporal_duration_record(item, context)?;
// 3. Return ! CreateTemporalDuration(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]]).
Ok(result)
}

/// 7.5.9 `ToTemporalDurationRecord ( temporalDurationLike )`
pub(crate) fn to_temporal_duration_record(
_temporal_duration_like: &JsValue,
temporal_duration_like: &JsValue,
context: &mut Context,
) -> JsResult<InnerDuration> {
Err(JsNativeError::range()
.with_message("Duration Parsing is not yet complete.")
.into())
// 1. If Type(temporalDurationLike) is not Object, then
let JsValue::Object(duration_obj) = temporal_duration_like else {
// a. If temporalDurationLike is not a String, throw a TypeError exception.
let JsValue::String(duration_string) = temporal_duration_like else {
return Err(JsNativeError::typ()
.with_message("Invalid TemporalDurationLike value.")
.into());
};

// b. Return ? ParseTemporalDurationString(temporalDurationLike).
return duration_string
.to_std_string_escaped()
.parse::<InnerDuration>()
.map_err(Into::into);
};

// 2. If temporalDurationLike has an [[InitializedTemporalDuration]] internal slot, then
if let Some(duration) = duration_obj.downcast_ref::<Duration>() {
// a. Return ! CreateDurationRecord(temporalDurationLike.[[Years]], temporalDurationLike.[[Months]], temporalDurationLike.[[Weeks]], temporalDurationLike.[[Days]], temporalDurationLike.[[Hours]], temporalDurationLike.[[Minutes]], temporalDurationLike.[[Seconds]], temporalDurationLike.[[Milliseconds]], temporalDurationLike.[[Microseconds]], temporalDurationLike.[[Nanoseconds]]).
return Ok(duration.inner);
}

// 3. Let result be a new Duration Record with each field set to 0.
// 4. Let partial be ? ToTemporalPartialDurationRecord(temporalDurationLike).
let partial = to_temporal_partial_duration(temporal_duration_like, context)?;

// 5. If partial.[[Years]] is not undefined, set result.[[Years]] to partial.[[Years]].
// 6. If partial.[[Months]] is not undefined, set result.[[Months]] to partial.[[Months]].
// 7. If partial.[[Weeks]] is not undefined, set result.[[Weeks]] to partial.[[Weeks]].
// 8. If partial.[[Days]] is not undefined, set result.[[Days]] to partial.[[Days]].
// 9. If partial.[[Hours]] is not undefined, set result.[[Hours]] to partial.[[Hours]].
// 10. If partial.[[Minutes]] is not undefined, set result.[[Minutes]] to partial.[[Minutes]].
// 11. If partial.[[Seconds]] is not undefined, set result.[[Seconds]] to partial.[[Seconds]].
// 12. If partial.[[Milliseconds]] is not undefined, set result.[[Milliseconds]] to partial.[[Milliseconds]].
// 13. If partial.[[Microseconds]] is not undefined, set result.[[Microseconds]] to partial.[[Microseconds]].
// 14. If partial.[[Nanoseconds]] is not undefined, set result.[[Nanoseconds]] to partial.[[Nanoseconds]].
// 15. If ! IsValidDuration(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]]) is false, then
// a. Throw a RangeError exception.
// 16. Return result.
InnerDuration::from_partial(&partial).map_err(Into::into)
}

/// 7.5.14 `CreateTemporalDuration ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds [ , newTarget ] )`
Expand Down
59 changes: 30 additions & 29 deletions core/engine/src/builtins/temporal/instant/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,8 @@ impl Instant {
})?;

// 3. Return ? AddDurationToOrSubtractDurationFromInstant(add, instant, temporalDurationLike).
let temporal_duration_like = to_temporal_duration_record(args.get_or_undefined(0))?;
let temporal_duration_like =
to_temporal_duration_record(args.get_or_undefined(0), context)?;
let result = instant.inner.add(temporal_duration_like)?;
create_temporal_instant(result, None, context)
}
Expand All @@ -258,7 +259,8 @@ impl Instant {
})?;

// 3. Return ? AddDurationToOrSubtractDurationFromInstant(subtract, instant, temporalDurationLike).
let temporal_duration_like = to_temporal_duration_record(args.get_or_undefined(0))?;
let temporal_duration_like =
to_temporal_duration_record(args.get_or_undefined(0), context)?;
let result = instant.inner.subtract(temporal_duration_like)?;
create_temporal_instant(result, None, context)
}
Expand Down Expand Up @@ -336,33 +338,32 @@ impl Instant {
JsNativeError::typ().with_message("the this object must be an instant object.")
})?;

let round_to = args.get_or_undefined(0);
// 3. If roundTo is undefined, then
if round_to.is_undefined() {
// a. Throw a TypeError exception.
return Err(JsNativeError::typ()
.with_message("roundTo cannot be undefined.")
.into());
};
// 4. If Type(roundTo) is String, then
let round_to = if round_to.is_string() {
// a. Let paramString be roundTo.
let param_string = round_to
.as_string()
.expect("roundTo is confirmed to be a string here.");
// b. Set roundTo to OrdinaryObjectCreate(null).
let new_round_to = JsObject::with_null_proto();
// c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit"), paramString).
new_round_to.create_data_property_or_throw(
utf16!("smallestUnit"),
param_string.clone(),
context,
)?;
new_round_to
// 5. Else,
} else {
// a. Set roundTo to ? GetOptionsObject(roundTo).
get_options_object(round_to)?
let round_to = match args.first() {
// 3. If roundTo is undefined, then
None | Some(JsValue::Undefined) => {
return Err(JsNativeError::typ()
.with_message("roundTo cannot be undefined.")
.into())
}
// 4. If Type(roundTo) is String, then
Some(JsValue::String(rt)) => {
// a. Let paramString be roundTo.
let param_string = rt.clone();
// b. Set roundTo to OrdinaryObjectCreate(null).
let new_round_to = JsObject::with_null_proto();
// c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString).
new_round_to.create_data_property_or_throw(
utf16!("smallestUnit"),
param_string,
context,
)?;
new_round_to
}
// 5. Else,
Some(round_to) => {
// a. Set roundTo to ? GetOptionsObject(roundTo).
get_options_object(round_to)?
}
};

// 6. NOTE: The following steps read options and perform independent validation in
Expand Down
6 changes: 1 addition & 5 deletions core/engine/src/builtins/temporal/plain_date/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,12 +505,8 @@ pub(crate) fn create_temporal_date(
new_target: Option<&JsValue>,
context: &mut Context,
) -> JsResult<JsObject> {
// NOTE (nekevss): The below should never trigger as `IsValidISODate` is enforced by Date.
// 1. If IsValidISODate(isoYear, isoMonth, isoDay) is false, throw a RangeError exception.
if !inner.is_valid() {
return Err(JsNativeError::range()
.with_message("Date is not a valid ISO date.")
.into());
};

// 2. If ISODateTimeWithinLimits(isoYear, isoMonth, isoDay, 12, 0, 0, 0, 0, 0) is false, throw a RangeError exception.
if !DateTime::<JsCustomCalendar>::validate(&inner) {
Expand Down
Loading
Loading