2020-03-01 14:53:52 -05:00
|
|
|
use std::fmt::{self, Display};
|
|
|
|
use std::iter::Peekable;
|
|
|
|
|
2020-02-16 10:54:25 -05:00
|
|
|
use crate::error::SassResult;
|
2020-03-17 20:13:53 -04:00
|
|
|
use crate::scope::Scope;
|
2020-02-01 21:59:23 -05:00
|
|
|
use crate::selector::Selector;
|
2020-03-29 13:28:17 -04:00
|
|
|
use crate::utils::{
|
2020-03-30 02:21:41 -04:00
|
|
|
devour_whitespace, devour_whitespace_or_comment, eat_ident,
|
|
|
|
read_until_semicolon_or_open_or_closing_curly_brace,
|
2020-03-29 13:28:17 -04:00
|
|
|
};
|
2020-01-25 09:54:38 -05:00
|
|
|
use crate::value::Value;
|
2020-03-29 13:28:17 -04:00
|
|
|
use crate::{Expr, Token};
|
2020-01-06 16:50:16 -05:00
|
|
|
|
2020-01-08 20:58:02 -05:00
|
|
|
/// A style: `color: red`
|
2020-01-06 16:50:16 -05:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
2020-01-20 13:15:47 -05:00
|
|
|
pub(crate) struct Style {
|
2020-02-01 19:33:56 -05:00
|
|
|
pub property: String,
|
|
|
|
pub value: Value,
|
2020-01-06 16:50:16 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for Style {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2020-01-12 10:54:46 -05:00
|
|
|
write!(f, "{}: {};", self.property, self.value)
|
2020-01-06 16:50:16 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Style {
|
2020-02-01 21:59:23 -05:00
|
|
|
pub fn parse_property<I: Iterator<Item = Token>>(
|
|
|
|
toks: &mut Peekable<I>,
|
|
|
|
scope: &Scope,
|
|
|
|
super_selector: &Selector,
|
|
|
|
super_property: String,
|
2020-02-17 07:18:54 -05:00
|
|
|
) -> SassResult<String> {
|
2020-02-01 21:59:23 -05:00
|
|
|
StyleParser::new(scope, super_selector).parse_property(toks, super_property)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn parse_value<I: Iterator<Item = Token>>(
|
|
|
|
toks: &mut Peekable<I>,
|
|
|
|
scope: &Scope,
|
|
|
|
super_selector: &Selector,
|
2020-02-16 10:54:25 -05:00
|
|
|
) -> SassResult<Value> {
|
2020-02-24 17:47:32 -05:00
|
|
|
StyleParser::new(scope, super_selector).parse_style_value(toks, scope)
|
2020-02-01 21:59:23 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn from_tokens<I: Iterator<Item = Token>>(
|
|
|
|
toks: &mut Peekable<I>,
|
|
|
|
scope: &Scope,
|
|
|
|
super_selector: &Selector,
|
|
|
|
super_property: String,
|
2020-02-16 10:54:25 -05:00
|
|
|
) -> SassResult<Expr> {
|
2020-02-24 17:47:32 -05:00
|
|
|
StyleParser::new(scope, super_selector).eat_style_group(toks, super_property, scope)
|
2020-01-06 16:50:16 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct StyleParser<'a> {
|
2020-01-12 17:44:49 -05:00
|
|
|
scope: &'a Scope,
|
2020-02-01 21:59:23 -05:00
|
|
|
super_selector: &'a Selector,
|
2020-01-06 16:50:16 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> StyleParser<'a> {
|
2020-02-09 19:07:44 -05:00
|
|
|
const fn new(scope: &'a Scope, super_selector: &'a Selector) -> Self {
|
2020-02-01 21:59:23 -05:00
|
|
|
StyleParser {
|
|
|
|
scope,
|
|
|
|
super_selector,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn parse_style_value<I: Iterator<Item = Token>>(
|
|
|
|
&self,
|
|
|
|
toks: &mut Peekable<I>,
|
2020-02-24 17:47:32 -05:00
|
|
|
scope: &Scope,
|
2020-02-16 10:54:25 -05:00
|
|
|
) -> SassResult<Value> {
|
2020-02-01 21:59:23 -05:00
|
|
|
devour_whitespace(toks);
|
2020-03-01 12:03:14 -05:00
|
|
|
Value::from_tokens(
|
2020-03-29 13:28:17 -04:00
|
|
|
&mut read_until_semicolon_or_open_or_closing_curly_brace(toks)
|
|
|
|
.into_iter()
|
|
|
|
.peekable(),
|
|
|
|
scope,
|
2020-03-01 12:03:14 -05:00
|
|
|
self.super_selector,
|
|
|
|
)
|
2020-01-06 16:50:16 -05:00
|
|
|
}
|
|
|
|
|
2020-02-01 21:59:23 -05:00
|
|
|
pub(crate) fn eat_style_group<I: Iterator<Item = Token>>(
|
|
|
|
&self,
|
|
|
|
toks: &mut Peekable<I>,
|
|
|
|
super_property: String,
|
2020-02-24 17:47:32 -05:00
|
|
|
scope: &Scope,
|
2020-02-16 10:54:25 -05:00
|
|
|
) -> SassResult<Expr> {
|
2020-02-01 21:59:23 -05:00
|
|
|
let mut styles = Vec::new();
|
|
|
|
devour_whitespace(toks);
|
|
|
|
while let Some(tok) = toks.peek() {
|
|
|
|
match tok.kind {
|
2020-03-29 13:28:17 -04:00
|
|
|
'{' => {
|
2020-02-01 21:59:23 -05:00
|
|
|
toks.next();
|
|
|
|
devour_whitespace(toks);
|
|
|
|
loop {
|
2020-02-17 07:18:54 -05:00
|
|
|
let property = self.parse_property(toks, super_property.clone())?;
|
2020-02-01 21:59:23 -05:00
|
|
|
if let Some(tok) = toks.peek() {
|
2020-03-29 13:28:17 -04:00
|
|
|
if tok.kind == '{' {
|
2020-02-24 17:47:32 -05:00
|
|
|
match self.eat_style_group(toks, property, scope)? {
|
2020-02-22 16:41:10 -05:00
|
|
|
Expr::Styles(s) => styles.extend(s),
|
2020-02-22 17:57:13 -05:00
|
|
|
Expr::Style(s) => styles.push(*s),
|
2020-02-22 16:41:10 -05:00
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
devour_whitespace(toks);
|
|
|
|
if let Some(tok) = toks.peek() {
|
2020-03-29 13:28:17 -04:00
|
|
|
if tok.kind == '}' {
|
2020-02-22 16:41:10 -05:00
|
|
|
toks.next();
|
|
|
|
devour_whitespace(toks);
|
|
|
|
return Ok(Expr::Styles(styles));
|
|
|
|
} else {
|
|
|
|
continue;
|
2020-02-01 21:59:23 -05:00
|
|
|
}
|
|
|
|
}
|
2020-02-22 16:41:10 -05:00
|
|
|
continue;
|
2020-02-01 21:59:23 -05:00
|
|
|
}
|
|
|
|
}
|
2020-02-24 17:47:32 -05:00
|
|
|
let value = self.parse_style_value(toks, scope)?;
|
2020-02-22 16:41:10 -05:00
|
|
|
match toks.peek().unwrap().kind {
|
2020-03-29 13:28:17 -04:00
|
|
|
'}' => {
|
2020-02-22 16:41:10 -05:00
|
|
|
styles.push(Style { property, value });
|
|
|
|
}
|
2020-03-29 13:28:17 -04:00
|
|
|
';' => {
|
2020-02-22 16:41:10 -05:00
|
|
|
toks.next();
|
|
|
|
devour_whitespace(toks);
|
|
|
|
styles.push(Style { property, value });
|
|
|
|
}
|
2020-03-29 13:28:17 -04:00
|
|
|
'{' => {
|
2020-02-22 16:41:10 -05:00
|
|
|
styles.push(Style {
|
|
|
|
property: property.clone(),
|
|
|
|
value,
|
|
|
|
});
|
2020-02-24 17:47:32 -05:00
|
|
|
match self.eat_style_group(toks, property, scope)? {
|
2020-02-22 17:57:13 -05:00
|
|
|
Expr::Style(s) => styles.push(*s),
|
2020-02-22 16:41:10 -05:00
|
|
|
Expr::Styles(s) => styles.extend(s),
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
devour_whitespace(toks);
|
|
|
|
styles.push(Style { property, value });
|
|
|
|
}
|
|
|
|
}
|
2020-02-01 21:59:23 -05:00
|
|
|
if let Some(tok) = toks.peek() {
|
|
|
|
match tok.kind {
|
2020-03-29 13:28:17 -04:00
|
|
|
'}' => {
|
2020-02-01 21:59:23 -05:00
|
|
|
toks.next();
|
|
|
|
devour_whitespace(toks);
|
|
|
|
return Ok(Expr::Styles(styles));
|
|
|
|
}
|
|
|
|
_ => continue,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
2020-02-24 17:47:32 -05:00
|
|
|
let val = self.parse_style_value(toks, scope)?;
|
2020-03-29 13:28:17 -04:00
|
|
|
let t = toks.peek().ok_or("expected more input.")?;
|
2020-03-21 10:40:38 -04:00
|
|
|
match t.kind {
|
2020-03-29 13:28:17 -04:00
|
|
|
'}' => {}
|
|
|
|
';' => {
|
2020-02-22 16:41:10 -05:00
|
|
|
toks.next();
|
|
|
|
devour_whitespace(toks);
|
|
|
|
}
|
2020-03-29 13:28:17 -04:00
|
|
|
'{' => {
|
2020-02-22 16:41:10 -05:00
|
|
|
let mut v = vec![Style {
|
|
|
|
property: super_property.clone(),
|
|
|
|
value: val,
|
|
|
|
}];
|
2020-02-24 17:47:32 -05:00
|
|
|
match self.eat_style_group(toks, super_property, scope)? {
|
2020-02-22 17:57:13 -05:00
|
|
|
Expr::Style(s) => v.push(*s),
|
2020-02-22 16:41:10 -05:00
|
|
|
Expr::Styles(s) => v.extend(s),
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
return Ok(Expr::Styles(v));
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
2020-02-22 17:57:13 -05:00
|
|
|
return Ok(Expr::Style(Box::new(Style {
|
2020-02-01 21:59:23 -05:00
|
|
|
property: super_property,
|
|
|
|
value: val,
|
2020-02-22 17:57:13 -05:00
|
|
|
})));
|
2020-02-01 21:59:23 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(Expr::Styles(styles))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn parse_property<I: Iterator<Item = Token>>(
|
|
|
|
&self,
|
|
|
|
toks: &mut Peekable<I>,
|
|
|
|
mut super_property: String,
|
2020-02-17 07:18:54 -05:00
|
|
|
) -> SassResult<String> {
|
2020-02-01 21:59:23 -05:00
|
|
|
devour_whitespace(toks);
|
2020-03-30 17:06:23 -04:00
|
|
|
let property = eat_ident(toks, self.scope, self.super_selector)?;
|
2020-03-30 02:21:41 -04:00
|
|
|
devour_whitespace_or_comment(toks)?;
|
2020-03-29 13:28:17 -04:00
|
|
|
if toks.peek().is_some() && toks.peek().unwrap().kind == ':' {
|
|
|
|
toks.next();
|
2020-03-30 02:21:41 -04:00
|
|
|
devour_whitespace_or_comment(toks)?;
|
2020-03-29 13:28:17 -04:00
|
|
|
}
|
|
|
|
|
2020-02-02 10:27:08 -05:00
|
|
|
if super_property.is_empty() {
|
2020-02-17 07:18:54 -05:00
|
|
|
Ok(property)
|
2020-02-02 10:27:08 -05:00
|
|
|
} else {
|
2020-02-01 21:59:23 -05:00
|
|
|
super_property.reserve(1 + property.len());
|
|
|
|
super_property.push('-');
|
|
|
|
super_property.push_str(&property);
|
2020-02-17 07:18:54 -05:00
|
|
|
Ok(super_property)
|
2020-02-01 21:59:23 -05:00
|
|
|
}
|
2020-01-06 16:50:16 -05:00
|
|
|
}
|
|
|
|
}
|