Skip to main content

cssparser/
parser.rs

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