add more tests for malformed @for
test for capitalization of keywords, error messages, and regression tests for integer overflows resulting when `from` or `to` == `std::i32::MAX`
This commit is contained in:
parent
38a37a3997
commit
f33739aa0f
@ -156,7 +156,6 @@ impl<'a> Parser<'a> {
|
||||
|
||||
pub(super) fn parse_for(&mut self) -> SassResult<Vec<Stmt>> {
|
||||
self.whitespace_or_comment();
|
||||
// todo: test for error here
|
||||
self.expect_char('$')?;
|
||||
|
||||
let var = self
|
||||
@ -236,14 +235,16 @@ impl<'a> Parser<'a> {
|
||||
self.whitespace_or_comment();
|
||||
let from_val = self.parse_value_from_vec(from_toks, true)?;
|
||||
let from = match from_val.node {
|
||||
Value::Dimension(Some(n), ..) => match n.to_integer().to_isize() {
|
||||
Value::Dimension(Some(n), ..) => match n.to_i32() {
|
||||
Some(std::i32::MAX) | None => {
|
||||
return Err((format!("{} is not an int.", n), from_val.span).into())
|
||||
}
|
||||
Some(v) => v,
|
||||
None => return Err((format!("{} is not a int.", n), from_val.span).into()),
|
||||
},
|
||||
Value::Dimension(None, ..) => todo!(),
|
||||
Value::Dimension(None, ..) => return Err(("NaN is not an int.", from_val.span).into()),
|
||||
v => {
|
||||
return Err((
|
||||
format!("{} is not an integer.", v.inspect(from_val.span)?),
|
||||
format!("{} is not a number.", v.inspect(from_val.span)?),
|
||||
from_val.span,
|
||||
)
|
||||
.into())
|
||||
@ -252,14 +253,16 @@ impl<'a> Parser<'a> {
|
||||
|
||||
let to_val = self.parse_value(true, &|_| false)?;
|
||||
let to = match to_val.node {
|
||||
Value::Dimension(Some(n), ..) => match n.to_integer().to_isize() {
|
||||
Value::Dimension(Some(n), ..) => match n.to_i32() {
|
||||
Some(std::i32::MAX) | None => {
|
||||
return Err((format!("{} is not an int.", n), to_val.span).into())
|
||||
}
|
||||
Some(v) => v,
|
||||
None => return Err((format!("{} is not a int.", n), to_val.span).into()),
|
||||
},
|
||||
Value::Dimension(None, ..) => todo!(),
|
||||
Value::Dimension(None, ..) => return Err(("NaN is not an int.", from_val.span).into()),
|
||||
v => {
|
||||
return Err((
|
||||
format!("{} is not an integer.", v.to_css_string(to_val.span)?),
|
||||
format!("{} is not a number.", v.to_css_string(to_val.span)?),
|
||||
to_val.span,
|
||||
)
|
||||
.into())
|
||||
@ -269,12 +272,13 @@ impl<'a> Parser<'a> {
|
||||
self.expect_char('{')?;
|
||||
|
||||
let body = read_until_closing_curly_brace(self.toks)?;
|
||||
self.toks.next();
|
||||
|
||||
self.expect_char('}')?;
|
||||
|
||||
let (mut x, mut y);
|
||||
// we can't use an inclusive range here
|
||||
#[allow(clippy::range_plus_one)]
|
||||
let iter: &mut dyn Iterator<Item = isize> = if from < to {
|
||||
let iter: &mut dyn Iterator<Item = i32> = if from < to {
|
||||
x = from..(to + through);
|
||||
&mut x
|
||||
} else {
|
||||
|
@ -318,6 +318,42 @@ impl fmt::Debug for Number {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToPrimitive for Number {
|
||||
fn to_u64(&self) -> Option<u64> {
|
||||
match self {
|
||||
Self::Small(n) => {
|
||||
if !n.denom().is_one() {
|
||||
return None;
|
||||
}
|
||||
n.to_u64()
|
||||
}
|
||||
Self::Big(n) => {
|
||||
if !n.denom().is_one() {
|
||||
return None;
|
||||
}
|
||||
n.to_u64()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_i64(&self) -> Option<i64> {
|
||||
match self {
|
||||
Self::Small(n) => {
|
||||
if !n.denom().is_one() {
|
||||
return None;
|
||||
}
|
||||
n.to_i64()
|
||||
}
|
||||
Self::Big(n) => {
|
||||
if !n.denom().is_one() {
|
||||
return None;
|
||||
}
|
||||
n.to_i64()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Number {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut whole = self.to_integer().abs();
|
||||
|
48
tests/for.rs
48
tests/for.rs
@ -118,3 +118,51 @@ test!(
|
||||
" /**/ @for /**/ $i /**/ from /**/ 0 /**/ to /**/ 2 /**/ {} /**/ ",
|
||||
"/**/\n/**/\n"
|
||||
);
|
||||
test!(
|
||||
uppercase_keywords,
|
||||
"@for $i FROM 0 TO 2 {
|
||||
@foo;
|
||||
}",
|
||||
"@foo;\n@foo;\n"
|
||||
);
|
||||
error!(
|
||||
missing_keyword_from,
|
||||
"@for $i fro", "Error: Expected \"from\"."
|
||||
);
|
||||
error!(missing_dollar_sign, "@for", "Error: expected \"$\".");
|
||||
error!(
|
||||
variable_missing_identifier,
|
||||
"@for $", "Error: Expected identifier."
|
||||
);
|
||||
error!(
|
||||
from_value_is_decimal,
|
||||
"@for $i from 0.5 to 2 {}", "Error: 0.5 is not an int."
|
||||
);
|
||||
error!(
|
||||
to_value_is_decimal,
|
||||
"@for $i from 0 to 1.5 {}", "Error: 1.5 is not an int."
|
||||
);
|
||||
error!(
|
||||
from_value_is_non_numeric,
|
||||
"@for $i from red to 2 {}", "Error: red is not a number."
|
||||
);
|
||||
error!(
|
||||
to_value_is_non_numeric,
|
||||
"@for $i from 0 to red {}", "Error: red is not a number."
|
||||
);
|
||||
error!(
|
||||
through_i32_max,
|
||||
"@for $i from 0 through 2147483647 {}", "Error: 2147483647 is not an int."
|
||||
);
|
||||
error!(
|
||||
from_i32_max,
|
||||
"@for $i from 2147483647 through 0 {}", "Error: 2147483647 is not an int."
|
||||
);
|
||||
error!(
|
||||
from_nan,
|
||||
"@for $i from (0/0) through 0 {}", "Error: NaN is not an int."
|
||||
);
|
||||
error!(
|
||||
to_nan,
|
||||
"@for $i from 0 through (0/0) {}", "Error: NaN is not an int."
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user