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