css_parse/syntax/
bad_declaration.rs

1use crate::{
2	CursorSink, Parse, Parser, Peek, 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<Iter>(p: &mut Parser<'a, Iter>) -> ParserResult<Self>
13	where
14		Iter: Iterator<Item = crate::Cursor> + Clone,
15	{
16		let mut values = Vec::new_in(p.bump());
17		// To consume the remnants of a bad declaration from a token stream input, given a bool nested:
18		//
19		// Process input:
20		loop {
21			// <eof-token>
22			// <semicolon-token>
23			//
24			//     Discard a token from input, and return nothing.
25			if p.at_end() {
26				return Ok(Self(values));
27			}
28			let c = p.peek_n(1);
29			if <T![;]>::peek(p, c) {
30				values.push(p.parse::<ComponentValue>()?);
31				return Ok(Self(values));
32			}
33
34			// <}-token>
35			//
36			//     If nested is true, return nothing. Otherwise, discard a token.
37			if <T!['}']>::peek(p, c) {
38				if p.is(State::Nested) {
39					return Ok(Self(values));
40				} else {
41					p.parse::<T!['}']>()?;
42				}
43			}
44
45			// anything else
46			//
47			//     Consume a component value from input, and do nothing.
48			//
49			values.push(p.parse::<ComponentValue>()?);
50		}
51	}
52}
53
54impl<'a> ToSpan for BadDeclaration<'a> {
55	fn to_span(&self) -> Span {
56		self.0.to_span()
57	}
58}
59
60impl<'a> ToCursors for BadDeclaration<'a> {
61	fn to_cursors(&self, s: &mut impl CursorSink) {
62		for value in &self.0 {
63			ToCursors::to_cursors(value, s);
64		}
65	}
66}