Skip to main content

oxc_css_parser/parser/
mod.rs

1use 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
26/// Create a parser with some source code, then parse it.
27pub 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    /// Create a parser with the given source code and specified syntax.
39    /// If you need to control more options, please use [`ParserBuilder`].
40    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    /// Start to parse.
54    pub fn parse<T>(&mut self) -> PResult<T>
55    where
56        T: Parse<'cmt, 's>,
57    {
58        T::parse(self)
59    }
60
61    /// Retrieve recoverable errors.
62    #[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}