tl/queryselector/
parser.rs1#[cfg(not(feature = "std"))]
2use crate::ParseError;
3use crate::{stream::Stream, util};
4
5use super::Selector;
6
7pub struct Parser<'a> {
9 stream: Stream<'a, u8>,
10}
11
12impl<'a> Parser<'a> {
13 pub fn new(input: &'a [u8]) -> Self {
15 Self {
16 stream: Stream::new(input),
17 }
18 }
19
20 fn skip_whitespaces(&mut self) -> bool {
21 let has_whitespace = self.stream.expect_and_skip_cond(b' ');
22 while !self.stream.is_eof() {
23 if self.stream.expect_and_skip(b' ').is_none() {
24 break;
25 }
26 }
27 has_whitespace
28 }
29
30 fn read_identifier(&mut self) -> &'a [u8] {
31 let start = self.stream.idx;
32
33 while !self.stream.is_eof() {
34 let is_ident = self.stream.current().copied().is_some_and(util::is_ident);
35 if !is_ident {
36 break;
37 } else {
38 self.stream.advance();
39 }
40 }
41
42 self.stream.slice(start, self.stream.idx)
43 }
44
45 #[cfg(feature = "std")]
46 fn parse_combinator(&mut self, left: Selector<'a>) -> Option<Selector<'a>> {
47 let has_whitespaces = self.skip_whitespaces();
48
49 let tok = if let Some(tok) = self.stream.current_cpy() {
50 tok
51 } else {
52 return Some(left);
53 };
54
55 let combinator = match tok {
56 b',' => {
57 self.stream.advance();
58 let right = self.selector()?;
59 Selector::Or(Box::new(left), Box::new(right))
60 }
61 b'>' => {
62 self.stream.advance();
63 let right = self.selector()?;
64 Selector::Parent(Box::new(left), Box::new(right))
65 }
66 _ if has_whitespaces => {
67 let right = self.selector()?;
68 Selector::Descendant(Box::new(left), Box::new(right))
69 }
70 _ if !has_whitespaces => {
71 let right = self.selector()?;
72 Selector::And(Box::new(left), Box::new(right))
73 }
74 _ => unreachable!(),
75 };
76
77 Some(combinator)
78 }
79
80 #[cfg(not(feature = "std"))]
81 fn parse_combinator<const MAX_SELECTOR_NODES: usize>(
82 &mut self,
83 left: Selector<'a, MAX_SELECTOR_NODES>,
84 ) -> Result<Selector<'a, MAX_SELECTOR_NODES>, ParseError> {
85 let has_whitespaces = self.skip_whitespaces();
86 if self.stream.current_cpy().is_none() {
87 return Ok(left);
88 }
89 if has_whitespaces || matches!(self.stream.current_cpy(), Some(b',' | b'>')) {
90 return Err(ParseError::SelectorCapacityExceeded);
91 }
92 Err(ParseError::SelectorCapacityExceeded)
93 }
94
95 fn parse_attribute<const MAX_SELECTOR_NODES: usize>(
96 &mut self,
97 ) -> Option<Selector<'a, MAX_SELECTOR_NODES>> {
98 let attribute = self.read_identifier();
99 let ty = match self.stream.current_cpy() {
100 Some(b']') => {
101 self.stream.advance();
102 Selector::Attribute(attribute)
103 }
104 Some(b'=') => {
105 self.stream.advance();
106 let quote = self.stream.expect_oneof_and_skip(b"\"'");
107 let value = self.read_identifier();
108 if let Some(quote) = quote {
109 self.stream.expect_and_skip(quote)?;
111 }
112 self.stream.expect_and_skip(b']')?;
113 Selector::AttributeValue(attribute, value)
114 }
115 Some(c @ b'~' | c @ b'^' | c @ b'$' | c @ b'*') => {
116 self.stream.advance();
117 self.stream.expect_and_skip(b'=')?;
118 let quote = self.stream.expect_oneof_and_skip(b"\"'");
119 let value = self.read_identifier();
120 if let Some(quote) = quote {
121 self.stream.expect_and_skip(quote)?;
123 }
124 self.stream.expect_and_skip(b']')?;
125 match c {
126 b'~' => Selector::AttributeValueWhitespacedContains(attribute, value),
127 b'^' => Selector::AttributeValueStartsWith(attribute, value),
128 b'$' => Selector::AttributeValueEndsWith(attribute, value),
129 b'*' => Selector::AttributeValueSubstring(attribute, value),
130 _ => unreachable!(),
131 }
132 }
133 _ => return None,
134 };
135 Some(ty)
136 }
137
138 #[cfg(feature = "std")]
140 pub fn selector(&mut self) -> Option<Selector<'a>> {
141 self.skip_whitespaces();
142 let tok = self.stream.current_cpy()?;
143
144 let left = match tok {
145 b'#' => {
146 self.stream.advance();
147 let id = self.read_identifier();
148 Selector::Id(id)
149 }
150 b'.' => {
151 self.stream.advance();
152 let class = self.read_identifier();
153 Selector::Class(class)
154 }
155 b'*' => {
156 self.stream.advance();
157 Selector::All
158 }
159 b'[' => {
160 self.stream.advance();
161 self.parse_attribute::<0>()?
162 }
163 _ if util::is_ident(tok) => {
164 let tag = self.read_identifier();
165 Selector::Tag(tag)
166 }
167 _ => return None,
168 };
169
170 self.parse_combinator(left)
171 }
172
173 #[cfg(not(feature = "std"))]
175 pub fn selector<const MAX_SELECTOR_NODES: usize>(
176 &mut self,
177 ) -> Result<Selector<'a, MAX_SELECTOR_NODES>, ParseError> {
178 self.skip_whitespaces();
179 let tok = self
180 .stream
181 .current_cpy()
182 .ok_or(ParseError::SelectorCapacityExceeded)?;
183
184 let left = match tok {
185 b'#' => {
186 self.stream.advance();
187 let id = self.read_identifier();
188 Selector::Id(id)
189 }
190 b'.' => {
191 self.stream.advance();
192 let class = self.read_identifier();
193 Selector::Class(class)
194 }
195 b'*' => {
196 self.stream.advance();
197 Selector::All
198 }
199 b'[' => {
200 self.stream.advance();
201 self.parse_attribute::<MAX_SELECTOR_NODES>()
202 .ok_or(ParseError::SelectorCapacityExceeded)?
203 }
204 _ if util::is_ident(tok) => {
205 let tag = self.read_identifier();
206 Selector::Tag(tag)
207 }
208 _ => return Err(ParseError::SelectorCapacityExceeded),
209 };
210
211 self.parse_combinator(left)
212 }
213}