From 05fde036971ea52c6e352b04e822684372b02d87 Mon Sep 17 00:00:00 2001 From: ConnorSkees <39542938+ConnorSkees@users.noreply.github.com> Date: Sun, 5 Apr 2020 23:36:24 -0400 Subject: [PATCH] refactor @ for parsing to separate file --- src/atrule/for_rule.rs | 143 +++++++++++++++++++++++++++++++++++++++++ src/atrule/mod.rs | 136 +-------------------------------------- 2 files changed, 146 insertions(+), 133 deletions(-) create mode 100644 src/atrule/for_rule.rs diff --git a/src/atrule/for_rule.rs b/src/atrule/for_rule.rs new file mode 100644 index 0000000..9234f23 --- /dev/null +++ b/src/atrule/for_rule.rs @@ -0,0 +1,143 @@ +use std::iter::Peekable; + +use num_traits::cast::ToPrimitive; + +use super::parse::eat_stmts; +use super::AtRule; + +use crate::error::SassResult; +use crate::scope::Scope; +use crate::selector::Selector; +use crate::unit::Unit; +use crate::utils::{ + devour_whitespace, eat_ident, read_until_closing_curly_brace, read_until_open_curly_brace, +}; +use crate::value::{Number, Value}; +use crate::Token; + +pub(crate) fn parse_for>( + toks: &mut Peekable, + scope: &mut Scope, + super_selector: &Selector, +) -> SassResult { + let mut stmts = Vec::new(); + devour_whitespace(toks); + let var = match toks.next().ok_or("expected \"$\".")?.kind { + '$' => eat_ident(toks, scope, super_selector)?, + _ => return Err("expected \"$\".".into()), + }; + devour_whitespace(toks); + if toks.peek().is_none() + || eat_ident(toks, scope, super_selector)?.to_ascii_lowercase() != "from" + { + return Err("Expected \"from\".".into()); + } + devour_whitespace(toks); + let mut from_toks = Vec::new(); + let mut through = 0; + while let Some(tok) = toks.next() { + let mut these_toks = vec![tok]; + match these_toks[0].kind.to_ascii_lowercase() { + 't' => { + these_toks.push(toks.next().unwrap()); + match these_toks[1].kind.to_ascii_lowercase() { + 'h' => { + let r = toks.next().unwrap(); + these_toks.push(r); + if r.kind != 'r' { + from_toks.extend(these_toks); + continue; + } + let o = toks.next().unwrap(); + these_toks.push(o); + if o.kind != 'o' { + from_toks.extend(these_toks); + continue; + } + let u = toks.next().unwrap(); + these_toks.push(u); + if u.kind != 'u' { + from_toks.extend(these_toks); + continue; + } + let g = toks.next().unwrap(); + these_toks.push(g); + if g.kind != 'g' { + from_toks.extend(these_toks); + continue; + } + let h = toks.next().unwrap(); + these_toks.push(h); + if h.kind != 'h' { + from_toks.extend(these_toks); + continue; + } + let peek = toks.peek().unwrap().kind; + if peek.is_alphanumeric() || peek == '\\' { + from_toks.extend(these_toks); + continue; + } + through = 1; + break; + } + 'o' => { + if toks.peek().unwrap().kind.is_whitespace() { + break; + } else { + from_toks.extend(these_toks); + } + } + _ => { + from_toks.extend(these_toks); + } + } + } + '{' => { + return Err("Expected \"to\" or \"through\".".into()); + } + _ => from_toks.extend(these_toks), + } + } + let from = + match Value::from_tokens(&mut from_toks.into_iter().peekable(), scope, super_selector)? { + Value::Dimension(n, _) => match n.to_integer().to_usize() { + Some(v) => v, + None => return Err(format!("{} is not a int.", n).into()), + }, + v => return Err(format!("{} is not an integer.", v).into()), + }; + devour_whitespace(toks); + let to_toks = read_until_open_curly_brace(toks); + toks.next(); + let to = match Value::from_tokens(&mut to_toks.into_iter().peekable(), scope, super_selector)? { + Value::Dimension(n, _) => match n.to_integer().to_usize() { + Some(v) => v, + None => return Err(format!("{} is not a int.", n).into()), + }, + v => return Err(format!("{} is not an integer.", v).into()), + }; + let body = read_until_closing_curly_brace(toks); + toks.next(); + + devour_whitespace(toks); + + let (mut x, mut y); + let iter: &mut dyn std::iter::Iterator = if from < to { + x = from..(to + through); + &mut x + } else { + y = ((to - through)..(from + 1)).skip(1).rev(); + &mut y + }; + + for i in iter { + scope.insert_var(&var, Value::Dimension(Number::from(i), Unit::None))?; + stmts.extend(eat_stmts( + &mut body.clone().into_iter().peekable(), + scope, + super_selector, + )?); + } + + Ok(AtRule::For(stmts)) +} diff --git a/src/atrule/mod.rs b/src/atrule/mod.rs index b40ef56..399bc8b 100644 --- a/src/atrule/mod.rs +++ b/src/atrule/mod.rs @@ -1,18 +1,15 @@ use std::fmt::{self, Display}; use std::iter::Peekable; -use num_traits::cast::ToPrimitive; - use crate::common::{Brackets, ListSeparator, Pos}; use crate::error::SassResult; use crate::scope::Scope; use crate::selector::Selector; -use crate::unit::Unit; use crate::utils::{ devour_whitespace, eat_ident, read_until_closing_curly_brace, read_until_open_curly_brace, read_until_semicolon_or_closing_curly_brace, }; -use crate::value::{Number, Value}; +use crate::value::Value; use crate::{Stmt, Token}; pub(crate) use function::Function; @@ -21,6 +18,7 @@ pub(crate) use mixin::{eat_include, Mixin}; use parse::eat_stmts; use unknown::UnknownAtRule; +mod for_rule; mod function; mod if_rule; mod mixin; @@ -184,135 +182,7 @@ impl AtRule { AtRuleKind::Extend => todo!("@extend not yet implemented"), AtRuleKind::If => AtRule::If(If::from_tokens(toks)?), AtRuleKind::Else => todo!("@else not yet implemented"), - AtRuleKind::For => { - let mut stmts = Vec::new(); - devour_whitespace(toks); - let var = match toks.next().ok_or("expected \"$\".")?.kind { - '$' => eat_ident(toks, scope, super_selector)?, - _ => return Err("expected \"$\".".into()), - }; - devour_whitespace(toks); - if toks.peek().is_none() - || eat_ident(toks, scope, super_selector)?.to_ascii_lowercase() != "from" - { - return Err("Expected \"from\".".into()); - } - devour_whitespace(toks); - let mut from_toks = Vec::new(); - let mut through = 0; - while let Some(tok) = toks.next() { - let mut these_toks = vec![tok]; - match these_toks[0].kind.to_ascii_lowercase() { - 't' => { - these_toks.push(toks.next().unwrap()); - match these_toks[1].kind.to_ascii_lowercase() { - 'h' => { - let r = toks.next().unwrap(); - these_toks.push(r); - if r.kind != 'r' { - from_toks.extend(these_toks); - continue; - } - let o = toks.next().unwrap(); - these_toks.push(o); - if o.kind != 'o' { - from_toks.extend(these_toks); - continue; - } - let u = toks.next().unwrap(); - these_toks.push(u); - if u.kind != 'u' { - from_toks.extend(these_toks); - continue; - } - let g = toks.next().unwrap(); - these_toks.push(g); - if g.kind != 'g' { - from_toks.extend(these_toks); - continue; - } - let h = toks.next().unwrap(); - these_toks.push(h); - if h.kind != 'h' { - from_toks.extend(these_toks); - continue; - } - let peek = toks.peek().unwrap().kind; - if peek.is_alphanumeric() || peek == '\\' { - from_toks.extend(these_toks); - continue; - } - through = 1; - break; - } - 'o' => { - if toks.peek().unwrap().kind.is_whitespace() { - break; - } else { - from_toks.extend(these_toks); - } - } - _ => { - from_toks.extend(these_toks); - } - } - } - '{' => { - return Err("Expected \"to\" or \"through\".".into()); - } - _ => from_toks.extend(these_toks), - } - } - let from = match Value::from_tokens( - &mut from_toks.into_iter().peekable(), - scope, - super_selector, - )? { - Value::Dimension(n, _) => match n.to_integer().to_usize() { - Some(v) => v, - None => return Err(format!("{} is not a int.", n).into()), - }, - v => return Err(format!("{} is not an integer.", v).into()), - }; - devour_whitespace(toks); - let to_toks = read_until_open_curly_brace(toks); - toks.next(); - let to = match Value::from_tokens( - &mut to_toks.into_iter().peekable(), - scope, - super_selector, - )? { - Value::Dimension(n, _) => match n.to_integer().to_usize() { - Some(v) => v, - None => return Err(format!("{} is not a int.", n).into()), - }, - v => return Err(format!("{} is not an integer.", v).into()), - }; - let body = read_until_closing_curly_brace(toks); - toks.next(); - - devour_whitespace(toks); - - let (mut x, mut y); - let iter: &mut dyn std::iter::Iterator = if from < to { - x = from..(to + through); - &mut x - } else { - y = ((to - through)..(from + 1)).skip(1).rev(); - &mut y - }; - - for i in iter { - scope.insert_var(&var, Value::Dimension(Number::from(i), Unit::None))?; - stmts.extend(eat_stmts( - &mut body.clone().into_iter().peekable(), - scope, - super_selector, - )?); - } - - AtRule::For(stmts) - } + AtRuleKind::For => for_rule::parse_for(toks, scope, super_selector)?, AtRuleKind::While => { let mut stmts = Vec::new(); devour_whitespace(toks);