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]
147 pub fn is(&self, state: State) -> bool {
148 self.state.contains(state)
149 }
150
151 #[inline]
152 pub fn set_state(&mut self, state: State) -> State {
153 let old = self.state;
154 self.state = state;
155 old
156 }
157
158 #[inline]
159 pub fn set_skip(&mut self, skip: KindSet) -> KindSet {
160 let old = self.skip;
161 self.skip = skip;
162 old
163 }
164
165 #[inline]
166 pub fn set_stop(&mut self, stop: KindSet) -> KindSet {
167 let old = self.stop;
168 self.stop = stop;
169 old
170 }
171
172 pub fn parse_entirely<T: Parse<'a> + ToCursors>(&mut self) -> ParserReturn<'a, T> {
173 let output = match T::parse(self) {
174 Ok(output) => Some(output),
175 Err(error) => {
176 self.errors.push(error);
177 None
178 }
179 };
180 let remaining_non_trivia = !self.at_end() && self.peek_n(1) != Kind::Eof;
181 let at_end = self.peek_n_with_skip(1, KindSet::NONE) == Kind::Eof;
182
183 if !at_end {
184 let start = self.peek_n_with_skip(1, KindSet::NONE);
185 let mut end;
186 loop {
187 end = self.next();
188 if end == Kind::Eof {
189 break;
190 }
191 }
192 if remaining_non_trivia {
193 self.errors.push(Diagnostic::new(start, Diagnostic::expected_end).with_end_cursor(end));
194 }
195 }
196 let errors = mem::replace(&mut self.errors, Vec::new_in(self.alloc));
197 let trivia = mem::replace(&mut self.trivia, Vec::new_in(self.alloc));
198 ParserReturn::new(output, self.source_text, errors, trivia)
199 }
200
201 pub fn parse<T: Parse<'a>>(&mut self) -> Result<T> {
202 T::parse(self)
203 }
204
205 pub fn peek<T: Peek<'a>>(&self) -> bool {
206 T::peek(self, self.peek_n(1))
207 }
208
209 pub fn parse_if_peek<T: Peek<'a> + Parse<'a>>(&mut self) -> Result<Option<T>> {
210 if T::peek(self, self.peek_n(1)) { T::parse(self).map(Some) } else { Ok(None) }
211 }
212
213 pub fn try_parse<T: Parse<'a>>(&mut self) -> Result<T> {
214 T::try_parse(self)
215 }
216
217 pub fn try_parse_if_peek<T: Peek<'a> + Parse<'a>>(&mut self) -> Result<Option<T>> {
218 if T::peek(self, self.peek_n(1)) { T::try_parse(self).map(Some) } else { Ok(None) }
219 }
220
221 pub fn equals_atom(&self, c: Cursor, atom: &'static dyn DynAtomSet) -> bool {
222 let mut cursor_bits = c.atom_bits();
223 if cursor_bits == 0 {
224 if c != KindSet::ATOM_LIKE {
225 return false;
226 }
227 let source_cursor = self.to_source_cursor(c);
228 cursor_bits = atom.str_to_bits(&source_cursor.parse(self.alloc));
229 }
230 cursor_bits == atom.bits()
231 }
232
233 pub fn to_atom<A: AtomSet + PartialEq>(&self, c: Cursor) -> A {
234 let bits = c.atom_bits();
235 if bits == 0 {
236 if c != KindSet::ATOM_LIKE {
237 return A::from_bits(0);
238 }
239 let source_cursor = self.to_source_cursor(c);
240 return A::from_str(&source_cursor.parse(self.alloc));
241 }
242 #[cfg(debug_assertions)]
243 if c == KindSet::ATOM_LIKE && c != Kind::Dimension {
244 let is_dashed = c.token().is_dashed_ident();
245 let source_cursor = self.to_source_cursor(c);
246 let text = source_cursor.parse(self.alloc);
247 let comparable = if is_dashed { &text[2..] } else { &text[..] };
248 debug_assert!(
249 A::from_bits(bits) == A::from_str(comparable),
250 "{:?} -> {:?} != {:?} ({:?})",
251 c,
252 A::from_bits(bits),
253 A::from_str(comparable),
254 comparable
255 );
256 }
257 A::from_bits(bits)
258 }
259
260 #[inline(always)]
261 pub fn offset(&self) -> SourceOffset {
262 self.buffer[self.buffer_index].offset()
263 }
264
265 #[inline(always)]
266 pub fn at_end(&self) -> bool {
267 self.buffer[self.buffer_index] == Kind::Eof
268 }
269
270 pub fn rewind(&mut self, checkpoint: ParserCheckpoint<I>) {
271 let ParserCheckpoint { iter, errors_pos, trivia_pos, buffer, buffer_index, skip, stop, state, .. } = checkpoint;
272
273 self.cursor_iter = iter;
274
275 self.errors.truncate(errors_pos as usize);
276 self.trivia.truncate(trivia_pos as usize);
277
278 self.buffer = buffer;
279 self.buffer_index = buffer_index;
280
281 self.skip = skip;
282 self.stop = stop;
283 self.state = state;
284
285 #[cfg(debug_assertions)]
286 {
287 self.last_cursor = None;
288 }
289 }
290
291 #[inline]
292 pub fn checkpoint(&self) -> ParserCheckpoint<I> {
293 ParserCheckpoint {
294 cursor: self.buffer[self.buffer_index],
295 errors_pos: self.errors.len() as u8,
296 trivia_pos: self.trivia.len() as u16,
297 iter: self.cursor_iter.clone(),
298 buffer: self.buffer,
299 buffer_index: self.buffer_index,
300 skip: self.skip,
301 stop: self.stop,
302 state: self.state,
303 }
304 }
305
306 #[inline]
307 pub fn next_is_stop(&self) -> bool {
308 for c in &self.buffer[self.buffer_index..BUFFER_LEN] {
309 if c != self.skip {
310 return c == self.stop;
311 }
312 }
313
314 let mut iter = self.cursor_iter.clone();
315 loop {
316 let Some(cursor) = iter.next() else {
317 return false;
318 };
319 if cursor != self.skip {
320 return cursor == self.stop;
321 }
322 }
323 }
324
325 #[inline]
326 pub(crate) fn peek_n_with_skip(&self, n: u8, skip: KindSet) -> Cursor {
327 let mut remaining = n;
328
329 for c in &self.buffer[self.buffer_index..BUFFER_LEN] {
330 if c == Kind::Eof {
331 return *c;
332 }
333 if c != skip {
334 remaining -= 1;
335 if remaining == 0 {
336 return *c;
337 }
338 }
339 }
340
341 let mut iter = self.cursor_iter.clone();
342 loop {
343 let Some(cursor) = iter.next() else {
344 return eof_cursor(self.source_text.len());
345 };
346 if cursor == Kind::Eof {
347 return cursor;
348 }
349 if cursor != skip {
350 remaining -= 1;
351 if remaining == 0 {
352 return cursor;
353 }
354 }
355 }
356 }
357
358 #[inline]
359 pub fn peek_n(&self, n: u8) -> Cursor {
360 self.peek_n_with_skip(n, self.skip)
361 }
362
363 #[inline]
364 pub fn peek_n_including_whitespace(&self, n: u8) -> Cursor {
365 self.peek_n_with_skip(n, self.skip.remove(Kind::Whitespace))
366 }
367
368 pub fn to_source_cursor(&self, cursor: Cursor) -> SourceCursor<'a> {
369 SourceCursor::from(cursor, cursor.str_slice(self.source_text))
370 }
371
372 pub fn consume_trivia(&mut self) -> Vec<'a, Cursor> {
373 let mut trivia = Vec::new_in(self.alloc);
374 for i in self.buffer_index..BUFFER_LEN {
375 let c = self.buffer[i];
376 if c == Kind::Eof {
377 self.buffer_index = i;
378 return trivia;
379 } else if c == self.skip {
380 trivia.push(c)
381 } else {
382 self.buffer_index = i;
383 self.fill_buffer(i);
384 return trivia;
385 }
386 }
387
388 let eof = eof_cursor(self.source_text.len());
389 loop {
390 let Some(c) = self.cursor_iter.next() else {
391 self.buffer = [eof; BUFFER_LEN];
392 self.buffer_index = 0;
393 return trivia;
394 };
395 if c == Kind::Eof {
396 self.buffer = [eof; BUFFER_LEN];
397 self.buffer_index = 0;
398 return trivia;
399 } else if c == self.skip {
400 trivia.push(c)
401 } else {
402 self.buffer[0] = c;
403 for i in 1..BUFFER_LEN {
404 self.buffer[i] = self.cursor_iter.next().unwrap_or(eof);
405 }
406 self.buffer_index = 0;
407 return trivia;
408 }
409 }
410 }
411
412 pub fn consume_trivia_as_leading(&mut self) {
416 let trivia = self.consume_trivia();
417 if !trivia.is_empty() {
418 let next = self.peek_n(1);
420 self.trivia.push((trivia, next));
421 }
422 }
423
424 #[allow(clippy::should_implement_trait)]
425 pub fn next(&mut self) -> Cursor {
426 let mut pending_trivia = Vec::new_in(self.alloc);
428
429 loop {
430 if self.buffer_index >= BUFFER_REFILL_INDEX {
431 self.fill_buffer(self.buffer_index);
432 }
433
434 for i in self.buffer_index..BUFFER_LEN {
435 let c = self.buffer[i];
436 if c == Kind::Eof {
437 self.buffer_index = i;
438 if !pending_trivia.is_empty() {
440 self.trivia.push((pending_trivia.clone(), c));
441 }
442 #[cfg(debug_assertions)]
443 {
444 self.last_cursor = None;
445 }
446 return c;
447 } else if c == self.skip {
448 pending_trivia.push(c);
449 } else {
450 self.buffer_index = i + 1;
451 if self.buffer_index >= BUFFER_REFILL_INDEX {
452 self.fill_buffer(self.buffer_index);
453 }
454 if !pending_trivia.is_empty() {
456 self.trivia.push((pending_trivia.clone(), c));
457 }
458 #[cfg(debug_assertions)]
459 {
460 if let Some(last_cursor) = self.last_cursor {
461 debug_assert!(last_cursor != c, "Detected a next loop, {c:?} was fetched twice");
462 }
463 self.last_cursor = Some(c);
464 }
465 return c;
466 }
467 }
468
469 self.fill_buffer(BUFFER_LEN);
471 }
472 }
473}
474
475#[test]
476fn test_filling_buffer_with_skip_tokens() {
477 let str = "/*x*//*x*//*x*//*x*//*x*//*x*//*x*//*x*//*x*//*x*//*x*/a";
478 let alloc = crate::Arena::default();
479 let lexer = css_lexer::Lexer::new(&css_lexer::EmptyAtomSet::ATOMS, str);
480 let mut p = Parser::new(&alloc, str, lexer);
481 let c = p.next();
482 assert_eq!(c.token(), Kind::Ident);
483 let _ = p.at_end();
485 let _ = p.offset();
486}
487
488#[test]
489fn peek_and_next() {
490 let str = "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21";
491 let alloc = crate::Arena::default();
492 let lexer = css_lexer::Lexer::new(&css_lexer::EmptyAtomSet::ATOMS, str);
493 let mut p = Parser::new(&alloc, str, lexer);
494 assert!(!p.at_end());
495 assert_eq!(p.offset(), 0);
496 for n in 0..=1 {
497 let c = p.checkpoint();
498 for i in 0..=19 {
499 let c = p.peek_n(1);
500 assert_eq!(c.token(), Kind::Number);
501 assert_eq!(c.token().value(), i as f32);
502 let c = p.peek_n(2);
503 assert_eq!(c.token(), Kind::Number);
504 assert_eq!(c.token().value(), (i + 1) as f32);
505 let c = p.peek_n(3);
506 assert_eq!(c.token(), Kind::Number);
507 assert_eq!(c.token().value(), (i + 2) as f32);
508 let c = p.next();
509 assert_eq!(c.token().value(), i as f32);
510 let c = p.peek_n(1);
511 assert_eq!(c.token(), Kind::Number);
512 assert_eq!(c.token().value(), (i + 1) as f32);
513 }
514 if n == 0 {
515 p.rewind(c)
516 }
517 }
518 let c = p.next();
519 assert_eq!(c.token(), Kind::Number);
520 assert_eq!(c.token().value(), 20.0);
521 let c = p.next();
522 assert_eq!(c.token(), Kind::Number);
523 assert_eq!(c.token().value(), 21.0);
524 let c = p.next();
525 assert_eq!(c.token(), Kind::Eof);
526}
527
528#[test]
529fn peek_and_next_with_whitsespace() {
530 let str = "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21";
531 let alloc = crate::Arena::default();
532 let lexer = css_lexer::Lexer::new(&css_lexer::EmptyAtomSet::ATOMS, str);
533 let mut p = Parser::new(&alloc, str, lexer);
534 p.set_skip(KindSet::COMMENTS);
535 assert!(!p.at_end());
536 assert_eq!(p.offset(), 0);
537 for n in 0..=1 {
538 let c = p.checkpoint();
539 for i in 0..=19 {
540 let c = p.peek_n(1);
541 assert_eq!(c.token(), Kind::Number);
542 assert_eq!(c.token().value(), i as f32);
543 let c = p.peek_n(2);
544 assert_eq!(c.token(), Kind::Whitespace);
545 let c = p.peek_n(3);
546 assert_eq!(c.token(), Kind::Number);
547 assert_eq!(c.token().value(), (i + 1) as f32);
548 let c = p.peek_n(4);
549 assert_eq!(c.token(), Kind::Whitespace);
550 let c = p.peek_n(5);
551 assert_eq!(c.token(), Kind::Number);
552 assert_eq!(c.token().value(), (i + 2) as f32);
553 let c = p.next();
554 assert_eq!(c.token().value(), i as f32);
555 let c = p.peek_n(1);
556 assert_eq!(c.token(), Kind::Whitespace);
557 let c = p.peek_n(2);
558 assert_eq!(c.token(), Kind::Number);
559 assert_eq!(c.token().value(), (i + 1) as f32);
560 p.next();
561 }
562 if n == 0 {
563 p.rewind(c);
564 }
565 }
566 let c = p.next();
567 assert_eq!(c.token(), Kind::Number);
568 assert_eq!(c.token().value(), 20.0);
569 let c = p.next();
570 assert_eq!(c.token(), Kind::Whitespace);
571 let c = p.next();
572 assert_eq!(c.token(), Kind::Number);
573 assert_eq!(c.token().value(), 21.0);
574 let c = p.next();
575 assert_eq!(c.token(), Kind::Eof);
576}