Coverage Report

Created: 2026-11-12 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rust-cssparser/src/parser.rs
Line
Count
Source
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
use crate::cow_rc_str::CowRcStr;
6
use crate::tokenizer::{SeenStatus, SourceLocation, SourcePosition, Token};
7
use smallvec::SmallVec;
8
use std::fmt;
9
use std::ops::BitOr;
10
11
/// A capture of the internal state of a `Parser` (including the position within the input),
12
/// obtained from the `Parser::position` method.
13
///
14
/// Can be used with the `Parser::reset` method to restore that state.
15
/// Should only be used with the `Parser` instance it came from.
16
#[derive(Clone, Default)]
17
pub struct ParserState {
18
    pub(crate) position: usize,
19
    pub(crate) current_line_start_position: u32,
20
    /// Current line number shifted by `Self::BLOCK_TYPE_BITS`, with the low 2 bits holding the
21
    /// `BlockType` discriminant of the block the last returned token opened (if any).
22
    line_number_and_block_type: u32,
23
}
24
25
impl fmt::Debug for ParserState {
26
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27
0
        f.debug_struct("ParserState")
28
0
            .field("position", &self.position)
29
0
            .field(
30
0
                "current_line_start_position",
31
0
                &self.current_line_start_position,
32
0
            )
33
0
            .field("current_line_number", &self.line_number())
34
0
            .field("at_start_of", &self.at_start_of())
35
0
            .finish()
36
0
    }
37
}
38
39
impl ParserState {
40
    const BLOCK_TYPE_BITS: u32 = 2;
41
    const BLOCK_TYPE_MASK: u32 = (1 << Self::BLOCK_TYPE_BITS) - 1;
42
43
    /// The position from the start of the input, counted in UTF-8 bytes.
44
    #[inline]
45
262k
    pub fn position(&self) -> SourcePosition {
46
262k
        SourcePosition(self.position)
47
262k
    }
48
49
    /// The line number and column number
50
    #[inline]
51
    pub fn source_location(&self) -> SourceLocation {
52
        SourceLocation {
53
            line: self.line_number(),
54
            column: (self.position as u32)
55
                .wrapping_sub(self.current_line_start_position)
56
                .wrapping_add(1),
57
        }
58
    }
59
60
    #[inline]
61
0
    pub(crate) fn line_number(&self) -> u32 {
62
0
        self.line_number_and_block_type >> Self::BLOCK_TYPE_BITS
63
0
    }
64
65
    #[inline]
66
4.70M
    pub(crate) fn advance_line_number(&mut self, count: u32) {
67
4.70M
        self.line_number_and_block_type += count << Self::BLOCK_TYPE_BITS;
68
4.70M
    }
69
70
    #[inline]
71
132M
    pub(crate) fn at_start_of(&self) -> Option<BlockType> {
72
132M
        let block_type = (self.line_number_and_block_type & Self::BLOCK_TYPE_MASK) as u8;
73
132M
        BlockType::from_byte(block_type)
74
132M
    }
<cssparser::parser::ParserState>::at_start_of
Line
Count
Source
71
444k
    pub(crate) fn at_start_of(&self) -> Option<BlockType> {
72
444k
        let block_type = (self.line_number_and_block_type & Self::BLOCK_TYPE_MASK) as u8;
73
444k
        BlockType::from_byte(block_type)
74
444k
    }
<cssparser::parser::ParserState>::at_start_of
Line
Count
Source
71
131M
    pub(crate) fn at_start_of(&self) -> Option<BlockType> {
72
131M
        let block_type = (self.line_number_and_block_type & Self::BLOCK_TYPE_MASK) as u8;
73
131M
        BlockType::from_byte(block_type)
74
131M
    }
75
76
    #[inline]
77
4.36M
    pub(crate) fn set_at_start_of(&mut self, block_type: BlockType) {
78
4.36M
        debug_assert!(self.at_start_of().is_none());
79
4.36M
        self.line_number_and_block_type |= block_type as u32;
80
4.36M
        debug_assert_eq!(self.at_start_of(), Some(block_type));
81
4.36M
    }
82
83
    #[inline]
84
132M
    pub(crate) fn take_at_start_of(&mut self) -> Option<BlockType> {
85
132M
        let block_type = self.at_start_of();
86
132M
        self.line_number_and_block_type &= !Self::BLOCK_TYPE_MASK;
87
132M
        block_type
88
132M
    }
<cssparser::parser::ParserState>::take_at_start_of
Line
Count
Source
84
444k
    pub(crate) fn take_at_start_of(&mut self) -> Option<BlockType> {
85
444k
        let block_type = self.at_start_of();
86
444k
        self.line_number_and_block_type &= !Self::BLOCK_TYPE_MASK;
87
444k
        block_type
88
444k
    }
<cssparser::parser::ParserState>::take_at_start_of
Line
Count
Source
84
131M
    pub(crate) fn take_at_start_of(&mut self) -> Option<BlockType> {
85
131M
        let block_type = self.at_start_of();
86
131M
        self.line_number_and_block_type &= !Self::BLOCK_TYPE_MASK;
87
131M
        block_type
88
131M
    }
89
}
90
91
/// When parsing until a given token, sometimes the caller knows that parsing is going to restart
92
/// at some earlier point, and consuming until we find a top level delimiter is just wasted work.
93
///
94
/// In that case, callers can pass ParseUntilErrorBehavior::Stop to avoid doing all that wasted
95
/// work.
96
///
97
/// This is important for things like CSS nesting, where something like:
98
///
99
///   foo:is(..) {
100
///     ...
101
///   }
102
///
103
/// Would need to scan the whole {} block to find a semicolon, only for parsing getting restarted
104
/// as a qualified rule later.
105
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
106
pub enum ParseUntilErrorBehavior {
107
    /// Consume until we see the relevant delimiter or the end of the stream.
108
    Consume,
109
    /// Eagerly error.
110
    Stop,
111
}
112
113
/// Details about a `BasicParseError`
114
#[derive(Clone, Debug, PartialEq)]
115
pub enum BasicParseErrorKind {
116
    /// An unexpected token was encountered.
117
    ///
118
    /// The token itself is deliberately not stored: it made this enum 32 bytes,
119
    /// which pushed `Result<&Token, BasicParseError>` (returned from every token
120
    /// fetch) to 40 bytes and therefore out of registers and into memory.
121
    /// Callers that want to name the token can recover it from the source text
122
    /// they already carry for the error message.
123
    UnexpectedToken,
124
    /// The end of the input was encountered unexpectedly.
125
    EndOfInput,
126
    /// An `@` rule was encountered that was invalid. See `UnexpectedToken` for
127
    /// why the rule name is not stored.
128
    AtRuleInvalid,
129
    /// The body of an '@' rule was invalid.
130
    AtRuleBodyInvalid,
131
    /// A qualified rule was encountered that was invalid.
132
    QualifiedRuleInvalid,
133
    /// We've gone over the nesting limit.
134
    TooManyNestedBlocks,
135
}
136
137
impl fmt::Display for BasicParseErrorKind {
138
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139
0
        match self {
140
            BasicParseErrorKind::TooManyNestedBlocks => {
141
0
                write!(f, "nesting block limit reached")
142
            }
143
0
            BasicParseErrorKind::UnexpectedToken => write!(f, "unexpected token"),
144
0
            BasicParseErrorKind::EndOfInput => write!(f, "unexpected end of input"),
145
0
            BasicParseErrorKind::AtRuleInvalid => write!(f, "invalid @ rule encountered"),
146
0
            BasicParseErrorKind::AtRuleBodyInvalid => write!(f, "invalid @ rule body encountered"),
147
            BasicParseErrorKind::QualifiedRuleInvalid => {
148
0
                write!(f, "invalid qualified rule encountered")
149
            }
150
        }
151
0
    }
152
}
153
154
/// The fundamental parsing errors that can be triggered by built-in parsing routines.
155
#[derive(Clone, Debug, PartialEq)]
156
pub struct BasicParseError {
157
    /// Details of this error
158
    pub kind: BasicParseErrorKind,
159
}
160
161
impl BasicParseError {
162
    /// Create a new BasicParseError of the given kind.
163
    #[inline]
164
454k
    pub fn new(kind: BasicParseErrorKind) -> Self {
165
454k
        Self { kind }
166
454k
    }
Unexecuted instantiation: <cssparser::parser::BasicParseError>::new
<cssparser::parser::BasicParseError>::new
Line
Count
Source
164
454k
    pub fn new(kind: BasicParseErrorKind) -> Self {
165
454k
        Self { kind }
166
454k
    }
167
168
    /// Create a new BasicParseError for an unexpected token.
169
    #[inline]
170
0
    pub fn unexpected_token() -> Self {
171
0
        Self::new(BasicParseErrorKind::UnexpectedToken)
172
0
    }
Unexecuted instantiation: <cssparser::parser::BasicParseError>::unexpected_token
Unexecuted instantiation: <cssparser::parser::BasicParseError>::unexpected_token
173
}
174
175
impl<T> From<BasicParseError> for ParseError<T> {
176
    #[inline]
177
0
    fn from(this: BasicParseError) -> ParseError<T> {
178
0
        ParseError {
179
0
            kind: ParseErrorKind::Basic(this.kind),
180
0
        }
181
0
    }
182
}
183
184
/// Details of a `ParseError`
185
#[derive(Clone, Debug, PartialEq)]
186
pub enum ParseErrorKind<T> {
187
    /// A fundamental parse error from a built-in parsing routine.
188
    Basic(BasicParseErrorKind),
189
    /// A parse error reported by downstream consumer code.
190
    Custom(T),
191
}
192
193
impl<T> ParseErrorKind<T> {
194
    /// Like `std::convert::Into::into`
195
    pub fn into<U>(self) -> ParseErrorKind<U>
196
    where
197
        T: Into<U>,
198
    {
199
        match self {
200
            ParseErrorKind::Basic(basic) => ParseErrorKind::Basic(basic),
201
            ParseErrorKind::Custom(custom) => ParseErrorKind::Custom(custom.into()),
202
        }
203
    }
204
}
205
206
impl<E: fmt::Display> fmt::Display for ParseErrorKind<E> {
207
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
208
        match self {
209
            ParseErrorKind::Basic(basic) => basic.fmt(f),
210
            ParseErrorKind::Custom(custom) => custom.fmt(f),
211
        }
212
    }
213
}
214
215
/// Extensible parse errors that can be encountered by client parsing implementations.
216
#[derive(Clone, Debug, PartialEq)]
217
pub struct ParseError<E> {
218
    /// Details of this error
219
    pub kind: ParseErrorKind<E>,
220
}
221
222
impl<T> ParseError<T> {
223
    /// Create a new ParseError from a basic error kind.
224
    #[inline]
225
1.17k
    pub fn from_basic_kind(kind: BasicParseErrorKind) -> Self {
226
1.17k
        Self {
227
1.17k
            kind: ParseErrorKind::Basic(kind),
228
1.17k
        }
229
1.17k
    }
230
231
    /// Create a new ParseError for an unexpected token.
232
    #[inline]
233
1.16k
    pub fn unexpected_token() -> Self {
234
1.16k
        Self::from_basic_kind(BasicParseErrorKind::UnexpectedToken)
235
1.16k
    }
236
237
    /// Create a new ParseError from a consumer-defined error.
238
    #[inline]
239
    pub fn custom<E: Into<T>>(error: E) -> Self {
240
        Self {
241
            kind: ParseErrorKind::Custom(error.into()),
242
        }
243
    }
244
245
    /// Extract the fundamental parse error from an extensible error.
246
    pub fn basic(self) -> BasicParseError {
247
        match self.kind {
248
            ParseErrorKind::Basic(kind) => BasicParseError { kind },
249
            ParseErrorKind::Custom(_) => panic!("Not a basic parse error"),
250
        }
251
    }
252
253
    /// Like `std::convert::Into::into`
254
    pub fn into<U>(self) -> ParseError<U>
255
    where
256
        T: Into<U>,
257
    {
258
        ParseError {
259
            kind: self.kind.into(),
260
        }
261
    }
262
}
263
264
impl<E: fmt::Display> fmt::Display for ParseError<E> {
265
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
266
        self.kind.fmt(f)
267
    }
268
}
269
270
impl<E: fmt::Display + fmt::Debug> std::error::Error for ParseError<E> {}
271
272
/// A CSS parser that borrows its `&str` input, yields `Token`s, and keeps track of nested blocks
273
/// and functions.
274
pub struct Parser<'i> {
275
    pub(crate) input: &'i str,
276
    pub(crate) state: ParserState,
277
    cached_token: CachedToken<'i>,
278
    current_block_depth: u8,
279
    nested_block_limit: u8,
280
    /// For parsers from `parse_until` or `parse_nested_block`
281
    stop_before: Delimiters,
282
    pub(crate) arbitrary_substitution_functions: SeenStatus<'i>,
283
    pub(crate) source_map_url: Option<&'i str>,
284
    pub(crate) source_url: Option<&'i str>,
285
}
286
287
struct CachedToken<'i> {
288
    token: Token<'i>,
289
    start_position: SourcePosition,
290
    end_state: ParserState,
291
}
292
293
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
294
#[repr(u8)]
295
pub(crate) enum BlockType {
296
    // NOTE: We rely on the discriminants being 1, 2, 3 for the `ParserState`
297
    // bit packing (and from_byte).
298
    Parenthesis = 1,
299
    SquareBracket,
300
    CurlyBracket,
301
}
302
303
impl BlockType {
304
    #[inline]
305
132M
    fn from_byte(b: u8) -> Option<BlockType> {
306
132M
        let ty = match b {
307
293k
            1 => BlockType::Parenthesis,
308
1.09M
            2 => BlockType::SquareBracket,
309
2.97M
            3 => BlockType::CurlyBracket,
310
128M
            _ => return None,
311
        };
312
4.36M
        debug_assert_eq!(ty as u8, b);
313
4.36M
        Some(ty)
314
132M
    }
<cssparser::parser::BlockType>::from_byte
Line
Count
Source
305
444k
    fn from_byte(b: u8) -> Option<BlockType> {
306
444k
        let ty = match b {
307
18.8k
            1 => BlockType::Parenthesis,
308
8.58k
            2 => BlockType::SquareBracket,
309
194k
            3 => BlockType::CurlyBracket,
310
222k
            _ => return None,
311
        };
312
222k
        debug_assert_eq!(ty as u8, b);
313
222k
        Some(ty)
314
444k
    }
<cssparser::parser::BlockType>::from_byte
Line
Count
Source
305
131M
    fn from_byte(b: u8) -> Option<BlockType> {
306
131M
        let ty = match b {
307
274k
            1 => BlockType::Parenthesis,
308
1.08M
            2 => BlockType::SquareBracket,
309
2.78M
            3 => BlockType::CurlyBracket,
310
127M
            _ => return None,
311
        };
312
4.14M
        debug_assert_eq!(ty as u8, b);
313
4.14M
        Some(ty)
314
131M
    }
315
316
1.47M
    fn closing(token: &Token) -> Option<BlockType> {
317
1.47M
        Some(match *token {
318
17.1k
            Token::CloseParenthesis => BlockType::Parenthesis,
319
4.11k
            Token::CloseSquareBracket => BlockType::SquareBracket,
320
260k
            Token::CloseCurlyBracket => BlockType::CurlyBracket,
321
1.19M
            _ => return None,
322
        })
323
1.47M
    }
324
}
325
326
/// A set of characters, to be used with the `Parser::parse_until*` methods.
327
///
328
/// The union of two sets can be obtained with the `|` operator. Example:
329
///
330
/// ```rust,ignore
331
/// input.parse_until_before(Delimiter::CurlyBracketBlock | Delimiter::Semicolon)
332
/// ```
333
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
334
pub struct Delimiters {
335
    bits: u8,
336
}
337
338
/// `Delimiters` constants.
339
#[allow(non_upper_case_globals, non_snake_case)]
340
pub mod Delimiter {
341
    use super::Delimiters;
342
343
    /// The empty delimiter set
344
    pub const None: Delimiters = Delimiters { bits: 0 };
345
    /// The delimiter set with only the `{` opening curly bracket
346
    pub const CurlyBracketBlock: Delimiters = Delimiters { bits: 1 << 1 };
347
    /// The delimiter set with only the `;` semicolon
348
    pub const Semicolon: Delimiters = Delimiters { bits: 1 << 2 };
349
    /// The delimiter set with only the `!` exclamation point
350
    pub const Bang: Delimiters = Delimiters { bits: 1 << 3 };
351
    /// The delimiter set with only the `,` comma
352
    pub const Comma: Delimiters = Delimiters { bits: 1 << 4 };
353
}
354
355
#[allow(non_upper_case_globals, non_snake_case)]
356
mod ClosingDelimiter {
357
    use super::Delimiters;
358
359
    pub const CloseCurlyBracket: Delimiters = Delimiters { bits: 1 << 5 };
360
    pub const CloseSquareBracket: Delimiters = Delimiters { bits: 1 << 6 };
361
    pub const CloseParenthesis: Delimiters = Delimiters { bits: 1 << 7 };
362
}
363
364
impl BitOr<Delimiters> for Delimiters {
365
    type Output = Delimiters;
366
367
    #[inline]
368
    fn bitor(self, other: Delimiters) -> Delimiters {
369
        Delimiters {
370
            bits: self.bits | other.bits,
371
        }
372
    }
373
}
374
375
impl Delimiters {
376
    #[inline]
377
126M
    fn contains(self, other: Delimiters) -> bool {
378
126M
        (self.bits & other.bits) != 0
379
126M
    }
380
381
    #[inline]
382
126M
    pub(crate) fn from_byte(byte: u8) -> Delimiters {
383
        const TABLE: [Delimiters; 256] = {
384
            let mut table = [Delimiter::None; 256];
385
            table[b';' as usize] = Delimiter::Semicolon;
386
            table[b'!' as usize] = Delimiter::Bang;
387
            table[b',' as usize] = Delimiter::Comma;
388
            table[b'{' as usize] = Delimiter::CurlyBracketBlock;
389
            table[b'}' as usize] = ClosingDelimiter::CloseCurlyBracket;
390
            table[b']' as usize] = ClosingDelimiter::CloseSquareBracket;
391
            table[b')' as usize] = ClosingDelimiter::CloseParenthesis;
392
            table
393
        };
394
395
126M
        TABLE[byte as usize]
396
126M
    }
397
}
398
399
/// Used in some `fn expect_*` methods
400
macro_rules! expect {
401
    ($parser: ident, $($branches: tt)+) => {
402
        {
403
            match *$parser.next()? {
404
                $($branches)+
405
                _ => {
406
                    return Err(BasicParseError::unexpected_token())
407
                }
408
            }
409
        }
410
    }
411
}
412
413
/// A list of arbitrary substitution functions. Should be lowercase ascii.
414
/// See https://drafts.csswg.org/css-values-5/#arbitrary-substitution
415
pub type ArbitrarySubstitutionFunctions<'a> = &'a [&'static str];
416
417
impl<'i> Parser<'i> {
418
    /// 75 nested blocks seems reasonable enough.
419
    const REASONABLE_NESTED_BLOCK_LIMIT: u8 = 75;
420
421
    /// Create a new parser for the given input.
422
    #[inline]
423
16.4k
    pub fn new(input: &'i str) -> Self {
424
16.4k
        Self {
425
16.4k
            input,
426
16.4k
            state: ParserState::default(),
427
16.4k
            stop_before: Delimiter::None,
428
16.4k
            nested_block_limit: Self::REASONABLE_NESTED_BLOCK_LIMIT,
429
16.4k
            current_block_depth: 0,
430
16.4k
            cached_token: CachedToken {
431
16.4k
                token: Token::Semicolon,                    // Anything would do.
432
16.4k
                start_position: SourcePosition(usize::MAX), // No token would match this cache.
433
16.4k
                end_state: ParserState::default(),
434
16.4k
            },
435
16.4k
            arbitrary_substitution_functions: SeenStatus::DontCare,
436
16.4k
            source_map_url: None,
437
16.4k
            source_url: None,
438
16.4k
        }
439
16.4k
    }
<cssparser::parser::Parser>::new
Line
Count
Source
423
16.4k
    pub fn new(input: &'i str) -> Self {
424
16.4k
        Self {
425
16.4k
            input,
426
16.4k
            state: ParserState::default(),
427
16.4k
            stop_before: Delimiter::None,
428
16.4k
            nested_block_limit: Self::REASONABLE_NESTED_BLOCK_LIMIT,
429
16.4k
            current_block_depth: 0,
430
16.4k
            cached_token: CachedToken {
431
16.4k
                token: Token::Semicolon,                    // Anything would do.
432
16.4k
                start_position: SourcePosition(usize::MAX), // No token would match this cache.
433
16.4k
                end_state: ParserState::default(),
434
16.4k
            },
435
16.4k
            arbitrary_substitution_functions: SeenStatus::DontCare,
436
16.4k
            source_map_url: None,
437
16.4k
            source_url: None,
438
16.4k
        }
439
16.4k
    }
Unexecuted instantiation: <cssparser::parser::Parser>::new
440
441
    /// Sets a limit for how many nested blocks we're allowed to parse. This is useful to avoid
442
    /// running out of stack space. By default, it's set to `REASONABLE_NESTED_BLOCK_LIMIT`, but it
443
    /// can be overridden or cleared. A limit of 0 will be equivalent to no limit at all.
444
0
    pub fn set_nested_block_limit(&mut self, limit: u8) {
445
0
        self.nested_block_limit = limit;
446
0
    }
447
448
    /// Check whether the input is exhausted. That is, if `.next()` would return a token.
449
    ///
450
    /// This ignores whitespace and comments.
451
    #[inline]
452
0
    pub fn is_exhausted(&mut self) -> bool {
453
0
        self.expect_exhausted().is_ok()
454
0
    }
455
456
    /// Check whether the input is exhausted. That is, if `.next()` would return a token.
457
    /// Return a `Result` so that the `?` operator can be used: `input.expect_exhausted()?`
458
    ///
459
    /// This ignores whitespace and comments.
460
    #[inline]
461
219k
    pub fn expect_exhausted(&mut self) -> Result<(), BasicParseError> {
462
219k
        let start = self.state();
463
219k
        let result = match self.next() {
464
            Err(BasicParseError {
465
                kind: BasicParseErrorKind::EndOfInput,
466
                ..
467
219k
            }) => Ok(()),
468
0
            Err(e) => unreachable!("Unexpected error encountered: {:?}", e),
469
0
            Ok(_) => Err(BasicParseError::unexpected_token()),
470
        };
471
219k
        self.reset(&start);
472
219k
        result
473
219k
    }
<cssparser::parser::Parser>::expect_exhausted
Line
Count
Source
461
219k
    pub fn expect_exhausted(&mut self) -> Result<(), BasicParseError> {
462
219k
        let start = self.state();
463
219k
        let result = match self.next() {
464
            Err(BasicParseError {
465
                kind: BasicParseErrorKind::EndOfInput,
466
                ..
467
219k
            }) => Ok(()),
468
0
            Err(e) => unreachable!("Unexpected error encountered: {:?}", e),
469
0
            Ok(_) => Err(BasicParseError::unexpected_token()),
470
        };
471
219k
        self.reset(&start);
472
219k
        result
473
219k
    }
Unexecuted instantiation: <cssparser::parser::Parser>::expect_exhausted
474
475
    /// Create a new unexpected token or EOF ParseError at the current location
476
    #[inline]
477
    pub fn new_error_for_next_token<E>(&mut self) -> ParseError<E> {
478
        match self.next() {
479
            Ok(_) => ParseError::unexpected_token(),
480
            Err(e) => e.into(),
481
        }
482
    }
483
484
    /// Return the current internal state of the parser (including position within the input).
485
    ///
486
    /// This state can later be restored with the `Parser::reset` method.
487
    #[inline]
488
219k
    pub fn state(&self) -> ParserState {
489
219k
        self.state.clone()
490
219k
    }
<cssparser::parser::Parser>::state
Line
Count
Source
488
219k
    pub fn state(&self) -> ParserState {
489
219k
        self.state.clone()
490
219k
    }
Unexecuted instantiation: <cssparser::parser::Parser>::state
491
492
    /// Like `next_byte`, but returns `None` if the next byte is one of the delimiters this
493
    /// parser was told to stop before.
494
    #[inline]
495
126M
    pub(crate) fn next_byte_before_delimiter(&self) -> Option<u8> {
496
126M
        let byte = self.next_byte()?;
497
126M
        if self.stop_before.contains(Delimiters::from_byte(byte)) {
498
407k
            return None;
499
125M
        }
500
125M
        Some(byte)
501
126M
    }
502
503
    /// Restore the internal state of the parser (including position within the input)
504
    /// to what was previously saved by the `Parser::position` method.
505
    ///
506
    /// Should only be used with `SourcePosition` values from the same `Parser` instance.
507
    #[inline]
508
219k
    pub fn reset(&mut self, state: &ParserState) {
509
219k
        self.state = state.clone();
510
219k
    }
<cssparser::parser::Parser>::reset
Line
Count
Source
508
219k
    pub fn reset(&mut self, state: &ParserState) {
509
219k
        self.state = state.clone();
510
219k
    }
Unexecuted instantiation: <cssparser::parser::Parser>::reset
511
512
    /// The old name of `try_parse`, which requires raw identifiers in the Rust 2018 edition.
513
    #[inline]
514
    pub fn r#try<F, T, E>(&mut self, thing: F) -> Result<T, E>
515
    where
516
        F: FnOnce(&mut Parser<'i>) -> Result<T, E>,
517
    {
518
        self.try_parse(thing)
519
    }
520
521
    /// Execute the given closure, passing it the parser.
522
    /// If the result (returned unchanged) is `Err`,
523
    /// the internal state of the parser  (including position within the input)
524
    /// is restored to what it was before the call.
525
    #[inline]
526
    pub fn try_parse<F, T, E>(&mut self, thing: F) -> Result<T, E>
527
    where
528
        F: FnOnce(&mut Parser<'i>) -> Result<T, E>,
529
    {
530
        let start = self.state();
531
        let result = thing(self);
532
        if result.is_err() {
533
            self.reset(&start)
534
        }
535
        result
536
    }
537
538
    /// Return the next token in the input that is neither whitespace or a comment,
539
    /// and advance the position accordingly.
540
    ///
541
    /// After returning a `Function`, `ParenthesisBlock`,
542
    /// `CurlyBracketBlock`, or `SquareBracketBlock` token,
543
    /// the next call will skip until after the matching `CloseParenthesis`,
544
    /// `CloseCurlyBracket`, or `CloseSquareBracket` token.
545
    ///
546
    /// See the `Parser::parse_nested_block` method to parse the content of functions or blocks.
547
    ///
548
    /// This only returns a closing token when it is unmatched (and therefore an error).
549
    #[allow(clippy::should_implement_trait)]
550
219k
    pub fn next(&mut self) -> Result<&Token<'i>, BasicParseError> {
551
219k
        self.skip_whitespace();
552
219k
        self.next_including_whitespace_and_comments()
553
219k
    }
554
555
    /// Same as `Parser::next`, but does not skip whitespace tokens.
556
90.7M
    pub fn next_including_whitespace(&mut self) -> Result<&Token<'i>, BasicParseError> {
557
125M
        while let Token::Comment(..) = self.next_including_whitespace_and_comments()? {
558
35.1M
            // Keep going
559
35.1M
        }
560
90.5M
        Ok(&self.cached_token.token)
561
90.7M
    }
562
563
    /// Same as `Parser::next`, but does not skip whitespace or comment tokens.
564
    ///
565
    /// **Note**: This should only be used in contexts like a CSS pre-processor
566
    /// where comments are preserved.
567
    /// When parsing higher-level values, per the CSS Syntax specification,
568
    /// comments should always be ignored between tokens.
569
126M
    pub fn next_including_whitespace_and_comments(
570
126M
        &mut self,
571
126M
    ) -> Result<&Token<'i>, BasicParseError> {
572
126M
        self.skip_block_at_start();
573
574
126M
        if self.next_byte_before_delimiter().is_none() {
575
454k
            return Err(BasicParseError::new(BasicParseErrorKind::EndOfInput));
576
125M
        }
577
578
125M
        let token_start_position = self.position();
579
125M
        let using_cached_token = self.cached_token.start_position == token_start_position;
580
125M
        if using_cached_token {
581
0
            self.state = self.cached_token.end_state.clone();
582
125M
        } else {
583
125M
            let new_token = self.next_unchecked();
584
125M
            self.cached_token = CachedToken {
585
125M
                token: new_token,
586
125M
                start_position: token_start_position,
587
125M
                end_state: self.state.clone(),
588
125M
            };
589
125M
        }
590
591
125M
        Ok(&self.cached_token.token)
592
126M
    }
593
594
    /// Have the given closure parse something, then check the the input is exhausted.
595
    /// The result is overridden to an `Err(..)` if some input remains.
596
    ///
597
    /// This can help tell e.g. `color: green;` from `color: green 4px;`
598
    #[inline]
599
222k
    pub fn parse_entirely<F, T, E>(&mut self, parse: F) -> Result<T, ParseError<E>>
600
222k
    where
601
222k
        F: FnOnce(&mut Parser<'i>) -> Result<T, ParseError<E>>,
602
    {
603
222k
        let result = parse(self)?;
604
219k
        self.expect_exhausted()?;
605
219k
        Ok(result)
606
222k
    }
607
608
    /// Parse a list of comma-separated values, all with the same syntax.
609
    ///
610
    /// The given closure is called repeatedly with a "delimited" parser
611
    /// (see the `Parser::parse_until_before` method) so that it can over
612
    /// consume the input past a comma at this block/function nesting level.
613
    ///
614
    /// Successful results are accumulated in a vector.
615
    ///
616
    /// This method returns an`Err(..)` the first time that a closure call does,
617
    /// or if a closure call leaves some input before the next comma or the end
618
    /// of the input.
619
    #[inline]
620
    pub fn parse_comma_separated<F, T, E>(&mut self, parse_one: F) -> Result<Vec<T>, ParseError<E>>
621
    where
622
        F: FnMut(&mut Parser<'i>) -> Result<T, ParseError<E>>,
623
    {
624
        self.parse_comma_separated_internal(parse_one, /* ignore_errors = */ false)
625
    }
626
627
    /// Like `parse_comma_separated`, but ignores errors on unknown components,
628
    /// rather than erroring out in the whole list.
629
    ///
630
    /// Caller must deal with the fact that the resulting list might be empty,
631
    /// if there's no valid component on the list.
632
    #[inline]
633
    pub fn parse_comma_separated_ignoring_errors<F, T, E>(&mut self, parse_one: F) -> Vec<T>
634
    where
635
        F: FnMut(&mut Parser<'i>) -> Result<T, ParseError<E>>,
636
    {
637
        match self.parse_comma_separated_internal(parse_one, /* ignore_errors = */ true) {
638
            Ok(values) => values,
639
            Err(..) => unreachable!(),
640
        }
641
    }
642
643
    #[inline]
644
    fn parse_comma_separated_internal<F, T, E>(
645
        &mut self,
646
        mut parse_one: F,
647
        ignore_errors: bool,
648
    ) -> Result<Vec<T>, ParseError<E>>
649
    where
650
        F: FnMut(&mut Parser<'i>) -> Result<T, ParseError<E>>,
651
    {
652
        // Vec grows from 0 to 4 by default on first push().  So allocate with
653
        // capacity 1, so in the somewhat common case of only one item we don't
654
        // way overallocate.  Note that we always push at least one item if
655
        // parsing succeeds.
656
        let mut values = Vec::with_capacity(1);
657
        loop {
658
            self.skip_whitespace(); // Unnecessary for correctness, but may help try() in parse_one rewind less.
659
            match self.parse_until_before(Delimiter::Comma, &mut parse_one) {
660
                Ok(v) => values.push(v),
661
                Err(e) if !ignore_errors => return Err(e),
662
                Err(_) => {}
663
            }
664
            match self.next() {
665
                Err(_) => return Ok(values),
666
                Ok(&Token::Comma) => continue,
667
                Ok(_) => unreachable!(),
668
            }
669
        }
670
    }
671
672
    /// Parse the content of a block or function.
673
    ///
674
    /// This method panics if the last token yielded by this parser
675
    /// (from one of the `next*` methods)
676
    /// is not a on that marks the start of a block or function:
677
    /// a `Function`, `ParenthesisBlock`, `CurlyBracketBlock`, or `SquareBracketBlock`.
678
    ///
679
    /// The given closure is called with a "delimited" parser
680
    /// that stops at the end of the block or function (at the matching closing token).
681
    ///
682
    /// The result is overridden to an `Err(..)` if the closure leaves some input before that point.
683
    #[inline]
684
222k
    pub fn parse_nested_block<F, T, E>(&mut self, parse: F) -> Result<T, ParseError<E>>
685
222k
    where
686
222k
        F: FnOnce(&mut Parser<'i>) -> Result<T, ParseError<E>>,
687
    {
688
222k
        parse_nested_block(self, parse)
689
222k
    }
690
691
    /// Limit parsing to until a given delimiter or the end of the input. (E.g.
692
    /// a semicolon for a property value.)
693
    ///
694
    /// The given closure is called with a "delimited" parser
695
    /// that stops before the first character at this block/function nesting level
696
    /// that matches the given set of delimiters, or at the end of the input.
697
    ///
698
    /// The result is overridden to an `Err(..)` if the closure leaves some input before that point.
699
    #[inline]
700
    pub fn parse_until_before<F, T, E>(
701
        &mut self,
702
        delimiters: Delimiters,
703
        parse: F,
704
    ) -> Result<T, ParseError<E>>
705
    where
706
        F: FnOnce(&mut Parser<'i>) -> Result<T, ParseError<E>>,
707
    {
708
        parse_until_before(self, delimiters, ParseUntilErrorBehavior::Consume, parse)
709
    }
710
711
    /// Like `parse_until_before`, but also consume the delimiter token.
712
    ///
713
    /// This can be useful when you don’t need to know which delimiter it was
714
    /// (e.g. if these is only one in the given set)
715
    /// or if it was there at all (as opposed to reaching the end of the input).
716
    #[inline]
717
    pub fn parse_until_after<F, T, E>(
718
        &mut self,
719
        delimiters: Delimiters,
720
        parse: F,
721
    ) -> Result<T, ParseError<E>>
722
    where
723
        F: FnOnce(&mut Parser<'i>) -> Result<T, ParseError<E>>,
724
    {
725
        parse_until_after(self, delimiters, ParseUntilErrorBehavior::Consume, parse)
726
    }
727
728
    /// Parse a <whitespace-token> and return its value.
729
    #[inline]
730
    pub fn expect_whitespace(&mut self) -> Result<&'i str, BasicParseError> {
731
        match *self.next_including_whitespace()? {
732
            Token::WhiteSpace(value) => Ok(value),
733
            _ => Err(BasicParseError::unexpected_token()),
734
        }
735
    }
736
737
    /// Parse a <ident-token> and return the unescaped value.
738
    #[inline]
739
0
    pub fn expect_ident(&mut self) -> Result<&CowRcStr<'i>, BasicParseError> {
740
0
        expect! {self,
741
0
            Token::Ident(ref value) => Ok(value),
742
        }
743
0
    }
744
745
    /// expect_ident, but clone the CowRcStr
746
    #[inline]
747
    pub fn expect_ident_cloned(&mut self) -> Result<CowRcStr<'i>, BasicParseError> {
748
        self.expect_ident().cloned()
749
    }
750
751
    /// Parse a <ident-token> whose unescaped value is an ASCII-insensitive match for the given value.
752
    #[inline]
753
0
    pub fn expect_ident_matching(&mut self, expected_value: &str) -> Result<(), BasicParseError> {
754
0
        expect! {self,
755
0
            Token::Ident(ref value) if value.eq_ignore_ascii_case(expected_value) => Ok(()),
756
        }
757
0
    }
758
759
    /// Parse a <string-token> and return the unescaped value.
760
    #[inline]
761
    pub fn expect_string(&mut self) -> Result<&CowRcStr<'i>, BasicParseError> {
762
        expect! {self,
763
            Token::QuotedString(ref value) => Ok(value),
764
        }
765
    }
766
767
    /// expect_string, but clone the CowRcStr
768
    #[inline]
769
    pub fn expect_string_cloned(&mut self) -> Result<CowRcStr<'i>, BasicParseError> {
770
        self.expect_string().cloned()
771
    }
772
773
    /// Parse either a <ident-token> or a <string-token>, and return the unescaped value.
774
    #[inline]
775
    pub fn expect_ident_or_string(&mut self) -> Result<&CowRcStr<'i>, BasicParseError> {
776
        expect! {self,
777
            Token::Ident(ref value) => Ok(value),
778
            Token::QuotedString(ref value) => Ok(value),
779
        }
780
    }
781
782
    /// Parse a <url-token> and return the unescaped value.
783
    #[inline]
784
    pub fn expect_url(&mut self) -> Result<CowRcStr<'i>, BasicParseError> {
785
        expect! {self,
786
            Token::UnquotedUrl(ref value) => Ok(value.clone()),
787
            Token::Function(ref name) if name.eq_ignore_ascii_case("url") => {
788
                self.parse_nested_block(|input| {
789
                    input.expect_string().map_err(Into::into).cloned()
790
                })
791
                .map_err(ParseError::<()>::basic)
792
            }
793
        }
794
    }
795
796
    /// Parse either a <url-token> or a <string-token>, and return the unescaped value.
797
    #[inline]
798
    pub fn expect_url_or_string(&mut self) -> Result<CowRcStr<'i>, BasicParseError> {
799
        expect! {self,
800
            Token::UnquotedUrl(ref value) => Ok(value.clone()),
801
            Token::QuotedString(ref value) => Ok(value.clone()),
802
            Token::Function(ref name) if name.eq_ignore_ascii_case("url") => {
803
                self.parse_nested_block(|input| {
804
                    input.expect_string().map_err(Into::into).cloned()
805
                })
806
                .map_err(ParseError::<()>::basic)
807
            }
808
        }
809
    }
810
811
    /// Parse a <number-token> and return the integer value.
812
    #[inline]
813
    pub fn expect_number(&mut self) -> Result<f32, BasicParseError> {
814
        expect! {self,
815
            Token::Number { value, .. } => Ok(value),
816
        }
817
    }
818
819
    /// Parse a <number-token> that does not have a fractional part, and return the integer value.
820
    #[inline]
821
    pub fn expect_integer(&mut self) -> Result<i32, BasicParseError> {
822
        expect! {self,
823
            Token::Number { int_value: Some(int_value), .. } => Ok(int_value),
824
        }
825
    }
826
827
    /// Parse a <percentage-token> and return the value.
828
    /// `0%` and `100%` map to `0.0` and `1.0` (not `100.0`), respectively.
829
    #[inline]
830
    pub fn expect_percentage(&mut self) -> Result<f32, BasicParseError> {
831
        expect! {self,
832
            Token::Percentage { unit_value, .. } => Ok(unit_value),
833
        }
834
    }
835
836
    /// Parse a `:` <colon-token>.
837
    #[inline]
838
0
    pub fn expect_colon(&mut self) -> Result<(), BasicParseError> {
839
0
        expect! {self,
840
0
            Token::Colon => Ok(()),
841
        }
842
0
    }
843
844
    /// Parse a `;` <semicolon-token>.
845
    #[inline]
846
    pub fn expect_semicolon(&mut self) -> Result<(), BasicParseError> {
847
        expect! {self,
848
            Token::Semicolon => Ok(()),
849
        }
850
    }
851
852
    /// Parse a `,` <comma-token>.
853
    #[inline]
854
    pub fn expect_comma(&mut self) -> Result<(), BasicParseError> {
855
        expect! {self,
856
            Token::Comma => Ok(()),
857
        }
858
    }
859
860
    /// Parse a <delim-token> with the given value.
861
    #[inline]
862
0
    pub fn expect_delim(&mut self, expected_value: char) -> Result<(), BasicParseError> {
863
0
        expect! {self,
864
0
            Token::Delim(value) if value == expected_value => Ok(()),
865
        }
866
0
    }
867
868
    /// Parse a `{ /* ... */ }` curly brackets block.
869
    ///
870
    /// If the result is `Ok`, you can then call the `Parser::parse_nested_block` method.
871
    #[inline]
872
    pub fn expect_curly_bracket_block(&mut self) -> Result<(), BasicParseError> {
873
        expect! {self,
874
            Token::CurlyBracketBlock => Ok(()),
875
        }
876
    }
877
878
    /// Parse a `[ /* ... */ ]` square brackets block.
879
    ///
880
    /// If the result is `Ok`, you can then call the `Parser::parse_nested_block` method.
881
    #[inline]
882
    pub fn expect_square_bracket_block(&mut self) -> Result<(), BasicParseError> {
883
        expect! {self,
884
            Token::SquareBracketBlock => Ok(()),
885
        }
886
    }
887
888
    /// Parse a `( /* ... */ )` parenthesis block.
889
    ///
890
    /// If the result is `Ok`, you can then call the `Parser::parse_nested_block` method.
891
    #[inline]
892
    pub fn expect_parenthesis_block(&mut self) -> Result<(), BasicParseError> {
893
        expect! {self,
894
            Token::ParenthesisBlock => Ok(()),
895
        }
896
    }
897
898
    /// Parse a <function> token and return its name.
899
    ///
900
    /// If the result is `Ok`, you can then call the `Parser::parse_nested_block` method.
901
    #[inline]
902
    pub fn expect_function(&mut self) -> Result<&CowRcStr<'i>, BasicParseError> {
903
        expect! {self,
904
            Token::Function(ref name) => Ok(name),
905
        }
906
    }
907
908
    /// Parse a <function> token whose name is an ASCII-insensitive match for the given value.
909
    ///
910
    /// If the result is `Ok`, you can then call the `Parser::parse_nested_block` method.
911
    #[inline]
912
    pub fn expect_function_matching(&mut self, expected_name: &str) -> Result<(), BasicParseError> {
913
        expect! {self,
914
            Token::Function(ref name) if name.eq_ignore_ascii_case(expected_name) => Ok(()),
915
        }
916
    }
917
918
    /// Parse the input until exhaustion and check that it contains no “error” token.
919
    ///
920
    /// See `Token::is_parse_error`. This also checks nested blocks and functions recursively.
921
    #[inline]
922
    pub fn expect_no_error_token(&mut self) -> Result<(), BasicParseError> {
923
        loop {
924
            match self.next_including_whitespace_and_comments() {
925
                Ok(&Token::Function(_))
926
                | Ok(&Token::ParenthesisBlock)
927
                | Ok(&Token::SquareBracketBlock)
928
                | Ok(&Token::CurlyBracketBlock) => self
929
                    .parse_nested_block(|input| input.expect_no_error_token().map_err(Into::into))
930
                    .map_err(ParseError::<()>::basic)?,
931
                Ok(t) => {
932
                    // FIXME: maybe these should be separate variants of
933
                    // BasicParseError instead?
934
                    if t.is_parse_error() {
935
                        return Err(BasicParseError::unexpected_token());
936
                    }
937
                }
938
                Err(_) => return Ok(()),
939
            }
940
        }
941
    }
942
}
943
944
pub fn parse_until_before<'i, F, T, E>(
945
    parser: &mut Parser<'i>,
946
    delimiters: Delimiters,
947
    error_behavior: ParseUntilErrorBehavior,
948
    parse: F,
949
) -> Result<T, ParseError<E>>
950
where
951
    F: FnOnce(&mut Parser<'i>) -> Result<T, ParseError<E>>,
952
{
953
    let old_stop_before = parser.stop_before;
954
    let delimiters = parser.stop_before | delimiters;
955
    parser.stop_before = delimiters;
956
    let result = parser.parse_entirely(parse);
957
    parser.stop_before = old_stop_before;
958
    if error_behavior == ParseUntilErrorBehavior::Stop && result.is_err() {
959
        return result;
960
    }
961
    parser.skip_block_at_start();
962
    // FIXME: have a special-purpose tokenizer method for this that does less work.
963
    while let Some(next_byte) = parser.next_byte() {
964
        if delimiters.contains(Delimiters::from_byte(next_byte)) {
965
            break;
966
        }
967
        parser.next_unchecked();
968
        parser.skip_block_at_start();
969
    }
970
    result
971
}
972
973
pub fn parse_until_after<'i, F, T, E>(
974
    parser: &mut Parser<'i>,
975
    delimiters: Delimiters,
976
    error_behavior: ParseUntilErrorBehavior,
977
    parse: F,
978
) -> Result<T, ParseError<E>>
979
where
980
    F: FnOnce(&mut Parser<'i>) -> Result<T, ParseError<E>>,
981
{
982
    let result = parse_until_before(parser, delimiters, error_behavior, parse);
983
    if error_behavior == ParseUntilErrorBehavior::Stop && result.is_err() {
984
        return result;
985
    }
986
    if let Some(next_byte) = parser.next_byte() {
987
        let delimiter = Delimiters::from_byte(next_byte);
988
        if !parser.stop_before.contains(delimiter) {
989
            debug_assert!(delimiters.contains(delimiter));
990
            // We know this byte is ASCII.
991
            parser.advance(1);
992
            if next_byte == b'{' {
993
                parser.consume_until_end_of_block(BlockType::CurlyBracket);
994
            }
995
        }
996
    }
997
    result
998
}
999
1000
222k
pub fn parse_nested_block<'i, F, T, E>(
1001
222k
    parser: &mut Parser<'i>,
1002
222k
    parse: F,
1003
222k
) -> Result<T, ParseError<E>>
1004
222k
where
1005
222k
    F: FnOnce(&mut Parser<'i>) -> Result<T, ParseError<E>>,
1006
{
1007
222k
    let block_type = parser.state.take_at_start_of().expect(
1008
222k
        "\
1009
222k
         A nested parser can only be created when a Function, \
1010
222k
         ParenthesisBlock, SquareBracketBlock, or CurlyBracketBlock \
1011
222k
         token was just consumed.\
1012
222k
         ",
1013
    );
1014
222k
    if parser.current_block_depth >= parser.nested_block_limit && parser.nested_block_limit != 0 {
1015
12
        return Err(ParseError::from_basic_kind(
1016
12
            BasicParseErrorKind::TooManyNestedBlocks,
1017
12
        ));
1018
222k
    }
1019
    // Fine to use wrapping addition, overflow can only occur without a limit.
1020
222k
    parser.current_block_depth = parser.current_block_depth.wrapping_add(1);
1021
1022
222k
    let old_stop_before = parser.stop_before;
1023
222k
    parser.stop_before = match block_type {
1024
194k
        BlockType::CurlyBracket => ClosingDelimiter::CloseCurlyBracket,
1025
8.58k
        BlockType::SquareBracket => ClosingDelimiter::CloseSquareBracket,
1026
18.8k
        BlockType::Parenthesis => ClosingDelimiter::CloseParenthesis,
1027
    };
1028
222k
    let result = parser.parse_entirely(parse);
1029
222k
    parser.skip_block_at_start();
1030
222k
    parser.consume_until_end_of_block(block_type);
1031
222k
    parser.stop_before = old_stop_before;
1032
222k
    parser.current_block_depth = parser.current_block_depth.wrapping_sub(1);
1033
222k
    result
1034
222k
}
1035
1036
impl Parser<'_> {
1037
    /// Consume tokens until the end of a block of the given type that we're at the start of,
1038
    /// ignoring any `stop_before` delimiters.
1039
    #[inline(never)]
1040
    #[cold]
1041
222k
    pub(crate) fn consume_until_end_of_block(&mut self, block_type: BlockType) {
1042
222k
        let mut stack = SmallVec::<[BlockType; 16]>::new();
1043
222k
        stack.push(block_type);
1044
1045
        // FIXME: have a special-purpose tokenizer method for this that does less work.
1046
5.63M
        while !self.is_eof() {
1047
5.62M
            let token = self.next_unchecked();
1048
5.62M
            if let Some(nested_block_type) = self.state.take_at_start_of() {
1049
4.14M
                stack.push(nested_block_type);
1050
4.14M
                continue;
1051
1.47M
            }
1052
1.47M
            if let Some(b) = BlockType::closing(&token) {
1053
282k
                if *stack.last().unwrap() == b {
1054
264k
                    stack.pop();
1055
264k
                    if stack.is_empty() {
1056
204k
                        return;
1057
60.3k
                    }
1058
17.4k
                }
1059
1.19M
            }
1060
        }
1061
222k
    }
1062
}