implement builtin function math.log

This commit is contained in:
Connor Skees 2020-07-27 01:52:34 -04:00
parent 313913734a
commit 458fcf0fd8
3 changed files with 143 additions and 2 deletions

View File

@ -1,6 +1,6 @@
use std::cmp::Ordering; use std::cmp::Ordering;
use num_traits::{One, Zero}; use num_traits::{One, Signed, Zero};
use crate::{ use crate::{
args::CallArgs, args::CallArgs,
@ -107,7 +107,69 @@ fn hypot(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
fn log(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn log(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(2)?; args.max_args(2)?;
let number = match args.get_err(0, "number")? {
Value::Dimension(Some(n), Unit::None, ..) => n,
v @ Value::Dimension(Some(..), ..) => {
return Err((
format!(
"$number: Expected {} to be unitless.",
v.inspect(args.span())?
),
args.span(),
)
.into())
}
v @ Value::Dimension(None, ..) => return Ok(v),
v => {
return Err((
format!("$number: {} is not a number.", v.inspect(args.span())?),
args.span(),
)
.into())
}
};
let base = match args.default_arg(1, "base", Value::Null)? {
Value::Null => None,
Value::Dimension(Some(n), Unit::None, ..) => Some(n),
v @ Value::Dimension(Some(..), ..) => {
return Err((
format!(
"$number: Expected {} to be unitless.",
v.inspect(args.span())?
),
args.span(),
)
.into())
}
v @ Value::Dimension(None, ..) => return Ok(v),
v => {
return Err((
format!("$base: {} is not a number.", v.inspect(args.span())?),
args.span(),
)
.into())
}
};
Ok(Value::Dimension(
if let Some(base) = base {
if base.is_zero() {
Some(Number::zero())
} else {
(|| Some(number.ln()? / base.ln()?))()
}
} else if number.is_negative() {
None
} else if number.is_zero() {
todo!() todo!()
} else {
number.ln()
},
Unit::None,
true,
))
} }
fn pow(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> { fn pow(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
@ -310,6 +372,7 @@ pub(crate) fn declare(f: &mut Module) {
f.insert_builtin("acos", acos); f.insert_builtin("acos", acos);
f.insert_builtin("asin", asin); f.insert_builtin("asin", asin);
f.insert_builtin("atan", atan); f.insert_builtin("atan", atan);
f.insert_builtin("log", log);
#[cfg(feature = "random")] #[cfg(feature = "random")]
f.insert_builtin("random", random); f.insert_builtin("random", random);

View File

@ -122,6 +122,12 @@ impl Number {
self.as_float()?.sqrt(), self.as_float()?.sqrt(),
)?))) )?)))
} }
pub fn ln(self) -> Option<Self> {
Some(Number::Big(Box::new(BigRational::from_float(
self.as_float()?.ln(),
)?)))
}
} }
macro_rules! trig_fn( macro_rules! trig_fn(

View File

@ -318,3 +318,75 @@ test!(
"@use 'sass:math';\na {\n color: math.atan((0 / 0));\n}\n", "@use 'sass:math';\na {\n color: math.atan((0 / 0));\n}\n",
"a {\n color: NaNdeg;\n}\n" "a {\n color: NaNdeg;\n}\n"
); );
test!(
log_above_one,
"@use 'sass:math';\na {\n color: math.log(2);\n}\n",
"a {\n color: 0.6931471806;\n}\n"
);
test!(
log_below_negative_one,
"@use 'sass:math';\na {\n color: math.log(-2);\n}\n",
"a {\n color: NaN;\n}\n"
);
test!(
log_one,
"@use 'sass:math';\na {\n color: math.log(1);\n}\n",
"a {\n color: 0;\n}\n"
);
test!(
log_negative_one,
"@use 'sass:math';\na {\n color: math.log(-1);\n}\n",
"a {\n color: NaN;\n}\n"
);
test!(
#[ignore = "we do not support Infinity"]
log_zero,
"@use 'sass:math';\na {\n color: math.log(0);\n}\n",
"a {\n color: -Infinity;\n}\n"
);
test!(
log_point_five,
"@use 'sass:math';\na {\n color: math.log(.5);\n}\n",
"a {\n color: -0.6931471806;\n}\n"
);
test!(
log_nan,
"@use 'sass:math';\na {\n color: math.log((0 / 0));\n}\n",
"a {\n color: NaN;\n}\n"
);
test!(
log_base_nan,
"@use 'sass:math';\na {\n color: math.log(1, (0 / 0));\n}\n",
"a {\n color: NaN;\n}\n"
);
test!(
log_base_above_one,
"@use 'sass:math';\na {\n color: math.log(2, 2);\n}\n",
"a {\n color: 1;\n}\n"
);
test!(
log_base_below_negative_one,
"@use 'sass:math';\na {\n color: math.log(2, -2);\n}\n",
"a {\n color: NaN;\n}\n"
);
test!(
#[ignore = "we do not support Infinity"]
log_base_one,
"@use 'sass:math';\na {\n color: math.log(2, 1);\n}\n",
"a {\n color: Infinity;\n}\n"
);
test!(
log_base_negative_one,
"@use 'sass:math';\na {\n color: math.log(2, -1);\n}\n",
"a {\n color: NaN;\n}\n"
);
test!(
log_base_zero,
"@use 'sass:math';\na {\n color: math.log(2, 0);\n}\n",
"a {\n color: 0;\n}\n"
);
test!(
log_base_point_five,
"@use 'sass:math';\na {\n color: math.log(2, .5);\n}\n",
"a {\n color: -1;\n}\n"
);