css_parse/traits/
selectors.rs1use crate::{Cursor, Diagnostic, Kind, KindSet, Parse, Parser, Peek, Result};
2use bumpalo::collections::Vec;
3
4pub trait CompoundSelector<'a>: Sized + Parse<'a> {
5 type SelectorComponent: Parse<'a> + SelectorComponent<'a>;
11
12 fn parse_compound_selector_part<I>(p: &mut Parser<'a, I>) -> Result<Option<Self::SelectorComponent>>
15 where
16 I: Iterator<Item = Cursor> + Clone,
17 {
18 let skip = p.set_skip(KindSet::TRIVIA);
20 let next = p.peek_n(1);
21 p.set_skip(skip);
22 if next == Kind::Eof || next == KindSet::LEFT_CURLY_RIGHT_PAREN_COMMA_OR_SEMICOLON {
23 return Ok(None);
24 }
25 p.parse::<Self::SelectorComponent>().map(Some)
26 }
27
28 fn parse_compound_selector<I>(p: &mut Parser<'a, I>) -> Result<Vec<'a, Self::SelectorComponent>>
29 where
30 I: Iterator<Item = Cursor> + Clone,
31 {
32 let mut components = Vec::new_in(p.bump());
33 p.consume_trivia();
35 while let Some(component) = Self::parse_compound_selector_part(p)? {
36 components.push(component);
37 }
38 Ok(components)
39 }
40}
41
42pub trait SelectorComponent<'a>: Sized {
43 type Wildcard: Peek<'a> + Parse<'a>;
44 type Id: Peek<'a> + Parse<'a>;
45 type Type: Peek<'a> + Parse<'a>;
46 type PseudoClass: Parse<'a>;
47 type PseudoElement: Parse<'a>;
48 type LegacyPseudoElement: Peek<'a> + Parse<'a>;
49 type Class: Parse<'a>;
50 type NsType: Parse<'a>;
51 type Combinator: Parse<'a>;
52 type Attribute: Parse<'a>;
53 type FunctionalPseudoClass: Parse<'a>;
54 type FunctionalPseudoElement: Parse<'a>;
55
56 fn build_wildcard(node: Self::Wildcard) -> Self;
57 fn build_id(node: Self::Id) -> Self;
58 fn build_class(node: Self::Class) -> Self;
59 fn build_type(node: Self::Type) -> Self;
60 fn build_pseudo_class(node: Self::PseudoClass) -> Self;
61 fn build_pseudo_element(node: Self::PseudoElement) -> Self;
62 fn build_legacy_pseudo_element(node: Self::LegacyPseudoElement) -> Self;
63 fn build_ns_type(node: Self::NsType) -> Self;
64 fn build_combinator(node: Self::Combinator) -> Self;
65 fn build_attribute(node: Self::Attribute) -> Self;
66 fn build_functional_pseudo_class(node: Self::FunctionalPseudoClass) -> Self;
67 fn build_functional_pseudo_element(node: Self::FunctionalPseudoElement) -> Self;
68
69 fn parse_selector_component<I>(p: &mut Parser<'a, I>) -> Result<Self>
70 where
71 I: Iterator<Item = Cursor> + Clone,
72 {
73 let skip = p.set_skip(KindSet::COMMENTS);
74 let c = p.peek_n(1);
75 let t = c.token();
76 match t.kind() {
77 Kind::Ident => match p.peek_n(2) {
78 t if t == '|' => {
79 p.set_skip(skip);
80 p.parse::<Self::NsType>().map(Self::build_ns_type)
81 }
82 _ => {
83 p.set_skip(skip);
84 if Self::Type::peek(p, c) {
85 Ok(Self::build_type(p.parse::<Self::Type>()?))
86 } else {
87 Err(Diagnostic::new(c, Diagnostic::unexpected_tag))?
88 }
89 }
90 },
91 Kind::Hash if t.hash_is_id_like() => {
92 p.set_skip(skip);
93 if Self::Id::peek(p, c) {
94 Ok(Self::build_id(p.parse::<Self::Id>()?))
95 } else {
96 Err(Diagnostic::new(c, Diagnostic::unexpected_id))?
97 }
98 }
99 Kind::LeftSquare => {
100 p.set_skip(skip);
101 p.parse::<Self::Attribute>().map(Self::build_attribute)
102 }
103 Kind::Delim => match t.char().unwrap() {
104 '.' => {
105 let c = p.peek_n(2);
106 p.set_skip(skip);
107 match c.token().kind() {
108 Kind::Ident => p.parse::<Self::Class>().map(Self::build_class),
109 _ => Err(Diagnostic::new(c, Diagnostic::expected_ident))?,
110 }
111 }
112 '*' => {
113 let t = p.peek_n(2);
114 p.set_skip(skip);
115 if t == '|' {
116 p.parse::<Self::NsType>().map(Self::build_ns_type)
117 } else {
118 Ok(Self::build_wildcard(p.parse::<Self::Wildcard>()?))
119 }
120 }
121 _ => {
122 p.set_skip(skip);
123 let value = p.parse::<Self::Combinator>().map(Self::build_combinator);
124 p.set_skip(KindSet::WHITESPACE);
125 p.consume_trivia_as_leading();
126 p.set_skip(skip);
127 value
128 }
129 },
130 Kind::Colon => {
131 let c2 = p.peek_n(2);
132 match c2.token().kind() {
133 Kind::Colon => {
134 let c3 = p.peek_n(3);
135 p.set_skip(skip);
136 match c3.token().kind() {
137 Kind::Ident => p.parse::<Self::PseudoElement>().map(Self::build_pseudo_element),
138 Kind::Function => {
139 p.parse::<Self::FunctionalPseudoElement>().map(Self::build_functional_pseudo_element)
140 }
141 _ => Err(Diagnostic::new(c3, Diagnostic::unexpected))?,
142 }
143 }
144 Kind::Ident => {
145 p.set_skip(skip);
146 if Self::LegacyPseudoElement::peek(p, c) {
147 p.parse::<Self::LegacyPseudoElement>().map(Self::build_legacy_pseudo_element)
148 } else {
149 p.parse::<Self::PseudoClass>().map(Self::build_pseudo_class)
150 }
151 }
152 Kind::Function => {
153 p.set_skip(skip);
154 p.parse::<Self::FunctionalPseudoClass>().map(Self::build_functional_pseudo_class)
155 }
156 _ => Err(Diagnostic::new(c2, Diagnostic::unexpected))?,
157 }
158 }
159 _ => {
160 if t.kind() == Kind::Whitespace {
165 p.set_skip(KindSet::TRIVIA);
166 let next = p.peek_n(1);
167 let next_is_explicit_combinator = match next.token().kind() {
168 Kind::Delim => matches!(next.token().char(), Some('>' | '+' | '~' | '|' | '&')),
169 _ => false,
170 };
171 if next_is_explicit_combinator {
172 p.consume_trivia_as_leading();
173 p.set_skip(skip);
174 return Self::parse_selector_component(p);
175 }
176 p.set_skip(skip);
177 }
178 let value = p.parse::<Self::Combinator>().map(Self::build_combinator);
179 p.set_skip(KindSet::WHITESPACE);
182 p.consume_trivia_as_leading();
183 p.set_skip(skip);
184 value
185 }
186 }
187 }
188}