use crate::common::{Scope, Symbol}; use crate::utils::{devour_whitespace_or_comment, eat_interpolation}; use crate::value::Value; use crate::{Token, TokenKind}; use std::fmt::{self, Display}; use std::iter::Peekable; use std::vec::IntoIter; /// A style: `color: red` #[derive(Clone, Debug, Eq, PartialEq)] pub(crate) struct Style { property: String, value: Value, } impl Display for Style { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}: {};", self.property, self.value) } } impl Style { pub fn from_tokens(tokens: Vec, scope: &Scope) -> Result { Ok(StyleParser::new(tokens, scope)?.parse()) } } struct StyleParser<'a> { tokens: Peekable>, scope: &'a Scope, } impl<'a> StyleParser<'a> { fn new(tokens: Vec, scope: &'a Scope) -> Result { if tokens.is_empty() { return Err(()); } let tokens = tokens.into_iter().peekable(); Ok(StyleParser { tokens, scope }) } fn parse(&mut self) -> Style { let mut property = String::new(); // read property until `:` while let Some(Token { kind, .. }) = self.tokens.next() { match kind { TokenKind::Whitespace(_) | TokenKind::MultilineComment(_) => continue, TokenKind::Ident(ref s) => property.push_str(s), TokenKind::Interpolation => property.push_str( &eat_interpolation(&mut self.tokens, self.scope) .iter() .map(|x| x.kind.to_string()) .collect::(), ), TokenKind::Symbol(Symbol::Colon) => break, _ => property.push_str(&kind.to_string()), }; } devour_whitespace_or_comment(&mut self.tokens); let value = Value::from_tokens(&mut self.tokens, self.scope).unwrap(); Style { property, value } } }