1use crate::{
2 Cursor, Diagnostic, Feature, Kind, KindSet, ParserCheckpoint, ParserReturn, Result, SourceOffset, ToCursors,
3 traits::{Parse, Peek},
4};
5use bitmask_enum::bitmask;
6use bumpalo::{Bump, collections::Vec};
7use css_lexer::{AtomSet, DynAtomSet, SourceCursor};
8use std::mem;
9
10const BUFFER_LEN: usize = 12;
15const BUFFER_REFILL_INDEX: usize = BUFFER_LEN - 5;
19
20#[derive(Debug)]
21pub struct Parser<'a, I: Iterator<Item = Cursor> + Clone> {
22 pub(crate) source_text: &'a str,
23
24 pub(crate) cursor_iter: I,
25
26 #[allow(dead_code)]
27 pub(crate) features: Feature,
28
29 pub(crate) errors: Vec<'a, Diagnostic>,
30
31 pub(crate) trivia: Vec<'a, (Vec<'a, Cursor>, Cursor)>,
32
33 pub(crate) state: State,
34
35 pub(crate) bump: &'a Bump,
36
37 skip: KindSet,
38
39 stop: KindSet,
40
41 buffer: [Cursor; BUFFER_LEN],
42 buffer_index: usize,
43
44 #[cfg(debug_assertions)]
45 pub(crate) last_cursor: Option<Cursor>,
46}
47
48#[bitmask(u8)]
49#[bitmask_config(vec_debug)]
50#[derive(Default)]
51pub enum State {
52 Nested = 0b0000_0001,
53 DisallowRelativeSelector = 0b0000_0010,
55}
56
57#[inline]
58fn eof_cursor(len: usize) -> Cursor {
59 let eof_offset = css_lexer::SourceOffset(len as u32);
60 Cursor::new(eof_offset, css_lexer::Token::EOF)
61}
62
63impl<'a, I> Parser<'a, I>
64where
65 I: Iterator<Item = Cursor> + Clone,
66{
67 pub fn new(bump: &'a Bump, source_text: &'a str, mut cursor_iter: I) -> Self {
69 let eof_cursor = eof_cursor(source_text.len());
70 let mut buffer = [eof_cursor; BUFFER_LEN];
71 buffer.fill_with(|| cursor_iter.next().unwrap_or(eof_cursor));
72
73 Self {
74 source_text,
75 cursor_iter,
76 features: Feature::none(),
77 errors: Vec::new_in(bump),
78 trivia: Vec::new_in(bump),
79 state: State::none(),
80 skip: KindSet::TRIVIA,
81 stop: KindSet::NONE,
82 buffer,
83 buffer_index: 0,
84 bump,
85 #[cfg(debug_assertions)]
86 last_cursor: None,
87 }
88 }
89
90 pub fn with_features(mut self, features: Feature) -> Self {
91 self.features = features;
92 self
93 }
94
95 fn fill_buffer(&mut self, from: usize) {
96 self.buffer.copy_within(from..BUFFER_LEN, 0);
98 let eof = eof_cursor(self.source_text.len());
100 for i in BUFFER_LEN - from..BUFFER_LEN {
101 self.buffer[i] = self.cursor_iter.next().unwrap_or(eof);
102 }
103 self.buffer_index = 0;
104 }
105
106 #[inline]
107 pub fn bump(&self) -> &'a Bump {
108 self.bump
109 }
110
111 #[inline]
112 pub fn enabled(&self, other: Feature) -> bool {
113 self.features.contains(other)
114 }
115
116 #[inline]
117 pub fn is(&self, state: State) -> bool {
118 self.state.contains(state)
119 }
120
121 #[inline]
122 pub fn set_state(&mut self, state: State) -> State {
123 let old = self.state;
124 self.state = state;
125 old
126 }
127
128 #[inline]
129 pub fn set_skip(&mut self, skip: KindSet) -> KindSet {
130 let old = self.skip;
131 self.skip = skip;
132 old
133 }
134
135 #[inline]
136 pub fn set_stop(&mut self, stop: KindSet) -> KindSet {
137 let old = self.stop;
138 self.stop = stop;
139 old
140 }
141
142 pub fn parse_entirely<T: Parse<'a> + ToCursors>(&mut self) -> ParserReturn<'a, T> {
143 let output = match T::parse(self) {
144 Ok(output) => Some(output),
145 Err(error) => {
146 self.errors.push(error);
147 None
148 }
149 };
150 let remaining_non_trivia = !self.at_end() && self.peek_n(1) != Kind::Eof;
151 let at_end = self.peek_n_with_skip(1, KindSet::NONE) == Kind::Eof;
152
153 if !at_end {
154 let start = self.peek_n_with_skip(1, KindSet::NONE);
155 let mut end;
156 loop {
157 end = self.next();
158 if end == Kind::Eof {
159 break;
160 }
161 }
162 if remaining_non_trivia {
163 self.errors.push(Diagnostic::new(start, Diagnostic::expected_end).with_end_cursor(end));
164 }
165 }
166 let errors = mem::replace(&mut self.errors, Vec::new_in(self.bump));
167 let trivia = mem::replace(&mut self.trivia, Vec::new_in(self.bump));
168 ParserReturn::new(output, self.source_text, errors, trivia)
169 }
170
171 pub fn parse<T: Parse<'a>>(&mut self) -> Result<T> {
172 T::parse(self)
173 }
174
175 pub fn peek<T: Peek<'a>>(&self) -> bool {
176 T::peek(self, self.peek_n(1))
177 }
178
179 pub fn parse_if_peek<T: Peek<'a> + Parse<'a>>(&mut self) -> Result<Option<T>> {
180 if T::peek(self, self.peek_n(1)) { T::parse(self).map(Some) } else { Ok(None) }
181 }
182
183 pub fn try_parse<T: Parse<'a>>(&mut self) -> Result<T> {
184 T::try_parse(self)
185 }
186
187 pub fn try_parse_if_peek<T: Peek<'a> + Parse<'a>>(&mut self) -> Result<Option<T>> {
188 if T::peek(self, self.peek_n(1)) { T::try_parse(self).map(Some) } else { Ok(None) }
189 }
190
191 pub fn equals_atom(&self, c: Cursor, atom: &'static dyn DynAtomSet) -> bool {
192 let mut cursor_bits = c.atom_bits();
193 if cursor_bits == 0 {
194 if c != KindSet::ATOM_LIKE {
195 return false;
196 }
197 let source_cursor = self.to_source_cursor(c);
198 cursor_bits = atom.str_to_bits(&source_cursor.parse(self.bump));
199 }
200 cursor_bits == atom.bits()
201 }
202
203 pub fn to_atom<A: AtomSet + PartialEq>(&self, c: Cursor) -> A {
204 let bits = c.atom_bits();
205 if bits == 0 {
206 if c != KindSet::ATOM_LIKE {
207 return A::from_bits(0);
208 }
209 let source_cursor = self.to_source_cursor(c);
210 return A::from_str(&source_cursor.parse(self.bump));
211 }
212 #[cfg(debug_assertions)]
213 if c == KindSet::ATOM_LIKE && !((c == Kind::Ident || c == Kind::Function) && c.token().is_dashed_ident()) {
214 let source_cursor = self.to_source_cursor(c);
215 debug_assert!(
216 A::from_bits(bits) == A::from_str(&source_cursor.parse(self.bump)),
217 "{:?} -> {:?} != {:?} ({:?})",
218 c,
219 A::from_bits(bits),
220 A::from_str(&source_cursor.parse(self.bump)),
221 source_cursor.parse(self.bump)
222 );
223 }
224 A::from_bits(bits)
225 }
226
227 #[inline(always)]
228 pub fn offset(&self) -> SourceOffset {
229 self.buffer[self.buffer_index].offset()
230 }
231
232 #[inline(always)]
233 pub fn at_end(&self) -> bool {
234 self.buffer[self.buffer_index] == Kind::Eof
235 }
236
237 pub fn rewind(&mut self, checkpoint: ParserCheckpoint<I>) {
238 let ParserCheckpoint { iter, errors_pos, trivia_pos, buffer, buffer_index, skip, stop, state, .. } = checkpoint;
239
240 self.cursor_iter = iter;
241
242 self.errors.truncate(errors_pos as usize);
243 self.trivia.truncate(trivia_pos as usize);
244
245 self.buffer = buffer;
246 self.buffer_index = buffer_index;
247
248 self.skip = skip;
249 self.stop = stop;
250 self.state = state;
251
252 #[cfg(debug_assertions)]
253 {
254 self.last_cursor = None;
255 }
256 }
257
258 #[inline]
259 pub fn checkpoint(&self) -> ParserCheckpoint<I> {
260 ParserCheckpoint {
261 cursor: self.buffer[self.buffer_index],
262 errors_pos: self.errors.len() as u8,
263 trivia_pos: self.trivia.len() as u16,
264 iter: self.cursor_iter.clone(),
265 buffer: self.buffer,
266 buffer_index: self.buffer_index,
267 skip: self.skip,
268 stop: self.stop,
269 state: self.state,
270 }
271 }
272
273 #[inline]
274 pub fn next_is_stop(&self) -> bool {
275 for c in &self.buffer[self.buffer_index..BUFFER_LEN] {
276 if c != self.skip {
277 return c == self.stop;
278 }
279 }
280
281 let mut iter = self.cursor_iter.clone();
282 loop {
283 let Some(cursor) = iter.next() else {
284 return false;
285 };
286 if cursor != self.skip {
287 return cursor == self.stop;
288 }
289 }
290 }
291
292 #[inline]
293 pub(crate) fn peek_n_with_skip(&self, n: u8, skip: KindSet) -> Cursor {
294 let mut remaining = n;
295
296 for c in &self.buffer[self.buffer_index..BUFFER_LEN] {
297 if c == Kind::Eof {
298 return *c;
299 }
300 if c != skip {
301 remaining -= 1;
302 if remaining == 0 {
303 return *c;
304 }
305 }
306 }
307
308 let mut iter = self.cursor_iter.clone();
309 loop {
310 let Some(cursor) = iter.next() else {
311 return eof_cursor(self.source_text.len());
312 };
313 if cursor == Kind::Eof {
314 return cursor;
315 }
316 if cursor != skip {
317 remaining -= 1;
318 if remaining == 0 {
319 return cursor;
320 }
321 }
322 }
323 }
324
325 #[inline]
326 pub fn peek_n(&self, n: u8) -> Cursor {
327 self.peek_n_with_skip(n, self.skip)
328 }
329
330 #[inline]
331 pub fn peek_n_including_whitespace(&self, n: u8) -> Cursor {
332 self.peek_n_with_skip(n, self.skip.remove(Kind::Whitespace))
333 }
334
335 pub fn to_source_cursor(&self, cursor: Cursor) -> SourceCursor<'a> {
336 SourceCursor::from(cursor, cursor.str_slice(self.source_text))
337 }
338
339 pub fn consume_trivia(&mut self) -> Vec<'a, Cursor> {
340 let mut trivia = Vec::new_in(self.bump);
341 for i in self.buffer_index..BUFFER_LEN {
342 let c = self.buffer[i];
343 if c == Kind::Eof {
344 self.buffer_index = i;
345 return trivia;
346 } else if c == self.skip {
347 trivia.push(c)
348 } else {
349 self.buffer_index = i;
350 self.fill_buffer(i);
351 return trivia;
352 }
353 }
354
355 let eof = eof_cursor(self.source_text.len());
356 loop {
357 let Some(c) = self.cursor_iter.next() else {
358 self.buffer = [eof; BUFFER_LEN];
359 self.buffer_index = 0;
360 return trivia;
361 };
362 if c == Kind::Eof {
363 self.buffer = [eof; BUFFER_LEN];
364 self.buffer_index = 0;
365 return trivia;
366 } else if c == self.skip {
367 trivia.push(c)
368 } else {
369 self.buffer[0] = c;
370 for i in 1..BUFFER_LEN {
371 self.buffer[i] = self.cursor_iter.next().unwrap_or(eof);
372 }
373 self.buffer_index = 0;
374 return trivia;
375 }
376 }
377 }
378
379 pub fn consume_trivia_as_leading(&mut self) {
383 let trivia = self.consume_trivia();
384 if !trivia.is_empty() {
385 let next = self.peek_n(1);
387 self.trivia.push((trivia, next));
388 }
389 }
390
391 #[allow(clippy::should_implement_trait)]
392 pub fn next(&mut self) -> Cursor {
393 let mut pending_trivia = Vec::new_in(self.bump);
395
396 loop {
397 if self.buffer_index >= BUFFER_REFILL_INDEX {
398 self.fill_buffer(self.buffer_index);
399 }
400
401 for i in self.buffer_index..BUFFER_LEN {
402 let c = self.buffer[i];
403 if c == Kind::Eof {
404 self.buffer_index = i;
405 if !pending_trivia.is_empty() {
407 self.trivia.push((pending_trivia.clone(), c));
408 }
409 #[cfg(debug_assertions)]
410 {
411 self.last_cursor = None;
412 }
413 return c;
414 } else if c == self.skip {
415 pending_trivia.push(c);
416 } else {
417 self.buffer_index = i + 1;
418 if self.buffer_index >= BUFFER_REFILL_INDEX {
419 self.fill_buffer(self.buffer_index);
420 }
421 if !pending_trivia.is_empty() {
423 self.trivia.push((pending_trivia.clone(), c));
424 }
425 #[cfg(debug_assertions)]
426 {
427 if let Some(last_cursor) = self.last_cursor {
428 debug_assert!(last_cursor != c, "Detected a next loop, {c:?} was fetched twice");
429 }
430 self.last_cursor = Some(c);
431 }
432 return c;
433 }
434 }
435
436 self.fill_buffer(BUFFER_LEN);
438 }
439 }
440}
441
442#[test]
443fn test_filling_buffer_with_skip_tokens() {
444 let str = "/*x*//*x*//*x*//*x*//*x*//*x*//*x*//*x*//*x*//*x*//*x*/a";
445 let bump = bumpalo::Bump::default();
446 let lexer = css_lexer::Lexer::new(&css_lexer::EmptyAtomSet::ATOMS, str);
447 let mut p = Parser::new(&bump, str, lexer);
448 let c = p.next();
449 assert_eq!(c.token(), Kind::Ident);
450 let _ = p.at_end();
452 let _ = p.offset();
453}
454
455#[test]
456fn peek_and_next() {
457 let str = "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21";
458 let bump = bumpalo::Bump::default();
459 let lexer = css_lexer::Lexer::new(&css_lexer::EmptyAtomSet::ATOMS, &str);
460 let mut p = Parser::new(&bump, &str, lexer);
461 assert_eq!(p.at_end(), false);
462 assert_eq!(p.offset(), 0);
463 for n in 0..=1 {
464 let c = p.checkpoint();
465 for i in 0..=19 {
466 let c = p.peek_n(1);
467 assert_eq!(c.token(), Kind::Number);
468 assert_eq!(c.token().value(), i as f32);
469 let c = p.peek_n(2);
470 assert_eq!(c.token(), Kind::Number);
471 assert_eq!(c.token().value(), (i + 1) as f32);
472 let c = p.peek_n(3);
473 assert_eq!(c.token(), Kind::Number);
474 assert_eq!(c.token().value(), (i + 2) as f32);
475 let c = p.next();
476 assert_eq!(c.token().value(), i as f32);
477 let c = p.peek_n(1);
478 assert_eq!(c.token(), Kind::Number);
479 assert_eq!(c.token().value(), (i + 1) as f32);
480 }
481 if n == 0 {
482 p.rewind(c)
483 }
484 }
485 let c = p.next();
486 assert_eq!(c.token(), Kind::Number);
487 assert_eq!(c.token().value(), 20.0);
488 let c = p.next();
489 assert_eq!(c.token(), Kind::Number);
490 assert_eq!(c.token().value(), 21.0);
491 let c = p.next();
492 assert_eq!(c.token(), Kind::Eof);
493}
494
495#[test]
496fn peek_and_next_with_whitsespace() {
497 let str = "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21";
498 let bump = bumpalo::Bump::default();
499 let lexer = css_lexer::Lexer::new(&css_lexer::EmptyAtomSet::ATOMS, &str);
500 let mut p = Parser::new(&bump, &str, lexer);
501 p.set_skip(KindSet::COMMENTS);
502 assert_eq!(p.at_end(), false);
503 assert_eq!(p.offset(), 0);
504 for n in 0..=1 {
505 let c = p.checkpoint();
506 for i in 0..=19 {
507 let c = p.peek_n(1);
508 assert_eq!(c.token(), Kind::Number);
509 assert_eq!(c.token().value(), i as f32);
510 let c = p.peek_n(2);
511 assert_eq!(c.token(), Kind::Whitespace);
512 let c = p.peek_n(3);
513 assert_eq!(c.token(), Kind::Number);
514 assert_eq!(c.token().value(), (i + 1) as f32);
515 let c = p.peek_n(4);
516 assert_eq!(c.token(), Kind::Whitespace);
517 let c = p.peek_n(5);
518 assert_eq!(c.token(), Kind::Number);
519 assert_eq!(c.token().value(), (i + 2) as f32);
520 let c = p.next();
521 assert_eq!(c.token().value(), i as f32);
522 let c = p.peek_n(1);
523 assert_eq!(c.token(), Kind::Whitespace);
524 let c = p.peek_n(2);
525 assert_eq!(c.token(), Kind::Number);
526 assert_eq!(c.token().value(), (i + 1) as f32);
527 p.next();
528 }
529 if n == 0 {
530 p.rewind(c);
531 }
532 }
533 let c = p.next();
534 assert_eq!(c.token(), Kind::Number);
535 assert_eq!(c.token().value(), 20.0);
536 let c = p.next();
537 assert_eq!(c.token(), Kind::Whitespace);
538 let c = p.next();
539 assert_eq!(c.token(), Kind::Number);
540 assert_eq!(c.token().value(), 21.0);
541 let c = p.next();
542 assert_eq!(c.token(), Kind::Eof);
543}