css_parse/traits/
rule_variants.rs

1use crate::{BadDeclaration, Cursor, Diagnostic, Parser, Peek, Result, State, T, ToCursors, ToSpan};
2
3/// A trait that can be used for AST nodes representing a Declaration's Value. It offers some
4/// convenience functions for handling such values.
5pub trait RuleVariants<'a>: Sized + ToCursors + ToSpan {
6	/// The declaration value type used when converting declaration groups to rules.
7	type DeclarationValue: crate::DeclarationValue<'a, Self::Metadata>;
8
9	/// The metadata type used when converting declaration groups to rules.
10	type Metadata: crate::NodeMetadata;
11
12	/// Like [crate::Parse::parse()] but with the additional context of the `name` [Cursor]. This cursor is known to be
13	/// an [AtKeyword][crate::token_macros::AtKeyword], therefore this should return a `Self` reflecting a AtRule. If the
14	/// AtRule is not _known_, or otherwise fails then this should [Err] and [RuleVariants::parse_unknown_at_rule()] can
15	/// be called.
16	///
17	/// The default implementation of this method is to return an Unexpected [Err].
18	fn parse_at_rule<I>(p: &mut Parser<'a, I>, _name: Cursor) -> Result<Self>
19	where
20		I: Iterator<Item = Cursor> + Clone,
21	{
22		let c = p.peek_n(1);
23		Err(Diagnostic::new(c, Diagnostic::unexpected))?
24	}
25
26	/// Like [crate::Parse::parse()] but with the additional context of the `name` [Cursor]. This cursor is known to be
27	/// an AtKeyword and that [RuleVariants::parse_at_rule()] failed. This should therefore return a Self that represents
28	/// an Unknown AtRule, or otherwise [Err].
29	///
30	/// The default implementation of this method is to return an Unexpected [Err].
31	fn parse_unknown_at_rule<I>(p: &mut Parser<'a, I>, _name: Cursor) -> Result<Self>
32	where
33		I: Iterator<Item = Cursor> + Clone,
34	{
35		let c = p.peek_n(1);
36		Err(Diagnostic::new(c, Diagnostic::unexpected))?
37	}
38
39	/// Like [crate::Parse::parse()] but with the additional context that the next cursor is _not_ an
40	/// [AtKeyword][crate::token_macros::AtKeyword], therefore this can attempt to parse a Qualified Rule. If the rule
41	/// fails to parse, then [RuleVariants::parse_unknown_qualified_rule()] will be called.
42	///
43	/// The default implementation of this method is to return an Unexpected [Err].
44	fn parse_qualified_rule<I>(p: &mut Parser<'a, I>, _name: Cursor) -> Result<Self>
45	where
46		I: Iterator<Item = Cursor> + Clone,
47	{
48		let c = p.peek_n(1);
49		Err(Diagnostic::new(c, Diagnostic::unexpected))?
50	}
51
52	/// Like [crate::Parse::parse()] but with the additional context that the next cursor is _not_ an
53	/// [AtKeyword][crate::token_macros::AtKeyword], and that [RuleVariants::parse_qualified_rule()] has failed.
54	/// Therefore this should attempt to parse an Unknown Qualified Rule, or [Err].
55	///
56	/// The default implementation of this method is to return an Unexpected [Err].
57	fn parse_unknown_qualified_rule<I>(p: &mut Parser<'a, I>, _name: Cursor) -> Result<Self>
58	where
59		I: Iterator<Item = Cursor> + Clone,
60	{
61		let c = p.peek_n(1);
62		Err(Diagnostic::new(c, Diagnostic::unexpected))?
63	}
64
65	/// If all of the parse steps have failed, including parsing the Unknown Qualified Rule, we may want to consume a bad
66	/// declaration (especially if the parser is in a nested context). This is done automatically on failing to parse
67	/// an Unknown Qualified Rule, and this method is given the [BadDeclaration].
68	///
69	/// This should attempt to build a Self that represents the [BadDeclaration], or return [None] so
70	/// [RuleVariants::parse_rule_variants()] can [Err].
71	///
72	/// The default implementation of this method is to return [None].
73	fn bad_declaration(_: BadDeclaration<'a>) -> Option<Self> {
74		None
75	}
76
77	/// Determines if the parsed Self was parsed as an unknown rule (UnknownAtRule or UnknownQualifiedRule).
78	///
79	/// This is used to distinguish between known rules (like @media, @supports, style rules) and unknown rules.
80	/// When disambiguating between declarations and rules, known rules should be preferred over unknown declarations,
81	/// but unknown declarations should be preferred over unknown rules.
82	///
83	/// The default implementation returns false, assuming all rules are known.
84	fn is_unknown(&self) -> bool {
85		false
86	}
87
88	/// Creates a rule variant from a group of declarations.
89	///
90	/// Per [CSS Syntax ยง 5.4.4](https://drafts.csswg.org/css-syntax-3/#consume-block-contents),
91	/// blocks can contain interleaved declarations and rules. This method allows wrapping groups
92	/// of declarations as a rule variant for storage in the rules list.
93	///
94	/// Returns `None` if this rule type doesn't support declaration interleaving.
95	fn from_declaration_group(
96		_group: crate::DeclarationGroup<'a, Self::DeclarationValue, Self::Metadata>,
97	) -> Option<Self> {
98		None
99	}
100
101	fn parse_rule_variants<I>(p: &mut Parser<'a, I>) -> Result<Self>
102	where
103		I: Iterator<Item = Cursor> + Clone,
104	{
105		let checkpoint = p.checkpoint();
106		let c: Cursor = p.peek_n(1);
107		if <T![AtKeyword]>::peek(p, c) {
108			Self::parse_at_rule(p, c).or_else(|_| {
109				p.rewind(checkpoint);
110				Self::parse_unknown_at_rule(p, c)
111			})
112		} else {
113			Self::parse_qualified_rule(p, c)
114				.or_else(|_| {
115					p.rewind(checkpoint.clone());
116					Self::parse_unknown_qualified_rule(p, c)
117				})
118				.or_else(|_| {
119					p.rewind(checkpoint);
120					let state = p.set_state(State::Nested);
121					let declaration = p.parse::<BadDeclaration>();
122					p.set_state(state);
123					if let Some(s) = Self::bad_declaration(declaration?) {
124						Ok(s)
125					} else {
126						Err(Diagnostic::new(c, Diagnostic::unexpected))?
127					}
128				})
129		}
130	}
131}