diff --git a/src/parse/control_flow.rs b/src/parse/control_flow.rs index 227ef72..77477eb 100644 --- a/src/parse/control_flow.rs +++ b/src/parse/control_flow.rs @@ -156,7 +156,6 @@ impl<'a> Parser<'a> { pub(super) fn parse_for(&mut self) -> SassResult> { 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 = if from < to { + let iter: &mut dyn Iterator = if from < to { x = from..(to + through); &mut x } else { diff --git a/src/value/number/mod.rs b/src/value/number/mod.rs index 522f915..f65952b 100644 --- a/src/value/number/mod.rs +++ b/src/value/number/mod.rs @@ -318,6 +318,42 @@ impl fmt::Debug for Number { } } +impl ToPrimitive for Number { + fn to_u64(&self) -> Option { + 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 { + 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(); diff --git a/tests/for.rs b/tests/for.rs index 820591a..8e5d069 100644 --- a/tests/for.rs +++ b/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." +);