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}