Refactor various devour_whitespace methods into single util function
This commit is contained in:
parent
2439579d20
commit
33843dd2ac
78
src/main.rs
78
src/main.rs
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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
18
src/utils.rs
Normal 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
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user