css_parse/syntax/
bad_declaration.rs

1use crate::{
2	CursorSink, Parse, Parser, Result as ParserResult, Span, State, T, ToCursors, ToSpan, syntax::ComponentValue,
3};
4use bumpalo::collections::Vec;
5
6#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
8pub struct BadDeclaration<'a>(Vec<'a, ComponentValue<'a>>);
9
10// https://drafts.csswg.org/css-syntax-3/#consume-the-remnants-of-a-bad-declaration
11impl<'a> Parse<'a> for BadDeclaration<'a> {
12	fn parse(p: &mut Parser<'a>) -> ParserResult<Self> {
13		let mut values = Vec::new_in(p.bump());
14		// To consume the remnants of a bad declaration from a token stream input, given a bool nested:
15		//
16		// Process input:
17		loop {
18			// <eof-token>
19			// <semicolon-token>
20			//
21			//     Discard a token from input, and return nothing.
22			if p.at_end() {
23				return Ok(Self(values));
24			}
25			if p.peek::<T![;]>() {
26				values.push(p.parse::<ComponentValue>()?);
27				return Ok(Self(values));
28			}
29
30			// <}-token>
31			//
32			//     If nested is true, return nothing. Otherwise, discard a token.
33			if p.peek::<T!['}']>() {
34				if p.is(State::Nested) {
35					return Ok(Self(values));
36				} else {
37					p.parse::<T!['}']>()?;
38				}
39			}
40
41			// anything else
42			//
43			//     Consume a component value from input, and do nothing.
44			//
45			values.push(p.parse::<ComponentValue>()?);
46		}
47	}
48}
49
50impl<'a> ToSpan for BadDeclaration<'a> {
51	fn to_span(&self) -> Span {
52		self.0.to_span()
53	}
54}
55
56impl<'a> ToCursors for BadDeclaration<'a> {
57	fn to_cursors(&self, s: &mut impl CursorSink) {
58		for value in &self.0 {
59			ToCursors::to_cursors(value, s);
60		}
61	}
62}