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