css_parse/syntax/
declaration_list.rs

1use crate::{
2	CursorSink, Declaration, DeclarationValue, Kind, KindSet, Parse, Parser, Peek, Result, Span, T, ToCursors, ToSpan,
3	token_macros,
4};
5use bumpalo::collections::Vec;
6
7/// A generic struct that can be used for AST nodes representing a rule's block, that is only capable of having child
8/// declarations.
9///
10/// It is an [implementation of "declaration-list"][1]. It includes an error tolerance in that the ending `}` token can
11/// be omitted, if at the end of the file.
12///
13/// The `<V>` must implement the [DeclarationValue] trait, as it is passed to [Declaration].
14///
15/// ```md
16/// <declaration-list>
17///  │├─ "{" ─╮─╭─ <declaration> ──╮─╭─╮─ "}" ─╭─┤│
18///           │ │                  │ │ ╰───────╯
19///           │ ╰──────────────────╯ │
20///           ╰──────────────────────╯
21/// ```
22///
23/// [1]: https://drafts.csswg.org/css-syntax-3/#typedef-declaration-list
24#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
26pub struct DeclarationList<'a, V: DeclarationValue<'a>> {
27	pub open_curly: token_macros::LeftCurly,
28	pub declarations: Vec<'a, Declaration<'a, V>>,
29	pub close_curly: Option<token_macros::RightCurly>,
30}
31
32impl<'a, V: DeclarationValue<'a>> Peek<'a> for DeclarationList<'a, V> {
33	const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::LeftCurly]);
34}
35
36impl<'a, V: DeclarationValue<'a>> Parse<'a> for DeclarationList<'a, V> {
37	fn parse(p: &mut Parser<'a>) -> Result<Self> {
38		let open_curly = p.parse::<T!['{']>()?;
39		let mut declarations = Vec::new_in(p.bump());
40		loop {
41			if p.at_end() {
42				return Ok(Self { open_curly, declarations, close_curly: None });
43			}
44			let close_curly = p.parse_if_peek::<T!['}']>()?;
45			if close_curly.is_some() {
46				return Ok(Self { open_curly, declarations, close_curly });
47			}
48			let declaration = p.parse::<Declaration<'a, V>>()?;
49			declarations.push(declaration);
50		}
51	}
52}
53
54impl<'a, V: DeclarationValue<'a> + ToCursors> ToCursors for DeclarationList<'a, V> {
55	fn to_cursors(&self, s: &mut impl CursorSink) {
56		ToCursors::to_cursors(&self.open_curly, s);
57		ToCursors::to_cursors(&self.declarations, s);
58		ToCursors::to_cursors(&self.close_curly, s);
59	}
60}
61
62impl<'a, V: DeclarationValue<'a> + ToSpan> ToSpan for DeclarationList<'a, V> {
63	fn to_span(&self) -> Span {
64		self.open_curly.to_span()
65			+ if let Some(close) = self.close_curly { close.to_span() } else { self.declarations.to_span() }
66	}
67}