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}