1use crate::{
2 Cursor, Feature, Kind, KindSet, ParserCheckpoint, ParserReturn, Result, SourceOffset, Span, ToCursors, diagnostics,
3 traits::{Parse, Peek},
4};
5use bitmask_enum::bitmask;
6use bumpalo::Bump;
7use css_lexer::{Lexer, SourceCursor};
8use miette::Error;
9use std::mem::take;
10
11#[derive(Debug)]
12pub struct Parser<'a> {
13 pub(crate) source_text: &'a str,
14
15 pub(crate) lexer: Lexer<'a>,
16
17 #[allow(dead_code)]
18 pub(crate) features: Feature,
19
20 pub(crate) errors: Vec<Error>,
21
22 pub(crate) trivia: Vec<Cursor>,
23
24 pub(crate) state: State,
25
26 pub(crate) bump: &'a Bump,
27
28 skip: KindSet,
29
30 stop: KindSet,
31
32 #[cfg(debug_assertions)]
33 pub(crate) last_cursor: Option<Cursor>,
34}
35
36#[bitmask(u8)]
37#[bitmask_config(vec_debug)]
38#[derive(Default)]
39pub enum State {
40 Nested = 0b0000_0001,
41}
42
43impl<'a> Parser<'a> {
44 pub fn new(bump: &'a Bump, source_text: &'a str) -> Self {
46 Self::new_with_features(bump, source_text, Feature::none())
47 }
48
49 pub fn with_features(mut self, features: Feature) -> Self {
50 self.features = features;
51 self
52 }
53
54 pub fn new_with_features(bump: &'a Bump, source_text: &'a str, features: Feature) -> Self {
55 Self {
56 source_text,
57 lexer: Lexer::new_with_features(source_text, features.into()),
58 features,
59 errors: vec![],
60 trivia: vec![],
61 state: State::none(),
62 skip: KindSet::TRIVIA,
63 stop: KindSet::NONE,
64 bump,
65 #[cfg(debug_assertions)]
66 last_cursor: None,
67 }
68 }
69
70 #[inline]
71 pub fn bump(&self) -> &'a Bump {
72 self.bump
73 }
74
75 #[inline]
76 pub fn enabled(&self, other: Feature) -> bool {
77 self.features.contains(other)
78 }
79
80 #[inline]
81 pub fn is(&self, state: State) -> bool {
82 self.state.contains(state)
83 }
84
85 #[inline]
86 pub fn set_state(&mut self, state: State) -> State {
87 let old = self.state;
88 self.state = state;
89 old
90 }
91
92 #[inline]
93 pub fn set_skip(&mut self, skip: KindSet) -> KindSet {
94 let old = self.skip;
95 self.skip = skip;
96 old
97 }
98
99 #[inline]
100 pub fn set_stop(&mut self, stop: KindSet) -> KindSet {
101 let old = self.stop;
102 self.stop = stop;
103 old
104 }
105
106 pub fn parse_entirely<T: Parse<'a> + ToCursors>(&mut self) -> ParserReturn<'a, T> {
107 let output = match T::parse(self) {
108 Ok(output) => Some(output),
109 Err(error) => {
110 self.errors.push(error);
111 None
112 }
113 };
114 if !self.at_end() && self.peek_next() != Kind::Eof {
115 let start = self.offset();
116 loop {
117 let cursor = self.next();
118 self.trivia.push(cursor);
119 if cursor == Kind::Eof {
120 break;
121 }
122 }
123 self.errors.push(diagnostics::ExpectedEnd(Span::new(start, self.offset())).into());
124 }
125 ParserReturn::new(output, self.source_text, take(&mut self.errors), take(&mut self.trivia))
126 }
127
128 pub fn parse<T: Parse<'a>>(&mut self) -> Result<T> {
129 T::parse(self)
130 }
131
132 pub fn peek<T: Peek<'a>>(&self) -> bool {
133 T::peek(self, self.peek_next())
134 }
135
136 pub fn parse_if_peek<T: Peek<'a> + Parse<'a>>(&mut self) -> Result<Option<T>> {
137 if T::peek(self, self.peek_next()) { T::parse(self).map(Some) } else { Ok(None) }
138 }
139
140 pub fn try_parse<T: Parse<'a>>(&mut self) -> Result<T> {
141 T::try_parse(self)
142 }
143
144 pub fn try_parse_if_peek<T: Peek<'a> + Parse<'a>>(&mut self) -> Result<Option<T>> {
145 if T::peek(self, self.peek_next()) { T::try_parse(self).map(Some) } else { Ok(None) }
146 }
147
148 #[inline]
149 pub fn parse_raw_str(&self, c: Cursor) -> &'a str {
150 c.str_slice(self.lexer.source())
151 }
152
153 #[inline]
154 pub fn parse_str(&self, c: Cursor) -> &str {
155 c.parse_str(self.lexer.source(), self.bump)
156 }
157
158 #[inline]
159 pub fn parse_str_lower(&self, c: Cursor) -> &str {
160 c.parse_str_lower(self.lexer.source(), self.bump)
161 }
162
163 #[inline]
164 pub fn eq_ignore_ascii_case(&self, c: Cursor, other: &'static str) -> bool {
165 c.eq_ignore_ascii_case(self.lexer.source(), other)
166 }
167
168 #[inline(always)]
169 pub fn offset(&self) -> SourceOffset {
170 self.lexer.offset()
171 }
172
173 #[inline(always)]
174 pub fn at_end(&self) -> bool {
175 self.lexer.at_end()
176 }
177
178 pub fn rewind(&mut self, checkpoint: ParserCheckpoint) {
179 let ParserCheckpoint { cursor, errors_pos, trivia_pos } = checkpoint;
180 self.lexer.rewind(cursor);
181 self.errors.truncate(errors_pos as usize);
182 self.trivia.truncate(trivia_pos as usize);
183 #[cfg(debug_assertions)]
184 {
185 self.last_cursor = None;
186 }
187 }
188
189 #[inline]
190 pub fn checkpoint(&self) -> ParserCheckpoint {
191 ParserCheckpoint {
192 cursor: self.lexer.checkpoint(),
193 errors_pos: self.errors.len() as u8,
194 trivia_pos: self.trivia.len() as u16,
195 }
196 }
197
198 #[inline]
199 pub fn next_is_stop(&self) -> bool {
200 let mut lexer = self.lexer.clone();
201 loop {
202 let t = lexer.advance();
203 if t.kind() != self.skip {
204 return t.kind() == self.stop;
205 }
206 }
207 }
208
209 #[inline]
210 pub(crate) fn peek_next(&self) -> Cursor {
211 let mut lexer = self.lexer.clone();
212 loop {
213 let offset = lexer.offset();
214 let t = lexer.advance();
215 if t == Kind::Eof || t != self.skip {
216 return t.with_cursor(offset);
217 }
218 }
219 }
220
221 #[inline]
222 pub(crate) fn peek_next_including_whitespace(&self) -> Cursor {
223 let mut lexer = self.lexer.clone();
224 loop {
225 let offset = lexer.offset();
226 let t = lexer.advance();
227 if t == Kind::Eof || t == Kind::Whitespace || t != self.skip {
228 return t.with_cursor(offset);
229 }
230 }
231 }
232
233 pub fn peek_n(&self, n: u8) -> Cursor {
234 let mut lex = self.lexer.clone();
235 let mut remaining = n;
236 loop {
237 let offset = lex.offset();
238 let t = lex.advance();
239 if t == Kind::Eof {
240 return t.with_cursor(offset);
241 }
242 if t != self.skip {
243 remaining -= 1;
244 if remaining == 0 {
245 return t.with_cursor(offset);
246 }
247 }
248 }
249 }
250
251 pub fn to_source_cursor(&self, cursor: Cursor) -> SourceCursor<'a> {
252 SourceCursor::from(cursor, cursor.str_slice(self.source_text))
253 }
254
255 pub fn consume_trivia(&mut self) {
256 loop {
257 let offset = self.lexer.offset();
258 let c = self.lexer.advance().with_cursor(offset);
259 if c == Kind::Eof {
260 return;
261 } else if c == self.skip {
262 self.trivia.push(c)
263 } else {
264 self.lexer.rewind(c);
265 return;
266 }
267 }
268 }
269
270 #[allow(clippy::should_implement_trait)]
271 pub fn next(&mut self) -> Cursor {
272 let mut c;
273 let mut offset;
274 loop {
275 offset = self.offset();
276 c = self.lexer.advance().with_cursor(offset);
277 if c == Kind::Eof || c != self.skip {
278 break;
279 }
280 self.trivia.push(c)
281 }
282
283 #[cfg(debug_assertions)]
284 if let Some(last_cursor) = self.last_cursor {
285 debug_assert!(last_cursor != c, "Detected a next loop, {c:?} was fetched twice");
286 }
287 #[cfg(debug_assertions)]
288 if c == Kind::Eof {
289 self.last_cursor = None;
290 } else {
291 self.last_cursor = Some(c);
292 }
293
294 c
295 }
296}