use None to represent NaN

This commit is contained in:
Connor Skees 2020-07-26 19:38:41 -04:00
parent dbfa691505
commit 53cf2816e0
15 changed files with 248 additions and 152 deletions

View File

@ -35,7 +35,8 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
}
let lightness = match channels.pop() {
Some(Value::Dimension(n, ..)) => n / Number::from(100),
Some(Value::Dimension(Some(n), ..)) => n / Number::from(100),
Some(Value::Dimension(None, ..)) => todo!(),
Some(v) => {
return Err((
format!("$lightness: {} is not a number.", v.inspect(args.span())?),
@ -47,7 +48,8 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
};
let saturation = match channels.pop() {
Some(Value::Dimension(n, ..)) => n / Number::from(100),
Some(Value::Dimension(Some(n), ..)) => n / Number::from(100),
Some(Value::Dimension(None, ..)) => todo!(),
Some(v) => {
return Err((
format!("$saturation: {} is not a number.", v.inspect(args.span())?),
@ -59,7 +61,8 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
};
let hue = match channels.pop() {
Some(Value::Dimension(n, ..)) => n,
Some(Value::Dimension(Some(n), ..)) => n,
Some(Value::Dimension(None, ..)) => todo!(),
Some(v) => {
return Err((
format!("$hue: {} is not a number.", v.inspect(args.span())?),
@ -78,7 +81,8 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
))))
} else {
let hue = match args.get_err(0, "hue")? {
Value::Dimension(n, ..) => n,
Value::Dimension(Some(n), ..) => n,
Value::Dimension(None, ..) => todo!(),
v if v.is_special_function() => {
let saturation = args.get_err(1, "saturation")?;
let lightness = args.get_err(2, "lightness")?;
@ -105,7 +109,8 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
}
};
let saturation = match args.get_err(1, "saturation")? {
Value::Dimension(n, ..) => n / Number::from(100),
Value::Dimension(Some(n), ..) => n / Number::from(100),
Value::Dimension(None, ..) => todo!(),
v if v.is_special_function() => {
let lightness = args.get_err(2, "lightness")?;
let mut string = format!(
@ -134,7 +139,8 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
}
};
let lightness = match args.get_err(2, "lightness")? {
Value::Dimension(n, ..) => n / Number::from(100),
Value::Dimension(Some(n), ..) => n / Number::from(100),
Value::Dimension(None, ..) => todo!(),
v if v.is_special_function() => {
let mut string = format!(
"{}({}, {}, {}",
@ -164,10 +170,11 @@ fn inner_hsl(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
let alpha = match args.default_arg(
3,
"alpha",
Value::Dimension(Number::one(), Unit::None, true),
Value::Dimension(Some(Number::one()), Unit::None, true),
)? {
Value::Dimension(n, Unit::None, _) => n,
Value::Dimension(n, Unit::Percent, _) => n / Number::from(100),
Value::Dimension(Some(n), Unit::None, _) => n,
Value::Dimension(Some(n), Unit::Percent, _) => n / Number::from(100),
Value::Dimension(None, ..) => todo!(),
v @ Value::Dimension(..) => {
return Err((
format!(
@ -216,7 +223,7 @@ pub(crate) fn hsla(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
pub(crate) fn hue(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?;
match args.get_err(0, "color")? {
Value::Color(c) => Ok(Value::Dimension(c.hue(), Unit::Deg, true)),
Value::Color(c) => Ok(Value::Dimension(Some(c.hue()), Unit::Deg, true)),
v => Err((
format!("$color: {} is not a color.", v.inspect(args.span())?),
args.span(),
@ -228,7 +235,7 @@ pub(crate) fn hue(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Val
pub(crate) fn saturation(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?;
match args.get_err(0, "color")? {
Value::Color(c) => Ok(Value::Dimension(c.saturation(), Unit::Percent, true)),
Value::Color(c) => Ok(Value::Dimension(Some(c.saturation()), Unit::Percent, true)),
v => Err((
format!("$color: {} is not a color.", v.inspect(args.span())?),
args.span(),
@ -240,7 +247,7 @@ pub(crate) fn saturation(mut args: CallArgs, parser: &mut Parser<'_>) -> SassRes
pub(crate) fn lightness(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?;
match args.get_err(0, "color")? {
Value::Color(c) => Ok(Value::Dimension(c.lightness(), Unit::Percent, true)),
Value::Color(c) => Ok(Value::Dimension(Some(c.lightness()), Unit::Percent, true)),
v => Err((
format!("$color: {} is not a color.", v.inspect(args.span())?),
args.span(),
@ -262,7 +269,8 @@ pub(crate) fn adjust_hue(mut args: CallArgs, parser: &mut Parser<'_>) -> SassRes
}
};
let degrees = match args.get_err(1, "degrees")? {
Value::Dimension(n, ..) => n,
Value::Dimension(Some(n), ..) => n,
Value::Dimension(None, ..) => todo!(),
v => {
return Err((
format!(
@ -290,7 +298,8 @@ fn lighten(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
}
};
let amount = match args.get_err(1, "amount")? {
Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 100) / Number::from(100),
Value::Dimension(Some(n), u, _) => bound!(args, "amount", n, u, 0, 100) / Number::from(100),
Value::Dimension(None, ..) => todo!(),
v => {
return Err((
format!(
@ -318,7 +327,8 @@ fn darken(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
}
};
let amount = match args.get_err(1, "amount")? {
Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 100) / Number::from(100),
Value::Dimension(Some(n), u, _) => bound!(args, "amount", n, u, 0, 100) / Number::from(100),
Value::Dimension(None, ..) => todo!(),
v => {
return Err((
format!(
@ -346,7 +356,8 @@ fn saturate(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
}
let amount = match args.get_err(1, "amount")? {
Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 100) / Number::from(100),
Value::Dimension(Some(n), u, _) => bound!(args, "amount", n, u, 0, 100) / Number::from(100),
Value::Dimension(None, ..) => todo!(),
v => {
return Err((
format!(
@ -360,7 +371,7 @@ fn saturate(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
};
let color = match args.get_err(0, "color")? {
Value::Color(c) => c,
Value::Dimension(n, u, _) => {
Value::Dimension(Some(n), u, _) => {
return Ok(Value::String(
format!("saturate({}{})", n, u),
QuoteKind::None,
@ -390,7 +401,8 @@ fn desaturate(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
}
};
let amount = match args.get_err(1, "amount")? {
Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 100) / Number::from(100),
Value::Dimension(Some(n), u, _) => bound!(args, "amount", n, u, 0, 100) / Number::from(100),
Value::Dimension(None, ..) => todo!(),
v => {
return Err((
format!(
@ -409,7 +421,7 @@ pub(crate) fn grayscale(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResu
args.max_args(1)?;
let color = match args.get_err(0, "color")? {
Value::Color(c) => c,
Value::Dimension(n, u, _) => {
Value::Dimension(Some(n), u, _) => {
return Ok(Value::String(
format!("grayscale({}{})", n, u),
QuoteKind::None,
@ -446,9 +458,10 @@ pub(crate) fn invert(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<
let weight = match args.default_arg(
1,
"weight",
Value::Dimension(Number::from(100), Unit::Percent, true),
Value::Dimension(Some(Number::from(100)), Unit::Percent, true),
)? {
Value::Dimension(n, u, _) => bound!(args, "weight", n, u, 0, 100) / Number::from(100),
Value::Dimension(Some(n), u, _) => bound!(args, "weight", n, u, 0, 100) / Number::from(100),
Value::Dimension(None, ..) => todo!(),
v => {
return Err((
format!(
@ -462,9 +475,10 @@ pub(crate) fn invert(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<
};
match args.get_err(0, "color")? {
Value::Color(c) => Ok(Value::Color(Box::new(c.invert(weight)))),
Value::Dimension(n, Unit::Percent, _) => {
Value::Dimension(Some(n), Unit::Percent, _) => {
Ok(Value::String(format!("invert({}%)", n), QuoteKind::None))
}
Value::Dimension(None, ..) => todo!(),
Value::Dimension(..) => Err((
"Only one argument may be passed to the plain-CSS invert() function.",
args.span(),

View File

@ -8,7 +8,8 @@ use crate::{
pub(crate) fn alpha(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?;
match args.get_err(0, "color")? {
Value::Color(c) => Ok(Value::Dimension(c.alpha(), Unit::None, true)),
Value::Color(c) => Ok(Value::Dimension(Some(c.alpha()), Unit::None, true)),
Value::Dimension(None, ..) => todo!(),
v => Err((
format!("$color: {} is not a color.", v.inspect(args.span())?),
args.span(),
@ -20,11 +21,12 @@ pub(crate) fn alpha(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<V
pub(crate) fn opacity(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?;
match args.get_err(0, "color")? {
Value::Color(c) => Ok(Value::Dimension(c.alpha(), Unit::None, true)),
Value::Dimension(num, unit, _) => Ok(Value::String(
Value::Color(c) => Ok(Value::Dimension(Some(c.alpha()), Unit::None, true)),
Value::Dimension(Some(num), unit, _) => Ok(Value::String(
format!("opacity({}{})", num, unit),
QuoteKind::None,
)),
Value::Dimension(None, ..) => todo!(),
v => Err((
format!("$color: {} is not a color.", v.inspect(args.span())?),
args.span(),
@ -47,7 +49,8 @@ fn opacify(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
}
};
let amount = match args.get_err(1, "amount")? {
Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 1),
Value::Dimension(Some(n), u, _) => bound!(args, "amount", n, u, 0, 1),
Value::Dimension(None, ..) => todo!(),
v => {
return Err((
format!("$amount: {} is not a number.", v.inspect(args.span())?),
@ -72,7 +75,8 @@ fn fade_in(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
}
};
let amount = match args.get_err(1, "amount")? {
Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 1),
Value::Dimension(Some(n), u, _) => bound!(args, "amount", n, u, 0, 1),
Value::Dimension(None, ..) => todo!(),
v => {
return Err((
format!("$amount: {} is not a number.", v.inspect(args.span())?),
@ -98,7 +102,8 @@ fn transparentize(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Val
}
};
let amount = match args.get_err(1, "amount")? {
Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 1),
Value::Dimension(Some(n), u, _) => bound!(args, "amount", n, u, 0, 1),
Value::Dimension(None, ..) => todo!(),
v => {
return Err((
format!("$amount: {} is not a number.", v.inspect(args.span())?),
@ -123,7 +128,8 @@ fn fade_out(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
}
};
let amount = match args.get_err(1, "amount")? {
Value::Dimension(n, u, _) => bound!(args, "amount", n, u, 0, 1),
Value::Dimension(Some(n), u, _) => bound!(args, "amount", n, u, 0, 1),
Value::Dimension(None, ..) => todo!(),
v => {
return Err((
format!("$amount: {} is not a number.", v.inspect(args.span())?),

View File

@ -15,7 +15,8 @@ use crate::{
macro_rules! opt_rgba {
($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal) => {
let $name = match $args.default_named_arg($arg, Value::Null)? {
Value::Dimension(n, u, _) => Some(bound!($args, $arg, n, u, $low, $high)),
Value::Dimension(Some(n), u, _) => Some(bound!($args, $arg, n, u, $low, $high)),
Value::Dimension(None, ..) => todo!(),
Value::Null => None,
v => {
return Err((
@ -31,9 +32,10 @@ macro_rules! opt_rgba {
macro_rules! opt_hsl {
($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal) => {
let $name = match $args.default_named_arg($arg, Value::Null)? {
Value::Dimension(n, u, _) => {
Value::Dimension(Some(n), u, _) => {
Some(bound!($args, $arg, n, u, $low, $high) / Number::from(100))
}
Value::Dimension(None, ..) => todo!(),
Value::Null => None,
v => {
return Err((
@ -81,7 +83,8 @@ pub(crate) fn change_color(mut args: CallArgs, parser: &mut Parser<'_>) -> SassR
}
let hue = match args.default_named_arg("hue", Value::Null)? {
Value::Dimension(n, ..) => Some(n),
Value::Dimension(Some(n), ..) => Some(n),
Value::Dimension(None, ..) => todo!(),
Value::Null => None,
v => {
return Err((
@ -140,7 +143,8 @@ pub(crate) fn adjust_color(mut args: CallArgs, parser: &mut Parser<'_>) -> SassR
}
let hue = match args.default_named_arg("hue", Value::Null)? {
Value::Dimension(n, ..) => Some(n),
Value::Dimension(Some(n), ..) => Some(n),
Value::Dimension(None, ..) => todo!(),
Value::Null => None,
v => {
return Err((
@ -198,9 +202,10 @@ pub(crate) fn scale_color(mut args: CallArgs, parser: &mut Parser<'_>) -> SassRe
macro_rules! opt_scale_arg {
($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal) => {
let $name = match $args.default_named_arg($arg, Value::Null)? {
Value::Dimension(n, Unit::Percent, _) => {
Value::Dimension(Some(n), Unit::Percent, _) => {
Some(bound!($args, $arg, n, Unit::Percent, $low, $high) / Number::from(100))
}
Value::Dimension(None, ..) => todo!(),
v @ Value::Dimension(..) => {
return Err((
format!(

View File

@ -38,10 +38,11 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
}
let blue = match channels.pop() {
Some(Value::Dimension(n, Unit::None, _)) => n,
Some(Value::Dimension(n, Unit::Percent, _)) => {
Some(Value::Dimension(Some(n), Unit::None, _)) => n,
Some(Value::Dimension(Some(n), Unit::Percent, _)) => {
(n / Number::from(100)) * Number::from(255)
}
Some(Value::Dimension(None, ..)) => todo!(),
Some(v) if v.is_special_function() => {
let green = channels.pop().unwrap();
let red = channels.pop().unwrap();
@ -67,10 +68,11 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
};
let green = match channels.pop() {
Some(Value::Dimension(n, Unit::None, _)) => n,
Some(Value::Dimension(n, Unit::Percent, _)) => {
Some(Value::Dimension(Some(n), Unit::None, _)) => n,
Some(Value::Dimension(Some(n), Unit::Percent, _)) => {
(n / Number::from(100)) * Number::from(255)
}
Some(Value::Dimension(None, ..)) => todo!(),
Some(v) if v.is_special_function() => {
let string = match channels.pop() {
Some(red) => format!(
@ -95,10 +97,11 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
};
let red = match channels.pop() {
Some(Value::Dimension(n, Unit::None, _)) => n,
Some(Value::Dimension(n, Unit::Percent, _)) => {
Some(Value::Dimension(Some(n), Unit::None, _)) => n,
Some(Value::Dimension(Some(n), Unit::Percent, _)) => {
(n / Number::from(100)) * Number::from(255)
}
Some(Value::Dimension(None, ..)) => todo!(),
Some(v) if v.is_special_function() => {
return Ok(Value::String(
format!(
@ -148,8 +151,9 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
}
};
let alpha = match args.get_err(1, "alpha")? {
Value::Dimension(n, Unit::None, _) => n,
Value::Dimension(n, Unit::Percent, _) => n / Number::from(100),
Value::Dimension(Some(n), Unit::None, _) => n,
Value::Dimension(Some(n), Unit::Percent, _) => n / Number::from(100),
Value::Dimension(None, ..) => todo!(),
v @ Value::Dimension(..) => {
return Err((
format!(
@ -184,8 +188,11 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
Ok(Value::Color(Box::new(color.with_alpha(alpha))))
} else {
let red = match args.get_err(0, "red")? {
Value::Dimension(n, Unit::None, _) => n,
Value::Dimension(n, Unit::Percent, _) => (n / Number::from(100)) * Number::from(255),
Value::Dimension(Some(n), Unit::None, _) => n,
Value::Dimension(Some(n), Unit::Percent, _) => {
(n / Number::from(100)) * Number::from(255)
}
Value::Dimension(None, ..) => todo!(),
v @ Value::Dimension(..) => {
return Err((
format!(
@ -222,8 +229,11 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
}
};
let green = match args.get_err(1, "green")? {
Value::Dimension(n, Unit::None, _) => n,
Value::Dimension(n, Unit::Percent, _) => (n / Number::from(100)) * Number::from(255),
Value::Dimension(Some(n), Unit::None, _) => n,
Value::Dimension(Some(n), Unit::Percent, _) => {
(n / Number::from(100)) * Number::from(255)
}
Value::Dimension(None, ..) => todo!(),
v @ Value::Dimension(..) => {
return Err((
format!(
@ -259,8 +269,11 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
}
};
let blue = match args.get_err(2, "blue")? {
Value::Dimension(n, Unit::None, _) => n,
Value::Dimension(n, Unit::Percent, _) => (n / Number::from(100)) * Number::from(255),
Value::Dimension(Some(n), Unit::None, _) => n,
Value::Dimension(Some(n), Unit::Percent, _) => {
(n / Number::from(100)) * Number::from(255)
}
Value::Dimension(None, ..) => todo!(),
v @ Value::Dimension(..) => {
return Err((
format!(
@ -297,10 +310,11 @@ fn inner_rgb(name: &'static str, mut args: CallArgs, parser: &mut Parser<'_>) ->
let alpha = match args.default_arg(
3,
"alpha",
Value::Dimension(Number::one(), Unit::None, true),
Value::Dimension(Some(Number::one()), Unit::None, true),
)? {
Value::Dimension(n, Unit::None, _) => n,
Value::Dimension(n, Unit::Percent, _) => n / Number::from(100),
Value::Dimension(Some(n), Unit::None, _) => n,
Value::Dimension(Some(n), Unit::Percent, _) => n / Number::from(100),
Value::Dimension(None, ..) => todo!(),
v @ Value::Dimension(..) => {
return Err((
format!(
@ -347,7 +361,7 @@ pub(crate) fn rgba(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
pub(crate) fn red(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?;
match args.get_err(0, "color")? {
Value::Color(c) => Ok(Value::Dimension(c.red(), Unit::None, true)),
Value::Color(c) => Ok(Value::Dimension(Some(c.red()), Unit::None, true)),
v => Err((
format!("$color: {} is not a color.", v.inspect(args.span())?),
args.span(),
@ -359,7 +373,7 @@ pub(crate) fn red(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Val
pub(crate) fn green(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?;
match args.get_err(0, "color")? {
Value::Color(c) => Ok(Value::Dimension(c.green(), Unit::None, true)),
Value::Color(c) => Ok(Value::Dimension(Some(c.green()), Unit::None, true)),
v => Err((
format!("$color: {} is not a color.", v.inspect(args.span())?),
args.span(),
@ -371,7 +385,7 @@ pub(crate) fn green(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<V
pub(crate) fn blue(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?;
match args.get_err(0, "color")? {
Value::Color(c) => Ok(Value::Dimension(c.blue(), Unit::None, true)),
Value::Color(c) => Ok(Value::Dimension(Some(c.blue()), Unit::None, true)),
v => Err((
format!("$color: {} is not a color.", v.inspect(args.span())?),
args.span(),
@ -407,9 +421,10 @@ pub(crate) fn mix(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Val
let weight = match args.default_arg(
2,
"weight",
Value::Dimension(Number::from(50), Unit::None, true),
Value::Dimension(Some(Number::from(50)), Unit::None, true),
)? {
Value::Dimension(n, u, _) => bound!(args, "weight", n, u, 0, 100) / Number::from(100),
Value::Dimension(Some(n), u, _) => bound!(args, "weight", n, u, 0, 100) / Number::from(100),
Value::Dimension(None, ..) => todo!(),
v => {
return Err((
format!(

View File

@ -14,7 +14,7 @@ use crate::{
pub(crate) fn length(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?;
Ok(Value::Dimension(
Number::from(args.get_err(0, "list")?.as_list().len()),
Some(Number::from(args.get_err(0, "list")?.as_list().len())),
Unit::None,
true,
))
@ -24,7 +24,8 @@ pub(crate) fn nth(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Val
args.max_args(2)?;
let mut list = args.get_err(0, "list")?.as_list();
let n = match args.get_err(1, "n")? {
Value::Dimension(num, ..) => num,
Value::Dimension(Some(num), ..) => num,
Value::Dimension(None, ..) => todo!(),
v => {
return Err((
format!("$n: {} is not a number.", v.inspect(args.span())?),
@ -81,7 +82,8 @@ pub(crate) fn set_nth(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult
v => (vec![v], ListSeparator::Space, Brackets::None),
};
let n = match args.get_err(1, "n")? {
Value::Dimension(num, ..) => num,
Value::Dimension(Some(num), ..) => num,
Value::Dimension(None, ..) => todo!(),
v => {
return Err((
format!("$n: {} is not a number.", v.inspect(args.span())?),
@ -244,7 +246,7 @@ pub(crate) fn index(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<V
Some(v) => Number::from(v + 1),
None => return Ok(Value::Null),
};
Ok(Value::Dimension(index, Unit::None, true))
Ok(Value::Dimension(Some(index), Unit::None, true))
}
pub(crate) fn zip(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {

View File

@ -16,7 +16,8 @@ use crate::{
pub(crate) fn percentage(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?;
let num = match args.get_err(0, "number")? {
Value::Dimension(n, Unit::None, _) => n * Number::from(100),
Value::Dimension(Some(n), Unit::None, _) => n * Number::from(100),
Value::Dimension(None, ..) => todo!(),
v @ Value::Dimension(..) => {
return Err((
format!(
@ -35,13 +36,14 @@ pub(crate) fn percentage(mut args: CallArgs, parser: &mut Parser<'_>) -> SassRes
.into())
}
};
Ok(Value::Dimension(num, Unit::Percent, true))
Ok(Value::Dimension(Some(num), Unit::Percent, true))
}
pub(crate) fn round(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?;
match args.get_err(0, "number")? {
Value::Dimension(n, u, _) => Ok(Value::Dimension(n.round(), u, true)),
Value::Dimension(Some(n), u, _) => Ok(Value::Dimension(Some(n.round()), u, true)),
Value::Dimension(None, ..) => todo!(),
v => Err((
format!("$number: {} is not a number.", v.inspect(args.span())?),
args.span(),
@ -53,7 +55,8 @@ pub(crate) fn round(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<V
pub(crate) fn ceil(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?;
match args.get_err(0, "number")? {
Value::Dimension(n, u, _) => Ok(Value::Dimension(n.ceil(), u, true)),
Value::Dimension(Some(n), u, _) => Ok(Value::Dimension(Some(n.ceil()), u, true)),
Value::Dimension(None, ..) => todo!(),
v => Err((
format!("$number: {} is not a number.", v.inspect(args.span())?),
args.span(),
@ -65,7 +68,8 @@ pub(crate) fn ceil(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Va
pub(crate) fn floor(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?;
match args.get_err(0, "number")? {
Value::Dimension(n, u, _) => Ok(Value::Dimension(n.floor(), u, true)),
Value::Dimension(Some(n), u, _) => Ok(Value::Dimension(Some(n.floor()), u, true)),
Value::Dimension(None, ..) => todo!(),
v => Err((
format!("$number: {} is not a number.", v.inspect(args.span())?),
args.span(),
@ -77,7 +81,8 @@ pub(crate) fn floor(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<V
pub(crate) fn abs(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?;
match args.get_err(0, "number")? {
Value::Dimension(n, u, _) => Ok(Value::Dimension(n.abs(), u, true)),
Value::Dimension(Some(n), u, _) => Ok(Value::Dimension(Some(n.abs()), u, true)),
Value::Dimension(None, ..) => todo!(),
v => Err((
format!("$number: {} is not a number.", v.inspect(args.span())?),
args.span(),
@ -117,11 +122,12 @@ pub(crate) fn comparable(mut args: CallArgs, parser: &mut Parser<'_>) -> SassRes
pub(crate) fn random(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
args.max_args(1)?;
let limit = match args.default_arg(0, "limit", Value::Null)? {
Value::Dimension(n, ..) => n,
Value::Dimension(Some(n), ..) => n,
Value::Dimension(None, ..) => todo!(),
Value::Null => {
let mut rng = rand::thread_rng();
return Ok(Value::Dimension(
Number::from(rng.gen_range(0.0, 1.0)),
Some(Number::from(rng.gen_range(0.0, 1.0))),
Unit::None,
true,
));
@ -136,7 +142,7 @@ pub(crate) fn random(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<
};
if limit.is_one() {
return Ok(Value::Dimension(Number::one(), Unit::None, true));
return Ok(Value::Dimension(Some(Number::one()), Unit::None, true));
}
if limit.is_decimal() {
@ -164,7 +170,7 @@ pub(crate) fn random(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<
let mut rng = rand::thread_rng();
Ok(Value::Dimension(
Number::from(rng.gen_range(0, limit) + 1),
Some(Number::from(rng.gen_range(0, limit) + 1)),
Unit::None,
true,
))
@ -177,7 +183,8 @@ pub(crate) fn min(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
.get_variadic()?
.into_iter()
.map(|val| match val.node {
Value::Dimension(number, unit, _) => Ok((number, unit)),
Value::Dimension(Some(number), unit, _) => Ok((number, unit)),
Value::Dimension(None, ..) => todo!(),
v => Err((format!("{} is not a number.", v.inspect(span)?), span).into()),
})
.collect::<SassResult<Vec<(Number, Unit)>>>()?
@ -190,12 +197,12 @@ pub(crate) fn min(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
if ValueVisitor::new(parser, span)
.less_than(
HigherIntermediateValue::Literal(Value::Dimension(
num.0.clone(),
Some(num.0.clone()),
num.1.clone(),
true,
)),
HigherIntermediateValue::Literal(Value::Dimension(
min.0.clone(),
Some(min.0.clone()),
min.1.clone(),
true,
)),
@ -205,7 +212,7 @@ pub(crate) fn min(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
min = num;
}
}
Ok(Value::Dimension(min.0, min.1, true))
Ok(Value::Dimension(Some(min.0), min.1, true))
}
pub(crate) fn max(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value> {
@ -215,7 +222,8 @@ pub(crate) fn max(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
.get_variadic()?
.into_iter()
.map(|val| match val.node {
Value::Dimension(number, unit, _) => Ok((number, unit)),
Value::Dimension(Some(number), unit, _) => Ok((number, unit)),
Value::Dimension(None, ..) => todo!(),
v => Err((format!("{} is not a number.", v.inspect(span)?), span).into()),
})
.collect::<SassResult<Vec<(Number, Unit)>>>()?
@ -228,12 +236,12 @@ pub(crate) fn max(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
if ValueVisitor::new(parser, span)
.greater_than(
HigherIntermediateValue::Literal(Value::Dimension(
num.0.clone(),
Some(num.0.clone()),
num.1.clone(),
true,
)),
HigherIntermediateValue::Literal(Value::Dimension(
max.0.clone(),
Some(max.0.clone()),
max.1.clone(),
true,
)),
@ -243,7 +251,7 @@ pub(crate) fn max(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
max = num;
}
}
Ok(Value::Dimension(max.0, max.1, true))
Ok(Value::Dimension(Some(max.0), max.1, true))
}
pub(crate) fn declare(f: &mut GlobalFunctionMap) {

View File

@ -49,7 +49,7 @@ pub(crate) fn str_length(mut args: CallArgs, parser: &mut Parser<'_>) -> SassRes
args.max_args(1)?;
match args.get_err(0, "string")? {
Value::String(i, _) => Ok(Value::Dimension(
Number::from(i.chars().count()),
Some(Number::from(i.chars().count())),
Unit::None,
true,
)),
@ -99,17 +99,18 @@ pub(crate) fn str_slice(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResu
};
let str_len = string.chars().count();
let start = match args.get_err(1, "start-at")? {
Value::Dimension(n, Unit::None, _) if n.is_decimal() => {
Value::Dimension(Some(n), Unit::None, _) if n.is_decimal() => {
return Err((format!("{} is not an int.", n), args.span()).into())
}
Value::Dimension(n, Unit::None, _) if n.is_positive() => {
Value::Dimension(Some(n), Unit::None, _) if n.is_positive() => {
n.to_integer().to_usize().unwrap_or(str_len + 1)
}
Value::Dimension(n, Unit::None, _) if n.is_zero() => 1_usize,
Value::Dimension(n, Unit::None, _) if n < -Number::from(str_len) => 1_usize,
Value::Dimension(n, Unit::None, _) => (n.to_integer() + BigInt::from(str_len + 1))
Value::Dimension(Some(n), Unit::None, _) if n.is_zero() => 1_usize,
Value::Dimension(Some(n), Unit::None, _) if n < -Number::from(str_len) => 1_usize,
Value::Dimension(Some(n), Unit::None, _) => (n.to_integer() + BigInt::from(str_len + 1))
.to_usize()
.unwrap(),
Value::Dimension(None, ..) => todo!(),
v @ Value::Dimension(..) => {
return Err((
format!(
@ -129,17 +130,18 @@ pub(crate) fn str_slice(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResu
}
};
let mut end = match args.default_arg(2, "end-at", Value::Null)? {
Value::Dimension(n, Unit::None, _) if n.is_decimal() => {
Value::Dimension(Some(n), Unit::None, _) if n.is_decimal() => {
return Err((format!("{} is not an int.", n), args.span()).into())
}
Value::Dimension(n, Unit::None, _) if n.is_positive() => {
Value::Dimension(Some(n), Unit::None, _) if n.is_positive() => {
n.to_integer().to_usize().unwrap_or(str_len + 1)
}
Value::Dimension(n, Unit::None, _) if n.is_zero() => 0_usize,
Value::Dimension(n, Unit::None, _) if n < -Number::from(str_len) => 0_usize,
Value::Dimension(n, Unit::None, _) => (n.to_integer() + BigInt::from(str_len + 1))
Value::Dimension(Some(n), Unit::None, _) if n.is_zero() => 0_usize,
Value::Dimension(Some(n), Unit::None, _) if n < -Number::from(str_len) => 0_usize,
Value::Dimension(Some(n), Unit::None, _) => (n.to_integer() + BigInt::from(str_len + 1))
.to_usize()
.unwrap_or(str_len + 1),
Value::Dimension(None, ..) => todo!(),
v @ Value::Dimension(..) => {
return Err((
format!(
@ -203,7 +205,7 @@ pub(crate) fn str_index(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResu
};
Ok(match s1.find(&substr) {
Some(v) => Value::Dimension(Number::from(v + 1), Unit::None, true),
Some(v) => Value::Dimension(Some(Number::from(v + 1)), Unit::None, true),
None => Value::Null,
})
}
@ -233,10 +235,11 @@ pub(crate) fn str_insert(mut args: CallArgs, parser: &mut Parser<'_>) -> SassRes
};
let index = match args.get_err(2, "index")? {
Value::Dimension(n, Unit::None, _) if n.is_decimal() => {
Value::Dimension(Some(n), Unit::None, _) if n.is_decimal() => {
return Err((format!("$index: {} is not an int.", n), args.span()).into())
}
Value::Dimension(n, Unit::None, _) => n,
Value::Dimension(Some(n), Unit::None, _) => n,
Value::Dimension(None, ..) => todo!(),
v @ Value::Dimension(..) => {
return Err((
format!(

View File

@ -170,10 +170,10 @@ pub(crate) fn declare(f: &mut Module) {
f.insert_builtin_var(
"pi",
Value::Dimension(Number::from(std::f64::consts::PI), Unit::None, true),
Value::Dimension(Some(Number::from(std::f64::consts::PI)), Unit::None, true),
);
f.insert_builtin_var(
"e",
Value::Dimension(Number::from(std::f64::consts::E), Unit::None, true),
Value::Dimension(Some(Number::from(std::f64::consts::E)), Unit::None, true),
);
}

View File

@ -264,7 +264,7 @@ impl Color {
return h.saturation() * Number::from(100);
}
let red = self.red() / Number::from(255);
let red: Number = self.red() / Number::from(255);
let green = self.green() / Number::from(255);
let blue = self.blue() / Number::from(255);
@ -291,7 +291,7 @@ impl Color {
return h.luminance() * Number::from(100);
}
let red = self.red() / Number::from(255);
let red: Number = self.red() / Number::from(255);
let green = self.green() / Number::from(255);
let blue = self.blue() / Number::from(255);
let min = min(&red, min(&green, &blue)).clone();

View File

@ -245,10 +245,11 @@ impl<'a> Parser<'a> {
self.whitespace();
let from_val = self.parse_value_from_vec(from_toks, true)?;
let from = match from_val.node {
Value::Dimension(n, ..) => match n.to_integer().to_isize() {
Value::Dimension(Some(n), ..) => match n.to_integer().to_isize() {
Some(v) => v,
None => return Err((format!("{} is not a int.", n), from_val.span).into()),
},
Value::Dimension(None, ..) => todo!(),
v => {
return Err((
format!("{} is not an integer.", v.inspect(from_val.span)?),
@ -260,10 +261,11 @@ impl<'a> Parser<'a> {
let to_val = self.parse_value(true)?;
let to = match to_val.node {
Value::Dimension(n, ..) => match n.to_integer().to_isize() {
Value::Dimension(Some(n), ..) => match n.to_integer().to_isize() {
Some(v) => v,
None => return Err((format!("{} is not a int.", n), to_val.span).into()),
},
Value::Dimension(None, ..) => todo!(),
v => {
return Err((
format!("{} is not an integer.", v.to_css_string(to_val.span)?),
@ -303,7 +305,7 @@ impl<'a> Parser<'a> {
self.scopes.insert_var_last(
var.node,
Spanned {
node: Value::Dimension(Number::from(i), Unit::None, true),
node: Value::Dimension(Some(Number::from(i)), Unit::None, true),
span: var.span,
},
);

View File

@ -3,6 +3,7 @@
use std::cmp::Ordering;
use codemap::{Span, Spanned};
use num_traits::Zero;
use crate::{
args::CallArgs,
@ -119,7 +120,11 @@ impl<'a, 'b: 'a> ValueVisitor<'a, 'b> {
fn unary_minus(&self, val: Value) -> SassResult<Value> {
Ok(match val {
Value::Dimension(n, u, should_divide) => Value::Dimension(-n, u, should_divide),
Value::Dimension(Some(n), u, should_divide) => {
Value::Dimension(Some(-n), u, should_divide)
}
// todo: NaN test
Value::Dimension(None, u, should_divide) => Value::Dimension(None, u, should_divide),
v => Value::String(format!("-{}", v.to_css_string(self.span)?), QuoteKind::None),
})
}
@ -205,8 +210,10 @@ impl<'a, 'b: 'a> ValueVisitor<'a, 'b> {
QuoteKind::None,
),
},
Value::Dimension(num, unit, _) => match right {
Value::Dimension(num2, unit2, _) => {
v @ Value::Dimension(None, ..) => v,
Value::Dimension(Some(num), unit, _) => match right {
v @ Value::Dimension(None, ..) => v,
Value::Dimension(Some(num2), unit2, _) => {
if !unit.comparable(&unit2) {
return Err((
format!("Incompatible units {} and {}.", unit2, unit),
@ -215,17 +222,19 @@ impl<'a, 'b: 'a> ValueVisitor<'a, 'b> {
.into());
}
if unit == unit2 {
Value::Dimension(num + num2, unit, true)
Value::Dimension(Some(num + num2), unit, true)
} else if unit == Unit::None {
Value::Dimension(num + num2, unit2, true)
Value::Dimension(Some(num + num2), unit2, true)
} else if unit2 == Unit::None {
Value::Dimension(num + num2, unit, true)
Value::Dimension(Some(num + num2), unit, true)
} else {
Value::Dimension(
Some(
num + num2
* UNIT_CONVERSION_TABLE[unit.to_string().as_str()]
[unit2.to_string().as_str()]
.clone(),
),
unit,
true,
)
@ -314,8 +323,10 @@ impl<'a, 'b: 'a> ValueVisitor<'a, 'b> {
format!("-{}", right.to_css_string(self.span)?),
QuoteKind::None,
),
Value::Dimension(num, unit, _) => match right {
Value::Dimension(num2, unit2, _) => {
Value::Dimension(None, ..) => todo!(),
Value::Dimension(Some(num), unit, _) => match right {
Value::Dimension(None, ..) => todo!(),
Value::Dimension(Some(num2), unit2, _) => {
if !unit.comparable(&unit2) {
return Err((
format!("Incompatible units {} and {}.", unit2, unit),
@ -324,17 +335,19 @@ impl<'a, 'b: 'a> ValueVisitor<'a, 'b> {
.into());
}
if unit == unit2 {
Value::Dimension(num - num2, unit, true)
Value::Dimension(Some(num - num2), unit, true)
} else if unit == Unit::None {
Value::Dimension(num - num2, unit2, true)
Value::Dimension(Some(num - num2), unit2, true)
} else if unit2 == Unit::None {
Value::Dimension(num - num2, unit, true)
Value::Dimension(Some(num - num2), unit, true)
} else {
Value::Dimension(
Some(
num - num2
* UNIT_CONVERSION_TABLE[unit.to_string().as_str()]
[unit2.to_string().as_str()]
.clone(),
),
unit,
true,
)
@ -434,14 +447,16 @@ impl<'a, 'b: 'a> ValueVisitor<'a, 'b> {
v => panic!("{:?}", v),
};
Ok(match left {
Value::Dimension(num, unit, _) => match right {
Value::Dimension(num2, unit2, _) => {
Value::Dimension(None, ..) => todo!(),
Value::Dimension(Some(num), unit, _) => match right {
Value::Dimension(None, ..) => todo!(),
Value::Dimension(Some(num2), unit2, _) => {
if unit == Unit::None {
Value::Dimension(num * num2, unit2, true)
Value::Dimension(Some(num * num2), unit2, true)
} else if unit2 == Unit::None {
Value::Dimension(num * num2, unit, true)
Value::Dimension(Some(num * num2), unit, true)
} else {
Value::Dimension(num * num2, unit * unit2, true)
Value::Dimension(Some(num * num2), unit * unit2, true)
}
}
_ => {
@ -490,28 +505,36 @@ impl<'a, 'b: 'a> ValueVisitor<'a, 'b> {
format!("/{}", right.to_css_string(self.span)?),
QuoteKind::None,
),
Value::Dimension(num, unit, should_divide1) => match right {
Value::Dimension(num2, unit2, should_divide2) => {
Value::Dimension(None, ..) => todo!(),
Value::Dimension(Some(num), unit, should_divide1) => match right {
Value::Dimension(None, ..) => todo!(),
Value::Dimension(Some(num2), unit2, should_divide2) => {
if should_divide1 || should_divide2 || in_parens {
if num.is_zero() && num2.is_zero() {
return Ok(Value::Dimension(None, Unit::None, true));
}
// `unit(1em / 1em)` => `""`
if unit == unit2 {
Value::Dimension(num / num2, Unit::None, true)
Value::Dimension(Some(num / num2), Unit::None, true)
// `unit(1 / 1em)` => `"em^-1"`
} else if unit == Unit::None {
Value::Dimension(num / num2, Unit::None / unit2, true)
Value::Dimension(Some(num / num2), Unit::None / unit2, true)
// `unit(1em / 1)` => `"em"`
} else if unit2 == Unit::None {
Value::Dimension(num / num2, unit, true)
Value::Dimension(Some(num / num2), unit, true)
// `unit(1in / 1px)` => `""`
} else if unit.comparable(&unit2) {
Value::Dimension(
Some(
num / (num2
* UNIT_CONVERSION_TABLE[unit.to_string().as_str()]
[unit2.to_string().as_str()]
.clone()),
),
Unit::None,
true,
)
@ -630,28 +653,30 @@ impl<'a, 'b: 'a> ValueVisitor<'a, 'b> {
v => panic!("{:?}", v),
};
Ok(match left {
Value::Dimension(n, u, _) => match right {
Value::Dimension(n2, u2, _) => {
Value::Dimension(None, ..) => todo!(),
Value::Dimension(Some(n), u, _) => match right {
Value::Dimension(None, ..) => todo!(),
Value::Dimension(Some(n2), u2, _) => {
if !u.comparable(&u2) {
return Err(
(format!("Incompatible units {} and {}.", u2, u), self.span).into()
);
}
if u == u2 {
Value::Dimension(n % n2, u, true)
Value::Dimension(Some(n % n2), u, true)
} else if u == Unit::None {
Value::Dimension(n % n2, u2, true)
Value::Dimension(Some(n % n2), u2, true)
} else if u2 == Unit::None {
Value::Dimension(n % n2, u, true)
Value::Dimension(Some(n % n2), u, true)
} else {
Value::Dimension(n, u, true)
Value::Dimension(Some(n), u, true)
}
}
_ => {
return Err((
format!(
"Undefined operation \"{} % {}\".",
Value::Dimension(n, u, true).inspect(self.span)?,
Value::Dimension(Some(n), u, true).inspect(self.span)?,
right.inspect(self.span)?
),
self.span,

View File

@ -459,7 +459,7 @@ impl<'a> Parser<'a> {
let n = Rational64::new_raw(parse_i64(&val.num), 1);
return Some(Ok(IntermediateValue::Value(
HigherIntermediateValue::Literal(Value::Dimension(
Number::new_small(n),
Some(Number::new_small(n)),
unit,
false,
)),
@ -472,7 +472,7 @@ impl<'a> Parser<'a> {
let n = Rational64::new(parse_i64(&val.num), pow(10, val.dec_len));
return Some(Ok(IntermediateValue::Value(
HigherIntermediateValue::Literal(Value::Dimension(
Number::new_small(n),
Some(Number::new_small(n)),
unit,
false,
)),
@ -485,7 +485,7 @@ impl<'a> Parser<'a> {
if val.times_ten.is_empty() {
return Some(Ok(IntermediateValue::Value(
HigherIntermediateValue::Literal(Value::Dimension(
Number::new_big(n),
Some(Number::new_big(n)),
unit,
false,
)),
@ -514,7 +514,7 @@ impl<'a> Parser<'a> {
};
IntermediateValue::Value(HigherIntermediateValue::Literal(Value::Dimension(
Number::new_big(n * times_ten),
Some(Number::new_big(n * times_ten)),
unit,
false,
)))

View File

@ -31,7 +31,8 @@ pub(crate) enum Value {
True,
False,
Null,
Dimension(Number, Unit, bool),
/// A `None` value for `Number` indicates a `NaN` value
Dimension(Option<Number>, Unit, bool),
List(Vec<Value>, ListSeparator, Brackets),
Color(Box<Color>),
String(String, QuoteKind),
@ -48,8 +49,8 @@ impl PartialEq for Value {
Value::String(s2, ..) => s1 == s2,
_ => false,
},
Value::Dimension(n, unit, _) => match other {
Value::Dimension(n2, unit2, _) => {
Value::Dimension(Some(n), unit, _) => match other {
Value::Dimension(Some(n2), unit2, _) => {
if !unit.comparable(unit2) {
false
} else if unit == unit2 {
@ -65,6 +66,7 @@ impl PartialEq for Value {
}
_ => false,
},
Value::Dimension(None, ..) => false,
Value::List(list1, sep1, brackets1) => match other {
Value::List(list2, sep2, brackets2) => {
if sep1 != sep2 || brackets1 != brackets2 || list1.len() != list2.len() {
@ -200,12 +202,13 @@ impl Value {
pub fn to_css_string(&self, span: Span) -> SassResult<Cow<'static, str>> {
Ok(match self {
Value::Important => Cow::const_str("!important"),
Value::Dimension(num, unit, _) => match unit {
Value::Dimension(Some(num), unit, _) => match unit {
Unit::Mul(..) | Unit::Div(..) => {
return Err((format!("{}{} isn't a valid CSS value.", num, unit), span).into());
}
_ => Cow::owned(format!("{}{}", num, unit)),
},
Value::Dimension(None, ..) => Cow::const_str("NaN"),
Value::Map(..) | Value::FunctionRef(..) => {
return Err((
format!("{} isn't a valid CSS value.", self.inspect(span)?),
@ -326,8 +329,10 @@ impl Value {
pub fn cmp(&self, other: &Self, span: Span, op: Op) -> SassResult<Ordering> {
Ok(match self {
Value::Dimension(num, unit, _) => match &other {
Value::Dimension(num2, unit2, _) => {
Value::Dimension(None, ..) => todo!(),
Value::Dimension(Some(num), unit, _) => match &other {
Value::Dimension(None, ..) => todo!(),
Value::Dimension(Some(num2), unit2, _) => {
if !unit.comparable(unit2) {
return Err(
(format!("Incompatible units {} and {}.", unit2, unit), span).into(),
@ -387,8 +392,8 @@ impl Value {
Value::String(s2, ..) => s1 != s2,
_ => true,
},
Value::Dimension(n, unit, _) => match other {
Value::Dimension(n2, unit2, _) => {
Value::Dimension(Some(n), unit, _) => match other {
Value::Dimension(Some(n2), unit2, _) => {
if !unit.comparable(unit2) {
true
} else if unit == unit2 {
@ -464,7 +469,8 @@ impl Value {
.collect::<SassResult<Vec<String>>>()?
.join(", ")
)),
Value::Dimension(num, unit, _) => Cow::owned(format!("{}{}", num, unit)),
Value::Dimension(Some(num), unit, _) => Cow::owned(format!("{}{}", num, unit)),
Value::Dimension(None, ..) => Cow::const_str("NaN"),
Value::ArgList(args) if args.is_empty() => Cow::const_str("()"),
Value::ArgList(args) if args.len() == 1 => Cow::owned(format!(
"({},)",

View File

@ -169,3 +169,8 @@ test!(
"a {\n color: 1 + 3 / 4;\n}\n",
"a {\n color: 1.75;\n}\n"
);
test!(
zero_div_zero_is_nan,
"a {\n color: (0 / 0);\n}\n",
"a {\n color: NaN;\n}\n"
);

View File

@ -195,6 +195,11 @@ test!(
"a {\n color: type-of(- 2)\n}\n",
"a {\n color: number;\n}\n"
);
test!(
type_of_nan,
"a {\n color: type-of((0 / 0))\n}\n",
"a {\n color: number;\n}\n"
);
test!(
type_of_arglist,
"@mixin foo($a...) {color: type-of($a);}\na {@include foo(1, 2, 3, 4, 5);}",