oxc_css_parser/parser/
mod.rs1use self::state::ParserState;
2use crate::{
3 ParserOptions,
4 config::Syntax,
5 error::{Error, PResult},
6 tokenizer::{Tokenizer, token::TokenWithSpan},
7};
8pub use builder::ParserBuilder;
9
10mod at_rule;
11mod builder;
12mod convert;
13mod less;
14mod macros;
15mod sass;
16mod selector;
17mod state;
18mod stmt;
19mod token_seq;
20mod value;
21
22pub trait Parse<'cmt, 's: 'cmt>: Sized {
23 fn parse(input: &mut Parser<'cmt, 's>) -> PResult<Self>;
24}
25
26pub struct Parser<'cmt, 's: 'cmt> {
28 source: &'s str,
29 syntax: Syntax,
30 options: ParserOptions,
31 tokenizer: Tokenizer<'cmt, 's>,
32 state: ParserState,
33 recoverable_errors: Vec<Error>,
34 cached_token: Option<TokenWithSpan<'s>>,
35}
36
37impl<'cmt, 's: 'cmt> Parser<'cmt, 's> {
38 pub fn new(source: &'s str, syntax: Syntax) -> Self {
41 let source = source.strip_prefix('\u{feff}').unwrap_or(source);
42 Parser {
43 source,
44 syntax,
45 options: Default::default(),
46 tokenizer: Tokenizer::new(source, syntax, None, None),
47 state: Default::default(),
48 recoverable_errors: vec![],
49 cached_token: None,
50 }
51 }
52
53 pub fn parse<T>(&mut self) -> PResult<T>
55 where
56 T: Parse<'cmt, 's>,
57 {
58 T::parse(self)
59 }
60
61 #[inline]
63 pub fn recoverable_errors(&self) -> &[Error] {
64 &self.recoverable_errors
65 }
66
67 fn try_parse<R, F: FnOnce(&mut Self) -> PResult<R>>(&mut self, f: F) -> PResult<R> {
68 let tokenizer_state = self.tokenizer.state.clone();
69 let comments_count = if let Some(comments) = &self.tokenizer.comments {
70 comments.len()
71 } else {
72 0
73 };
74 let recoverable_errors_count = self.recoverable_errors.len();
75 let cached_token = self.cached_token.clone();
76 let result = f(self);
77 if result.is_err() {
78 self.tokenizer.state = tokenizer_state;
79 if let Some(comments) = &mut self.tokenizer.comments {
80 comments.truncate(comments_count);
81 }
82 self.recoverable_errors.truncate(recoverable_errors_count);
83 self.cached_token = cached_token;
84 }
85 result
86 }
87}