2020-03-24 22:13:38 -04:00
|
|
|
use std::iter::Peekable;
|
|
|
|
|
2020-03-29 13:28:17 -04:00
|
|
|
use super::{eat_stmts, AtRule};
|
2020-03-24 22:13:38 -04:00
|
|
|
|
|
|
|
use crate::error::SassResult;
|
|
|
|
use crate::scope::Scope;
|
|
|
|
use crate::selector::Selector;
|
|
|
|
use crate::utils::{
|
2020-03-29 13:28:17 -04:00
|
|
|
devour_whitespace, eat_ident, read_until_closing_curly_brace, read_until_open_curly_brace,
|
2020-03-24 22:13:38 -04:00
|
|
|
};
|
|
|
|
use crate::value::Value;
|
2020-03-29 13:28:17 -04:00
|
|
|
use crate::{Stmt, Token};
|
2020-03-24 22:13:38 -04:00
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub(crate) struct If {
|
|
|
|
pub branches: Vec<Branch>,
|
|
|
|
pub else_: Vec<Token>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub(crate) struct Branch {
|
|
|
|
pub cond: Vec<Token>,
|
|
|
|
pub toks: Vec<Token>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Branch {
|
|
|
|
pub fn new(cond: Vec<Token>, toks: Vec<Token>) -> Branch {
|
|
|
|
Branch { cond, toks }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl If {
|
|
|
|
pub fn from_tokens<I: Iterator<Item = Token>>(toks: &mut Peekable<I>) -> SassResult<If> {
|
|
|
|
let mut branches = Vec::new();
|
|
|
|
let init_cond = read_until_open_curly_brace(toks);
|
|
|
|
toks.next();
|
2020-03-29 13:28:17 -04:00
|
|
|
devour_whitespace(toks);
|
2020-03-24 22:13:38 -04:00
|
|
|
let mut init_toks = read_until_closing_curly_brace(toks);
|
|
|
|
init_toks.push(toks.next().unwrap());
|
2020-03-29 13:28:17 -04:00
|
|
|
devour_whitespace(toks);
|
2020-03-24 22:13:38 -04:00
|
|
|
|
|
|
|
branches.push(Branch::new(init_cond, init_toks));
|
|
|
|
|
|
|
|
let mut else_ = Vec::new();
|
|
|
|
|
|
|
|
loop {
|
2020-03-29 13:28:17 -04:00
|
|
|
if toks.peek().is_some() {
|
|
|
|
if toks.peek().unwrap().kind == '@' {
|
2020-03-24 22:13:38 -04:00
|
|
|
toks.next();
|
2020-03-29 13:28:17 -04:00
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if eat_ident(toks, &Scope::new(), &Selector::new())?.to_ascii_lowercase() == "else"
|
|
|
|
{
|
|
|
|
devour_whitespace(toks);
|
2020-03-24 22:13:38 -04:00
|
|
|
if let Some(tok) = toks.next() {
|
2020-03-29 13:28:17 -04:00
|
|
|
devour_whitespace(toks);
|
|
|
|
match tok.kind.to_ascii_lowercase() {
|
|
|
|
'i' if toks.next().unwrap().kind.to_ascii_lowercase() == 'f' => {
|
|
|
|
toks.next();
|
|
|
|
let cond = read_until_open_curly_brace(toks);
|
|
|
|
toks.next();
|
|
|
|
devour_whitespace(toks);
|
2020-03-31 22:00:38 -04:00
|
|
|
branches
|
|
|
|
.push(Branch::new(cond, read_until_closing_curly_brace(toks)));
|
2020-03-29 13:28:17 -04:00
|
|
|
toks.next();
|
|
|
|
devour_whitespace(toks);
|
|
|
|
}
|
|
|
|
'{' => {
|
|
|
|
else_ = read_until_closing_curly_brace(toks);
|
|
|
|
toks.next();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
return Err("expected \"{\".".into());
|
|
|
|
}
|
2020-03-24 22:13:38 -04:00
|
|
|
}
|
2020-03-29 13:28:17 -04:00
|
|
|
} else {
|
|
|
|
break;
|
2020-03-24 22:13:38 -04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-03-29 13:28:17 -04:00
|
|
|
devour_whitespace(toks);
|
|
|
|
|
2020-03-24 22:13:38 -04:00
|
|
|
Ok(If { branches, else_ })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn eval(self, scope: &mut Scope, super_selector: &Selector) -> SassResult<Vec<Stmt>> {
|
|
|
|
let mut stmts = Vec::new();
|
|
|
|
let mut toks = Vec::new();
|
|
|
|
let mut found_true = false;
|
|
|
|
for branch in self.branches {
|
|
|
|
if Value::from_tokens(
|
|
|
|
&mut branch.cond.into_iter().peekable(),
|
|
|
|
scope,
|
|
|
|
super_selector,
|
|
|
|
)?
|
|
|
|
.is_true()?
|
|
|
|
{
|
|
|
|
toks = branch.toks;
|
|
|
|
found_true = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !found_true {
|
|
|
|
toks = self.else_;
|
|
|
|
}
|
|
|
|
for stmt in eat_stmts(&mut toks.into_iter().peekable(), scope, super_selector)? {
|
|
|
|
match stmt {
|
|
|
|
Stmt::AtRule(AtRule::If(i)) => stmts.extend(i.eval(scope, super_selector)?),
|
|
|
|
Stmt::RuleSet(r) if r.selector.is_empty() => stmts.extend(r.rules),
|
|
|
|
v => stmts.push(v),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(stmts)
|
|
|
|
}
|
|
|
|
}
|