Refactor unknown at rule parsing to separate file

This commit is contained in:
ConnorSkees 2020-03-01 08:02:59 -05:00
parent 286f67b984
commit 14eb173c56
4 changed files with 131 additions and 97 deletions

View File

@ -9,9 +9,15 @@ use crate::function::Function;
use crate::mixin::Mixin; use crate::mixin::Mixin;
use crate::selector::Selector; use crate::selector::Selector;
use crate::units::Unit; use crate::units::Unit;
use crate::utils::{devour_whitespace, devour_whitespace_or_comment, parse_interpolation}; use crate::utils::{devour_whitespace, devour_whitespace_or_comment};
use crate::value::{Number, Value}; use crate::value::{Number, Value};
use crate::{eat_expr, Expr, RuleSet, Stmt, Token, TokenKind}; use crate::{Stmt, Token, TokenKind};
use parse::eat_stmts;
use unknown::UnknownAtRule;
mod parse;
mod unknown;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) enum AtRule { pub(crate) enum AtRule {
@ -26,14 +32,6 @@ pub(crate) enum AtRule {
For(Vec<Stmt>), For(Vec<Stmt>),
} }
#[derive(Debug, Clone)]
pub(crate) struct UnknownAtRule {
pub name: String,
pub super_selector: Selector,
pub params: String,
pub body: Vec<Stmt>,
}
impl AtRule { impl AtRule {
pub fn from_tokens<I: Iterator<Item = Token>>( pub fn from_tokens<I: Iterator<Item = Token>>(
rule: &AtRuleKind, rule: &AtRuleKind,
@ -182,7 +180,7 @@ impl AtRule {
if from < to { if from < to {
for i in from..(to + through) { for i in from..(to + through) {
scope.insert_var(&var, Value::Dimension(Number::from(i), Unit::None))?; scope.insert_var(&var, Value::Dimension(Number::from(i), Unit::None))?;
stmts.extend(eat_unknown_atrule_body( stmts.extend(eat_stmts(
&mut body.clone().into_iter().peekable(), &mut body.clone().into_iter().peekable(),
&scope, &scope,
super_selector, super_selector,
@ -191,7 +189,7 @@ impl AtRule {
} else if from > to { } else if from > to {
for i in ((to - through)..(from + 1)).skip(1).rev() { for i in ((to - through)..(from + 1)).skip(1).rev() {
scope.insert_var(&var, Value::Dimension(Number::from(i), Unit::None))?; scope.insert_var(&var, Value::Dimension(Number::from(i), Unit::None))?;
stmts.extend(eat_unknown_atrule_body( stmts.extend(eat_stmts(
&mut body.clone().into_iter().peekable(), &mut body.clone().into_iter().peekable(),
&scope, &scope,
super_selector, super_selector,
@ -202,95 +200,17 @@ impl AtRule {
} }
AtRuleKind::While => todo!("@while not yet implemented"), AtRuleKind::While => todo!("@while not yet implemented"),
AtRuleKind::Keyframes => todo!("@keyframes not yet implemented"), AtRuleKind::Keyframes => todo!("@keyframes not yet implemented"),
AtRuleKind::Unknown(name) => { AtRuleKind::Unknown(name) => AtRule::Unknown(UnknownAtRule::from_tokens(
let mut params = String::new(); toks,
while let Some(tok) = toks.next() { name,
match tok.kind { scope,
TokenKind::Symbol(Symbol::OpenCurlyBrace) => break, super_selector,
TokenKind::Interpolation => { )?),
params.push_str(
&parse_interpolation(toks, scope)?
.into_iter()
.map(|x| x.kind.to_string())
.collect::<String>(),
);
continue;
}
TokenKind::Variable(..) => params.push('$'),
TokenKind::Whitespace(..) => {
devour_whitespace(toks);
params.push(' ');
continue;
}
_ => {}
}
params.push_str(&tok.kind.to_string());
}
let raw_body = eat_unknown_atrule_body(toks, scope, super_selector)?;
let mut body = Vec::with_capacity(raw_body.len());
body.push(Stmt::RuleSet(RuleSet::new()));
let mut rules = Vec::new();
for stmt in raw_body {
match stmt {
s @ Stmt::Style(..) => rules.push(s),
s => body.push(s),
}
}
body[0] = Stmt::RuleSet(RuleSet {
selector: super_selector.clone(),
rules,
super_selector: Selector::new(),
});
let u = UnknownAtRule {
name: name.clone(),
super_selector: Selector::new(),
params: params.trim().to_owned(),
body,
};
AtRule::Unknown(u)
}
_ => todo!("encountered unimplemented at rule"), _ => todo!("encountered unimplemented at rule"),
}) })
} }
} }
fn eat_unknown_atrule_body<I: Iterator<Item = Token>>(
toks: &mut Peekable<I>,
scope: &Scope,
super_selector: &Selector,
) -> SassResult<Vec<Stmt>> {
let mut stmts = Vec::new();
let mut scope = scope.clone();
while let Some(expr) = eat_expr(toks, &scope, super_selector)? {
match expr {
Expr::AtRule(a) => stmts.push(Stmt::AtRule(a)),
Expr::Style(s) => stmts.push(Stmt::Style(s)),
Expr::Styles(s) => stmts.extend(s.into_iter().map(Box::new).map(Stmt::Style)),
Expr::Include(s) => stmts.extend(s),
Expr::MixinDecl(..) | Expr::FunctionDecl(..) | Expr::Debug(..) | Expr::Warn(..) => {
todo!()
}
Expr::Selector(selector) => {
let rules = eat_unknown_atrule_body(toks, &scope, &super_selector.zip(&selector))?;
stmts.push(Stmt::RuleSet(RuleSet {
super_selector: super_selector.clone(),
selector,
rules,
}));
}
Expr::VariableDecl(name, val) => {
scope.insert_var(&name, *val)?;
}
Expr::MultilineComment(s) => stmts.push(Stmt::MultilineComment(s)),
}
}
Ok(stmts)
}
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum AtRuleKind { pub enum AtRuleKind {
// SASS specific @rules // SASS specific @rules

39
src/atrule/parse.rs Normal file
View File

@ -0,0 +1,39 @@
use std::iter::Peekable;
use crate::common::Scope;
use crate::error::SassResult;
use crate::selector::Selector;
use crate::{eat_expr, Expr, RuleSet, Stmt, Token};
pub(crate) fn eat_stmts<I: Iterator<Item = Token>>(
toks: &mut Peekable<I>,
scope: &Scope,
super_selector: &Selector,
) -> SassResult<Vec<Stmt>> {
let mut stmts = Vec::new();
let mut scope = scope.clone();
while let Some(expr) = eat_expr(toks, &scope, super_selector)? {
match expr {
Expr::AtRule(a) => stmts.push(Stmt::AtRule(a)),
Expr::Style(s) => stmts.push(Stmt::Style(s)),
Expr::Styles(s) => stmts.extend(s.into_iter().map(Box::new).map(Stmt::Style)),
Expr::Include(s) => stmts.extend(s),
Expr::MixinDecl(..) | Expr::FunctionDecl(..) | Expr::Debug(..) | Expr::Warn(..) => {
todo!()
}
Expr::Selector(selector) => {
let rules = eat_stmts(toks, &scope, &super_selector.zip(&selector))?;
stmts.push(Stmt::RuleSet(RuleSet {
super_selector: super_selector.clone(),
selector,
rules,
}));
}
Expr::VariableDecl(name, val) => {
scope.insert_var(&name, *val)?;
}
Expr::MultilineComment(s) => stmts.push(Stmt::MultilineComment(s)),
}
}
Ok(stmts)
}

73
src/atrule/unknown.rs Normal file
View File

@ -0,0 +1,73 @@
use std::iter::Peekable;
use super::parse::eat_stmts;
use crate::common::{Scope, Symbol};
use crate::error::SassResult;
use crate::selector::Selector;
use crate::utils::{devour_whitespace, parse_interpolation};
use crate::{RuleSet, Stmt, Token, TokenKind};
#[derive(Debug, Clone)]
pub(crate) struct UnknownAtRule {
pub name: String,
pub super_selector: Selector,
pub params: String,
pub body: Vec<Stmt>,
}
impl UnknownAtRule {
pub fn from_tokens<I: Iterator<Item = Token>>(
toks: &mut Peekable<I>,
name: &str,
scope: &Scope,
super_selector: &Selector,
) -> SassResult<UnknownAtRule> {
let mut params = String::new();
while let Some(tok) = toks.next() {
match tok.kind {
TokenKind::Symbol(Symbol::OpenCurlyBrace) => break,
TokenKind::Interpolation => {
params.push_str(
&parse_interpolation(toks, scope)?
.into_iter()
.map(|x| x.kind.to_string())
.collect::<String>(),
);
continue;
}
TokenKind::Variable(..) => params.push('$'),
TokenKind::Whitespace(..) => {
devour_whitespace(toks);
params.push(' ');
continue;
}
_ => {}
}
params.push_str(&tok.kind.to_string());
}
let raw_body = eat_stmts(toks, scope, super_selector)?;
let mut body = Vec::with_capacity(raw_body.len());
body.push(Stmt::RuleSet(RuleSet::new()));
let mut rules = Vec::new();
for stmt in raw_body {
match stmt {
s @ Stmt::Style(..) => rules.push(s),
s => body.push(s),
}
}
body[0] = Stmt::RuleSet(RuleSet {
selector: super_selector.clone(),
rules,
super_selector: Selector::new(),
});
Ok(UnknownAtRule {
name: name.to_owned(),
super_selector: Selector::new(),
params: params.trim().to_owned(),
body,
})
}
}

View File

@ -82,7 +82,9 @@ impl Add for Value {
}; };
Value::Ident(format!("{}{}", s1, c), quotes) Value::Ident(format!("{}{}", s1, c), quotes)
} }
Self::BinaryOp(..) | Self::Paren(..) => return Self::Ident(s1, quotes1) + other.eval()?, Self::BinaryOp(..) | Self::Paren(..) => {
return Self::Ident(s1, quotes1) + other.eval()?
}
Self::List(..) => todo!(), Self::List(..) => todo!(),
}, },
_ => todo!(), _ => todo!(),