diff --git a/src/format.rs b/src/format.rs index 88fc419..744ba54 100644 --- a/src/format.rs +++ b/src/format.rs @@ -1,6 +1,6 @@ use std::io::{self, Write}; -use crate::{RuleSet, Stmt, Style, StyleSheet}; +use crate::{RuleSet, Stmt, StyleSheet}; pub(crate) struct PrettyPrinter { buf: W, @@ -28,18 +28,8 @@ impl PrettyPrinter { writeln!(self.buf, "{}}}", padding)?; self.scope -= 1; } - Stmt::Style(Style { property, value }) => { - writeln!( - self.buf, - "{}{}: {};", - padding, - property, - value - .iter() - .map(ToString::to_string) - .collect::>() - .join(" ") - )?; + Stmt::Style(s) => { + writeln!(self.buf, "{}{}", padding, s)?; } } Ok(()) @@ -79,18 +69,8 @@ impl PrettyPrinter { writeln!(self.buf, "{}}}", padding)?; self.scope -= 1; } - Stmt::Style(Style { property, value }) => { - writeln!( - self.buf, - "{}{}: {};", - padding, - property, - value - .iter() - .map(ToString::to_string) - .collect::>() - .join(" ") - )?; + Stmt::Style(s) => { + writeln!(self.buf, "{}{}", padding, s)?; } } Ok(()) @@ -161,6 +141,8 @@ mod test_scss { test!(selector_universal_el_descendant, "* a {\n}\n"); test!(selector_attribute_any, "[attr] {\n}\n"); test!(selector_attribute_equals, "[attr=val] {\n}\n"); + test!(selector_attribute_single_quotes, "[attr='val'] {\n}\n"); + test!(selector_attribute_double_quotes, "[attr=\"val\"] {\n}\n"); test!(selector_attribute_in, "[attr~=val] {\n}\n"); test!( selector_attribute_begins_hyphen_or_exact, @@ -192,17 +174,15 @@ mod test_scss { space_separated_style_value, "a {\n border: solid red;\n}\n" ); - test!( - single_quoted_style_value, - "a {\n font: 'Open-Sans';\n}\n", - "a {\n font: Open-Sans;\n}\n" - ); + test!(single_quoted_style_value, "a {\n font: 'Open-Sans';\n}\n"); test!( double_quoted_style_value, - "a {\n font: \"Open-Sans\";\n}\n", - "a {\n font: Open-Sans;\n}\n" + "a {\n font: \"Open-Sans\";\n}\n" + ); + test!( + comma_style_value, + "a {\n font: Open-Sans, sans-serif;\n}\n" ); - // test!(comma_style_value, "a {\n font: Open-Sans, sans-serif;\n}\n"); test!( nested_style_in_parent, "a {\n color: red;\n b {\n }\n}\n" diff --git a/src/lexer.rs b/src/lexer.rs index c5aa2d2..eba078c 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -214,22 +214,11 @@ impl<'a> Lexer<'a> { self.devour_whitespace(); - match self - .buf - .peek() - .expect("todo! expected either value or quote") - { - '\'' | '"' => { - self.buf.next(); - } - _ => {} - } - let mut value = String::with_capacity(99); let mut case_sensitive = true; while let Some(c) = self.buf.peek() { - if !c.is_alphabetic() && c != &'-' && c != &'_' { + if !c.is_alphabetic() && c != &'-' && c != &'_' && c != &'"' && c != &'\'' { break; } @@ -260,17 +249,6 @@ impl<'a> Lexer<'a> { value.push(tok); } - match self - .buf - .peek() - .expect("todo! expected either value or quote") - { - '\'' | '"' => { - self.buf.next(); - } - _ => {} - } - self.devour_whitespace(); assert!(self.buf.next() == Some(']')); diff --git a/src/main.rs b/src/main.rs index 85dfd6e..ec08177 100644 --- a/src/main.rs +++ b/src/main.rs @@ -82,27 +82,6 @@ impl Display for TokenKind { } } -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum StyleToken { - Ident(String), - Function(String, Vec), - Keyword(Keyword), - Symbol(Symbol), - Dimension(String, Unit), -} - -impl Display for StyleToken { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - StyleToken::Ident(s) => write!(f, "{}", s), - StyleToken::Symbol(s) => write!(f, "{}", s), - StyleToken::Function(name, args) => write!(f, "{}({})", name, args.join(", ")), - StyleToken::Keyword(kw) => write!(f, "{}", kw), - StyleToken::Dimension(val, unit) => write!(f, "{}{}", val, unit), - } - } -} - #[derive(Clone, Debug, Eq, PartialEq)] pub struct Token { pos: Pos, @@ -117,27 +96,18 @@ pub struct StyleSheet { #[derive(Clone, Debug, Eq, PartialEq)] pub struct Style { property: String, - value: Vec, + value: String, } impl Display for Style { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}: {};", - self.property, - self.value - .iter() - .map(|x| format!("{}", x)) - .collect::>() - .join(" ") - ) + write!(f, "{}:{};", self.property, self.value) } } impl Style { pub fn from_tokens(tokens: &[Token], vars: &HashMap>) -> Result { - StyleParser::new(tokens, vars).parse() + Ok(StyleParser::new(tokens, vars)?.parse()) } } @@ -147,8 +117,11 @@ struct StyleParser<'a> { } impl<'a> StyleParser<'a> { - const fn new(tokens: &'a [Token], vars: &'a HashMap>) -> Self { - StyleParser { tokens, vars } + fn new(tokens: &'a [Token], vars: &'a HashMap>) -> Result { + if tokens.is_empty() { + return Err(()); + } + Ok(StyleParser { tokens, vars }) } fn deref_variable(&mut self, variable: &TokenKind) -> String { @@ -180,22 +153,18 @@ impl<'a> StyleParser<'a> { val } - fn parse(&mut self) -> Result { - let mut iter = self.tokens.iter(); - let property: String; - loop { - if let Some(tok) = iter.next() { - match tok.kind { - TokenKind::Whitespace(_) => continue, - TokenKind::Ident(ref s) => { - property = s.clone(); - break; - } - _ => todo!(), - }; - } else { - return Err(()); - } + fn parse(&mut self) -> Style { + let mut iter = self.tokens.iter().peekable(); + let mut property = String::new(); + while let Some(tok) = iter.next() { + match tok.kind { + TokenKind::Whitespace(_) => continue, + TokenKind::Ident(ref s) => { + property = s.clone(); + break; + } + _ => todo!(), + }; } while let Some(tok) = iter.next() { @@ -206,42 +175,25 @@ impl<'a> StyleParser<'a> { } } - let mut value = Vec::new(); + let mut value = String::new(); while let Some(tok) = iter.next() { - match tok.kind { - TokenKind::Whitespace(_) - | TokenKind::Symbol(Symbol::SingleQuote) - | TokenKind::Symbol(Symbol::DoubleQuote) => continue, - TokenKind::Ident(ref s) => value.push(StyleToken::Ident(s.clone())), - TokenKind::Symbol(s) => value.push(StyleToken::Symbol(s)), - TokenKind::Unit(u) => value.push(StyleToken::Ident(u.into())), - TokenKind::Variable(_) => { - value.push(StyleToken::Ident(self.deref_variable(&tok.kind))) - } - TokenKind::Number(ref num) => { - if let Some(t) = iter.next() { - match &t.kind { - &TokenKind::Unit(unit) => { - value.push(StyleToken::Dimension(num.clone(), unit)) - } - TokenKind::Ident(ref s) => { - value.push(StyleToken::Dimension(num.clone(), Unit::None)); - value.push(StyleToken::Ident(s.clone())); - } - TokenKind::Whitespace(_) => { - value.push(StyleToken::Dimension(num.clone(), Unit::None)) - } - _ => todo!(), + match &tok.kind { + TokenKind::Whitespace(_) => { + while let Some(w) = iter.peek() { + if let TokenKind::Whitespace(_) = w.kind { + iter.next(); + } else { + value.push(' '); + break; } - } else { - value.push(StyleToken::Dimension(num.clone(), Unit::None)) } } - _ => todo!("style value not ident or dimension"), + TokenKind::Variable(_) => value.push_str(&self.deref_variable(&tok.kind)), + _ => value.push_str(&tok.kind.to_string()), } } - Ok(Style { property, value }) + Style { property, value } } } @@ -462,8 +414,12 @@ mod test_css { }; } - test!(nesting_el_mul_el, "a, b {\n a, b {\n color: red\n}\n}\n", "a a, b a, a b, b b {\n color: red;\n}\n"); + test!( + nesting_el_mul_el, + "a, b {\n a, b {\n color: red\n}\n}\n", + "a a, b a, a b, b b {\n color: red;\n}\n" + ); test!(basic_style, "a {\n color: red;\n}\n"); test!(two_styles, "a {\n color: red;\n color: blue;\n}\n"); test!(selector_mul, "a, b {\n color: red;\n}\n"); -} \ No newline at end of file +}