Browse Source

Refactor the `Math` builtin object (#1584)

* Document the `Math` builtin object

* Fix typos and rename variables
pull/1587/head
jedel1043 3 years ago committed by GitHub
parent
commit
dd84439ea0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 492
      boa/src/builtins/math/mod.rs

492
boa/src/builtins/math/mod.rs

@ -16,6 +16,8 @@ use crate::{
BoaProfiler, Context, JsResult, JsValue,
};
use super::JsArgs;
#[cfg(test)]
mod tests;
@ -37,13 +39,13 @@ impl BuiltIn for Math {
let string_tag = WellKnownSymbols::to_string_tag();
let object = ObjectInitializer::new(context)
.property("E", std::f64::consts::E, attribute)
.property("LN2", std::f64::consts::LN_2, attribute)
.property("LN10", std::f64::consts::LN_10, attribute)
.property("LOG2E", std::f64::consts::LOG2_E, attribute)
.property("LN2", std::f64::consts::LN_2, attribute)
.property("LOG10E", std::f64::consts::LOG10_E, attribute)
.property("LOG2E", std::f64::consts::LOG2_E, attribute)
.property("PI", std::f64::consts::PI, attribute)
.property("SQRT1_2", std::f64::consts::FRAC_1_SQRT_2, attribute)
.property("SQRT2", std::f64::consts::SQRT_2, attribute)
.property("PI", std::f64::consts::PI, attribute)
.function(Self::abs, "abs", 1)
.function(Self::acos, "acos", 1)
.function(Self::acosh, "acosh", 1)
@ -101,10 +103,15 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/abs
pub(crate) fn abs(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::abs)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 3. If n is -0𝔽, return +0𝔽.
// 2. If n is NaN, return NaN.
// 4. If n is -∞𝔽, return +∞𝔽.
// 5. If n < +0𝔽, return -n.
// 6. Return n.
.abs()
.into())
}
@ -118,10 +125,13 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/acos
pub(crate) fn acos(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::acos)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN, n > 1𝔽, or n < -1𝔽, return NaN.
// 3. If n is 1𝔽, return +0𝔽.
// 4. Return an implementation-approximated value representing the result of the inverse cosine of ℝ(n).
.acos()
.into())
}
@ -135,10 +145,14 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/acosh
pub(crate) fn acosh(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::acosh)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 4. If n < 1𝔽, return NaN.
// 2. If n is NaN or n is +∞𝔽, return n.
// 3. If n is 1𝔽, return +0𝔽.
// 5. Return an implementation-approximated value representing the result of the inverse hyperbolic cosine of ℝ(n).
.acosh()
.into())
}
@ -152,10 +166,13 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/asin
pub(crate) fn asin(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::asin)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN, n is +0𝔽, or n is -0𝔽, return n.
// 3. If n > 1𝔽 or n < -1𝔽, return NaN.
// 4. Return an implementation-approximated value representing the result of the inverse sine of ℝ(n).
.asin()
.into())
}
@ -169,10 +186,12 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/asinh
pub(crate) fn asinh(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::asinh)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN, n is +0𝔽, n is -0𝔽, n is +∞𝔽, or n is -∞𝔽, return n.
// 3. Return an implementation-approximated value representing the result of the inverse hyperbolic sine of ℝ(n).
.asinh()
.into())
}
@ -186,10 +205,14 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atan
pub(crate) fn atan(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::atan)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN, n is +0𝔽, or n is -0𝔽, return n.
// 3. If n is +∞𝔽, return an implementation-approximated value representing π / 2.
// 4. If n is -∞𝔽, return an implementation-approximated value representing -π / 2.
// 5. Return an implementation-approximated value representing the result of the inverse tangent of ℝ(n).
.atan()
.into())
}
@ -203,14 +226,19 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atanh
pub(crate) fn atanh(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::atanh)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN, n is +0𝔽, or n is -0𝔽, return n.
// 3. If n > 1𝔽 or n < -1𝔽, return NaN.
// 4. If n is 1𝔽, return +∞𝔽.
// 5. If n is -1𝔽, return -∞𝔽.
// 6. Return an implementation-approximated value representing the result of the inverse hyperbolic tangent of ℝ(n).
.atanh()
.into())
}
/// Get the arctangent of a numbers.
/// Get the four quadrant arctangent of the quotient y / x.
///
/// More information:
/// - [ECMAScript reference][spec]
@ -219,14 +247,38 @@ impl Math {
/// [spec]: https://tc39.es/ecma262/#sec-math.atan2
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atan2
pub(crate) fn atan2(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(match (
args.get(0).map(|x| x.to_number(context)).transpose()?,
args.get(1).map(|x| x.to_number(context)).transpose()?,
) {
(Some(x), Some(y)) => x.atan2(y),
(_, _) => f64::NAN,
}
.into())
// 1. Let ny be ? ToNumber(y).
let y = args.get_or_undefined(0).to_number(context)?;
// 2. Let nx be ? ToNumber(x).
let x = args.get_or_undefined(1).to_number(context)?;
// 4. If ny is +∞𝔽, then
// a. If nx is +∞𝔽, return an implementation-approximated value representing π / 4.
// b. If nx is -∞𝔽, return an implementation-approximated value representing 3π / 4.
// c. Return an implementation-approximated value representing π / 2.
// 5. If ny is -∞𝔽, then
// a. If nx is +∞𝔽, return an implementation-approximated value representing -π / 4.
// b. If nx is -∞𝔽, return an implementation-approximated value representing -3π / 4.
// c. Return an implementation-approximated value representing -π / 2.
// 6. If ny is +0𝔽, then
// a. If nx > +0𝔽 or nx is +0𝔽, return +0𝔽.
// b. Return an implementation-approximated value representing π.
// 7. If ny is -0𝔽, then
// a. If nx > +0𝔽 or nx is +0𝔽, return -0𝔽.
// b. Return an implementation-approximated value representing -π.
// 8. Assert: ny is finite and is neither +0𝔽 nor -0𝔽.
// 9. If ny > +0𝔽, then
// a. If nx is +∞𝔽, return +0𝔽.
// b. If nx is -∞𝔽, return an implementation-approximated value representing π.
// c. If nx is +0𝔽 or nx is -0𝔽, return an implementation-approximated value representing π / 2.
// 10. If ny < +0𝔽, then
// a. If nx is +∞𝔽, return -0𝔽.
// b. If nx is -∞𝔽, return an implementation-approximated value representing -π.
// c. If nx is +0𝔽 or nx is -0𝔽, return an implementation-approximated value representing -π / 2.
// 11. Assert: nx is finite and is neither +0𝔽 nor -0𝔽.
// 12. Return an implementation-approximated value representing the result of the inverse tangent of the quotient ℝ(ny) / ℝ(nx).
Ok(y.atan2(x).into())
}
/// Get the cubic root of a number.
@ -239,10 +291,12 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cbrt
pub(crate) fn cbrt(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::cbrt)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN, n is +0𝔽, n is -0𝔽, n is +∞𝔽, or n is -∞𝔽, return n.
// 3. Return an implementation-approximated value representing the result of the cube root of ℝ(n).
.cbrt()
.into())
}
@ -256,10 +310,14 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/ceil
pub(crate) fn ceil(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::ceil)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN, n is +0𝔽, n is -0𝔽, n is +∞𝔽, or n is -∞𝔽, return n.
// 3. If n < +0𝔽 and n > -1𝔽, return -0𝔽.
// 4. If n is an integral Number, return n.
// 5. Return the smallest (closest to -∞) integral Number value that is not less than n.
.ceil()
.into())
}
@ -273,11 +331,12 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32
pub(crate) fn clz32(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_u32(context))
.transpose()?
.map(u32::leading_zeros)
.unwrap_or(32)
.get_or_undefined(0)
// 1. Let n be ? ToUint32(x).
.to_u32(context)?
// 2. Let p be the number of leading zero bits in the unsigned 32-bit binary representation of n.
// 3. Return 𝔽(p).
.leading_zeros()
.into())
}
@ -291,10 +350,13 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cos
pub(crate) fn cos(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::cos)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN, n is +∞𝔽, or n is -∞𝔽, return NaN.
// 3. If n is +0𝔽 or n is -0𝔽, return 1𝔽.
// 4. Return an implementation-approximated value representing the result of the cosine of ℝ(n).
.cos()
.into())
}
@ -308,10 +370,14 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cosh
pub(crate) fn cosh(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::cosh)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN, return NaN.
// 3. If n is +∞𝔽 or n is -∞𝔽, return +∞𝔽.
// 4. If n is +0𝔽 or n is -0𝔽, return 1𝔽.
// 5. Return an implementation-approximated value representing the result of the hyperbolic cosine of ℝ(n).
.cosh()
.into())
}
@ -325,10 +391,14 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/exp
pub(crate) fn exp(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::exp)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN or n is +∞𝔽, return n.
// 3. If n is +0𝔽 or n is -0𝔽, return 1𝔽.
// 4. If n is -∞𝔽, return +0𝔽.
// 5. Return an implementation-approximated value representing the result of the exponential function of ℝ(n).
.exp()
.into())
}
@ -344,10 +414,13 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/expm1
pub(crate) fn expm1(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::exp_m1)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN, n is +0𝔽, n is -0𝔽, or n is +∞𝔽, return n.
// 3. If n is -∞𝔽, return -1𝔽.
// 4. Return an implementation-approximated value representing the result of subtracting 1 from the exponential function of ℝ(n).
.exp_m1()
.into())
}
@ -361,10 +434,14 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor
pub(crate) fn floor(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::floor)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN, n is +0𝔽, n is -0𝔽, n is +∞𝔽, or n is -∞𝔽, return n.
// 3. If n < 1𝔽 and n > +0𝔽, return +0𝔽.
// 4. If n is an integral Number, return n.
// 5. Return the greatest (closest to +∞) integral Number value that is not greater than n.
.floor()
.into())
}
@ -381,12 +458,15 @@ impl Math {
args: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, |x| (x as f32) as f64)
.into())
// 1. Let n be ? ToNumber(x).
let x = args.get_or_undefined(0).to_number(context)?;
// 2. If n is NaN, return NaN.
// 3. If n is one of +0𝔽, -0𝔽, +∞𝔽, or -∞𝔽, return n.
// 4. Let n32 be the result of converting n to a value in IEEE 754-2019 binary32 format using roundTiesToEven mode.
// 5. Let n64 be the result of converting n32 to a value in IEEE 754-2019 binary64 format.
// 6. Return the ECMAScript Number value corresponding to n64.
Ok((x as f32 as f64).into())
}
/// Get an approximation of the square root of the sum of squares of all arguments.
@ -398,11 +478,24 @@ impl Math {
/// [spec]: https://tc39.es/ecma262/#sec-math.hypot
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/hypot
pub(crate) fn hypot(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
// 1. Let coerced be a new empty List.
// 2. For each element arg of args, do
// a. Let n be ? ToNumber(arg).
// b. Append n to coerced.
// 3. For each element number of coerced, do
// 5. For each element number of coerced, do
let mut result = 0f64;
for arg in args {
let x = arg.to_number(context)?;
result = result.hypot(x);
let num = arg.to_number(context)?;
// a. If number is +∞𝔽 or number is -∞𝔽, return +∞𝔽.
// 4. Let onlyZero be true.
// a. If number is NaN, return NaN.
// b. If number is neither +0𝔽 nor -0𝔽, set onlyZero to false.
// 6. If onlyZero is true, return +0𝔽.
// 7. Return an implementation-approximated value representing the square root of the sum of squares of the mathematical values of the elements of coerced.
result = result.hypot(num);
}
Ok(result.into())
}
@ -415,14 +508,15 @@ impl Math {
/// [spec]: https://tc39.es/ecma262/#sec-math.imul
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul
pub(crate) fn imul(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(match (
args.get(0).map(|x| x.to_u32(context)).transpose()?,
args.get(1).map(|x| x.to_u32(context)).transpose()?,
) {
(Some(x), Some(y)) => x.wrapping_mul(y) as i32,
(_, _) => 0,
}
.into())
// 1. Let a be ℝ(? ToUint32(x)).
let x = args.get_or_undefined(0).to_u32(context)?;
// 2. Let b be ℝ(? ToUint32(y)).
let y = args.get_or_undefined(1).to_u32(context)?;
// 3. Let product be (a × b) modulo 2^32.
// 4. If product ≥ 2^31, return 𝔽(product - 2^32); otherwise return 𝔽(product).
Ok((x.wrapping_mul(y) as i32).into())
}
/// Get the natural logarithm of a number.
@ -435,10 +529,15 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log
pub(crate) fn log(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, |x| if x <= 0.0 { f64::NAN } else { x.ln() })
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN or n is +∞𝔽, return n.
// 3. If n is 1𝔽, return +0𝔽.
// 4. If n is +0𝔽 or n is -0𝔽, return -∞𝔽.
// 5. If n < +0𝔽, return NaN.
// 6. Return an implementation-approximated value representing the result of the natural logarithm of ℝ(n).
.ln()
.into())
}
@ -452,10 +551,14 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log1p
pub(crate) fn log1p(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::ln_1p)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN, n is +0𝔽, n is -0𝔽, or n is +∞𝔽, return n.
// 3. If n is -1𝔽, return -∞𝔽.
// 4. If n < -1𝔽, return NaN.
// 5. Return an implementation-approximated value representing the result of the natural logarithm of 1 + ℝ(n).
.ln_1p()
.into())
}
@ -469,10 +572,15 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log10
pub(crate) fn log10(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, |x| if x <= 0.0 { f64::NAN } else { x.log10() })
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN or n is +∞𝔽, return n.
// 3. If n is 1𝔽, return +0𝔽.
// 4. If n is +0𝔽 or n is -0𝔽, return -∞𝔽.
// 5. If n < +0𝔽, return NaN.
// 6. Return an implementation-approximated value representing the result of the base 10 logarithm of ℝ(n).
.log10()
.into())
}
@ -486,10 +594,15 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log2
pub(crate) fn log2(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, |x| if x <= 0.0 { f64::NAN } else { x.log2() })
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN or n is +∞𝔽, return n.
// 3. If n is 1𝔽, return +0𝔽.
// 4. If n is +0𝔽 or n is -0𝔽, return -∞𝔽.
// 5. If n < +0𝔽, return NaN.
// 6. Return an implementation-approximated value representing the result of the base 2 logarithm of ℝ(n).
.log2()
.into())
}
@ -502,12 +615,30 @@ impl Math {
/// [spec]: https://tc39.es/ecma262/#sec-math.max
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max
pub(crate) fn max(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let mut max = f64::NEG_INFINITY;
// 1. Let coerced be a new empty List.
// 2. For each element arg of args, do
// b. Append n to coerced.
// 3. Let highest be -∞𝔽.
let mut highest = f64::NEG_INFINITY;
// 4. For each element number of coerced, do
for arg in args {
// a. Let n be ? ToNumber(arg).
let num = arg.to_number(context)?;
max = max.max(num);
highest = if highest.is_nan() {
continue;
} else if num.is_nan() {
// a. If number is NaN, return NaN.
f64::NAN
} else {
// b. If number is +0𝔽 and highest is -0𝔽, set highest to +0𝔽.
// c. If number > highest, set highest to number.
highest.max(num)
};
}
Ok(max.into())
// 5. Return highest.
Ok(highest.into())
}
/// Get the minimum of several numbers.
@ -519,12 +650,30 @@ impl Math {
/// [spec]: https://tc39.es/ecma262/#sec-math.min
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min
pub(crate) fn min(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let mut min = f64::INFINITY;
// 1. Let coerced be a new empty List.
// 2. For each element arg of args, do
// b. Append n to coerced.
// 3. Let lowest be +∞𝔽.
let mut lowest = f64::INFINITY;
// 4. For each element number of coerced, do
for arg in args {
// a. Let n be ? ToNumber(arg).
let num = arg.to_number(context)?;
min = min.min(num);
lowest = if lowest.is_nan() {
continue;
} else if num.is_nan() {
// a. If number is NaN, return NaN.
f64::NAN
} else {
// b. If number is -0𝔽 and lowest is +0𝔽, set lowest to -0𝔽.
// c. If number < lowest, set lowest to number.
lowest.min(num)
};
}
Ok(min.into())
// 5. Return lowest.
Ok(lowest.into())
}
/// Raise a number to a power.
@ -536,14 +685,14 @@ impl Math {
/// [spec]: https://tc39.es/ecma262/#sec-math.pow
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/pow
pub(crate) fn pow(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(match (
args.get(0).map(|x| x.to_number(context)).transpose()?,
args.get(1).map(|x| x.to_number(context)).transpose()?,
) {
(Some(x), Some(y)) => x.powf(y),
(_, _) => f64::NAN,
}
.into())
// 1. Set base to ? ToNumber(base).
let x = args.get_or_undefined(0).to_number(context)?;
// 2. Set exponent to ? ToNumber(exponent).
let y = args.get_or_undefined(1).to_number(context)?;
// 3. Return ! Number::exponentiate(base, exponent).
Ok(x.powf(y).into())
}
/// Generate a random floating-point number between `0` and `1`.
@ -555,6 +704,7 @@ impl Math {
/// [spec]: https://tc39.es/ecma262/#sec-math.random
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
pub(crate) fn random(_: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
// NOTE: Each Math.random function created for distinct realms must produce a distinct sequence of values from successive calls.
Ok(rand::random::<f64>().into())
}
@ -568,10 +718,14 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
pub(crate) fn round(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::round)
.get_or_undefined(0)
//1. Let n be ? ToNumber(x).
.to_number(context)?
//2. If n is NaN, +∞𝔽, -∞𝔽, or an integral Number, return n.
//3. If n < 0.5𝔽 and n > +0𝔽, return +0𝔽.
//4. If n < +0𝔽 and n ≥ -0.5𝔽, return -0𝔽.
//5. Return the integral Number closest to n, preferring the Number closer to +∞ in the case of a tie.
.round()
.into())
}
@ -584,21 +738,16 @@ impl Math {
/// [spec]: https://tc39.es/ecma262/#sec-math.sign
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign
pub(crate) fn sign(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(
f64::NAN,
|x| {
if x == 0.0 || x == -0.0 {
x
} else {
x.signum()
}
},
)
.into())
// 1. Let n be ? ToNumber(x).
let n = args.get_or_undefined(0).to_number(context)?;
// 2. If n is NaN, n is +0𝔽, or n is -0𝔽, return n.
if n == 0.0 {
return Ok(n.into());
}
// 3. If n < +0𝔽, return -1𝔽.
// 4. Return 1𝔽.
Ok(n.signum().into())
}
/// Get the sine of a number.
@ -611,10 +760,13 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sin
pub(crate) fn sin(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::sin)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN, n is +0𝔽, or n is -0𝔽, return n.
// 3. If n is +∞𝔽 or n is -∞𝔽, return NaN.
// 4. Return an implementation-approximated value representing the result of the sine of ℝ(n).
.sin()
.into())
}
@ -628,10 +780,12 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sinh
pub(crate) fn sinh(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::sinh)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN, n is +0𝔽, n is -0𝔽, n is +∞𝔽, or n is -∞𝔽, return n.
// 3. Return an implementation-approximated value representing the result of the hyperbolic sine of ℝ(n).
.sinh()
.into())
}
@ -645,10 +799,13 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sqrt
pub(crate) fn sqrt(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::sqrt)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN, n is +0𝔽, n is -0𝔽, or n is +∞𝔽, return n.
// 3. If n < +0𝔽, return NaN.
// 4. Return an implementation-approximated value representing the result of the square root of ℝ(n).
.sqrt()
.into())
}
@ -662,10 +819,13 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/tan
pub(crate) fn tan(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::tan)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN, n is +0𝔽, or n is -0𝔽, return n.
// 3. If n is +∞𝔽, or n is -∞𝔽, return NaN.
// 4. Return an implementation-approximated value representing the result of the tangent of ℝ(n).
.tan()
.into())
}
@ -679,10 +839,14 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/tanh
pub(crate) fn tanh(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::tanh)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN, n is +0𝔽, or n is -0𝔽, return n.
// 3. If n is +∞𝔽, return 1𝔽.
// 4. If n is -∞𝔽, return -1𝔽.
// 5. Return an implementation-approximated value representing the result of the hyperbolic tangent of ℝ(n).
.tanh()
.into())
}
@ -696,10 +860,14 @@ impl Math {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc
pub(crate) fn trunc(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Ok(args
.get(0)
.map(|x| x.to_number(context))
.transpose()?
.map_or(f64::NAN, f64::trunc)
.get_or_undefined(0)
// 1. Let n be ? ToNumber(x).
.to_number(context)?
// 2. If n is NaN, n is +0𝔽, n is -0𝔽, n is +∞𝔽, or n is -∞𝔽, return n.
// 3. If n < 1𝔽 and n > +0𝔽, return +0𝔽.
// 4. If n < +0𝔽 and n > -1𝔽, return -0𝔽.
// 5. Return the integral Number nearest n in the direction of +0𝔽.
.trunc()
.into())
}
}

Loading…
Cancel
Save