Skip to main content

css_parse/traits/
rule_variants.rs

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