From e12d3a581d97491b2445212613a9c978726390f5 Mon Sep 17 00:00:00 2001 From: ConnorSkees <39542938+ConnorSkees@users.noreply.github.com> Date: Thu, 25 Jun 2020 00:27:24 -0400 Subject: [PATCH] reduce size of parse::Stmt --- src/atrule/media.rs | 69 ++++++++++++++++++++++++++++++++++++++++++ src/atrule/mod.rs | 5 +++ src/atrule/supports.rs | 7 +++++ src/atrule/unknown.rs | 9 ++++++ src/output.rs | 47 ++++++++++++++++++++-------- src/parse/function.rs | 6 ++-- src/parse/media.rs | 61 ------------------------------------- src/parse/mod.rs | 44 ++++++++++----------------- src/parse/style.rs | 6 ++-- src/style.rs | 6 ++-- 10 files changed, 149 insertions(+), 111 deletions(-) create mode 100644 src/atrule/media.rs create mode 100644 src/atrule/supports.rs create mode 100644 src/atrule/unknown.rs diff --git a/src/atrule/media.rs b/src/atrule/media.rs new file mode 100644 index 0000000..ec6a93a --- /dev/null +++ b/src/atrule/media.rs @@ -0,0 +1,69 @@ +use std::fmt; + +use crate::{parse::Stmt, selector::Selector}; + +#[derive(Debug, Clone)] +pub(crate) struct MediaRule { + pub super_selector: Selector, + pub query: String, + pub body: Vec<Stmt>, +} + +#[derive(Debug, Eq, PartialEq, Clone)] +pub(crate) struct MediaQuery { + /// The modifier, probably either "not" or "only". + /// + /// This may be `None` if no modifier is in use. + pub modifier: Option<String>, + + /// The media type, for example "screen" or "print". + /// + /// This may be `None`. If so, `self.features` will not be empty. + pub media_type: Option<String>, + + /// Feature queries, including parentheses. + pub features: Vec<String>, +} + +#[allow(dead_code)] +impl MediaQuery { + pub fn is_condition(&self) -> bool { + self.modifier.is_none() && self.media_type.is_none() + } + + pub fn matches_all_types(&self) -> bool { + self.media_type.is_none() + || self + .media_type + .as_ref() + .map_or(false, |v| v.to_ascii_lowercase() == "all") + } + + pub fn condition(features: Vec<String>) -> Self { + Self { + modifier: None, + media_type: None, + features, + } + } + + #[allow(dead_code, unused_variables)] + pub fn merge(other: &Self) -> Self { + todo!() + } +} + +impl fmt::Display for MediaQuery { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(modifier) = &self.modifier { + f.write_str(modifier)?; + } + if let Some(media_type) = &self.media_type { + f.write_str(media_type)?; + if !&self.features.is_empty() { + f.write_str(" and ")?; + } + } + f.write_str(&self.features.join(" and ")) + } +} diff --git a/src/atrule/mod.rs b/src/atrule/mod.rs index 5c42d66..e12a576 100644 --- a/src/atrule/mod.rs +++ b/src/atrule/mod.rs @@ -1,7 +1,12 @@ pub(crate) use function::Function; pub(crate) use kind::AtRuleKind; pub(crate) use mixin::Mixin; +pub(crate) use supports::SupportsRule; +pub(crate) use unknown::UnknownAtRule; mod function; mod kind; +pub mod media; mod mixin; +mod supports; +mod unknown; diff --git a/src/atrule/supports.rs b/src/atrule/supports.rs new file mode 100644 index 0000000..145c3dd --- /dev/null +++ b/src/atrule/supports.rs @@ -0,0 +1,7 @@ +use crate::parse::Stmt; + +#[derive(Debug, Clone)] +pub(crate) struct SupportsRule { + pub params: String, + pub body: Vec<Stmt>, +} diff --git a/src/atrule/unknown.rs b/src/atrule/unknown.rs new file mode 100644 index 0000000..2d0df7d --- /dev/null +++ b/src/atrule/unknown.rs @@ -0,0 +1,9 @@ +use crate::{parse::Stmt, selector::Selector}; + +#[derive(Debug, Clone)] +pub(crate) struct UnknownAtRule { + pub name: String, + pub super_selector: Selector, + pub params: String, + pub body: Vec<Stmt>, +} diff --git a/src/output.rs b/src/output.rs index 5b1cdfa..9d17bd2 100644 --- a/src/output.rs +++ b/src/output.rs @@ -3,7 +3,14 @@ use std::io::Write; use codemap::CodeMap; -use crate::{error::SassResult, parse::Stmt, selector::Extender, selector::Selector, style::Style}; +use crate::{ + atrule::{media::MediaRule, SupportsRule, UnknownAtRule}, + error::SassResult, + parse::Stmt, + selector::Extender, + selector::Selector, + style::Style, +}; #[derive(Debug, Clone)] enum Toplevel { @@ -23,7 +30,7 @@ enum Toplevel { body: Vec<Stmt>, }, Newline, - Style(Box<Style>), + Style(Style), } #[derive(Debug, Clone)] @@ -92,17 +99,22 @@ impl Css { for rule in body { match rule { Stmt::RuleSet { .. } => vals.extend(self.parse_stmt(rule, extender)?), - Stmt::Style(s) => vals.get_mut(0).unwrap().push_style(*s)?, + Stmt::Style(s) => vals.get_mut(0).unwrap().push_style(s)?, Stmt::Comment(s) => vals.get_mut(0).unwrap().push_comment(s), - Stmt::Media { query, body, .. } => { + Stmt::Media(m) => { + let MediaRule { query, body, .. } = *m; vals.push(Toplevel::Media { query, body }) } - Stmt::Supports { params, body, .. } => { + Stmt::Supports(s) => { + let SupportsRule { params, body, .. } = *s; vals.push(Toplevel::Supports { params, body }) } - Stmt::UnknownAtRule { - params, body, name, .. - } => vals.push(Toplevel::UnknownAtRule { params, body, name }), + Stmt::UnknownAtRule(u) => { + let UnknownAtRule { + params, body, name, .. + } = *u; + vals.push(Toplevel::UnknownAtRule { params, body, name }) + } Stmt::Return(..) => unreachable!(), Stmt::AtRoot { body } => body .into_iter() @@ -114,11 +126,20 @@ impl Css { } Stmt::Comment(s) => vec![Toplevel::MultilineComment(s)], Stmt::Style(s) => vec![Toplevel::Style(s)], - Stmt::Media { query, body, .. } => vec![Toplevel::Media { query, body }], - Stmt::Supports { params, body, .. } => vec![Toplevel::Supports { params, body }], - Stmt::UnknownAtRule { - params, name, body, .. - } => vec![Toplevel::UnknownAtRule { params, name, body }], + Stmt::Media(m) => { + let MediaRule { query, body, .. } = *m; + vec![Toplevel::Media { query, body }] + } + Stmt::Supports(s) => { + let SupportsRule { params, body, .. } = *s; + vec![Toplevel::Supports { params, body }] + } + Stmt::UnknownAtRule(u) => { + let UnknownAtRule { + params, body, name, .. + } = *u; + vec![Toplevel::UnknownAtRule { params, name, body }] + } Stmt::Return(..) => unreachable!("@return: {:?}", stmt), Stmt::AtRoot { .. } => unreachable!("@at-root: {:?}", stmt), }) diff --git a/src/parse/function.rs b/src/parse/function.rs index 5b95614..651bd4b 100644 --- a/src/parse/function.rs +++ b/src/parse/function.rs @@ -82,13 +82,13 @@ impl<'a> Parser<'a> { Ok(()) } - pub(super) fn parse_return(&mut self) -> SassResult<Value> { + pub(super) fn parse_return(&mut self) -> SassResult<Box<Value>> { let toks = read_until_semicolon_or_closing_curly_brace(self.toks)?; let v = self.parse_value_from_vec(toks)?; if let Some(Token { kind: ';', .. }) = self.toks.peek() { self.toks.next(); } - Ok(v.node) + Ok(Box::new(v.node)) } pub fn eval_function(&mut self, mut function: Function, args: CallArgs) -> SassResult<Value> { @@ -117,7 +117,7 @@ impl<'a> Parser<'a> { .pop() .ok_or(("Function finished without @return.", self.span_before))? { - Stmt::Return(v) => Ok(v), + Stmt::Return(v) => Ok(*v), _ => todo!("should be unreachable"), } } diff --git a/src/parse/media.rs b/src/parse/media.rs index e71b7d6..2a5e761 100644 --- a/src/parse/media.rs +++ b/src/parse/media.rs @@ -1,5 +1,3 @@ -use std::fmt; - use crate::{ error::SassResult, utils::{is_name_start, peek_ident_no_interpolation, read_until_closing_paren}, @@ -8,65 +6,6 @@ use crate::{ use super::Parser; -#[derive(Debug, Eq, PartialEq, Clone)] -pub(super) struct MediaQuery { - /// The modifier, probably either "not" or "only". - /// - /// This may be `None` if no modifier is in use. - modifier: Option<String>, - - /// The media type, for example "screen" or "print". - /// - /// This may be `None`. If so, `self.features` will not be empty. - media_type: Option<String>, - - /// Feature queries, including parentheses. - features: Vec<String>, -} - -#[allow(dead_code)] -impl MediaQuery { - pub fn is_condition(&self) -> bool { - self.modifier.is_none() && self.media_type.is_none() - } - - pub fn matches_all_types(&self) -> bool { - self.media_type.is_none() - || self - .media_type - .as_ref() - .map_or(false, |v| v.to_ascii_lowercase() == "all") - } - - pub fn condition(features: Vec<String>) -> Self { - Self { - modifier: None, - media_type: None, - features, - } - } - - #[allow(dead_code, unused_variables)] - pub fn merge(other: &Self) -> Self { - todo!() - } -} - -impl fmt::Display for MediaQuery { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(modifier) = &self.modifier { - f.write_str(modifier)?; - } - if let Some(media_type) = &self.media_type { - f.write_str(media_type)?; - if !&self.features.is_empty() { - f.write_str(" and ")?; - } - } - f.write_str(&self.features.join(" and ")) - } -} - impl<'a> Parser<'a> { pub fn scan_identifier(&mut self, ident: &str) -> SassResult<bool> { let peeked_identifier = diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 01feb12..273da76 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -5,7 +5,7 @@ use num_traits::cast::ToPrimitive; use peekmore::{PeekMore, PeekMoreIterator}; use crate::{ - atrule::AtRuleKind, + atrule::{media::MediaRule, AtRuleKind, SupportsRule, UnknownAtRule}, common::{Brackets, ListSeparator}, error::SassResult, scope::Scope, @@ -46,27 +46,15 @@ pub(crate) enum Stmt { selector: ExtendedSelector, body: Vec<Self>, }, - Style(Box<Style>), - Media { - super_selector: Selector, - query: String, - body: Vec<Stmt>, - }, - UnknownAtRule { - name: String, - super_selector: Selector, - params: String, - body: Vec<Stmt>, - }, - Supports { - params: String, - body: Vec<Stmt>, - }, + Style(Style), + Media(Box<MediaRule>), + UnknownAtRule(Box<UnknownAtRule>), + Supports(Box<SupportsRule>), AtRoot { body: Vec<Stmt>, }, Comment(String), - Return(Value), + Return(Box<Value>), } /// We could use a generic for the toks, but it makes the API @@ -252,12 +240,12 @@ impl<'a> Parser<'a> { let styles = if let Some(value) = value { vec![Style { property, - value: *value, + value: value, }] } else { self.parse_style_group(property)? }; - stmts.extend(styles.into_iter().map(Box::new).map(Stmt::Style)); + stmts.extend(styles.into_iter().map(Stmt::Style)); } SelectorOrStyle::Selector(init) => { let at_root = self.at_root; @@ -1003,12 +991,12 @@ impl<'a> Parser<'a> { self.whitespace(); if let Some(Token { kind: ';', .. }) | None = self.toks.peek() { self.toks.next(); - return Ok(Stmt::UnknownAtRule { + return Ok(Stmt::UnknownAtRule(Box::new(UnknownAtRule { name, super_selector: Selector::new(self.span_before), params: String::new(), body: Vec::new(), - }); + }))); } while let Some(tok) = self.toks.next() { match tok.kind { @@ -1053,12 +1041,12 @@ impl<'a> Parser<'a> { body.append(&mut rules); - Ok(Stmt::UnknownAtRule { + Ok(Stmt::UnknownAtRule(Box::new(UnknownAtRule { name, super_selector: Selector::new(self.span_before), params: params.trim().to_owned(), body, - }) + }))) } fn parse_media(&mut self) -> SassResult<Stmt> { @@ -1107,11 +1095,11 @@ impl<'a> Parser<'a> { body.append(&mut rules); - Ok(Stmt::Media { + Ok(Stmt::Media(Box::new(MediaRule { super_selector: Selector::new(self.span_before), query, body, - }) + }))) } fn parse_at_root(&mut self) -> SassResult<Vec<Stmt>> { @@ -1292,10 +1280,10 @@ impl<'a> Parser<'a> { body.append(&mut rules); - Ok(Stmt::Supports { + Ok(Stmt::Supports(Box::new(SupportsRule { params: params.trim().to_owned(), body, - }) + }))) } #[allow(dead_code, clippy::unused_self)] diff --git a/src/parse/style.rs b/src/parse/style.rs index 18dd5e1..85c28d1 100644 --- a/src/parse/style.rs +++ b/src/parse/style.rs @@ -198,7 +198,7 @@ impl<'a> Parser<'a> { continue; } } - let value = self.parse_style_value()?; + let value = Box::new(self.parse_style_value()?); match self.toks.peek() { Some(Token { kind: '}', .. }) => { styles.push(Style { property, value }); @@ -246,7 +246,7 @@ impl<'a> Parser<'a> { '{' => { let mut v = vec![Style { property: super_property.clone(), - value, + value: Box::new(value), }]; v.append(&mut self.parse_style_group(super_property)?); return Ok(v); @@ -255,7 +255,7 @@ impl<'a> Parser<'a> { } return Ok(vec![Style { property: super_property, - value, + value: Box::new(value), }]); } } diff --git a/src/style.rs b/src/style.rs index bda0e42..1191bf7 100644 --- a/src/style.rs +++ b/src/style.rs @@ -6,7 +6,7 @@ use crate::{error::SassResult, value::Value}; #[derive(Clone, Debug, Eq, PartialEq)] pub(crate) struct Style { pub property: String, - pub value: Spanned<Value>, + pub value: Box<Spanned<Value>>, } impl Style { @@ -21,10 +21,10 @@ impl Style { pub(crate) fn eval(self) -> SassResult<Self> { Ok(Style { property: self.property, - value: Spanned { + value: Box::new(Spanned { span: self.value.span, node: self.value.node.eval(self.value.span)?.node, - }, + }), }) } }