From b5a0957aa78eaed2f7716fd3eea199a2bcdf4c73 Mon Sep 17 00:00:00 2001 From: ConnorSkees <39542938+ConnorSkees@users.noreply.github.com> Date: Mon, 6 Apr 2020 21:58:47 -0400 Subject: [PATCH] handle special functions in 3args rgba --- src/builtin/color/rgb.rs | 451 +++++++++++++++++++++++++++------------ 1 file changed, 319 insertions(+), 132 deletions(-) diff --git a/src/builtin/color/rgb.rs b/src/builtin/color/rgb.rs index 1694a37..c2b9e87 100644 --- a/src/builtin/color/rgb.rs +++ b/src/builtin/color/rgb.rs @@ -9,147 +9,334 @@ use crate::unit::Unit; use crate::value::{Number, Value}; pub(crate) fn register(f: &mut HashMap) { - let rgb = Builtin::new(|mut args, scope, super_selector| { - if args.is_empty() { - return Err("Missing argument $channels.".into()); - } - - if args.len() == 1 { - let mut channels = match arg!(args, scope, super_selector, 0, "channels") { - Value::List(v, ..) => v, - _ => return Err("Missing argument $channels.".into()), - }; - - if channels.len() > 3 { - return Err(format!( - "Only 3 elements allowed, but {} were passed.", - channels.len() - ) - .into()); + f.insert( + "rgb".to_owned(), + Builtin::new(|mut args, scope, super_selector| { + if args.is_empty() { + return Err("Missing argument $channels.".into()); } - let blue = match channels.pop() { - Some(Value::Dimension(n, Unit::None)) => n, - Some(Value::Dimension(n, Unit::Percent)) => { - (n / Number::from(100)) * Number::from(255) - } - Some(v) => return Err(format!("$blue: {} is not a number.", v).into()), - None => return Err("Missing element $blue.".into()), - }; + if args.len() == 1 { + let mut channels = match arg!(args, scope, super_selector, 0, "channels") { + Value::List(v, ..) => v, + _ => return Err("Missing argument $channels.".into()), + }; - let green = match channels.pop() { - Some(Value::Dimension(n, Unit::None)) => n, - Some(Value::Dimension(n, Unit::Percent)) => { - (n / Number::from(100)) * Number::from(255) + if channels.len() > 3 { + return Err(format!( + "Only 3 elements allowed, but {} were passed.", + channels.len() + ) + .into()); } - Some(v) => return Err(format!("$green: {} is not a number.", v).into()), - None => return Err("Missing element $green.".into()), - }; - let red = match channels.pop() { - Some(Value::Dimension(n, Unit::None)) => n, - Some(Value::Dimension(n, Unit::Percent)) => { - (n / Number::from(100)) * Number::from(255) - } - Some(v) => return Err(format!("$red: {} is not a number.", v).into()), - None => return Err("Missing element $red.".into()), - }; - - let color = Color::from_rgba(red, green, blue, Number::one()); - - Ok(Value::Color(color)) - } else if args.len() == 2 { - let color = match arg!(args, scope, super_selector, 0, "color") { - Value::Color(c) => c, - v => return Err(format!("$color: {} is not a color.", v).into()), - }; - let alpha = match arg!(args, scope, super_selector, 1, "alpha") { - Value::Dimension(n, Unit::None) => n, - Value::Dimension(n, Unit::Percent) => n / Number::from(100), - v @ Value::Dimension(..) => { - return Err(format!("$alpha: Expected {} to have no units or \"%\".", v).into()) - } - v => return Err(format!("$alpha: {} is not a number.", v).into()), - }; - Ok(Value::Color(color.with_alpha(alpha))) - } else { - let red = match arg!(args, scope, super_selector, 0, "red") { - Value::Dimension(n, Unit::None) => n, - Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255), - v @ Value::Dimension(..) => { - return Err(format!("$red: Expected {} to have no units or \"%\".", v).into()) - } - v if v.is_special_function() => { - let green = arg!(args, scope, super_selector, 1, "green"); - let blue = arg!(args, scope, super_selector, 2, "blue"); - let mut string = format!("rgb({}, {}, {}", v, green, blue); - if !args.is_empty() { - string.push_str(", "); - string.push_str(&arg!(args, scope, super_selector, 3, "alpha").to_string()); + let blue = match channels.pop() { + Some(Value::Dimension(n, Unit::None)) => n, + Some(Value::Dimension(n, Unit::Percent)) => { + (n / Number::from(100)) * Number::from(255) } - string.push(')'); - return Ok(Value::Ident(string, QuoteKind::None)); - } - v => return Err(format!("$red: {} is not a number.", v).into()), - }; - let green = match arg!(args, scope, super_selector, 1, "green") { - Value::Dimension(n, Unit::None) => n, - Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255), - v @ Value::Dimension(..) => { - return Err(format!("$green: Expected {} to have no units or \"%\".", v).into()) - } - v if v.is_special_function() => { - let blue = arg!(args, scope, super_selector, 2, "blue"); - let mut string = format!("rgb({}, {}, {}", red, v, blue); - if !args.is_empty() { - string.push_str(", "); - string.push_str(&arg!(args, scope, super_selector, 3, "alpha").to_string()); + Some(v) => return Err(format!("$blue: {} is not a number.", v).into()), + None => return Err("Missing element $blue.".into()), + }; + + let green = match channels.pop() { + Some(Value::Dimension(n, Unit::None)) => n, + Some(Value::Dimension(n, Unit::Percent)) => { + (n / Number::from(100)) * Number::from(255) } - string.push(')'); - return Ok(Value::Ident(string, QuoteKind::None)); - } - v => return Err(format!("$green: {} is not a number.", v).into()), - }; - let blue = match arg!(args, scope, super_selector, 2, "blue") { - Value::Dimension(n, Unit::None) => n, - Value::Dimension(n, Unit::Percent) => (n / Number::from(100)) * Number::from(255), - v @ Value::Dimension(..) => { - return Err(format!("$blue: Expected {} to have no units or \"%\".", v).into()) - } - v if v.is_special_function() => { - let mut string = format!("rgb({}, {}, {}", red, green, v); - if !args.is_empty() { - string.push_str(", "); - string.push_str(&arg!(args, scope, super_selector, 3, "alpha").to_string()); + Some(v) => return Err(format!("$green: {} is not a number.", v).into()), + None => return Err("Missing element $green.".into()), + }; + + let red = match channels.pop() { + Some(Value::Dimension(n, Unit::None)) => n, + Some(Value::Dimension(n, Unit::Percent)) => { + (n / Number::from(100)) * Number::from(255) } - string.push(')'); - return Ok(Value::Ident(string, QuoteKind::None)); + Some(v) => return Err(format!("$red: {} is not a number.", v).into()), + None => return Err("Missing element $red.".into()), + }; + + let color = Color::from_rgba(red, green, blue, Number::one()); + + Ok(Value::Color(color)) + } else if args.len() == 2 { + let color = match arg!(args, scope, super_selector, 0, "color") { + Value::Color(c) => c, + v => return Err(format!("$color: {} is not a color.", v).into()), + }; + let alpha = match arg!(args, scope, super_selector, 1, "alpha") { + Value::Dimension(n, Unit::None) => n, + Value::Dimension(n, Unit::Percent) => n / Number::from(100), + v @ Value::Dimension(..) => { + return Err( + format!("$alpha: Expected {} to have no units or \"%\".", v).into() + ) + } + v => return Err(format!("$alpha: {} is not a number.", v).into()), + }; + Ok(Value::Color(color.with_alpha(alpha))) + } else { + let red = match arg!(args, scope, super_selector, 0, "red") { + Value::Dimension(n, Unit::None) => n, + Value::Dimension(n, Unit::Percent) => { + (n / Number::from(100)) * Number::from(255) + } + v @ Value::Dimension(..) => { + return Err( + format!("$red: Expected {} to have no units or \"%\".", v).into() + ) + } + v if v.is_special_function() => { + let green = arg!(args, scope, super_selector, 1, "green"); + let blue = arg!(args, scope, super_selector, 2, "blue"); + let mut string = format!("rgb({}, {}, {}", v, green, blue); + if !args.is_empty() { + string.push_str(", "); + string.push_str( + &arg!(args, scope, super_selector, 3, "alpha").to_string(), + ); + } + string.push(')'); + return Ok(Value::Ident(string, QuoteKind::None)); + } + v => return Err(format!("$red: {} is not a number.", v).into()), + }; + let green = match arg!(args, scope, super_selector, 1, "green") { + Value::Dimension(n, Unit::None) => n, + Value::Dimension(n, Unit::Percent) => { + (n / Number::from(100)) * Number::from(255) + } + v @ Value::Dimension(..) => { + return Err( + format!("$green: Expected {} to have no units or \"%\".", v).into() + ) + } + v if v.is_special_function() => { + let blue = arg!(args, scope, super_selector, 2, "blue"); + let mut string = format!("rgb({}, {}, {}", red, v, blue); + if !args.is_empty() { + string.push_str(", "); + string.push_str( + &arg!(args, scope, super_selector, 3, "alpha").to_string(), + ); + } + string.push(')'); + return Ok(Value::Ident(string, QuoteKind::None)); + } + v => return Err(format!("$green: {} is not a number.", v).into()), + }; + let blue = match arg!(args, scope, super_selector, 2, "blue") { + Value::Dimension(n, Unit::None) => n, + Value::Dimension(n, Unit::Percent) => { + (n / Number::from(100)) * Number::from(255) + } + v @ Value::Dimension(..) => { + return Err( + format!("$blue: Expected {} to have no units or \"%\".", v).into() + ) + } + v if v.is_special_function() => { + let mut string = format!("rgb({}, {}, {}", red, green, v); + if !args.is_empty() { + string.push_str(", "); + string.push_str( + &arg!(args, scope, super_selector, 3, "alpha").to_string(), + ); + } + string.push(')'); + return Ok(Value::Ident(string, QuoteKind::None)); + } + v => return Err(format!("$blue: {} is not a number.", v).into()), + }; + let alpha = match arg!( + args, + scope, + super_selector, + 3, + "alpha" = Value::Dimension(Number::one(), Unit::None) + ) { + Value::Dimension(n, Unit::None) => n, + Value::Dimension(n, Unit::Percent) => n / Number::from(100), + v @ Value::Dimension(..) => { + return Err( + format!("$alpha: Expected {} to have no units or \"%\".", v).into() + ) + } + v if v.is_special_function() => { + let string = format!("rgb({}, {}, {}, {})", red, green, blue, v); + return Ok(Value::Ident(string, QuoteKind::None)); + } + v => return Err(format!("$alpha: {} is not a number.", v).into()), + }; + Ok(Value::Color(Color::from_rgba(red, green, blue, alpha))) + } + }), + ); + f.insert( + "rgba".to_owned(), + Builtin::new(|mut args, scope, super_selector| { + if args.is_empty() { + return Err("Missing argument $channels.".into()); + } + + if args.len() == 1 { + let mut channels = match arg!(args, scope, super_selector, 0, "channels") { + Value::List(v, ..) => v, + _ => return Err("Missing argument $channels.".into()), + }; + + if channels.len() > 3 { + return Err(format!( + "Only 3 elements allowed, but {} were passed.", + channels.len() + ) + .into()); } - v => return Err(format!("$blue: {} is not a number.", v).into()), - }; - let alpha = match arg!( - args, - scope, - super_selector, - 3, - "alpha" = Value::Dimension(Number::one(), Unit::None) - ) { - Value::Dimension(n, Unit::None) => n, - Value::Dimension(n, Unit::Percent) => n / Number::from(100), - v @ Value::Dimension(..) => { - return Err(format!("$alpha: Expected {} to have no units or \"%\".", v).into()) - } - v if v.is_special_function() => { - let string = format!("rgb({}, {}, {}, {})", red, green, blue, v); - return Ok(Value::Ident(string, QuoteKind::None)); - } - v => return Err(format!("$alpha: {} is not a number.", v).into()), - }; - Ok(Value::Color(Color::from_rgba(red, green, blue, alpha))) - } - }); - f.insert("rgb".to_owned(), rgb.clone()); - f.insert("rgba".to_owned(), rgb); + + let blue = match channels.pop() { + Some(Value::Dimension(n, Unit::None)) => n, + Some(Value::Dimension(n, Unit::Percent)) => { + (n / Number::from(100)) * Number::from(255) + } + Some(v) => return Err(format!("$blue: {} is not a number.", v).into()), + None => return Err("Missing element $blue.".into()), + }; + + let green = match channels.pop() { + Some(Value::Dimension(n, Unit::None)) => n, + Some(Value::Dimension(n, Unit::Percent)) => { + (n / Number::from(100)) * Number::from(255) + } + Some(v) => return Err(format!("$green: {} is not a number.", v).into()), + None => return Err("Missing element $green.".into()), + }; + + let red = match channels.pop() { + Some(Value::Dimension(n, Unit::None)) => n, + Some(Value::Dimension(n, Unit::Percent)) => { + (n / Number::from(100)) * Number::from(255) + } + Some(v) => return Err(format!("$red: {} is not a number.", v).into()), + None => return Err("Missing element $red.".into()), + }; + + let color = Color::from_rgba(red, green, blue, Number::one()); + + Ok(Value::Color(color)) + } else if args.len() == 2 { + let color = match arg!(args, scope, super_selector, 0, "color") { + Value::Color(c) => c, + v => return Err(format!("$color: {} is not a color.", v).into()), + }; + let alpha = match arg!(args, scope, super_selector, 1, "alpha") { + Value::Dimension(n, Unit::None) => n, + Value::Dimension(n, Unit::Percent) => n / Number::from(100), + v @ Value::Dimension(..) => { + return Err( + format!("$alpha: Expected {} to have no units or \"%\".", v).into() + ) + } + v => return Err(format!("$alpha: {} is not a number.", v).into()), + }; + Ok(Value::Color(color.with_alpha(alpha))) + } else { + let red = match arg!(args, scope, super_selector, 0, "red") { + Value::Dimension(n, Unit::None) => n, + Value::Dimension(n, Unit::Percent) => { + (n / Number::from(100)) * Number::from(255) + } + v @ Value::Dimension(..) => { + return Err( + format!("$red: Expected {} to have no units or \"%\".", v).into() + ) + } + v if v.is_special_function() => { + let green = arg!(args, scope, super_selector, 1, "green"); + let blue = arg!(args, scope, super_selector, 2, "blue"); + let mut string = format!("rgba({}, {}, {}", v, green, blue); + if !args.is_empty() { + string.push_str(", "); + string.push_str( + &arg!(args, scope, super_selector, 3, "alpha").to_string(), + ); + } + string.push(')'); + return Ok(Value::Ident(string, QuoteKind::None)); + } + v => return Err(format!("$red: {} is not a number.", v).into()), + }; + let green = match arg!(args, scope, super_selector, 1, "green") { + Value::Dimension(n, Unit::None) => n, + Value::Dimension(n, Unit::Percent) => { + (n / Number::from(100)) * Number::from(255) + } + v @ Value::Dimension(..) => { + return Err( + format!("$green: Expected {} to have no units or \"%\".", v).into() + ) + } + v if v.is_special_function() => { + let blue = arg!(args, scope, super_selector, 2, "blue"); + let mut string = format!("rgba({}, {}, {}", red, v, blue); + if !args.is_empty() { + string.push_str(", "); + string.push_str( + &arg!(args, scope, super_selector, 3, "alpha").to_string(), + ); + } + string.push(')'); + return Ok(Value::Ident(string, QuoteKind::None)); + } + v => return Err(format!("$green: {} is not a number.", v).into()), + }; + let blue = match arg!(args, scope, super_selector, 2, "blue") { + Value::Dimension(n, Unit::None) => n, + Value::Dimension(n, Unit::Percent) => { + (n / Number::from(100)) * Number::from(255) + } + v @ Value::Dimension(..) => { + return Err( + format!("$blue: Expected {} to have no units or \"%\".", v).into() + ) + } + v if v.is_special_function() => { + let mut string = format!("rgba({}, {}, {}", red, green, v); + if !args.is_empty() { + string.push_str(", "); + string.push_str( + &arg!(args, scope, super_selector, 3, "alpha").to_string(), + ); + } + string.push(')'); + return Ok(Value::Ident(string, QuoteKind::None)); + } + v => return Err(format!("$blue: {} is not a number.", v).into()), + }; + let alpha = match arg!( + args, + scope, + super_selector, + 3, + "alpha" = Value::Dimension(Number::one(), Unit::None) + ) { + Value::Dimension(n, Unit::None) => n, + Value::Dimension(n, Unit::Percent) => n / Number::from(100), + v @ Value::Dimension(..) => { + return Err( + format!("$alpha: Expected {} to have no units or \"%\".", v).into() + ) + } + v if v.is_special_function() => { + let string = format!("rgba({}, {}, {}, {})", red, green, blue, v); + return Ok(Value::Ident(string, QuoteKind::None)); + } + v => return Err(format!("$alpha: {} is not a number.", v).into()), + }; + Ok(Value::Color(Color::from_rgba(red, green, blue, alpha))) + } + }), + ); f.insert( "red".to_owned(), Builtin::new(|mut args, scope, super_selector| {