implement @if/@else

This commit is contained in:
ConnorSkees 2020-03-22 02:14:01 -04:00
parent 1127897bd8
commit f1238c4d3a
3 changed files with 67 additions and 2 deletions

View File

@ -32,6 +32,7 @@ pub(crate) enum AtRule {
Content,
Unknown(UnknownAtRule),
For(Vec<Stmt>),
If(Vec<Token>, Vec<Stmt>, Vec<Stmt>),
}
impl AtRule {
@ -104,7 +105,46 @@ impl AtRule {
}
AtRuleKind::Each => todo!("@each not yet implemented"),
AtRuleKind::Extend => todo!("@extend not yet implemented"),
AtRuleKind::If => todo!("@if not yet implemented"),
AtRuleKind::If => {
let mut cond = Vec::new();
let mut n = 0;
while let Some(tok) = toks.peek() {
match tok.kind {
TokenKind::Symbol(Symbol::OpenCurlyBrace) => n += 1,
TokenKind::Symbol(Symbol::CloseCurlyBrace) => n -= 1,
TokenKind::Interpolation => n += 1,
_ => {}
}
if n == 1 {
break;
}
cond.push(toks.next().unwrap());
}
toks.next();
devour_whitespace_or_comment(toks);
let mut yes = Vec::new();
yes.extend(eat_stmts(toks, scope, super_selector)?);
devour_whitespace_or_comment(toks);
let mut no = Vec::new();
if let Some(tok) = toks.peek() {
if tok.kind == TokenKind::AtRule(AtRuleKind::Else) {
toks.next();
devour_whitespace_or_comment(toks);
if let Some(tok) = toks.next() {
if !tok.is_symbol(Symbol::OpenCurlyBrace) {
return Err("expected \"{\".".into());
}
}
devour_whitespace_or_comment(toks);
no.extend(eat_stmts(toks, scope, super_selector)?);
}
}
devour_whitespace_or_comment(toks);
AtRule::If(cond, yes, no)
}
AtRuleKind::Else => todo!("@else not yet implemented"),
AtRuleKind::For => {
let mut stmts = Vec::new();

View File

@ -153,7 +153,7 @@ impl Css {
.pretty_print(buf, nesting + 1)?;
writeln!(buf, "{}}}", padding)?;
}
_ => todo!(),
_ => todo!("at-rule other than unknown at toplevel"),
},
Toplevel::Newline => {
if has_written {

View File

@ -417,6 +417,17 @@ impl<'a> StyleSheetParser<'a> {
}
AtRule::For(s) => rules.extend(s),
AtRule::Content => return Err("@content is only allowed within mixin declarations.".into()),
AtRule::If(cond, yes, no) => {
if Value::from_tokens(
&mut cond.into_iter().peekable(),
&mut GLOBAL_SCOPE.with(|s| s.borrow().clone()),
&Selector::new(),
)?.is_true()? {
rules.extend(yes);
} else {
rules.extend(no);
}
}
u @ AtRule::Unknown(..) => rules.push(Stmt::AtRule(u)),
}
}
@ -443,6 +454,19 @@ impl<'a> StyleSheetParser<'a> {
Expr::Style(s) => stmts.push(Stmt::Style(s)),
Expr::AtRule(a) => match a {
AtRule::For(s) => stmts.extend(s),
AtRule::If(cond, yes, no) => {
if Value::from_tokens(
&mut cond.into_iter().peekable(),
&mut GLOBAL_SCOPE.with(|s| s.borrow().clone()),
&Selector::new(),
)?
.is_true()?
{
stmts.extend(yes);
} else {
stmts.extend(no);
}
}
AtRule::Content => {
return Err("@content is only allowed within mixin declarations.".into())
}
@ -620,6 +644,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
AtRule::Content => {
return Err("@content is only allowed within mixin declarations.".into())
}
f @ AtRule::If(..) => Ok(Some(Expr::AtRule(f))),
f @ AtRule::For(..) => Ok(Some(Expr::AtRule(f))),
u @ AtRule::Unknown(..) => Ok(Some(Expr::AtRule(u))),
};