From 0363134ba37f86c9cb4c44ecd4f2f2f1c1b5ebe5 Mon Sep 17 00:00:00 2001 From: Connor Skees Date: Tue, 27 Dec 2022 19:09:43 -0500 Subject: [PATCH] box colors and complex units --- src/ast/expr.rs | 2 +- src/builtin/functions/color/hsl.rs | 22 ++++++++++--------- src/builtin/functions/color/hwb.rs | 4 ++-- src/builtin/functions/color/opacity.rs | 4 ++-- src/builtin/functions/color/other.rs | 30 +++++++++++++------------- src/builtin/functions/color/rgb.rs | 10 ++++----- src/parse/value.rs | 10 +++++---- src/unit/mod.rs | 23 ++++++++++++-------- src/value/calculation.rs | 4 ++-- src/value/mod.rs | 4 ++-- 10 files changed, 61 insertions(+), 52 deletions(-) diff --git a/src/ast/expr.rs b/src/ast/expr.rs index 654efdb..e73d3cb 100644 --- a/src/ast/expr.rs +++ b/src/ast/expr.rs @@ -55,7 +55,7 @@ pub(crate) enum AstExpr { name: CalculationName, args: Vec, }, - Color(Color), + Color(Box), FunctionCall(FunctionCallExpr), If(Box), InterpolatedFunction(InterpolatedFunction), diff --git a/src/builtin/functions/color/hsl.rs b/src/builtin/functions/color/hsl.rs index 5110870..468510b 100644 --- a/src/builtin/functions/color/hsl.rs +++ b/src/builtin/functions/color/hsl.rs @@ -59,12 +59,12 @@ fn hsl_3_args( visitor, )?; - Ok(Value::Color(Color::from_hsla_fn( + Ok(Value::Color(Box::new(Color::from_hsla_fn( Number(hue.num().rem_euclid(360.0)), saturation.num() / Number(100.0), lightness.num() / Number(100.0), Number(alpha), - ))) + )))) } fn inner_hsl( @@ -181,7 +181,7 @@ pub(crate) fn adjust_hue(mut args: ArgumentResult, visitor: &mut Visitor) -> Sas .assert_number_with_name("degrees", args.span())? .num(); - Ok(Value::Color(color.adjust_hue(degrees))) + Ok(Value::Color(Box::new(color.adjust_hue(degrees)))) } fn lighten(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult { @@ -202,7 +202,7 @@ fn lighten(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult .assert_number_with_name("amount", args.span())?; let amount = bound!(args, "amount", amount.num(), amount.unit, 0, 100) / Number(100.0); - Ok(Value::Color(color.lighten(amount))) + Ok(Value::Color(Box::new(color.lighten(amount)))) } fn darken(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult { @@ -235,7 +235,7 @@ fn darken(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult .into()) } }; - Ok(Value::Color(color.darken(amount))) + Ok(Value::Color(Box::new(color.darken(amount)))) } fn saturate(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult { @@ -293,7 +293,7 @@ fn saturate(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult SassResult { @@ -326,7 +326,7 @@ fn desaturate(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult SassResult { @@ -351,7 +351,7 @@ pub(crate) fn grayscale(mut args: ArgumentResult, visitor: &mut Visitor) -> Sass .into()) } }; - Ok(Value::Color(color.desaturate(Number::one()))) + Ok(Value::Color(Box::new(color.desaturate(Number::one())))) } pub(crate) fn complement(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult { @@ -366,7 +366,7 @@ pub(crate) fn complement(mut args: ArgumentResult, visitor: &mut Visitor) -> Sas .into()) } }; - Ok(Value::Color(color.complement())) + Ok(Value::Color(Box::new(color.complement()))) } pub(crate) fn invert(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult { @@ -398,7 +398,9 @@ pub(crate) fn invert(mut args: ArgumentResult, visitor: &mut Visitor) -> SassRes } }; match args.get_err(0, "color")? { - Value::Color(c) => Ok(Value::Color(c.invert(weight.unwrap_or_else(Number::one)))), + Value::Color(c) => Ok(Value::Color(Box::new( + c.invert(weight.unwrap_or_else(Number::one)), + ))), Value::Dimension(SassNumber { num: n, unit: u, diff --git a/src/builtin/functions/color/hwb.rs b/src/builtin/functions/color/hwb.rs index 8f2b059..ce65956 100644 --- a/src/builtin/functions/color/hwb.rs +++ b/src/builtin/functions/color/hwb.rs @@ -90,12 +90,12 @@ fn hwb_inner(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult Number::one(), }; - Ok(Value::Color(Color::from_hwb( + Ok(Value::Color(Box::new(Color::from_hwb( hue, whiteness.num, blackness.num, alpha, - ))) + )))) } pub(crate) fn hwb(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult { diff --git a/src/builtin/functions/color/opacity.rs b/src/builtin/functions/color/opacity.rs index 146165d..60f284a 100644 --- a/src/builtin/functions/color/opacity.rs +++ b/src/builtin/functions/color/opacity.rs @@ -111,7 +111,7 @@ fn opacify(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult let amount = bound!(args, "amount", amount.num(), amount.unit(), 0, 1); - Ok(Value::Color(color.fade_in(amount))) + Ok(Value::Color(Box::new(color.fade_in(amount)))) } fn transparentize(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult { @@ -141,7 +141,7 @@ fn transparentize(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult .into()) } }; - Ok(Value::Color(color.fade_out(amount))) + Ok(Value::Color(Box::new(color.fade_out(amount)))) } pub(crate) fn declare(f: &mut GlobalFunctionMap) { diff --git a/src/builtin/functions/color/other.rs b/src/builtin/functions/color/other.rs index 0ed4a1d..662819c 100644 --- a/src/builtin/functions/color/other.rs +++ b/src/builtin/functions/color/other.rs @@ -64,12 +64,12 @@ pub(crate) fn change_color(mut args: ArgumentResult, visitor: &mut Visitor) -> S opt_rgba!(args, blue, "blue", 0, 255); if red.is_some() || green.is_some() || blue.is_some() { - return Ok(Value::Color(Color::from_rgba( + return Ok(Value::Color(Box::new(Color::from_rgba( red.unwrap_or_else(|| color.red()), green.unwrap_or_else(|| color.green()), blue.unwrap_or_else(|| color.blue()), alpha.unwrap_or_else(|| color.alpha()), - ))); + )))); } let hue = match args.default_named_arg("hue", Value::Null) { @@ -91,16 +91,16 @@ pub(crate) fn change_color(mut args: ArgumentResult, visitor: &mut Visitor) -> S if hue.is_some() || saturation.is_some() || luminance.is_some() { // Color::as_hsla() returns more exact values than Color::hue(), etc. let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla(); - return Ok(Value::Color(Color::from_hsla( + return Ok(Value::Color(Box::new(Color::from_hsla( hue.unwrap_or(this_hue), saturation.unwrap_or(this_saturation), luminance.unwrap_or(this_luminance), alpha.unwrap_or(this_alpha), - ))); + )))); } Ok(Value::Color(if let Some(a) = alpha { - color.with_alpha(a) + Box::new(color.with_alpha(a)) } else { color })) @@ -124,12 +124,12 @@ pub(crate) fn adjust_color(mut args: ArgumentResult, visitor: &mut Visitor) -> S opt_rgba!(args, blue, "blue", -255, 255); if red.is_some() || green.is_some() || blue.is_some() { - return Ok(Value::Color(Color::from_rgba( + return Ok(Value::Color(Box::new(Color::from_rgba( color.red() + red.unwrap_or_else(Number::zero), color.green() + green.unwrap_or_else(Number::zero), color.blue() + blue.unwrap_or_else(Number::zero), color.alpha() + alpha.unwrap_or_else(Number::zero), - ))); + )))); } let hue = match args.default_named_arg("hue", Value::Null) { @@ -151,17 +151,17 @@ pub(crate) fn adjust_color(mut args: ArgumentResult, visitor: &mut Visitor) -> S if hue.is_some() || saturation.is_some() || luminance.is_some() { // Color::as_hsla() returns more exact values than Color::hue(), etc. let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla(); - return Ok(Value::Color(Color::from_hsla( + return Ok(Value::Color(Box::new(Color::from_hsla( this_hue + hue.unwrap_or_else(Number::zero), this_saturation + saturation.unwrap_or_else(Number::zero), this_luminance + luminance.unwrap_or_else(Number::zero), this_alpha + alpha.unwrap_or_else(Number::zero), - ))); + )))); } Ok(Value::Color(if let Some(a) = alpha { let temp_alpha = color.alpha(); - color.with_alpha(temp_alpha + a) + Box::new(color.with_alpha(temp_alpha + a)) } else { color })) @@ -227,7 +227,7 @@ pub(crate) fn scale_color(mut args: ArgumentResult, visitor: &mut Visitor) -> Sa opt_scale_arg!(args, blue, "blue", -100, 100); if red.is_some() || green.is_some() || blue.is_some() { - return Ok(Value::Color(Color::from_rgba( + return Ok(Value::Color(Box::new(Color::from_rgba( scale(color.red(), red.unwrap_or_else(Number::zero), Number(255.0)), scale( color.green(), @@ -244,7 +244,7 @@ pub(crate) fn scale_color(mut args: ArgumentResult, visitor: &mut Visitor) -> Sa alpha.unwrap_or_else(Number::zero), Number::one(), ), - ))); + )))); } opt_scale_arg!(args, saturation, "saturation", -100, 100); @@ -253,7 +253,7 @@ pub(crate) fn scale_color(mut args: ArgumentResult, visitor: &mut Visitor) -> Sa if saturation.is_some() || luminance.is_some() { // Color::as_hsla() returns more exact values than Color::hue(), etc. let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla(); - return Ok(Value::Color(Color::from_hsla( + return Ok(Value::Color(Box::new(Color::from_hsla( scale(this_hue, Number::zero(), Number(360.0)), scale( this_saturation, @@ -270,12 +270,12 @@ pub(crate) fn scale_color(mut args: ArgumentResult, visitor: &mut Visitor) -> Sa alpha.unwrap_or_else(Number::zero), Number::one(), ), - ))); + )))); } Ok(Value::Color(if let Some(a) = alpha { let temp_alpha = color.alpha(); - color.with_alpha(scale(temp_alpha, a, Number::one())) + Box::new(color.with_alpha(scale(temp_alpha, a, Number::one()))) } else { color })) diff --git a/src/builtin/functions/color/rgb.rs b/src/builtin/functions/color/rgb.rs index 1f13cf1..2f234d3 100644 --- a/src/builtin/functions/color/rgb.rs +++ b/src/builtin/functions/color/rgb.rs @@ -72,9 +72,9 @@ fn inner_rgb_2_arg( let color = color.assert_color_with_name("color", args.span())?; let alpha = alpha.assert_number_with_name("alpha", args.span())?; - Ok(Value::Color(color.with_alpha(Number( + Ok(Value::Color(Box::new(color.with_alpha(Number( percentage_or_unitless(&alpha, 1.0, "alpha", args.span(), visitor)?, - )))) + ))))) } fn inner_rgb_3_arg( @@ -120,7 +120,7 @@ fn inner_rgb_3_arg( let green = green.assert_number_with_name("green", span)?; let blue = blue.assert_number_with_name("blue", span)?; - Ok(Value::Color(Color::from_rgba_fn( + Ok(Value::Color(Box::new(Color::from_rgba_fn( Number(fuzzy_round(percentage_or_unitless( &red, 255.0, "red", span, visitor, )?)), @@ -144,7 +144,7 @@ fn inner_rgb_3_arg( .transpose()? .unwrap_or(1.0), ), - ))) + )))) } pub(crate) fn percentage_or_unitless( @@ -450,7 +450,7 @@ pub(crate) fn mix(mut args: ArgumentResult, visitor: &mut Visitor) -> SassResult .into()) } }; - Ok(Value::Color(color1.mix(&color2, weight))) + Ok(Value::Color(Box::new(color1.mix(&color2, weight)))) } pub(crate) fn declare(f: &mut GlobalFunctionMap) { diff --git a/src/parse/value.rs b/src/parse/value.rs index 08f6da1..88c6ce2 100644 --- a/src/parse/value.rs +++ b/src/parse/value.rs @@ -839,7 +839,7 @@ impl<'a, 'c, P: StylesheetParser<'a>> ValueParser<'a, 'c, P> { }) ) { let color = self.parse_hex_color_contents(parser)?; - return Ok(AstExpr::Color(color).span(parser.toks_mut().span_from(start))); + return Ok(AstExpr::Color(Box::new(color)).span(parser.toks_mut().span_from(start))); } let after_hash = parser.toks().cursor(); @@ -847,7 +847,9 @@ impl<'a, 'c, P: StylesheetParser<'a>> ValueParser<'a, 'c, P> { if is_hex_color(&ident) { parser.toks_mut().set_cursor(after_hash); let color = self.parse_hex_color_contents(parser)?; - return Ok(AstExpr::Color(color).span(parser.toks_mut().span_from(after_hash))); + return Ok( + AstExpr::Color(Box::new(color)).span(parser.toks_mut().span_from(after_hash)) + ); } let mut buffer = Interpolation::new(); @@ -1176,13 +1178,13 @@ impl<'a, 'c, P: StylesheetParser<'a>> ValueParser<'a, 'c, P> { } if let Some(color) = NAMED_COLORS.get_by_name(lower_ref.as_str()) { - return Ok(AstExpr::Color(Color::new( + return Ok(AstExpr::Color(Box::new(Color::new( color[0], color[1], color[2], color[3], plain.to_owned(), - )) + ))) .span(parser.toks_mut().span_from(start))); } } diff --git a/src/unit/mod.rs b/src/unit/mod.rs index 7ff26b1..970fa3c 100644 --- a/src/unit/mod.rs +++ b/src/unit/mod.rs @@ -6,7 +6,7 @@ pub(crate) use conversion::{known_compatibilities_by_unit, UNIT_CONVERSION_TABLE mod conversion; -#[derive(Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub(crate) enum Unit { // Absolute units /// Pixels @@ -100,10 +100,13 @@ pub(crate) enum Unit { /// Unspecified unit None, - Complex { - numer: Vec, - denom: Vec, - }, + Complex(Box), +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub(crate) struct ComplexUnit { + pub(crate) numer: Vec, + pub(crate) denom: Vec, } pub(crate) fn are_any_convertible(units1: &[Unit], units2: &[Unit]) -> bool { @@ -138,13 +141,13 @@ impl Unit { } else if denom.is_empty() && numer.len() == 1 { numer.pop().unwrap() } else { - Unit::Complex { numer, denom } + Unit::Complex(Box::new(ComplexUnit { numer, denom })) } } pub fn numer_and_denom(self) -> (Vec, Vec) { match self { - Self::Complex { numer, denom } => (numer, denom), + Self::Complex(complex) => (complex.numer, complex.denom), Self::None => (Vec::new(), Vec::new()), v => (vec![v], Vec::new()), } @@ -157,7 +160,7 @@ impl Unit { } pub fn is_complex(&self) -> bool { - matches!(self, Unit::Complex { numer, denom } if numer.len() != 1 || !denom.is_empty()) + matches!(self, Unit::Complex(complex) if complex.numer.len() != 1 || !complex.denom.is_empty()) } pub fn comparable(&self, other: &Unit) -> bool { @@ -279,7 +282,9 @@ impl fmt::Display for Unit { Unit::Fr => write!(f, "fr"), Unit::Unknown(s) => write!(f, "{}", s), Unit::None => Ok(()), - Unit::Complex { numer, denom } => { + Unit::Complex(complex) => { + let numer = &complex.numer; + let denom = &complex.denom; debug_assert!( numer.len() > 1 || !denom.is_empty(), "unsimplified complex unit" diff --git a/src/value/calculation.rs b/src/value/calculation.rs index 9e78aed..e5e73bc 100644 --- a/src/value/calculation.rs +++ b/src/value/calculation.rs @@ -261,8 +261,8 @@ impl SassCalculation { for arg in args { match arg { CalculationArg::Number(num) => match &num.unit { - Unit::Complex { numer, denom } => { - if numer.len() > 1 || !denom.is_empty() { + Unit::Complex(complex) => { + if complex.numer.len() > 1 || !complex.denom.is_empty() { let num = num.clone(); let value = Value::Dimension(num); return Err(( diff --git a/src/value/mod.rs b/src/value/mod.rs index 9a4ac01..e4ebd35 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -35,7 +35,7 @@ pub(crate) enum Value { Null, Dimension(SassNumber), List(Vec, ListSeparator, Brackets), - Color(Color), + Color(Box), String(String, QuoteKind), Map(SassMap), ArgList(ArgList), @@ -237,7 +237,7 @@ impl Value { pub fn assert_color_with_name(self, name: &str, span: Span) -> SassResult { match self { - Value::Color(c) => Ok(c), + Value::Color(c) => Ok(*c), _ => Err(( format!("${name}: {} is not a color.", self.inspect(span)?), span,