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

View File

@ -1,4 +1,5 @@
use crate::common::{Scope, Symbol};
use crate::utils::{devour_whitespace, IsWhitespace};
use crate::{Token, TokenKind};
use std::fmt::{self, Display};
use std::iter::Peekable;
@ -8,28 +9,6 @@ use std::string::ToString;
#[derive(Clone, Debug, Eq, PartialEq)]
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 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut iter = self.0.iter().peekable();
@ -100,6 +79,18 @@ pub enum 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 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
@ -214,7 +205,7 @@ impl<'a> SelectorParser<'a> {
&mut self,
toks: &mut Peekable<Iter<'_, Token>>,
) -> Option<SelectorKind> {
if devour_whitespace_from_tokens(toks) {
if devour_whitespace(toks) {
if let Some(&&Token {
kind: TokenKind::Symbol(Symbol::Comma),
..
@ -329,7 +320,7 @@ impl<'a> SelectorParser<'a> {
}
fn consume_selector(&mut self) -> Option<SelectorKind> {
if self.devour_whitespace() {
if devour_whitespace(&mut self.tokens) {
if let Some(&&Token {
kind: TokenKind::Symbol(Symbol::Comma),
..
@ -359,20 +350,6 @@ impl<'a> SelectorParser<'a> {
}
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 {

View File

@ -82,7 +82,9 @@ impl<'a> StyleParser<'a> {
while let Some(Token { kind, .. }) = self.tokens.next() {
match &kind {
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)),
_ => 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
}