handle negative values in @for
This commit is contained in:
parent
4321a383f2
commit
96e916e750
@ -1,4 +1,5 @@
|
|||||||
use std::iter::Iterator;
|
use std::iter::{Iterator, Rev, Skip};
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
use codemap::{Span, Spanned};
|
use codemap::{Span, Spanned};
|
||||||
|
|
||||||
@ -20,11 +21,27 @@ use crate::utils::{
|
|||||||
use crate::value::{Number, Value};
|
use crate::value::{Number, Value};
|
||||||
use crate::{Stmt, Token};
|
use crate::{Stmt, Token};
|
||||||
|
|
||||||
|
pub(crate) enum ForIterator {
|
||||||
|
Forward(Range<isize>),
|
||||||
|
Backward(Rev<Skip<Range<isize>>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for ForIterator {
|
||||||
|
type Item = isize;
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
match self {
|
||||||
|
Self::Forward(i) => i.next(),
|
||||||
|
Self::Backward(i) => i.next(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct For {
|
pub(crate) struct For {
|
||||||
pub var: Spanned<String>,
|
pub var: Spanned<String>,
|
||||||
// TODO: optimization: this could be a generic or &dyn Iterator maybe?
|
from: isize,
|
||||||
pub iter: Vec<usize>,
|
to: isize,
|
||||||
|
through: isize,
|
||||||
pub body: Vec<Token>,
|
pub body: Vec<Token>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +53,7 @@ impl For {
|
|||||||
content: Option<&[Spanned<Stmt>]>,
|
content: Option<&[Spanned<Stmt>]>,
|
||||||
) -> SassResult<Vec<Spanned<Stmt>>> {
|
) -> SassResult<Vec<Spanned<Stmt>>> {
|
||||||
let mut stmts = Vec::new();
|
let mut stmts = Vec::new();
|
||||||
for i in self.iter {
|
for i in self.iter() {
|
||||||
scope.insert_var(
|
scope.insert_var(
|
||||||
&self.var.node,
|
&self.var.node,
|
||||||
Spanned {
|
Spanned {
|
||||||
@ -45,7 +62,7 @@ impl For {
|
|||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
ruleset_eval(
|
ruleset_eval(
|
||||||
&mut self.body.clone().into_iter().peekmore(),
|
&mut self.body.iter().cloned().peekmore(),
|
||||||
scope,
|
scope,
|
||||||
super_selector,
|
super_selector,
|
||||||
false,
|
false,
|
||||||
@ -56,8 +73,12 @@ impl For {
|
|||||||
Ok(stmts)
|
Ok(stmts)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter(&self) -> std::slice::Iter<'_, usize> {
|
pub fn iter(&self) -> ForIterator {
|
||||||
self.iter.iter()
|
if self.from < self.to {
|
||||||
|
ForIterator::Forward(self.from..(self.to + self.through))
|
||||||
|
} else {
|
||||||
|
ForIterator::Backward(((self.to - self.through)..(self.from + 1)).skip(1).rev())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,8 +131,8 @@ pub(crate) fn parse_for<I: Iterator<Item = Token>>(
|
|||||||
}
|
}
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
let from_val = Value::from_vec(from_toks, scope, super_selector)?;
|
let from_val = Value::from_vec(from_toks, scope, super_selector)?;
|
||||||
let from = match from_val.node {
|
let from = match from_val.node.eval(from_val.span)?.node {
|
||||||
Value::Dimension(n, _) => match n.to_integer().to_usize() {
|
Value::Dimension(n, _) => match n.to_integer().to_isize() {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => return Err((format!("{} is not a int.", n), from_val.span).into()),
|
None => return Err((format!("{} is not a int.", n), from_val.span).into()),
|
||||||
},
|
},
|
||||||
@ -127,8 +148,8 @@ pub(crate) fn parse_for<I: Iterator<Item = Token>>(
|
|||||||
let to_toks = read_until_open_curly_brace(toks);
|
let to_toks = read_until_open_curly_brace(toks);
|
||||||
toks.next();
|
toks.next();
|
||||||
let to_val = Value::from_vec(to_toks, scope, super_selector)?;
|
let to_val = Value::from_vec(to_toks, scope, super_selector)?;
|
||||||
let to = match to_val.node {
|
let to = match to_val.node.eval(to_val.span)?.node {
|
||||||
Value::Dimension(n, _) => match n.to_integer().to_usize() {
|
Value::Dimension(n, _) => match n.to_integer().to_isize() {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => return Err((format!("{} is not a int.", n), to_val.span).into()),
|
None => return Err((format!("{} is not a int.", n), to_val.span).into()),
|
||||||
},
|
},
|
||||||
@ -145,11 +166,11 @@ pub(crate) fn parse_for<I: Iterator<Item = Token>>(
|
|||||||
|
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
|
|
||||||
let iter = if from < to {
|
Ok(AtRule::For(For {
|
||||||
(from..(to + through)).collect()
|
from,
|
||||||
} else {
|
to,
|
||||||
((to - through)..(from + 1)).skip(1).rev().collect()
|
through,
|
||||||
};
|
body,
|
||||||
|
var,
|
||||||
Ok(AtRule::For(For { iter, body, var }))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -141,7 +141,7 @@ impl Function {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
Stmt::AtRule(AtRule::For(f)) => {
|
Stmt::AtRule(AtRule::For(f)) => {
|
||||||
for i in f.iter().cloned() {
|
for i in f.iter() {
|
||||||
self.scope.insert_var(
|
self.scope.insert_var(
|
||||||
&f.var.node,
|
&f.var.node,
|
||||||
Spanned {
|
Spanned {
|
||||||
|
@ -157,6 +157,7 @@ impl From<f64> for Number {
|
|||||||
|
|
||||||
from_integer!(u16);
|
from_integer!(u16);
|
||||||
from_integer!(usize);
|
from_integer!(usize);
|
||||||
|
from_integer!(isize);
|
||||||
from_integer!(i32);
|
from_integer!(i32);
|
||||||
from_integer!(u32);
|
from_integer!(u32);
|
||||||
from_integer!(u8);
|
from_integer!(u8);
|
||||||
|
10
tests/for.rs
10
tests/for.rs
@ -58,3 +58,13 @@ test!(
|
|||||||
"a {\n @for $i from 1 to 3 {\n @if $i==2 {\n color: red;\n }\n }\n}\n",
|
"a {\n @for $i from 1 to 3 {\n @if $i==2 {\n color: red;\n }\n }\n}\n",
|
||||||
"a {\n color: red;\n}\n"
|
"a {\n color: red;\n}\n"
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
from_negative_to_positive,
|
||||||
|
"@for $i from -1 to 3 {\n a {\n color: red;\n }\n}\n",
|
||||||
|
"a {\n color: red;\n}\n\na {\n color: red;\n}\n\na {\n color: red;\n}\n\na {\n color: red;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
from_negative_to_negative,
|
||||||
|
"@for $i from -1 to -3 {\n a {\n color: red;\n }\n}\n",
|
||||||
|
"a {\n color: red;\n}\n\na {\n color: red;\n}\n"
|
||||||
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user