Refactor style parsing to separate module

This commit is contained in:
ConnorSkees 2020-01-06 16:50:16 -05:00
parent 3f063709c5
commit 3ba585b40d
3 changed files with 133 additions and 125 deletions

View File

@ -84,7 +84,7 @@ impl<W: Write> PrettyPrinter<W> {
s: &StyleSheet,
) -> io::Result<()> {
for rule in &s.rules {
self.pretty_print_stmt(rule)?;
self.pretty_print_stmt_preserve_super_selectors(rule)?;
}
writeln!(self.buf)?;
Ok(())

View File

@ -37,6 +37,7 @@ use crate::css::Css;
use crate::format::PrettyPrinter;
use crate::lexer::Lexer;
use crate::selector::Selector;
use crate::style::Style;
use crate::units::Unit;
mod color;
@ -46,6 +47,7 @@ mod error;
mod format;
mod lexer;
mod selector;
mod style;
mod units;
#[derive(Clone, Debug, Eq, PartialEq)]
@ -95,130 +97,6 @@ pub struct StyleSheet {
rules: Vec<Stmt>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Style {
property: String,
value: String,
}
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: &[Token], vars: &HashMap<String, Vec<Token>>) -> Result<Self, ()> {
Ok(StyleParser::new(tokens, vars)?.parse())
}
}
struct StyleParser<'a> {
tokens: Peekable<std::slice::Iter<'a, Token>>,
vars: &'a HashMap<String, Vec<Token>>,
}
impl<'a> StyleParser<'a> {
fn new(tokens: &'a [Token], vars: &'a HashMap<String, Vec<Token>>) -> Result<Self, ()> {
if tokens.is_empty() {
return Err(());
}
let tokens = tokens.iter().peekable();
Ok(StyleParser { tokens, vars })
}
fn deref_variable(&mut self, variable: &TokenKind) -> String {
let mut val = String::with_capacity(25);
let mut v = match variable {
TokenKind::Variable(ref v) => {
self.vars.get(v).expect("todo! expected variable to exist")
}
_ => panic!("expected variable"),
}
.iter()
.peekable();
while let Some(tok) = v.next() {
match &tok.kind {
TokenKind::Variable(_) => val.push_str(&self.deref_variable(&tok.kind)),
TokenKind::Whitespace(_) => {
while let Some(w) = v.peek() {
if let TokenKind::Whitespace(_) = w.kind {
v.next();
} else {
val.push(' ');
break;
}
}
}
_ => val.push_str(&tok.kind.to_string()),
};
}
val
}
fn devour_whitespace(&mut self) {
while let Some(tok) = self.tokens.peek() {
if let TokenKind::Whitespace(_) = tok.kind {
self.tokens.next();
} else {
break;
}
}
}
fn parse(&mut self) -> Style {
let mut property = String::new();
// read property
while let Some(tok) = self.tokens.next() {
match tok.kind {
TokenKind::Whitespace(_) => continue,
TokenKind::Ident(ref s) => {
property = s.clone();
break;
}
_ => todo!(),
};
}
// read until `:`
while let Some(tok) = self.tokens.next() {
match tok.kind {
TokenKind::Whitespace(_) => continue,
TokenKind::Symbol(Symbol::Colon) => break,
_ => todo!("found tokens before style value"),
}
}
let mut value = String::new();
// read styles
while let Some(tok) = self.tokens.next() {
match &tok.kind {
TokenKind::Whitespace(_) => {
while let Some(w) = self.tokens.peek() {
if let TokenKind::Whitespace(_) = w.kind {
self.tokens.next();
continue;
} else if let TokenKind::Ident(ref s) = w.kind {
if s == &String::from("-") {
self.tokens.next();
value.push('-');
self.devour_whitespace();
break;
}
}
value.push(' ');
break;
}
}
TokenKind::Variable(_) => value.push_str(&self.deref_variable(&tok.kind)),
_ => value.push_str(&tok.kind.to_string()),
}
}
Style { property, value }
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Stmt {
Style(Style),

130
src/style.rs Normal file
View File

@ -0,0 +1,130 @@
use crate::{Token, TokenKind};
use crate::common::Symbol;
use std::fmt::{self, Display};
use std::collections::HashMap;
use std::slice::Iter;
use std::iter::Peekable;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Style {
property: String,
value: String,
}
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: &[Token], vars: &HashMap<String, Vec<Token>>) -> Result<Self, ()> {
Ok(StyleParser::new(tokens, vars)?.parse())
}
}
struct StyleParser<'a> {
tokens: Peekable<Iter<'a, Token>>,
vars: &'a HashMap<String, Vec<Token>>,
}
impl<'a> StyleParser<'a> {
fn new(tokens: &'a [Token], vars: &'a HashMap<String, Vec<Token>>) -> Result<Self, ()> {
if tokens.is_empty() {
return Err(());
}
let tokens = tokens.iter().peekable();
Ok(StyleParser { tokens, vars })
}
fn deref_variable(&mut self, variable: &TokenKind) -> String {
let mut val = String::with_capacity(25);
let mut v = match variable {
TokenKind::Variable(ref v) => {
self.vars.get(v).expect("todo! expected variable to exist")
}
_ => panic!("expected variable"),
}
.iter()
.peekable();
while let Some(tok) = v.next() {
match &tok.kind {
TokenKind::Variable(_) => val.push_str(&self.deref_variable(&tok.kind)),
TokenKind::Whitespace(_) => {
while let Some(w) = v.peek() {
if let TokenKind::Whitespace(_) = w.kind {
v.next();
} else {
val.push(' ');
break;
}
}
}
_ => val.push_str(&tok.kind.to_string()),
};
}
val
}
fn devour_whitespace(&mut self) {
while let Some(tok) = self.tokens.peek() {
if let TokenKind::Whitespace(_) = tok.kind {
self.tokens.next();
} else {
break;
}
}
}
fn parse(&mut self) -> Style {
let mut property = String::new();
// read property
while let Some(tok) = self.tokens.next() {
match tok.kind {
TokenKind::Whitespace(_) => continue,
TokenKind::Ident(ref s) => {
property = s.clone();
break;
}
_ => todo!(),
};
}
// read until `:`
while let Some(tok) = self.tokens.next() {
match tok.kind {
TokenKind::Whitespace(_) => continue,
TokenKind::Symbol(Symbol::Colon) => break,
_ => todo!("found tokens before style value"),
}
}
let mut value = String::new();
// read styles
while let Some(tok) = self.tokens.next() {
match &tok.kind {
TokenKind::Whitespace(_) => {
while let Some(w) = self.tokens.peek() {
if let TokenKind::Whitespace(_) = w.kind {
self.tokens.next();
continue;
} else if let TokenKind::Ident(ref s) = w.kind {
if s == &String::from("-") {
self.tokens.next();
value.push('-');
self.devour_whitespace();
break;
}
}
value.push(' ');
break;
}
}
TokenKind::Variable(_) => value.push_str(&self.deref_variable(&tok.kind)),
_ => value.push_str(&tok.kind.to_string()),
}
}
Style { property, value }
}
}