Browse Source

Made all `Math` methods spec compliant (#541)

pull/547/head
HalidOdat 4 years ago committed by GitHub
parent
commit
5f7ec62306
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 309
      boa/src/builtins/math/mod.rs
  2. 8
      boa/src/builtins/math/tests.rs
  3. 11
      boa/src/builtins/value/conversions.rs

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

@ -40,8 +40,13 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.abs /// [spec]: https://tc39.es/ecma262/#sec-math.abs
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/abs /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/abs
pub(crate) fn abs(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn abs(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args.get(0).map_or(f64::NAN, |x| f64::from(x).abs()).into()) Ok(args
.get(0)
.map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::abs)
.into())
} }
/// Get the arccos of a number. /// Get the arccos of a number.
@ -52,8 +57,13 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.acos /// [spec]: https://tc39.es/ecma262/#sec-math.acos
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/acos /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/acos
pub(crate) fn acos(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn acos(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args.get(0).map_or(f64::NAN, |x| f64::from(x).acos()).into()) Ok(args
.get(0)
.map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::acos)
.into())
} }
/// Get the hyperbolic arccos of a number. /// Get the hyperbolic arccos of a number.
@ -64,10 +74,12 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.acosh /// [spec]: https://tc39.es/ecma262/#sec-math.acosh
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/acosh /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/acosh
pub(crate) fn acosh(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn acosh(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args Ok(args
.get(0) .get(0)
.map_or(f64::NAN, |x| f64::from(x).acosh()) .map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::acosh)
.into()) .into())
} }
@ -79,8 +91,13 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.asin /// [spec]: https://tc39.es/ecma262/#sec-math.asin
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/asin /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/asin
pub(crate) fn asin(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn asin(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args.get(0).map_or(f64::NAN, |x| f64::from(x).asin()).into()) Ok(args
.get(0)
.map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::asin)
.into())
} }
/// Get the hyperbolic arcsine of a number. /// Get the hyperbolic arcsine of a number.
@ -91,10 +108,12 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.asinh /// [spec]: https://tc39.es/ecma262/#sec-math.asinh
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/asinh /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/asinh
pub(crate) fn asinh(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn asinh(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args Ok(args
.get(0) .get(0)
.map_or(f64::NAN, |x| f64::from(x).asinh()) .map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::asinh)
.into()) .into())
} }
@ -106,8 +125,13 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.atan /// [spec]: https://tc39.es/ecma262/#sec-math.atan
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atan /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atan
pub(crate) fn atan(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn atan(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args.get(0).map_or(f64::NAN, |x| f64::from(x).atan()).into()) Ok(args
.get(0)
.map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::atan)
.into())
} }
/// Get the hyperbolic arctangent of a number. /// Get the hyperbolic arctangent of a number.
@ -118,10 +142,12 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.atanh /// [spec]: https://tc39.es/ecma262/#sec-math.atanh
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atanh /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atanh
pub(crate) fn atanh(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn atanh(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args Ok(args
.get(0) .get(0)
.map_or(f64::NAN, |x| f64::from(x).atanh()) .map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::atanh)
.into()) .into())
} }
@ -133,10 +159,13 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.atan2 /// [spec]: https://tc39.es/ecma262/#sec-math.atan2
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atan2 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atan2
pub(crate) fn atan2(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn atan2(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(match (args.get(0), args.get(1)) { Ok(match (
(Some(y), Some(x)) => f64::from(y).atan2(f64::from(x)), args.get(0).map(|x| ctx.to_number(x)).transpose()?,
_ => f64::NAN, args.get(1).map(|x| ctx.to_number(x)).transpose()?,
) {
(Some(x), Some(y)) => x.atan2(y),
(_, _) => f64::NAN,
} }
.into()) .into())
} }
@ -149,8 +178,13 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.cbrt /// [spec]: https://tc39.es/ecma262/#sec-math.cbrt
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cbrt /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cbrt
pub(crate) fn cbrt(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn cbrt(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args.get(0).map_or(f64::NAN, |x| f64::from(x).cbrt()).into()) Ok(args
.get(0)
.map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::cbrt)
.into())
} }
/// Get lowest integer above a number. /// Get lowest integer above a number.
@ -161,8 +195,13 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.ceil /// [spec]: https://tc39.es/ecma262/#sec-math.ceil
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/ceil /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/ceil
pub(crate) fn ceil(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn ceil(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args.get(0).map_or(f64::NAN, |x| f64::from(x).ceil()).into()) Ok(args
.get(0)
.map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::ceil)
.into())
} }
/// Get the number of leading zeros in the 32 bit representation of a number /// Get the number of leading zeros in the 32 bit representation of a number
@ -173,10 +212,13 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.clz32 /// [spec]: https://tc39.es/ecma262/#sec-math.clz32
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32
pub(crate) fn clz32(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn clz32(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args Ok(args
.get(0) .get(0)
.map_or(32i32, |x| (f64::from(x) as u32).leading_zeros() as i32) .map(|x| ctx.to_uint32(x))
.transpose()?
.map(u32::leading_zeros)
.unwrap_or(32)
.into()) .into())
} }
@ -188,8 +230,13 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.cos /// [spec]: https://tc39.es/ecma262/#sec-math.cos
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cos /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cos
pub(crate) fn cos(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn cos(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args.get(0).map_or(f64::NAN, |x| f64::from(x).cos()).into()) Ok(args
.get(0)
.map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::cos)
.into())
} }
/// Get the hyperbolic cosine of a number. /// Get the hyperbolic cosine of a number.
@ -200,8 +247,13 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.cosh /// [spec]: https://tc39.es/ecma262/#sec-math.cosh
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cosh /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cosh
pub(crate) fn cosh(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn cosh(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args.get(0).map_or(f64::NAN, |x| f64::from(x).cosh()).into()) Ok(args
.get(0)
.map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::cosh)
.into())
} }
/// Get the power to raise the natural logarithm to get the number. /// Get the power to raise the natural logarithm to get the number.
@ -212,8 +264,13 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.exp /// [spec]: https://tc39.es/ecma262/#sec-math.exp
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/exp /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/exp
pub(crate) fn exp(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn exp(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args.get(0).map_or(f64::NAN, |x| f64::from(x).exp()).into()) Ok(args
.get(0)
.map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::exp)
.into())
} }
/// The Math.expm1() function returns e^x - 1, where x is the argument, and e the base of /// The Math.expm1() function returns e^x - 1, where x is the argument, and e the base of
@ -226,10 +283,12 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.expm1 /// [spec]: https://tc39.es/ecma262/#sec-math.expm1
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/expm1 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/expm1
pub(crate) fn expm1(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn expm1(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args Ok(args
.get(0) .get(0)
.map_or(f64::NAN, |x| f64::from(x).exp_m1()) .map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::exp_m1)
.into()) .into())
} }
@ -241,10 +300,12 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.floor /// [spec]: https://tc39.es/ecma262/#sec-math.floor
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor
pub(crate) fn floor(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn floor(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args Ok(args
.get(0) .get(0)
.map_or(f64::NAN, |x| f64::from(x).floor()) .map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::floor)
.into()) .into())
} }
@ -256,10 +317,12 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.fround /// [spec]: https://tc39.es/ecma262/#sec-math.fround
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround
pub(crate) fn fround(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn fround(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args Ok(args
.get(0) .get(0)
.map_or(f64::NAN, |x| (f64::from(x) as f32) as f64) .map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, |x| (x as f32) as f64)
.into()) .into())
} }
@ -271,8 +334,13 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.hypot /// [spec]: https://tc39.es/ecma262/#sec-math.hypot
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/hypot /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/hypot
pub(crate) fn hypot(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn hypot(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args.iter().fold(0f64, |x, v| f64::from(v).hypot(x)).into()) let mut result = 0f64;
for arg in args {
let x = ctx.to_number(arg)?;
result = result.hypot(x);
}
Ok(result.into())
} }
/// Get the result of the C-like 32-bit multiplication of the two parameters. /// Get the result of the C-like 32-bit multiplication of the two parameters.
@ -283,10 +351,15 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.imul /// [spec]: https://tc39.es/ecma262/#sec-math.imul
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul
pub(crate) fn imul(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn imul(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
let a = args.get(0).map_or(0f64, f64::from); Ok(match (
let b = args.get(1).map_or(0f64, f64::from); args.get(0).map(|x| ctx.to_uint32(x)).transpose()?,
Ok(((a as u32).wrapping_mul(b as u32) as i32).into()) args.get(1).map(|x| ctx.to_uint32(x)).transpose()?,
) {
(Some(x), Some(y)) => x.wrapping_mul(y) as i32,
(_, _) => 0,
}
.into())
} }
/// Get the natural logarithm of a number. /// Get the natural logarithm of a number.
@ -297,17 +370,12 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.log /// [spec]: https://tc39.es/ecma262/#sec-math.log
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log
pub(crate) fn log(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn log(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args Ok(args
.get(0) .get(0)
.map_or(f64::NAN, |value| { .map(|x| ctx.to_number(x))
let x = f64::from(value); .transpose()?
if x <= 0.0 { .map_or(f64::NAN, |x| if x <= 0.0 { f64::NAN } else { x.ln() })
f64::NAN
} else {
x.log(f64::consts::E)
}
})
.into()) .into())
} }
@ -319,10 +387,12 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.log1p /// [spec]: https://tc39.es/ecma262/#sec-math.log1p
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log1p /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log1p
pub(crate) fn log1p(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn log1p(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args Ok(args
.get(0) .get(0)
.map_or(f64::NAN, |x| f64::from(x).ln_1p()) .map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::ln_1p)
.into()) .into())
} }
@ -334,18 +404,12 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.log10 /// [spec]: https://tc39.es/ecma262/#sec-math.log10
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log10 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log10
pub(crate) fn log10(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn log10(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args Ok(args
.get(0) .get(0)
.map_or(f64::NAN, |value| { .map(|x| ctx.to_number(x))
let x = f64::from(value); .transpose()?
.map_or(f64::NAN, |x| if x <= 0.0 { f64::NAN } else { x.log10() })
if x <= 0.0 {
f64::NAN
} else {
x.log10()
}
})
.into()) .into())
} }
@ -357,18 +421,12 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.log2 /// [spec]: https://tc39.es/ecma262/#sec-math.log2
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log2 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log2
pub(crate) fn log2(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn log2(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args Ok(args
.get(0) .get(0)
.map_or(f64::NAN, |value| { .map(|x| ctx.to_number(x))
let x = f64::from(value); .transpose()?
.map_or(f64::NAN, |x| if x <= 0.0 { f64::NAN } else { x.log2() })
if x <= 0.0 {
f64::NAN
} else {
x.log2()
}
})
.into()) .into())
} }
@ -380,13 +438,13 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.max /// [spec]: https://tc39.es/ecma262/#sec-math.max
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max
pub(crate) fn max(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn max(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
let mut max = f64::NEG_INFINITY; let mut max = f64::NEG_INFINITY;
for arg in args { for arg in args {
let num = f64::from(arg); let num = ctx.to_number(arg)?;
max = max.max(num); max = max.max(num);
} }
Ok(Value::from(max)) Ok(max.into())
} }
/// Get the minimum of several numbers. /// Get the minimum of several numbers.
@ -397,13 +455,13 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.min /// [spec]: https://tc39.es/ecma262/#sec-math.min
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min
pub(crate) fn min(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn min(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
let mut min = f64::INFINITY; let mut min = f64::INFINITY;
for arg in args { for arg in args {
let num = f64::from(arg); let num = ctx.to_number(arg)?;
min = min.min(num); min = min.min(num);
} }
Ok(Value::from(min)) Ok(min.into())
} }
/// Raise a number to a power. /// Raise a number to a power.
@ -414,10 +472,13 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.pow /// [spec]: https://tc39.es/ecma262/#sec-math.pow
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/pow /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/pow
pub(crate) fn pow(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn pow(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(match (args.get(0), args.get(1)) { Ok(match (
(Some(base), Some(exponent)) => f64::from(base).powf(f64::from(exponent)), args.get(0).map(|x| ctx.to_number(x)).transpose()?,
_ => f64::NAN, args.get(1).map(|x| ctx.to_number(x)).transpose()?,
) {
(Some(x), Some(y)) => x.powf(y),
(_, _) => f64::NAN,
} }
.into()) .into())
} }
@ -431,7 +492,7 @@ impl Math {
/// [spec]: https://tc39.es/ecma262/#sec-math.random /// [spec]: https://tc39.es/ecma262/#sec-math.random
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
pub(crate) fn random(_: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn random(_: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(Value::from(rand::random::<f64>())) Ok(rand::random::<f64>().into())
} }
/// Round a number to the nearest integer. /// Round a number to the nearest integer.
@ -442,10 +503,12 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.round /// [spec]: https://tc39.es/ecma262/#sec-math.round
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
pub(crate) fn round(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn round(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args Ok(args
.get(0) .get(0)
.map_or(f64::NAN, |x| f64::from(x).round()) .map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::round)
.into()) .into())
} }
@ -457,18 +520,21 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.sign /// [spec]: https://tc39.es/ecma262/#sec-math.sign
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign
pub(crate) fn sign(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn sign(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args Ok(args
.get(0) .get(0)
.map_or(f64::NAN, |value| { .map(|x| ctx.to_number(x))
let x = f64::from(value); .transpose()?
.map_or(
if x == 0.0 || x == -0.0 { f64::NAN,
x |x| {
} else { if x == 0.0 || x == -0.0 {
x.signum() x
} } else {
}) x.signum()
}
},
)
.into()) .into())
} }
@ -480,8 +546,13 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.sin /// [spec]: https://tc39.es/ecma262/#sec-math.sin
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sin /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sin
pub(crate) fn sin(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn sin(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args.get(0).map_or(f64::NAN, |x| f64::from(x).sin()).into()) Ok(args
.get(0)
.map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::sin)
.into())
} }
/// Get the hyperbolic sine of a number. /// Get the hyperbolic sine of a number.
@ -492,8 +563,13 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.sinh /// [spec]: https://tc39.es/ecma262/#sec-math.sinh
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sinh /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sinh
pub(crate) fn sinh(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn sinh(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args.get(0).map_or(f64::NAN, |x| f64::from(x).sinh()).into()) Ok(args
.get(0)
.map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::sinh)
.into())
} }
/// Get the square root of a number. /// Get the square root of a number.
@ -504,8 +580,13 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.sqrt /// [spec]: https://tc39.es/ecma262/#sec-math.sqrt
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sqrt /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sqrt
pub(crate) fn sqrt(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn sqrt(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args.get(0).map_or(f64::NAN, |x| f64::from(x).sqrt()).into()) Ok(args
.get(0)
.map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::sqrt)
.into())
} }
/// Get the tangent of a number. /// Get the tangent of a number.
@ -516,8 +597,13 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.tan /// [spec]: https://tc39.es/ecma262/#sec-math.tan
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/tan /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/tan
pub(crate) fn tan(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn tan(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args.get(0).map_or(f64::NAN, |x| f64::from(x).tan()).into()) Ok(args
.get(0)
.map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::tan)
.into())
} }
/// Get the hyperbolic tangent of a number. /// Get the hyperbolic tangent of a number.
@ -528,8 +614,13 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.tanh /// [spec]: https://tc39.es/ecma262/#sec-math.tanh
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/tanh /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/tanh
pub(crate) fn tanh(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn tanh(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args.get(0).map_or(f64::NAN, |x| f64::from(x).tanh()).into()) Ok(args
.get(0)
.map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::tanh)
.into())
} }
/// Get the integer part of a number. /// Get the integer part of a number.
@ -540,10 +631,12 @@ impl Math {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-math.trunc /// [spec]: https://tc39.es/ecma262/#sec-math.trunc
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc
pub(crate) fn trunc(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { pub(crate) fn trunc(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
Ok(args Ok(args
.get(0) .get(0)
.map_or(f64::NAN, |x| f64::from(x).trunc()) .map(|x| ctx.to_number(x))
.transpose()?
.map_or(f64::NAN, f64::trunc)
.into()) .into())
} }

8
boa/src/builtins/math/tests.rs

@ -383,16 +383,16 @@ fn hypot() {
let b = forward_val(&mut engine, "b").unwrap(); let b = forward_val(&mut engine, "b").unwrap();
let c = forward_val(&mut engine, "c").unwrap(); let c = forward_val(&mut engine, "c").unwrap();
let d = forward_val(&mut engine, "d").unwrap(); let d = forward_val(&mut engine, "d").unwrap();
let e = forward(&mut engine, "e"); let e = forward_val(&mut engine, "e").unwrap();
let f = forward(&mut engine, "f"); let f = forward_val(&mut engine, "f").unwrap();
let g = forward_val(&mut engine, "g").unwrap(); let g = forward_val(&mut engine, "g").unwrap();
assert_eq!(a.to_number(), 0f64); assert_eq!(a.to_number(), 0f64);
assert_eq!(b.to_number(), 5f64); assert_eq!(b.to_number(), 5f64);
assert_eq!(c.to_number(), 13f64); assert_eq!(c.to_number(), 13f64);
assert_eq!(d.to_number(), 7.071_067_811_865_475_5); assert_eq!(d.to_number(), 7.071_067_811_865_475_5);
assert_eq!(e, String::from("NaN")); assert_eq!(e.to_number(), 8.774964387392123);
assert_eq!(f, String::from("Infinity")); assert!(f.to_number().is_infinite());
assert_eq!(g.to_number(), 12f64); assert_eq!(g.to_number(), 12f64);
} }

11
boa/src/builtins/value/conversions.rs

@ -77,6 +77,17 @@ impl From<&Value> for f64 {
} }
} }
impl From<u32> for Value {
#[inline]
fn from(value: u32) -> Value {
if let Ok(integer) = i32::try_from(value) {
Value::integer(integer)
} else {
Value::rational(value)
}
}
}
impl From<i32> for Value { impl From<i32> for Value {
fn from(value: i32) -> Value { fn from(value: i32) -> Value {
Value::integer(value) Value::integer(value)

Loading…
Cancel
Save