better support for NaN passed to builtin functions
This commit is contained in:
parent
a665cb13cc
commit
2d798a6386
@ -25,7 +25,9 @@ pub(crate) fn nth(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Val
|
||||
let mut list = args.get_err(0, "list")?.as_list();
|
||||
let n = match args.get_err(1, "n")? {
|
||||
Value::Dimension(Some(num), ..) => num,
|
||||
Value::Dimension(None, ..) => todo!(),
|
||||
Value::Dimension(None, u, ..) => {
|
||||
return Err((format!("$n: NaN{} is not an int.", u), args.span()).into())
|
||||
}
|
||||
v => {
|
||||
return Err((
|
||||
format!("$n: {} is not a number.", v.inspect(args.span())?),
|
||||
@ -83,7 +85,9 @@ pub(crate) fn set_nth(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult
|
||||
};
|
||||
let n = match args.get_err(1, "n")? {
|
||||
Value::Dimension(Some(num), ..) => num,
|
||||
Value::Dimension(None, ..) => todo!(),
|
||||
Value::Dimension(None, u, ..) => {
|
||||
return Err((format!("$n: NaN{} is not an int.", u), args.span()).into())
|
||||
}
|
||||
v => {
|
||||
return Err((
|
||||
format!("$n: {} is not a number.", v.inspect(args.span())?),
|
||||
|
@ -16,8 +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(Some(n), Unit::None, _) => n * Number::from(100),
|
||||
Value::Dimension(None, ..) => todo!(),
|
||||
Value::Dimension(Some(n), Unit::None, _) => Some(n * Number::from(100)),
|
||||
Value::Dimension(None, ..) => None,
|
||||
v @ Value::Dimension(..) => {
|
||||
return Err((
|
||||
format!(
|
||||
@ -36,14 +36,14 @@ pub(crate) fn percentage(mut args: CallArgs, parser: &mut Parser<'_>) -> SassRes
|
||||
.into())
|
||||
}
|
||||
};
|
||||
Ok(Value::Dimension(Some(num), Unit::Percent, true))
|
||||
Ok(Value::Dimension(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(Some(n), u, _) => Ok(Value::Dimension(Some(n.round()), u, true)),
|
||||
Value::Dimension(None, ..) => todo!(),
|
||||
Value::Dimension(None, ..) => Err(("Infinity or NaN toInt", args.span()).into()),
|
||||
v => Err((
|
||||
format!("$number: {} is not a number.", v.inspect(args.span())?),
|
||||
args.span(),
|
||||
@ -56,7 +56,7 @@ pub(crate) fn ceil(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Va
|
||||
args.max_args(1)?;
|
||||
match args.get_err(0, "number")? {
|
||||
Value::Dimension(Some(n), u, _) => Ok(Value::Dimension(Some(n.ceil()), u, true)),
|
||||
Value::Dimension(None, ..) => todo!(),
|
||||
Value::Dimension(None, ..) => Err(("Infinity or NaN toInt", args.span()).into()),
|
||||
v => Err((
|
||||
format!("$number: {} is not a number.", v.inspect(args.span())?),
|
||||
args.span(),
|
||||
@ -69,7 +69,7 @@ pub(crate) fn floor(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<V
|
||||
args.max_args(1)?;
|
||||
match args.get_err(0, "number")? {
|
||||
Value::Dimension(Some(n), u, _) => Ok(Value::Dimension(Some(n.floor()), u, true)),
|
||||
Value::Dimension(None, ..) => todo!(),
|
||||
Value::Dimension(None, ..) => Err(("Infinity or NaN toInt", args.span()).into()),
|
||||
v => Err((
|
||||
format!("$number: {} is not a number.", v.inspect(args.span())?),
|
||||
args.span(),
|
||||
@ -82,7 +82,7 @@ pub(crate) fn abs(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Val
|
||||
args.max_args(1)?;
|
||||
match args.get_err(0, "number")? {
|
||||
Value::Dimension(Some(n), u, _) => Ok(Value::Dimension(Some(n.abs()), u, true)),
|
||||
Value::Dimension(None, ..) => todo!(),
|
||||
Value::Dimension(None, u, ..) => Ok(Value::Dimension(None, u, true)),
|
||||
v => Err((
|
||||
format!("$number: {} is not a number.", v.inspect(args.span())?),
|
||||
args.span(),
|
||||
@ -123,7 +123,9 @@ pub(crate) fn random(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResult<
|
||||
args.max_args(1)?;
|
||||
let limit = match args.default_arg(0, "limit", Value::Null)? {
|
||||
Value::Dimension(Some(n), ..) => n,
|
||||
Value::Dimension(None, ..) => todo!(),
|
||||
Value::Dimension(None, u, ..) => {
|
||||
return Err((format!("$limit: NaN{} is not an int.", u), args.span()).into())
|
||||
}
|
||||
Value::Null => {
|
||||
let mut rng = rand::thread_rng();
|
||||
return Ok(Value::Dimension(
|
||||
@ -183,22 +185,29 @@ pub(crate) fn min(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
|
||||
.get_variadic()?
|
||||
.into_iter()
|
||||
.map(|val| match val.node {
|
||||
Value::Dimension(Some(number), unit, _) => Ok((number, unit)),
|
||||
Value::Dimension(None, ..) => todo!(),
|
||||
Value::Dimension(number, unit, _) => Ok((number, unit)),
|
||||
v => Err((format!("{} is not a number.", v.inspect(span)?), span).into()),
|
||||
})
|
||||
.collect::<SassResult<Vec<(Number, Unit)>>>()?
|
||||
.collect::<SassResult<Vec<(Option<Number>, Unit)>>>()?
|
||||
.into_iter();
|
||||
|
||||
// we know that there *must* be at least one item
|
||||
let mut min = nums.next().unwrap();
|
||||
let mut min = match nums.next() {
|
||||
Some((Some(n), u)) => (n, u),
|
||||
Some((None, u)) => return Ok(Value::Dimension(None, u, true)),
|
||||
None => unreachable!(),
|
||||
};
|
||||
|
||||
for (num, unit) in nums {
|
||||
let num = match num {
|
||||
Some(n) => n,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
for num in nums {
|
||||
if ValueVisitor::new(parser, span)
|
||||
.less_than(
|
||||
HigherIntermediateValue::Literal(Value::Dimension(
|
||||
Some(num.0.clone()),
|
||||
num.1.clone(),
|
||||
Some(num.clone()),
|
||||
unit.clone(),
|
||||
true,
|
||||
)),
|
||||
HigherIntermediateValue::Literal(Value::Dimension(
|
||||
@ -209,7 +218,7 @@ pub(crate) fn min(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
|
||||
)?
|
||||
.is_true()
|
||||
{
|
||||
min = num;
|
||||
min = (num, unit);
|
||||
}
|
||||
}
|
||||
Ok(Value::Dimension(Some(min.0), min.1, true))
|
||||
@ -222,22 +231,29 @@ pub(crate) fn max(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
|
||||
.get_variadic()?
|
||||
.into_iter()
|
||||
.map(|val| match val.node {
|
||||
Value::Dimension(Some(number), unit, _) => Ok((number, unit)),
|
||||
Value::Dimension(None, ..) => todo!(),
|
||||
Value::Dimension(number, unit, _) => Ok((number, unit)),
|
||||
v => Err((format!("{} is not a number.", v.inspect(span)?), span).into()),
|
||||
})
|
||||
.collect::<SassResult<Vec<(Number, Unit)>>>()?
|
||||
.collect::<SassResult<Vec<(Option<Number>, Unit)>>>()?
|
||||
.into_iter();
|
||||
|
||||
// we know that there *must* be at least one item
|
||||
let mut max = nums.next().unwrap();
|
||||
let mut max = match nums.next() {
|
||||
Some((Some(n), u)) => (n, u),
|
||||
Some((None, u)) => return Ok(Value::Dimension(None, u, true)),
|
||||
None => unreachable!(),
|
||||
};
|
||||
|
||||
for (num, unit) in nums {
|
||||
let num = match num {
|
||||
Some(n) => n,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
for num in nums {
|
||||
if ValueVisitor::new(parser, span)
|
||||
.greater_than(
|
||||
HigherIntermediateValue::Literal(Value::Dimension(
|
||||
Some(num.0.clone()),
|
||||
num.1.clone(),
|
||||
Some(num.clone()),
|
||||
unit.clone(),
|
||||
true,
|
||||
)),
|
||||
HigherIntermediateValue::Literal(Value::Dimension(
|
||||
@ -248,7 +264,7 @@ pub(crate) fn max(args: CallArgs, parser: &mut Parser<'_>) -> SassResult<Value>
|
||||
)?
|
||||
.is_true()
|
||||
{
|
||||
max = num;
|
||||
max = (num, unit);
|
||||
}
|
||||
}
|
||||
Ok(Value::Dimension(Some(max.0), max.1, true))
|
||||
|
@ -110,7 +110,9 @@ pub(crate) fn str_slice(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResu
|
||||
Value::Dimension(Some(n), Unit::None, _) => (n.to_integer() + BigInt::from(str_len + 1))
|
||||
.to_usize()
|
||||
.unwrap(),
|
||||
Value::Dimension(None, ..) => todo!(),
|
||||
Value::Dimension(None, u, ..) => {
|
||||
return Err((format!("NaN{} is not an int.", u), args.span()).into())
|
||||
}
|
||||
v @ Value::Dimension(..) => {
|
||||
return Err((
|
||||
format!(
|
||||
@ -141,7 +143,9 @@ pub(crate) fn str_slice(mut args: CallArgs, parser: &mut Parser<'_>) -> SassResu
|
||||
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!(),
|
||||
Value::Dimension(None, u, ..) => {
|
||||
return Err((format!("NaN{} is not an int.", u), args.span()).into())
|
||||
}
|
||||
v @ Value::Dimension(..) => {
|
||||
return Err((
|
||||
format!(
|
||||
@ -239,7 +243,9 @@ pub(crate) fn str_insert(mut args: CallArgs, parser: &mut Parser<'_>) -> SassRes
|
||||
return Err((format!("$index: {} is not an int.", n), args.span()).into())
|
||||
}
|
||||
Value::Dimension(Some(n), Unit::None, _) => n,
|
||||
Value::Dimension(None, ..) => todo!(),
|
||||
Value::Dimension(None, u, ..) => {
|
||||
return Err((format!("$index: NaN{} is not an int.", u), args.span()).into())
|
||||
}
|
||||
v @ Value::Dimension(..) => {
|
||||
return Err((
|
||||
format!(
|
||||
|
79
tests/nan.rs
Normal file
79
tests/nan.rs
Normal file
@ -0,0 +1,79 @@
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
error!(
|
||||
unitless_nan_str_slice_start_at,
|
||||
"a {\n color: str-slice(\"\", (0/0));\n}\n", "Error: NaN is not an int."
|
||||
);
|
||||
error!(
|
||||
unitless_nan_str_slice_end_at,
|
||||
"a {\n color: str-slice(\"\", 0, (0/0));\n}\n", "Error: NaN is not an int."
|
||||
);
|
||||
error!(
|
||||
unitless_nan_str_insert_index,
|
||||
"a {\n color: str-insert(\"\", \"\", (0/0));\n}\n", "Error: $index: NaN is not an int."
|
||||
);
|
||||
test!(
|
||||
unitless_nan_percentage_number,
|
||||
"a {\n color: percentage((0/0));\n}\n",
|
||||
"a {\n color: NaN%;\n}\n"
|
||||
);
|
||||
test!(
|
||||
unitless_nan_abs_number,
|
||||
"a {\n color: abs((0/0));\n}\n",
|
||||
"a {\n color: NaN;\n}\n"
|
||||
);
|
||||
error!(
|
||||
unitless_nan_round_number,
|
||||
"a {\n color: round((0/0));\n}\n", "Error: Infinity or NaN toInt"
|
||||
);
|
||||
error!(
|
||||
unitless_nan_ceil_number,
|
||||
"a {\n color: ceil((0/0));\n}\n", "Error: Infinity or NaN toInt"
|
||||
);
|
||||
error!(
|
||||
unitless_nan_floor_number,
|
||||
"a {\n color: floor((0/0));\n}\n", "Error: Infinity or NaN toInt"
|
||||
);
|
||||
error!(
|
||||
unitless_nan_random_limit,
|
||||
"a {\n color: random((0/0));\n}\n", "Error: $limit: NaN is not an int."
|
||||
);
|
||||
error!(
|
||||
unitless_nan_nth_n,
|
||||
"a {\n color: nth([a], (0/0));\n}\n", "Error: $n: NaN is not an int."
|
||||
);
|
||||
error!(
|
||||
unitless_nan_set_nth_n,
|
||||
"a {\n color: set-nth([a], (0/0), b);\n}\n", "Error: $n: NaN is not an int."
|
||||
);
|
||||
test!(
|
||||
unitless_nan_min_first_arg,
|
||||
"$n: (0/0);\na {\n color: min($n, 1px);\n}\n",
|
||||
"a {\n color: NaN;\n}\n"
|
||||
);
|
||||
test!(
|
||||
unitless_nan_min_last_arg,
|
||||
"$n: (0/0);\na {\n color: min(1px, $n);\n}\n",
|
||||
"a {\n color: 1px;\n}\n"
|
||||
);
|
||||
test!(
|
||||
unitless_nan_min_middle_arg,
|
||||
"$n: (0/0);\na {\n color: min(1px, $n, 0);\n}\n",
|
||||
"a {\n color: 0;\n}\n"
|
||||
);
|
||||
test!(
|
||||
unitless_nan_max_first_arg,
|
||||
"$n: (0/0);\na {\n color: max($n, 1px);\n}\n",
|
||||
"a {\n color: NaN;\n}\n"
|
||||
);
|
||||
test!(
|
||||
unitless_nan_max_last_arg,
|
||||
"$n: (0/0);\na {\n color: max(1px, $n);\n}\n",
|
||||
"a {\n color: 1px;\n}\n"
|
||||
);
|
||||
test!(
|
||||
unitless_nan_max_middle_arg,
|
||||
"$n: (0/0);\na {\n color: max(1px, $n, 0);\n}\n",
|
||||
"a {\n color: 1px;\n}\n"
|
||||
);
|
Loading…
x
Reference in New Issue
Block a user