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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
use super::prelude::*;
use crate::{Declaration, KindSet, NodeMetadata, NodeWithMetadata, SemanticEq, ToCursors};
use css_lexer::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 DeclarationValue<'a, M: NodeMetadata>: Sized + NodeWithMetadata<M> + ToSpan + ToCursors + SemanticEq {
/// Returns metadata for this value when used in a declaration context.
/// This allows the value to inspect the declaration (e.g., checking for !important)
/// and include that information in the metadata.
///
/// The default implementation returns the value's metadata marked as a declaration, ignoring the
/// declaration context.
fn declaration_metadata(declaration: &Declaration<'a, Self, M>) -> M {
declaration.value.metadata().with_declaration()
}
/// Determines if the given [Cursor] represents a valid [Ident][crate::token_macros::Ident] matching a known property
/// name.
///
/// If implementing a set of declarations where ony limited property-ids are valid (such as the declarations allowed
/// by an at-rule) then it might be worthwhile changing this to sometimes return `false`, which consumers of this
/// trait can use to error early without having to do too much backtracking.
fn valid_declaration_name<Iter>(_p: &Parser<'a, Iter>, _c: Cursor) -> bool
where
Iter: Iterator<Item = crate::Cursor> + Clone,
{
true
}
/// Determines if the parsed Self was parsed as an unknown value.
///
/// If implementing a set of declarations where any name is accepted, or where the value might result in re-parsing
/// as unknown, this method can be used to signal that to upstream consumers of this trait. By default this returns
/// `false` because `valid_declaration_name` returns `true`, the assumption being that any successful construction of
/// Self is indeed a valid and known declaration.
fn is_unknown(&self) -> bool {
false
}
/// Determines if the parsed Self was parsed as a Custom value.
///
/// If implementing a set of declarations where custom names are accepted, or where the value might result in
/// re-parsing as unknown, this method can be used to signal that to upstream consumers of this trait. By default
/// this returns `false` because `valid_declaration_name` returns `true`, the assumption being that any successful
/// construction of Self is indeed a valid and known declaration.
fn is_custom(&self) -> bool {
false
}
/// Determines if the parsed Self was parsed as the "initial" keyword.
///
/// If implementing a set of declarations where the "initial" keyword is accepted this method can be used to signal
/// that to upstream consumers of this trait. Defaults to returning false.
fn is_initial(&self) -> bool {
false
}
/// Determines if the parsed Self was parsed as the "inherit" keyword.
///
/// If implementing a set of declarations where the "inherit" keyword is accepted this method can be used to signal
/// that to upstream consumers of this trait. Defaults to returning false.
fn is_inherit(&self) -> bool {
false
}
/// Determines if the parsed Self was parsed as the "unset" keyword.
///
/// If implementing a set of declarations where the "unset" keyword is accepted this method can be used to signal
/// that to upstream consumers of this trait. Defaults to returning false.
fn is_unset(&self) -> bool {
false
}
/// Determines if the parsed Self was parsed as the "revert" keyword.
///
/// If implementing a set of declarations where the "revert" keyword is accepted this method can be used to signal
/// that to upstream consumers of this trait. Defaults to returning false.
fn is_revert(&self) -> bool {
false
}
/// Determines if the parsed Self was parsed as the "revert-layer" keyword.
///
/// If implementing a set of declarations where the "revert-layer" keyword is accepted this method can be used to signal
/// that to upstream consumers of this trait. Defaults to returning false.
fn is_revert_layer(&self) -> bool {
false
}
/// Determines if the parsed Self was parsed as the "revert-rule" keyword.
///
/// If implementing a set of declarations where the "revert-rule" keyword is accepted this method can be used to signal
/// that to upstream consumers of this trait. Defaults to returning false.
fn is_revert_rule(&self) -> bool {
false
}
/// Determines if the parsed Self is not a valid literal production of the grammar, and instead some of its
/// constituent parts will need additional computation to reify into a known value.
///
/// CSS properties are allowed to include substitutions, such as `calc()` or `var()`. These are not defined in the
/// declaration's grammar but are instead stored so that when a style object is reified the declarations that had
/// those tokens can be recomputed against the context of their node. Defaults to returning false.
fn needs_computing(&self) -> bool {
false
}
/// Like `parse()` but with the additional context of the `name` [Cursor]. This cursor is known to be dashed ident,
/// therefore this should return a `Self` reflecting a Custom property. Alternatively, if this DeclarationValue
/// disallows custom declarations then this is the right place to return a parse Error.
///
/// The default implementation of this method is to return an Unexpected Err.
fn parse_custom_declaration_value<Iter>(p: &mut Parser<'a, Iter>, _name: Cursor) -> Result<Self>
where
Iter: Iterator<Item = crate::Cursor> + Clone,
{
let c = p.peek_n(1);
Err(Diagnostic::new(c, Diagnostic::unexpected))?
}
/// Determines if the given [Cursor] begins a computed value (an arbitrary substitution function such as
/// `var()`/`env()`, or a typed math function such as `calc()`/`min()`).
///
/// This is used by [`parse_declaration_value`][DeclarationValue::parse_declaration_value] as the fallback check after
/// property-specific parsing fails or stops early: if this returns `true` the whole declaration is re-parsed via
/// [`parse_computed_declaration_value`][DeclarationValue::parse_computed_declaration_value].
///
/// The default implementation returns `false`, i.e. this DeclarationValue has no computed fallback.
fn is_computed_declaration_value<Iter>(_p: &Parser<'a, Iter>, _c: Cursor) -> bool
where
Iter: Iterator<Item = crate::Cursor> + Clone,
{
false
}
/// Like `parse()` but with the additional context of the `name` [Cursor]. This is only called before verifying that
/// the next token was peeked to be a ComputedValue, therefore this should return a `Self` reflecting a Computed
/// property. Alternatively, if this DeclarationValue disallows computed declarations then this is the right place to
/// return a parse Error.
///
/// The default implementation of this method is to return an Unexpected Err.
fn parse_computed_declaration_value<Iter>(p: &mut Parser<'a, Iter>, _name: Cursor) -> Result<Self>
where
Iter: Iterator<Item = crate::Cursor> + Clone,
{
let c = p.peek_n(1);
Err(Diagnostic::new(c, Diagnostic::unexpected))?
}
/// Like `parse()` but with the additional context of the `name` [Cursor]. This is only called on values that are
/// assumed to be _specified_, that is, they're not custom and not computed. Therefore this should return a `Self`
/// reflecting a specified value. If this results in a Parse error then ComputedValue will be checked to see if the
/// parser stopped because it saw a computed value function. If this results in a success, the next token is still
/// checked as it may be a ComputedValue, which - if so - the parsed value will be discarded, and the parser rewound
/// to re-parse this as a ComputedValue.
///
/// The default implementation of this method is to return an Unexpected Err.
fn parse_specified_declaration_value<Iter>(p: &mut Parser<'a, Iter>, _name: Cursor) -> Result<Self>
where
Iter: Iterator<Item = crate::Cursor> + Clone,
{
let c = p.peek_n(1);
Err(Diagnostic::new(c, Diagnostic::unexpected))?
}
/// Like `parse()` but with the additional context of the `name` [Cursor]. This is only called on values that are
/// didn't parse as either a Custom, Computed or Specified value therefore this should return a `Self` reflecting an
/// unknown property, or alternatively the right place to return a parse error.
///
/// The default implementation of this method is to return an Unexpected Err.
fn parse_unknown_declaration_value<Iter>(p: &mut Parser<'a, Iter>, _name: Cursor) -> Result<Self>
where
Iter: Iterator<Item = crate::Cursor> + Clone,
{
let c = p.peek_n(1);
Err(Diagnostic::new(c, Diagnostic::unexpected))?
}
// Like `parse()` but with the additional context of the `name` [Cursor] - the same [Cursor]
// passed to [DeclarationValue::valid_declaration_name()].
//
// Parsing order:
// 1. Custom properties (--dashed-ident)
// 2. Unknown property names
// 3. Property-specific parsing (via parse_specified_declaration_value)
// 4. Fallback to Computed for var/calc if property parsing failed/stopped early
// 5. Unknown as final fallback
fn parse_declaration_value<Iter>(p: &mut Parser<'a, Iter>, name: Cursor) -> Result<Self>
where
Iter: Iterator<Item = crate::Cursor> + Clone,
{
if name.token().is_dashed_ident() {
return Self::parse_custom_declaration_value(p, name);
}
if !Self::valid_declaration_name(p, name) {
return Self::parse_unknown_declaration_value(p, name);
}
let checkpoint = p.checkpoint();
if let Ok(val) = Self::parse_specified_declaration_value(p, name) {
let c = p.peek_n(1);
if p.at_end() || c == KindSet::RIGHT_CURLY_SEMICOLON_OR_RIGHT_PAREN || <T![!]>::peek(p, c) {
return Ok(val);
}
}
p.rewind(checkpoint.clone());
if Self::is_computed_declaration_value(p, p.peek_n(1))
&& let Ok(val) = Self::parse_computed_declaration_value(p, name)
{
return Ok(val);
}
p.rewind(checkpoint);
Self::parse_unknown_declaration_value(p, name)
}
}