reduce size of parse::Stmt
This commit is contained in:
parent
177cacd9c9
commit
e12d3a581d
69
src/atrule/media.rs
Normal file
69
src/atrule/media.rs
Normal 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 "))
|
||||
}
|
||||
}
|
@ -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
7
src/atrule/supports.rs
Normal 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
9
src/atrule/unknown.rs
Normal 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>,
|
||||
}
|
@ -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),
|
||||
})
|
||||
|
@ -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"),
|
||||
}
|
||||
}
|
||||
|
@ -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 =
|
||||
|
@ -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)]
|
||||
|
@ -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),
|
||||
}]);
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
},
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user