diff --git a/src/atrule/mod.rs b/src/atrule/mod.rs index 3c24e02..f054e71 100644 --- a/src/atrule/mod.rs +++ b/src/atrule/mod.rs @@ -40,6 +40,7 @@ pub(crate) enum AtRule { Unknown(UnknownAtRule), For(Vec), Each(Vec), + While(Vec), If(If), } @@ -312,7 +313,32 @@ impl AtRule { AtRule::For(stmts) } - AtRuleKind::While => todo!("@while not yet implemented"), + AtRuleKind::While => { + let mut stmts = Vec::new(); + devour_whitespace(toks); + let cond = read_until_open_curly_brace(toks); + toks.next(); + let scope = &mut scope.clone(); + let body = read_until_closing_curly_brace(toks); + toks.next(); + + devour_whitespace(toks); + + while Value::from_tokens( + &mut cond.clone().into_iter().peekable(), + scope, + super_selector, + )? + .is_true()? + { + stmts.extend(eat_stmts( + &mut body.clone().into_iter().peekable(), + scope, + super_selector, + )?); + } + AtRule::While(stmts) + } AtRuleKind::Keyframes => todo!("@keyframes not yet implemented"), AtRuleKind::Unknown(name) => AtRule::Unknown(UnknownAtRule::from_tokens( toks, diff --git a/src/lib.rs b/src/lib.rs index 1daf91e..0eb3808 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -382,7 +382,7 @@ impl<'a> StyleSheetParser<'a> { AtRule::Return(_) => { return Err("This at-rule is not allowed here.".into()) } - AtRule::Each(s) | AtRule::For(s) => rules.extend(s), + AtRule::While(s) | AtRule::Each(s) | AtRule::For(s) => rules.extend(s), AtRule::Content => return Err("@content is only allowed within mixin declarations.".into()), AtRule::If(i) => { rules.extend(i.eval(&mut Scope::new(), &Selector::new())?); @@ -412,7 +412,7 @@ impl<'a> StyleSheetParser<'a> { match expr { Expr::Style(s) => stmts.push(Stmt::Style(s)), Expr::AtRule(a) => match a { - AtRule::Each(s) | AtRule::For(s) => stmts.extend(s), + AtRule::While(s) | AtRule::Each(s) | AtRule::For(s) => stmts.extend(s), AtRule::If(i) => stmts.extend(i.eval(scope, super_selector)?), AtRule::Content => { return Err("@content is only allowed within mixin declarations.".into()) @@ -595,6 +595,7 @@ pub(crate) fn eat_expr>( c @ AtRule::Content => Ok(Some(Expr::AtRule(c))), f @ AtRule::If(..) => Ok(Some(Expr::AtRule(f))), f @ AtRule::For(..) => Ok(Some(Expr::AtRule(f))), + f @ AtRule::While(..) => Ok(Some(Expr::AtRule(f))), f @ AtRule::Each(..) => Ok(Some(Expr::AtRule(f))), u @ AtRule::Unknown(..) => Ok(Some(Expr::AtRule(u))), }; diff --git a/tests/while.rs b/tests/while.rs new file mode 100644 index 0000000..8b4314b --- /dev/null +++ b/tests/while.rs @@ -0,0 +1,25 @@ +#![cfg(test)] + +#[macro_use] +mod macros; + +test!( + inner_increment_var, + "$a: 4;\n$b: 1;\na {\n @while $a > $b {\n color: $b;\n $b: $b + 1;\n }\n}", + "a {\n color: 1;\n color: 2;\n color: 3;\n}\n" +); +test!( + outer_increment_var, + "$a: 4;\n$b: 1;\n@while $a > $b {\na {\n color: $b;\n }\n $b: $b + 1;\n}", + "a {\n color: 1;\n}\n\na {\n color: 2;\n}\n\na {\n color: 3;\n}\n" +); +test!( + inner_while_false, + "a {\n @while false {\n color: foo;\n }\n}", + "" +); +test!( + outer_while_false, + "@while false {\na {\n color: $b;\n }\n $b: $b + 1;\n}", + "" +);