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

Patch Temporal.PlainTime and Temporal.Duration constructors #4078

Merged
merged 2 commits into from
Dec 11, 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
96 changes: 43 additions & 53 deletions core/engine/src/builtins/temporal/duration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,76 +221,66 @@ impl BuiltInConstructor for Duration {
}

// 2. If years is undefined, let y be 0; else let y be ? ToIntegerIfIntegral(years).
let years = FiniteF64::from(
args.first()
.map_or(Ok(0), |y| to_integer_if_integral(y, context))?,
);
let years = args
.get_or_undefined(0)
.map_or(Ok(0), |y| to_integer_if_integral(y, context))?;

// 3. If months is undefined, let mo be 0; else let mo be ? ToIntegerIfIntegral(months).
let months = FiniteF64::from(
args.get(1)
.map_or(Ok(0), |mo| to_integer_if_integral(mo, context))?,
);
let months = args
.get_or_undefined(1)
.map_or(Ok(0), |mo| to_integer_if_integral(mo, context))?;

// 4. If weeks is undefined, let w be 0; else let w be ? ToIntegerIfIntegral(weeks).
let weeks = FiniteF64::from(
args.get(2)
.map_or(Ok(0), |wk| to_integer_if_integral(wk, context))?,
);
let weeks = args
.get_or_undefined(2)
.map_or(Ok(0), |wk| to_integer_if_integral(wk, context))?;

// 5. If days is undefined, let d be 0; else let d be ? ToIntegerIfIntegral(days).
let days = FiniteF64::from(
args.get(3)
.map_or(Ok(0), |d| to_integer_if_integral(d, context))?,
);
let days = args
.get_or_undefined(3)
.map_or(Ok(0), |d| to_integer_if_integral(d, context))?;

// 6. If hours is undefined, let h be 0; else let h be ? ToIntegerIfIntegral(hours).
let hours = FiniteF64::from(
args.get(4)
.map_or(Ok(0), |h| to_integer_if_integral(h, context))?,
);
let hours = args
.get_or_undefined(4)
.map_or(Ok(0), |h| to_integer_if_integral(h, context))?;

// 7. If minutes is undefined, let m be 0; else let m be ? ToIntegerIfIntegral(minutes).
let minutes = FiniteF64::from(
args.get(5)
.map_or(Ok(0), |m| to_integer_if_integral(m, context))?,
);
let minutes = args
.get_or_undefined(5)
.map_or(Ok(0), |m| to_integer_if_integral(m, context))?;

// 8. If seconds is undefined, let s be 0; else let s be ? ToIntegerIfIntegral(seconds).
let seconds = FiniteF64::from(
args.get(6)
.map_or(Ok(0), |s| to_integer_if_integral(s, context))?,
);
let seconds = args
.get_or_undefined(6)
.map_or(Ok(0), |s| to_integer_if_integral(s, context))?;

// 9. If milliseconds is undefined, let ms be 0; else let ms be ? ToIntegerIfIntegral(milliseconds).
let milliseconds = FiniteF64::from(
args.get(7)
.map_or(Ok(0), |ms| to_integer_if_integral(ms, context))?,
);
let milliseconds = args
.get_or_undefined(7)
.map_or(Ok(0), |ms| to_integer_if_integral(ms, context))?;

// 10. If microseconds is undefined, let mis be 0; else let mis be ? ToIntegerIfIntegral(microseconds).
let microseconds = FiniteF64::from(
args.get(8)
.map_or(Ok(0), |mis| to_integer_if_integral(mis, context))?,
);
let microseconds = args
.get_or_undefined(8)
.map_or(Ok(0), |mis| to_integer_if_integral(mis, context))?;

// 11. If nanoseconds is undefined, let ns be 0; else let ns be ? ToIntegerIfIntegral(nanoseconds).
let nanoseconds = FiniteF64::from(
args.get(9)
.map_or(Ok(0), |ns| to_integer_if_integral(ns, context))?,
);
let nanoseconds = args
.get_or_undefined(9)
.map_or(Ok(0), |ns| to_integer_if_integral(ns, context))?;

let record = InnerDuration::new(
years,
months,
weeks,
days,
hours,
minutes,
seconds,
milliseconds,
microseconds,
nanoseconds,
years.into(),
months.into(),
weeks.into(),
days.into(),
hours.into(),
minutes.into(),
seconds.into(),
milliseconds.into(),
microseconds.into(),
nanoseconds.into(),
)?;

// 12. Return ? CreateTemporalDuration(y, mo, w, d, h, m, s, ms, mis, ns, NewTarget).
Expand Down Expand Up @@ -786,21 +776,21 @@ impl Duration {

// TODO: Implement the rest of the new `Temporal.Duration.prototype.total`

Err(JsNativeError::range()
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
}

/// 7.3.22 `Temporal.Duration.prototype.toString ( [ options ] )`
pub(crate) fn to_string(_this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::range()
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
}

/// 7.3.23 `Temporal.Duration.prototype.toJSON ( )`
pub(crate) fn to_json(_this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::range()
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
}
Expand Down
12 changes: 6 additions & 6 deletions core/engine/src/builtins/temporal/plain_date_time/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,27 +314,27 @@ impl BuiltInConstructor for PlainDateTime {
let iso_day = to_integer_with_truncation(args.get_or_undefined(2), context)?;
// 5. If hour is undefined, set hour to 0; else set hour to ? ToIntegerWithTruncation(hour).
let hour = args
.get(3)
.get_or_undefined(3)
.map_or(Ok(0), |v| to_integer_with_truncation(v, context))?;
// 6. If minute is undefined, set minute to 0; else set minute to ? ToIntegerWithTruncation(minute).
let minute = args
.get(4)
.get_or_undefined(4)
.map_or(Ok(0), |v| to_integer_with_truncation(v, context))?;
// 7. If second is undefined, set second to 0; else set second to ? ToIntegerWithTruncation(second).
let second = args
.get(5)
.get_or_undefined(5)
.map_or(Ok(0), |v| to_integer_with_truncation(v, context))?;
// 8. If millisecond is undefined, set millisecond to 0; else set millisecond to ? ToIntegerWithTruncation(millisecond).
let millisecond = args
.get(6)
.get_or_undefined(6)
.map_or(Ok(0), |v| to_integer_with_truncation(v, context))?;
// 9. If microsecond is undefined, set microsecond to 0; else set microsecond to ? ToIntegerWithTruncation(microsecond).
let microsecond = args
.get(7)
.get_or_undefined(7)
.map_or(Ok(0), |v| to_integer_with_truncation(v, context))?;
// 10. If nanosecond is undefined, set nanosecond to 0; else set nanosecond to ? ToIntegerWithTruncation(nanosecond).
let nanosecond = args
.get(8)
.get_or_undefined(8)
.map_or(Ok(0), |v| to_integer_with_truncation(v, context))?;
// 11. Let calendar be ? ToTemporalCalendarSlotValue(calendarLike, "iso8601").
let calendar_slot = to_temporal_calendar_slot_value(args.get_or_undefined(9))?;
Expand Down
36 changes: 12 additions & 24 deletions core/engine/src/builtins/temporal/plain_time/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,40 +150,28 @@ impl BuiltInConstructor for PlainTime {

// 2. If hour is undefined, set hour to 0; else set hour to ? ToIntegerWithTruncation(hour).
let hour = args
.first()
.map(|v| to_integer_with_truncation(v, context))
.transpose()?
.unwrap_or(0);
.get_or_undefined(0)
.map_or(Ok(0), |v| to_integer_with_truncation(v, context))?;
// 3. If minute is undefined, set minute to 0; else set minute to ? ToIntegerWithTruncation(minute).
let minute = args
.get(1)
.map(|v| to_integer_with_truncation(v, context))
.transpose()?
.unwrap_or(0);
.get_or_undefined(1)
.map_or(Ok(0), |v| to_integer_with_truncation(v, context))?;
// 4. If second is undefined, set second to 0; else set second to ? ToIntegerWithTruncation(second).
let second = args
.get(2)
.map(|v| to_integer_with_truncation(v, context))
.transpose()?
.unwrap_or(0);
.get_or_undefined(2)
.map_or(Ok(0), |v| to_integer_with_truncation(v, context))?;
// 5. If millisecond is undefined, set millisecond to 0; else set millisecond to ? ToIntegerWithTruncation(millisecond).
let millisecond = args
.get(3)
.map(|v| to_integer_with_truncation(v, context))
.transpose()?
.unwrap_or(0);
.get_or_undefined(3)
.map_or(Ok(0), |v| to_integer_with_truncation(v, context))?;
// 6. If microsecond is undefined, set microsecond to 0; else set microsecond to ? ToIntegerWithTruncation(microsecond).
let microsecond = args
.get(4)
.map(|v| to_integer_with_truncation(v, context))
.transpose()?
.unwrap_or(0);
.get_or_undefined(4)
.map_or(Ok(0), |v| to_integer_with_truncation(v, context))?;
// 7. If nanosecond is undefined, set nanosecond to 0; else set nanosecond to ? ToIntegerWithTruncation(nanosecond).
let nanosecond = args
.get(5)
.map(|v| to_integer_with_truncation(v, context))
.transpose()?
.unwrap_or(0);
.get_or_undefined(5)
.map_or(Ok(0), |v| to_integer_with_truncation(v, context))?;

let inner =
PlainTimeInner::new(hour, minute, second, millisecond, microsecond, nanosecond)?;
Expand Down
40 changes: 38 additions & 2 deletions core/engine/src/value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1054,7 +1054,7 @@ impl JsValue {
}
}

/// Maps a `JsValue` into a `Option<T>` where T is the result of an
/// Maps a `JsValue` into `Option<T>` where T is the result of an
/// operation on a defined value. If the value is `JsValue::undefined`,
/// then `JsValue::map` will return None.
///
Expand All @@ -1075,7 +1075,6 @@ impl JsValue {
/// assert_eq!(undefined_result, None);
///
/// ```
///
#[inline]
#[must_use]
pub fn map<T, F>(&self, f: F) -> Option<T>
Expand All @@ -1088,6 +1087,43 @@ impl JsValue {
Some(f(self))
}

/// Maps a `JsValue` into `T` where T is the result of an
/// operation on a defined value. If the value is `JsValue::undefined`,
/// then `JsValue::map` will return the provided default value.
///
/// # Example
///
/// ```
/// use boa_engine::{JsValue, Context};
///
/// let mut context = Context::default();
///
/// let defined_value = JsValue::from(5);
/// let undefined = JsValue::undefined();
///
/// let defined_result = defined_value
/// .map_or(Ok(JsValue::Boolean(true)), |v| v.add(&JsValue::from(5), &mut context))
/// .unwrap();
/// let undefined_result = undefined
/// .map_or(Ok(JsValue::Boolean(true)), |v| v.add(&JsValue::from(5), &mut context))
/// .unwrap();
///
/// assert_eq!(defined_result, JsValue::Integer(10));
/// assert_eq!(undefined_result, JsValue::Boolean(true));
///
/// ```
#[inline]
#[must_use]
pub fn map_or<T, F>(&self, default: T, f: F) -> T
where
F: FnOnce(&JsValue) -> T,
{
if self.is_undefined() {
return default;
}
f(self)
}

/// Abstract operation `IsArray ( argument )`
///
/// Check if a value is an array.
Expand Down
Loading