diff --git a/src/css.rs b/src/css.rs index 51bc488..87247ab 100644 --- a/src/css.rs +++ b/src/css.rs @@ -75,7 +75,7 @@ impl Css { } else { self.blocks[self.idx + self.inner_rulesets - 1].push_style(s) } - }, + } Stmt::MultilineComment(s) => { if self.idx == 0 { self.blocks.push(Toplevel::MultilineComment(s)); diff --git a/src/imports.rs b/src/imports.rs index 6a49091..f112f43 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -3,11 +3,7 @@ use crate::StyleSheetParser; pub struct Importer {} impl Importer { - pub fn import(path: &str) { + pub fn import(path: &str) {} - } - - fn find_files() { - - } -} \ No newline at end of file + fn find_files() {} +} diff --git a/src/lexer.rs b/src/lexer.rs index a228106..e077d79 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -40,6 +40,8 @@ impl<'a> Iterator for Lexer<'a> { ',' => symbol!(self, Comma), '.' => symbol!(self, Period), ';' => symbol!(self, SemiColon), + '(' => symbol!(self, OpenParen), + ')' => symbol!(self, CloseParen), '+' => symbol!(self, Plus), '~' => symbol!(self, Tilde), '\'' => symbol!(self, SingleQuote), diff --git a/src/main.rs b/src/main.rs index de40c6e..805442c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -538,6 +538,31 @@ mod test_css { selector_pseudo_el_descendant, ":pseudo a {\n color: red;\n}\n" ); + test!( + selector_pseudo_paren_comma, + ":pseudo(a, b, c) {\n color: red;\n}\n" + ); + test!( + selector_pseudo_paren_space, + ":pseudo(a b c) {\n color: red;\n}\n" + ); + test!( + selector_el_pseudo_paren_and, + "a:pseudo(a, b, c) {\n color: red;\n}\n" + ); + test!( + selector_el_pseudo_paren_descendant, + "a :pseudo(a, b, c) {\n color: red;\n}\n" + ); + test!( + selector_pseudo_paren_el_descendant, + ":pseudo(a, b, c) a {\n color: red;\n}\n" + ); + test!( + selector_pseudo_paren_el_nested, + "a {\n :pseudo(a, b, c) {\n color: red;\n }\n}\n", + "a :pseudo(a, b, c) {\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"); diff --git a/src/selector.rs b/src/selector.rs index 0f17fa2..f0bf27d 100644 --- a/src/selector.rs +++ b/src/selector.rs @@ -3,6 +3,7 @@ use crate::{Token, TokenKind}; use std::fmt::{self, Display}; use std::iter::Peekable; use std::slice::Iter; +use std::string::ToString; #[derive(Clone, Debug, Eq, PartialEq)] pub struct Selector(pub Vec); @@ -25,6 +26,7 @@ impl Display for Selector { SelectorKind::Whitespace => continue, SelectorKind::Attribute(_) | SelectorKind::Pseudo(_) + | SelectorKind::PseudoParen(..) | SelectorKind::Class | SelectorKind::Id | SelectorKind::Universal @@ -34,6 +36,7 @@ impl Display for Selector { match iter.peek() { Some(SelectorKind::Attribute(_)) | Some(SelectorKind::Pseudo(_)) + | Some(SelectorKind::PseudoParen(..)) | Some(SelectorKind::Class) | Some(SelectorKind::Id) | Some(SelectorKind::Universal) @@ -73,6 +76,8 @@ pub enum SelectorKind { Attribute(Attribute), /// Pseudo selector: `:hover` Pseudo(String), + /// Pseudo selector with additional parens: `:any(h1, h2, h3, h4, h5, h6)` + PseudoParen(String, Vec), /// Use the super selector: `&.red` Super, /// Used to signify no selector (when there is no super_selector of a rule) @@ -94,6 +99,12 @@ impl Display for SelectorKind { SelectorKind::Preceding => write!(f, " ~ "), SelectorKind::Attribute(attr) => write!(f, "{}", attr), SelectorKind::Pseudo(s) => write!(f, ":{}", s), + SelectorKind::PseudoParen(s, toks) => write!( + f, + ":{}({})", + s, + toks.iter().map(ToString::to_string).collect::() + ), SelectorKind::Super | SelectorKind::None => write!(f, ""), } } @@ -177,6 +188,36 @@ impl<'a> SelectorParser<'a> { Selector(v) } + fn consume_pseudo_selector(&mut self) -> Option { + if let Some(Token { + kind: TokenKind::Ident(s), + .. + }) = self.tokens.next() + { + if let Some(Token { + kind: TokenKind::Symbol(Symbol::OpenParen), + .. + }) = self.tokens.peek() + { + self.tokens.next(); + let mut toks = Vec::new(); + while let Some(Token { kind, .. }) = self.tokens.peek() { + if kind == &TokenKind::Symbol(Symbol::CloseParen) { + break; + } + let tok = self.tokens.next().unwrap(); + toks.push(tok.kind.clone()); + } + self.tokens.next(); + Some(SelectorKind::PseudoParen(s.clone(), toks)) + } else { + Some(SelectorKind::Pseudo(s.clone())) + } + } else { + todo!("expected ident after `:` in selector") + } + } + fn consume_selector(&mut self) -> Option { if self.devour_whitespace() { if let Some(&&Token { @@ -194,17 +235,7 @@ impl<'a> SelectorParser<'a> { TokenKind::Ident(tok) => SelectorKind::Element(tok.clone()), TokenKind::Symbol(Symbol::Period) => SelectorKind::Class, TokenKind::Symbol(Symbol::Hash) => SelectorKind::Id, - TokenKind::Symbol(Symbol::Colon) => { - if let Some(Token { - kind: TokenKind::Ident(s), - .. - }) = self.tokens.next() - { - SelectorKind::Pseudo(s.clone()) - } else { - todo!("expected ident after `:` in selector") - } - } + TokenKind::Symbol(Symbol::Colon) => return self.consume_pseudo_selector(), TokenKind::Symbol(Symbol::Comma) => SelectorKind::Multiple, TokenKind::Symbol(Symbol::Gt) => SelectorKind::ImmediateChild, TokenKind::Symbol(Symbol::Plus) => SelectorKind::Following,