From 405a1c2d42e5f79472b43d1446e4e21a64fcc15a Mon Sep 17 00:00:00 2001 From: ConnorSkees <39542938+ConnorSkees@users.noreply.github.com> Date: Sun, 9 Feb 2020 16:05:07 -0500 Subject: [PATCH] Implement mul and div for Value and builtin function `percentage()` --- src/builtin/math.rs | 15 ++++++ src/builtin/mod.rs | 1 + src/value/mod.rs | 2 + src/value/ops.rs | 124 ++++++++++++++++++++++++++++++++++++++++---- tests/math.rs | 20 +++++++ 5 files changed, 153 insertions(+), 9 deletions(-) create mode 100644 tests/math.rs diff --git a/src/builtin/math.rs b/src/builtin/math.rs index 8b13789..25a1f7b 100644 --- a/src/builtin/math.rs +++ b/src/builtin/math.rs @@ -1 +1,16 @@ +use std::collections::BTreeMap; +use super::Builtin; +use crate::units::Unit; +use crate::value::{Number, Value}; + +pub(crate) fn register(f: &mut BTreeMap) { + decl!(f "percentage", |args, _| { + let arg = dbg!(arg!(args, 0, "number").eval()); + let num = match arg { + Value::Dimension(n, Unit::None) => n * Number::from(100), + _ => todo!("expected unitless number in builtin function `percentage()`") + }; + Some(Value::Dimension(num, Unit::Percent)) + }); +} \ No newline at end of file diff --git a/src/builtin/mod.rs b/src/builtin/mod.rs index df49aea..eed9302 100644 --- a/src/builtin/mod.rs +++ b/src/builtin/mod.rs @@ -22,6 +22,7 @@ lazy_static! { pub(crate) static ref GLOBAL_FUNCTIONS: BTreeMap = { let mut m = BTreeMap::new(); color::register(&mut m); + math::register(&mut m); meta::register(&mut m); string::register(&mut m); m diff --git a/src/value/mod.rs b/src/value/mod.rs index 2a19a54..39e7d0b 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -98,6 +98,8 @@ impl Value { Op::Minus => *lhs.clone() - *rhs.clone(), Op::Equal => Self::bool(*lhs == *rhs), Op::NotEqual => Self::bool(*lhs != *rhs), + Op::Mul => *lhs.clone() * *rhs.clone(), + Op::Div => *lhs.clone() / *rhs.clone(), _ => Self::BinaryOp(lhs.clone(), *op, rhs.clone()), }, _ => self.clone(), diff --git a/src/value/ops.rs b/src/value/ops.rs index a08acaa..49e1e3d 100644 --- a/src/value/ops.rs +++ b/src/value/ops.rs @@ -1,6 +1,7 @@ -use std::ops::{Add, Sub}; +use std::ops::{Add, Sub, Mul, Div}; use crate::common::QuoteKind; +use crate::units::Unit; use crate::value::Value; impl Add for Value { @@ -78,12 +79,9 @@ impl Sub for Value { fn sub(self, other: Self) -> Self { match self { - // Self::Important => todo!(), - // Self::True => todo!(), - // Self::False => todo!(), - // Self::Null => todo!(), + Self::Null => todo!(), Self::Dimension(num, unit) => match other { - // Self::Dimension(num2, unit2) => Value::Dimension(num - num2, unit), + Self::Dimension(num2, unit2) => Value::Dimension(num - num2, unit), _ => todo!(), }, // Self::List(..) => todo!(), @@ -99,8 +97,8 @@ impl Sub for Value { Self::Dimension(..) => todo!("investigate adding numbers and colors"), _ => Value::Ident(format!("{}-{}", c, other), QuoteKind::None), }, - // Self::BinaryOp(..) => todo!(), - // Self::Paren(..) => todo!(), + Self::BinaryOp(..) + | Self::Paren(..) => self.eval(), Self::Ident(s1, quotes1) => match other { Self::Ident(s2, quotes2) => { let quotes1 = match quotes1 { @@ -139,7 +137,115 @@ impl Sub for Value { } _ => todo!(), }, - _ => todo!(), + _ => match other { + Self::Ident(s, quotes) => { + let quotes = match quotes { + QuoteKind::Double | QuoteKind::Single => QuoteKind::Double, + QuoteKind::None => QuoteKind::None, + }; + Value::Ident(format!("{}-{}{}{}", self, quotes, s, quotes), QuoteKind::None) + } + Self::Null => Value::Ident(format!("{}-", self), QuoteKind::None), + _ => Value::Ident(format!("{}-{}", self, other), QuoteKind::None), + }, + } + } +} + +impl Mul for Value { + type Output = Self; + + fn mul(self, other: Self) -> Self { + match self { + Self::Null => todo!(), + Self::Dimension(num, unit) => match other { + Self::Dimension(num2, unit2) => Value::Dimension(num - num2, unit), + _ => todo!(), + }, + Self::BinaryOp(..) + | Self::Paren(..) => self.eval(), + _ => todo!("incompatible mul types") + } + } +} +impl Div for Value { + type Output = Self; + + fn div(self, other: Self) -> Self { + match self { + Self::Null => todo!(), + Self::Dimension(num, unit) => match other { + Self::Dimension(num2, unit2) => if unit == unit2 { + Value::Dimension(num / num2, Unit::None) + } else { + todo!("unit conversions") + }, + _ => todo!(), + }, + // Self::List(..) => todo!(), + Self::Color(c) => match other { + Self::Ident(s, quotes) => { + let quotes = match quotes { + QuoteKind::Double | QuoteKind::Single => QuoteKind::Double, + QuoteKind::None => QuoteKind::None, + }; + Value::Ident(format!("{}/{}{}{}", c, quotes, s, quotes), QuoteKind::None) + } + Self::Null => Value::Ident(format!("{}/", c), QuoteKind::None), + Self::Dimension(..) => todo!("investigate adding numbers and colors"), + _ => Value::Ident(format!("{}/{}", c, other), QuoteKind::None), + }, + Self::BinaryOp(..) + | Self::Paren(..) => self.eval(), + Self::Ident(s1, quotes1) => match other { + Self::Ident(s2, quotes2) => { + let quotes1 = match quotes1 { + QuoteKind::Double | QuoteKind::Single => QuoteKind::Double, + QuoteKind::None => QuoteKind::None, + }; + let quotes2 = match quotes2 { + QuoteKind::Double | QuoteKind::Single => QuoteKind::Double, + QuoteKind::None => QuoteKind::None, + }; + Value::Ident( + format!("{}{}{}/{}{}{}", quotes1, s1, quotes1, quotes2, s2, quotes2), + QuoteKind::None, + ) + } + Self::Important + | Self::True + | Self::False + | Self::Dimension(..) + | Self::Color(..) => { + let quotes = match quotes1 { + QuoteKind::Double | QuoteKind::Single => QuoteKind::Double, + QuoteKind::None => QuoteKind::None, + }; + Value::Ident( + format!("{}{}{}/{}", quotes, s1, quotes, other), + QuoteKind::None, + ) + } + Self::Null => { + let quotes = match quotes1 { + QuoteKind::Double | QuoteKind::Single => QuoteKind::Double, + QuoteKind::None => QuoteKind::None, + }; + Value::Ident(format!("{}{}{}/", quotes, s1, quotes), QuoteKind::None) + } + _ => todo!(), + }, + _ => match other { + Self::Ident(s, quotes) => { + let quotes = match quotes { + QuoteKind::Double | QuoteKind::Single => QuoteKind::Double, + QuoteKind::None => QuoteKind::None, + }; + Value::Ident(format!("{}/{}{}{}", self, quotes, s, quotes), QuoteKind::None) + } + Self::Null => Value::Ident(format!("{}/", self), QuoteKind::None), + _ => Value::Ident(format!("{}/{}", self, other), QuoteKind::None), + }, } } } diff --git a/tests/math.rs b/tests/math.rs new file mode 100644 index 0000000..68b1e32 --- /dev/null +++ b/tests/math.rs @@ -0,0 +1,20 @@ +#![cfg(test)] + +#[macro_use] +mod macros; + +test!( + percentage_decimal, + "a {\n color: percentage(0.2);\n}\n", + "a {\n color: 20%;\n}\n" +); +test!( + percentage_division, + "a {\n color: percentage(100px / 50px);\n}\n", + "a {\n color: 200%;\n}\n" +); +test!( + integer_division, + "a {\n color: percentage(2);\n}\n", + "a {\n color: 200%;\n}\n" +);