reduce size of parse::Stmt

This commit is contained in:
ConnorSkees 2020-06-25 00:27:24 -04:00
parent 177cacd9c9
commit e12d3a581d
10 changed files with 149 additions and 111 deletions

69
src/atrule/media.rs Normal file
View File

@ -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 "))
}
}

View File

@ -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;

7
src/atrule/supports.rs Normal file
View File

@ -0,0 +1,7 @@
use crate::parse::Stmt;
#[derive(Debug, Clone)]
pub(crate) struct SupportsRule {
pub params: String,
pub body: Vec<Stmt>,
}

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

@ -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>,
}

View File

@ -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),
})

View File

@ -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"),
}
}

View File

@ -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 =

View File

@ -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)]

View File

@ -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),
}]);
}
}

View File

@ -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,
},
}),
})
}
}