diff --git a/src/builtin/modules/math.rs b/src/builtin/modules/math.rs index 9de39cc..07d64af 100644 --- a/src/builtin/modules/math.rs +++ b/src/builtin/modules/math.rs @@ -174,7 +174,52 @@ fn log(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult { fn pow(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult { args.max_args(2)?; - todo!() + + let base = match args.get_err(0, "base")? { + Value::Dimension(Some(n), Unit::None, ..) => n, + v @ Value::Dimension(Some(..), ..) => { + return Err(( + format!( + "$base: Expected {} to have no units.", + v.inspect(args.span())? + ), + args.span(), + ) + .into()) + } + Value::Dimension(None, ..) => return Ok(Value::Dimension(None, Unit::None, true)), + v => { + return Err(( + format!("$base: {} is not a number.", v.inspect(args.span())?), + args.span(), + ) + .into()) + } + }; + + let exponent = match args.get_err(1, "exponent")? { + Value::Dimension(Some(n), Unit::None, ..) => n, + v @ Value::Dimension(Some(..), ..) => { + return Err(( + format!( + "$exponent: Expected {} to have no units.", + v.inspect(args.span())? + ), + args.span(), + ) + .into()) + } + Value::Dimension(None, ..) => return Ok(Value::Dimension(None, Unit::None, true)), + v => { + return Err(( + format!("$exponent: {} is not a number.", v.inspect(args.span())?), + args.span(), + ) + .into()) + } + }; + + Ok(Value::Dimension(base.pow(exponent), Unit::None, true)) } fn sqrt(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult { @@ -375,6 +420,7 @@ pub(crate) fn declare(f: &mut Module) { f.insert_builtin("asin", asin); f.insert_builtin("atan", atan); f.insert_builtin("log", log); + f.insert_builtin("pow", pow); #[cfg(feature = "random")] f.insert_builtin("random", random); diff --git a/src/value/number/mod.rs b/src/value/number/mod.rs index 14eb52c..a95a81a 100644 --- a/src/value/number/mod.rs +++ b/src/value/number/mod.rs @@ -128,6 +128,12 @@ impl Number { self.as_float()?.ln(), )?))) } + + pub fn pow(self, exponent: Self) -> Option { + Some(Number::Big(Box::new(BigRational::from_float( + self.as_float()?.powf(exponent.as_float()?), + )?))) + } } macro_rules! trig_fn( diff --git a/tests/math-module.rs b/tests/math-module.rs index 9a32c9a..2915c28 100644 --- a/tests/math-module.rs +++ b/tests/math-module.rs @@ -390,3 +390,59 @@ test!( "@use 'sass:math';\na {\n color: math.log(2, .5);\n}\n", "a {\n color: -1;\n}\n" ); + +test!( + pow_exponent_and_base_one, + "@use 'sass:math';\na {\n color: math.pow(1, 1);\n}\n", + "a {\n color: 1;\n}\n" +); +test!( + pow_exponent_and_base_ten, + "@use 'sass:math';\na {\n color: math.pow(10, 10);\n}\n", + "a {\n color: 10000000000;\n}\n" +); +test!( + pow_base_negative_exponent_positive, + "@use 'sass:math';\na {\n color: math.pow(-2, 3);\n}\n", + "a {\n color: -8;\n}\n" +); +test!( + pow_base_positive_exponent_negative, + "@use 'sass:math';\na {\n color: math.pow(2, -3);\n}\n", + "a {\n color: 0.125;\n}\n" +); +test!( + pow_base_negative_exponent_negative, + "@use 'sass:math';\na {\n color: math.pow(-2, -3);\n}\n", + "a {\n color: -0.125;\n}\n" +); +test!( + pow_base_decimal, + "@use 'sass:math';\na {\n color: math.pow(2.4, 3);\n}\n", + "a {\n color: 13.824;\n}\n" +); +test!( + pow_exponent_decimal, + "@use 'sass:math';\na {\n color: math.pow(2, 3.5);\n}\n", + "a {\n color: 11.313708499;\n}\n" +); +test!( + pow_base_nan, + "@use 'sass:math';\na {\n color: math.pow((0 / 0), 3);\n}\n", + "a {\n color: NaN;\n}\n" +); +test!( + pow_exponent_nan, + "@use 'sass:math';\na {\n color: math.pow(2, (0 / 0));\n}\n", + "a {\n color: NaN;\n}\n" +); +test!( + pow_base_and_exponent_nan, + "@use 'sass:math';\na {\n color: math.pow((0 / 0), (0 / 0));\n}\n", + "a {\n color: NaN;\n}\n" +); +test!( + pow_exponent_zero, + "@use 'sass:math';\na {\n color: math.pow(2, 0);\n}\n", + "a {\n color: 1;\n}\n" +);