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