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<I>(p: &mut Parser<'a, I>) -> Result<Vec<'a, Self::SelectorComponent>>
13 where
14 I: Iterator<Item = Cursor> + Clone,
15 {
16 let mut components = Vec::new_in(p.bump());
17 p.consume_trivia();
19 loop {
20 if p.at_end() || p.peek_n(1) == KindSet::LEFT_CURLY_RIGHT_PAREN_COMMA_OR_SEMICOLON {
22 break;
23 }
24 components.push(p.parse::<Self::SelectorComponent>()?);
25 }
26 Ok(components)
27 }
28}
29
30pub trait SelectorComponent<'a>: Sized {
31 type Wildcard: Peek<'a> + Parse<'a>;
32 type Id: Peek<'a> + Parse<'a>;
33 type Type: Peek<'a> + Parse<'a>;
34 type PseudoClass: Parse<'a>;
35 type PseudoElement: Parse<'a>;
36 type LegacyPseudoElement: Peek<'a> + Parse<'a>;
37 type Class: Parse<'a>;
38 type NsType: Parse<'a>;
39 type Combinator: Parse<'a>;
40 type Attribute: Parse<'a>;
41 type FunctionalPseudoClass: Parse<'a>;
42 type FunctionalPseudoElement: Parse<'a>;
43
44 fn build_wildcard(node: Self::Wildcard) -> Self;
45 fn build_id(node: Self::Id) -> Self;
46 fn build_class(node: Self::Class) -> Self;
47 fn build_type(node: Self::Type) -> Self;
48 fn build_pseudo_class(node: Self::PseudoClass) -> Self;
49 fn build_pseudo_element(node: Self::PseudoElement) -> Self;
50 fn build_legacy_pseudo_element(node: Self::LegacyPseudoElement) -> Self;
51 fn build_ns_type(node: Self::NsType) -> Self;
52 fn build_combinator(node: Self::Combinator) -> Self;
53 fn build_attribute(node: Self::Attribute) -> Self;
54 fn build_functional_pseudo_class(node: Self::FunctionalPseudoClass) -> Self;
55 fn build_functional_pseudo_element(node: Self::FunctionalPseudoElement) -> Self;
56
57 fn parse_selector_component<I>(p: &mut Parser<'a, I>) -> Result<Self>
58 where
59 I: Iterator<Item = Cursor> + Clone,
60 {
61 let skip = p.set_skip(KindSet::COMMENTS);
62 let c = p.peek_n(1);
63 let t = c.token();
64 match t.kind() {
65 Kind::Ident => match p.peek_n(2) {
66 t if t == '|' => {
67 p.set_skip(skip);
68 p.parse::<Self::NsType>().map(Self::build_ns_type)
69 }
70 _ => {
71 p.set_skip(skip);
72 if Self::Type::peek(p, c) {
73 Ok(Self::build_type(p.parse::<Self::Type>()?))
74 } else {
75 Err(Diagnostic::new(c, Diagnostic::unexpected_tag))?
76 }
77 }
78 },
79 Kind::Hash if t.hash_is_id_like() => {
80 p.set_skip(skip);
81 if Self::Id::peek(p, c) {
82 Ok(Self::build_id(p.parse::<Self::Id>()?))
83 } else {
84 Err(Diagnostic::new(c, Diagnostic::unexpected_id))?
85 }
86 }
87 Kind::LeftSquare => {
88 p.set_skip(skip);
89 p.parse::<Self::Attribute>().map(Self::build_attribute)
90 }
91 Kind::Delim => match t.char().unwrap() {
92 '.' => {
93 let c = p.peek_n(2);
94 p.set_skip(skip);
95 match c.token().kind() {
96 Kind::Ident => p.parse::<Self::Class>().map(Self::build_class),
97 _ => Err(Diagnostic::new(c, Diagnostic::expected_ident))?,
98 }
99 }
100 '*' => {
101 let t = p.peek_n(2);
102 p.set_skip(skip);
103 if t == '|' {
104 p.parse::<Self::NsType>().map(Self::build_ns_type)
105 } else {
106 Ok(Self::build_wildcard(p.parse::<Self::Wildcard>()?))
107 }
108 }
109 _ => {
110 p.set_skip(skip);
111 p.parse::<Self::Combinator>().map(Self::build_combinator)
112 }
113 },
114 Kind::Colon => {
115 let c2 = p.peek_n(2);
116 match c2.token().kind() {
117 Kind::Colon => {
118 let c3 = p.peek_n(3);
119 p.set_skip(skip);
120 match c3.token().kind() {
121 Kind::Ident => p.parse::<Self::PseudoElement>().map(Self::build_pseudo_element),
122 Kind::Function => {
123 p.parse::<Self::FunctionalPseudoElement>().map(Self::build_functional_pseudo_element)
124 }
125 _ => Err(Diagnostic::new(c3, Diagnostic::unexpected))?,
126 }
127 }
128 Kind::Ident => {
129 p.set_skip(skip);
130 if Self::LegacyPseudoElement::peek(p, c) {
131 p.parse::<Self::LegacyPseudoElement>().map(Self::build_legacy_pseudo_element)
132 } else {
133 p.parse::<Self::PseudoClass>().map(Self::build_pseudo_class)
134 }
135 }
136 Kind::Function => {
137 p.set_skip(skip);
138 p.parse::<Self::FunctionalPseudoClass>().map(Self::build_functional_pseudo_class)
139 }
140 _ => Err(Diagnostic::new(c2, Diagnostic::unexpected))?,
141 }
142 }
143 _ => {
144 let value = p.parse::<Self::Combinator>().map(Self::build_combinator);
145 p.set_skip(KindSet::WHITESPACE);
148 p.consume_trivia();
149 p.set_skip(skip);
150 value
151 }
152 }
153 }
154}