Refactor various devour_whitespace methods into single util function

This commit is contained in:
ConnorSkees 2020-01-12 20:15:27 -05:00
parent 2439579d20
commit 33843dd2ac
4 changed files with 83 additions and 70 deletions

View File

@ -41,7 +41,7 @@ use crate::mixin::{CallArgs, FuncArgs, Mixin};
use crate::selector::{Attribute, Selector}; use crate::selector::{Attribute, Selector};
use crate::style::Style; use crate::style::Style;
use crate::units::Unit; use crate::units::Unit;
use crate::utils::{IsWhitespace, devour_whitespace}; use crate::utils::{devour_whitespace, IsWhitespace};
mod color; mod color;
mod common; mod common;
@ -64,6 +64,24 @@ pub struct Token {
pub kind: TokenKind, pub kind: TokenKind,
} }
impl IsWhitespace for Token {
fn is_whitespace(&self) -> bool {
if let TokenKind::Whitespace(_) = self.kind {
return true;
}
false
}
}
impl IsWhitespace for &Token {
fn is_whitespace(&self) -> bool {
if let TokenKind::Whitespace(_) = self.kind {
return true;
}
false
}
}
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum TokenKind { pub enum TokenKind {
Ident(String), Ident(String),
@ -226,7 +244,7 @@ impl<'a> StyleSheetParser<'a> {
.lexer .lexer
.next() .next()
.expect("this cannot occur as we have already peeked"); .expect("this cannot occur as we have already peeked");
self.devour_whitespace(); devour_whitespace(&mut self.lexer);
if self if self
.lexer .lexer
.next() .next()
@ -243,7 +261,9 @@ impl<'a> StyleSheetParser<'a> {
self.lexer.next(); self.lexer.next();
rules.push(Stmt::MultilineComment(comment)); rules.push(Stmt::MultilineComment(comment));
} }
TokenKind::AtRule(_) => {self.eat_at_rule();}, TokenKind::AtRule(_) => {
self.eat_at_rule();
}
_ => { _ => {
if let Some(Token { pos, .. }) = self.lexer.next() { if let Some(Token { pos, .. }) = self.lexer.next() {
self.error(pos.clone(), "unexpected toplevel token") self.error(pos.clone(), "unexpected toplevel token")
@ -258,7 +278,7 @@ impl<'a> StyleSheetParser<'a> {
fn eat_mixin(&mut self) { fn eat_mixin(&mut self) {
let Token { pos, .. } = self.lexer.next().unwrap(); let Token { pos, .. } = self.lexer.next().unwrap();
self.devour_whitespace(); devour_whitespace(&mut self.lexer);
let name = if let Some(Token { let name = if let Some(Token {
kind: TokenKind::Ident(s), kind: TokenKind::Ident(s),
.. ..
@ -268,7 +288,7 @@ impl<'a> StyleSheetParser<'a> {
} else { } else {
self.error(pos, "expected identifier after mixin declaration") self.error(pos, "expected identifier after mixin declaration")
}; };
self.devour_whitespace(); devour_whitespace(&mut self.lexer);
let args = match self.lexer.next() { let args = match self.lexer.next() {
Some(Token { Some(Token {
kind: TokenKind::Symbol(Symbol::OpenParen), kind: TokenKind::Symbol(Symbol::OpenParen),
@ -304,7 +324,7 @@ impl<'a> StyleSheetParser<'a> {
{ {
match rule { match rule {
AtRule::Error => { AtRule::Error => {
self.devour_whitespace(); devour_whitespace(&mut self.lexer);
let message = self let message = self
.lexer .lexer
.by_ref() .by_ref()
@ -314,7 +334,7 @@ impl<'a> StyleSheetParser<'a> {
self.error(pos, &message); self.error(pos, &message);
} }
AtRule::Warn => { AtRule::Warn => {
self.devour_whitespace(); devour_whitespace(&mut self.lexer);
let message = self let message = self
.lexer .lexer
.by_ref() .by_ref()
@ -324,7 +344,7 @@ impl<'a> StyleSheetParser<'a> {
self.warn(pos, &message); self.warn(pos, &message);
} }
AtRule::Debug => { AtRule::Debug => {
self.devour_whitespace(); devour_whitespace(&mut self.lexer);
let message = self let message = self
.lexer .lexer
.by_ref() .by_ref()
@ -342,7 +362,7 @@ impl<'a> StyleSheetParser<'a> {
} }
fn eat_include(&mut self) -> Expr { fn eat_include(&mut self) -> Expr {
self.devour_whitespace(); devour_whitespace(&mut self.lexer);
let Token { kind, pos } = self.lexer.next().unwrap(); let Token { kind, pos } = self.lexer.next().unwrap();
let name = if let TokenKind::Ident(s) = kind { let name = if let TokenKind::Ident(s) = kind {
s s
@ -350,11 +370,17 @@ impl<'a> StyleSheetParser<'a> {
self.error(pos, "expected identifier") self.error(pos, "expected identifier")
}; };
self.devour_whitespace(); devour_whitespace(&mut self.lexer);
match self.lexer.next() { match self.lexer.next() {
Some(Token { kind: TokenKind::Symbol(Symbol::SemiColon), .. }) => {}, Some(Token {
Some(Token { kind: TokenKind::Symbol(Symbol::OpenParen), .. }) => {}, kind: TokenKind::Symbol(Symbol::SemiColon),
..
}) => {}
Some(Token {
kind: TokenKind::Symbol(Symbol::OpenParen),
..
}) => {}
Some(Token { pos, .. }) => self.error(pos, "expected `(` or `;`"), Some(Token { pos, .. }) => self.error(pos, "expected `(` or `;`"),
None => self.error(pos, "unexpected EOF"), None => self.error(pos, "unexpected EOF"),
} }
@ -365,12 +391,12 @@ impl<'a> StyleSheetParser<'a> {
self.error(pos, "expected identifier") self.error(pos, "expected identifier")
}; };
let styles = mixin.eval(); let styles = mixin.eval();
self.devour_whitespace(); devour_whitespace(&mut self.lexer);
Expr::Styles(styles) Expr::Styles(styles)
} }
fn eat_variable_value(&mut self) -> Vec<Token> { fn eat_variable_value(&mut self) -> Vec<Token> {
self.devour_whitespace(); devour_whitespace(&mut self.lexer);
let iter1 = self let iter1 = self
.lexer .lexer
.by_ref() .by_ref()
@ -436,14 +462,15 @@ impl<'a> StyleSheetParser<'a> {
let mut values = Vec::with_capacity(5); let mut values = Vec::with_capacity(5);
while let Some(tok) = self.lexer.peek() { while let Some(tok) = self.lexer.peek() {
match &tok.kind { match &tok.kind {
TokenKind::Symbol(Symbol::SemiColon) | TokenKind::Symbol(Symbol::CloseCurlyBrace) => { TokenKind::Symbol(Symbol::SemiColon)
| TokenKind::Symbol(Symbol::CloseCurlyBrace) => {
self.lexer.next(); self.lexer.next();
self.devour_whitespace(); devour_whitespace(&mut self.lexer);
return Ok(Expr::Style(Style::from_tokens(&values, scope)?)); return Ok(Expr::Style(Style::from_tokens(&values, scope)?));
} }
TokenKind::Symbol(Symbol::OpenCurlyBrace) => { TokenKind::Symbol(Symbol::OpenCurlyBrace) => {
self.lexer.next(); self.lexer.next();
self.devour_whitespace(); devour_whitespace(&mut self.lexer);
return Ok(Expr::Selector(Selector::from_tokens( return Ok(Expr::Selector(Selector::from_tokens(
values.iter().peekable(), values.iter().peekable(),
super_selector, super_selector,
@ -464,7 +491,7 @@ impl<'a> StyleSheetParser<'a> {
.kind .kind
{ {
self.lexer.next(); self.lexer.next();
self.devour_whitespace(); devour_whitespace(&mut self.lexer);
return Ok(Expr::VariableDecl(name, self.eat_variable_value())); return Ok(Expr::VariableDecl(name, self.eat_variable_value()));
} else { } else {
values.push(Token { values.push(Token {
@ -480,7 +507,7 @@ impl<'a> StyleSheetParser<'a> {
} else { } else {
unsafe { std::hint::unreachable_unchecked() } unsafe { std::hint::unreachable_unchecked() }
}; };
self.devour_whitespace(); devour_whitespace(&mut self.lexer);
if values.is_empty() { if values.is_empty() {
return Ok(Expr::MultilineComment(s.clone())); return Ok(Expr::MultilineComment(s.clone()));
} else { } else {
@ -491,7 +518,7 @@ impl<'a> StyleSheetParser<'a> {
if let Some(a) = self.eat_at_rule() { if let Some(a) = self.eat_at_rule() {
return Ok(a); return Ok(a);
} }
}, }
TokenKind::Interpolation => { TokenKind::Interpolation => {
while let Some(tok) = self.lexer.next() { while let Some(tok) = self.lexer.next() {
if tok.kind == TokenKind::Symbol(Symbol::CloseCurlyBrace) { if tok.kind == TokenKind::Symbol(Symbol::CloseCurlyBrace) {
@ -512,17 +539,6 @@ impl<'a> StyleSheetParser<'a> {
} }
Err(()) Err(())
} }
fn devour_whitespace(&mut self) {
while let Some(tok) = self.lexer.peek() {
match tok.kind {
TokenKind::Whitespace(_) => {
self.lexer.next();
}
_ => break,
}
}
}
} }
/// Functions that print to stdout or stderr /// Functions that print to stdout or stderr

View File

@ -1,4 +1,5 @@
use crate::common::{Scope, Symbol}; use crate::common::{Scope, Symbol};
use crate::utils::{devour_whitespace, IsWhitespace};
use crate::{Token, TokenKind}; use crate::{Token, TokenKind};
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use std::iter::Peekable; use std::iter::Peekable;
@ -8,28 +9,6 @@ use std::string::ToString;
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct Selector(pub Vec<SelectorKind>); pub struct Selector(pub Vec<SelectorKind>);
fn devour_whitespace(i: &mut Peekable<Iter<SelectorKind>>) -> bool {
let mut found_whitespace = false;
while let Some(SelectorKind::Whitespace) = i.peek() {
i.next();
found_whitespace = true;
}
found_whitespace
}
fn devour_whitespace_from_tokens(i: &mut Peekable<Iter<Token>>) -> bool {
let mut found_whitespace = false;
while let Some(Token {
kind: TokenKind::Whitespace(_),
..
}) = i.peek()
{
i.next();
found_whitespace = true;
}
found_whitespace
}
impl Display for Selector { impl Display for Selector {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut iter = self.0.iter().peekable(); let mut iter = self.0.iter().peekable();
@ -100,6 +79,18 @@ pub enum SelectorKind {
Several(Vec<SelectorKind>), Several(Vec<SelectorKind>),
} }
impl IsWhitespace for SelectorKind {
fn is_whitespace(&self) -> bool {
self == &Self::Whitespace
}
}
impl IsWhitespace for &SelectorKind {
fn is_whitespace(&self) -> bool {
self == &&SelectorKind::Whitespace
}
}
impl Display for SelectorKind { impl Display for SelectorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
@ -214,7 +205,7 @@ impl<'a> SelectorParser<'a> {
&mut self, &mut self,
toks: &mut Peekable<Iter<'_, Token>>, toks: &mut Peekable<Iter<'_, Token>>,
) -> Option<SelectorKind> { ) -> Option<SelectorKind> {
if devour_whitespace_from_tokens(toks) { if devour_whitespace(toks) {
if let Some(&&Token { if let Some(&&Token {
kind: TokenKind::Symbol(Symbol::Comma), kind: TokenKind::Symbol(Symbol::Comma),
.. ..
@ -329,7 +320,7 @@ impl<'a> SelectorParser<'a> {
} }
fn consume_selector(&mut self) -> Option<SelectorKind> { fn consume_selector(&mut self) -> Option<SelectorKind> {
if self.devour_whitespace() { if devour_whitespace(&mut self.tokens) {
if let Some(&&Token { if let Some(&&Token {
kind: TokenKind::Symbol(Symbol::Comma), kind: TokenKind::Symbol(Symbol::Comma),
.. ..
@ -359,20 +350,6 @@ impl<'a> SelectorParser<'a> {
} }
None None
} }
fn devour_whitespace(&mut self) -> bool {
let mut found_whitespace = false;
while let Some(tok) = self.tokens.peek() {
match tok.kind {
TokenKind::Whitespace(_) => {
self.tokens.next();
found_whitespace = true;
}
_ => break,
}
}
found_whitespace
}
} }
impl Selector { impl Selector {

View File

@ -82,7 +82,9 @@ impl<'a> StyleParser<'a> {
while let Some(Token { kind, .. }) = self.tokens.next() { while let Some(Token { kind, .. }) = self.tokens.next() {
match &kind { match &kind {
TokenKind::Symbol(Symbol::CloseCurlyBrace) => break, TokenKind::Symbol(Symbol::CloseCurlyBrace) => break,
TokenKind::Symbol(Symbol::OpenCurlyBrace) => todo!("invalid character in interpolation"), TokenKind::Symbol(Symbol::OpenCurlyBrace) => {
todo!("invalid character in interpolation")
}
TokenKind::Variable(_) => val.push_str(&self.deref_variable(kind)), TokenKind::Variable(_) => val.push_str(&self.deref_variable(kind)),
_ => val.push_str(&kind.to_string()), _ => val.push_str(&kind.to_string()),
} }

18
src/utils.rs Normal file
View File

@ -0,0 +1,18 @@
use std::iter::Iterator;
use std::iter::Peekable;
pub trait IsWhitespace {
fn is_whitespace(&self) -> bool;
}
pub fn devour_whitespace<I: Iterator<Item = W>, W: IsWhitespace>(s: &mut Peekable<I>) -> bool {
let mut found_whitespace = false;
while let Some(w) = s.peek() {
if !w.is_whitespace() {
break;
}
found_whitespace = true;
s.next();
}
found_whitespace
}