Skip to main content

css_parse/traits/
declaration_value.rs

1use super::prelude::*;
2use crate::{Declaration, KindSet, NodeMetadata, NodeWithMetadata, SemanticEq, ToCursors};
3use css_lexer::ToSpan;
4
5/// A trait that can be used for AST nodes representing a Declaration's Value. It offers some
6/// convenience functions for handling such values.
7pub trait DeclarationValue<'a, M: NodeMetadata>: Sized + NodeWithMetadata<M> + ToSpan + ToCursors + SemanticEq {
8	/// Returns metadata for this value when used in a declaration context.
9	/// This allows the value to inspect the declaration (e.g., checking for !important)
10	/// and include that information in the metadata.
11	///
12	/// The default implementation returns the value's metadata marked as a declaration, ignoring the
13	/// declaration context.
14	fn declaration_metadata(declaration: &Declaration<'a, Self, M>) -> M {
15		declaration.value.metadata().with_declaration()
16	}
17
18	/// Determines if the given [Cursor] represents a valid [Ident][crate::token_macros::Ident] matching a known property
19	/// name.
20	///
21	/// If implementing a set of declarations where ony limited property-ids are valid (such as the declarations allowed
22	/// by an at-rule) then it might be worthwhile changing this to sometimes return `false`, which consumers of this
23	/// trait can use to error early without having to do too much backtracking.
24	fn valid_declaration_name<Iter>(_p: &Parser<'a, Iter>, _c: Cursor) -> bool
25	where
26		Iter: Iterator<Item = crate::Cursor> + Clone,
27	{
28		true
29	}
30
31	/// Determines if the parsed Self was parsed as an unknown value.
32	///
33	/// If implementing a set of declarations where any name is accepted, or where the value might result in re-parsing
34	/// as unknown, this method can be used to signal that to upstream consumers of this trait. By default this returns
35	/// `false` because `valid_declaration_name` returns `true`, the assumption being that any successful construction of
36	/// Self is indeed a valid and known declaration.
37	fn is_unknown(&self) -> bool {
38		false
39	}
40
41	/// Determines if the parsed Self was parsed as a Custom value.
42	///
43	/// If implementing a set of declarations where custom names are accepted, or where the value might result in
44	/// re-parsing as unknown, this method can be used to signal that to upstream consumers of this trait. By default
45	/// this returns `false` because `valid_declaration_name` returns `true`, the assumption being that any successful
46	/// construction of Self is indeed a valid and known declaration.
47	fn is_custom(&self) -> bool {
48		false
49	}
50
51	/// Determines if the parsed Self was parsed as the "initial" keyword.
52	///
53	/// If implementing a set of declarations where the "initial" keyword is accepted this method can be used to signal
54	/// that to upstream consumers of this trait. Defaults to returning false.
55	fn is_initial(&self) -> bool {
56		false
57	}
58
59	/// Determines if the parsed Self was parsed as the "inherit" keyword.
60	///
61	/// If implementing a set of declarations where the "inherit" keyword is accepted this method can be used to signal
62	/// that to upstream consumers of this trait. Defaults to returning false.
63	fn is_inherit(&self) -> bool {
64		false
65	}
66
67	/// Determines if the parsed Self was parsed as the "unset" keyword.
68	///
69	/// If implementing a set of declarations where the "unset" keyword is accepted this method can be used to signal
70	/// that to upstream consumers of this trait. Defaults to returning false.
71	fn is_unset(&self) -> bool {
72		false
73	}
74
75	/// Determines if the parsed Self was parsed as the "revert" keyword.
76	///
77	/// If implementing a set of declarations where the "revert" keyword is accepted this method can be used to signal
78	/// that to upstream consumers of this trait. Defaults to returning false.
79	fn is_revert(&self) -> bool {
80		false
81	}
82
83	/// Determines if the parsed Self was parsed as the "revert-layer" keyword.
84	///
85	/// If implementing a set of declarations where the "revert-layer" keyword is accepted this method can be used to signal
86	/// that to upstream consumers of this trait. Defaults to returning false.
87	fn is_revert_layer(&self) -> bool {
88		false
89	}
90
91	/// Determines if the parsed Self was parsed as the "revert-rule" keyword.
92	///
93	/// If implementing a set of declarations where the "revert-rule" keyword is accepted this method can be used to signal
94	/// that to upstream consumers of this trait. Defaults to returning false.
95	fn is_revert_rule(&self) -> bool {
96		false
97	}
98
99	/// Determines if the parsed Self is not a valid literal production of the grammar, and instead some of its
100	/// constituent parts will need additional computation to reify into a known value.
101	///
102	/// CSS properties are allowed to include substitutions, such as `calc()` or `var()`. These are not defined in the
103	/// declaration's grammar but are instead stored so that when a style object is reified the declarations that had
104	/// those tokens can be recomputed against the context of their node. Defaults to returning false.
105	fn needs_computing(&self) -> bool {
106		false
107	}
108
109	/// Like `parse()` but with the additional context of the `name` [Cursor]. This cursor is known to be dashed ident,
110	/// therefore this should return a `Self` reflecting a Custom property. Alternatively, if this DeclarationValue
111	/// disallows custom declarations then this is the right place to return a parse Error.
112	///
113	/// The default implementation of this method is to return an Unexpected Err.
114	fn parse_custom_declaration_value<Iter>(p: &mut Parser<'a, Iter>, _name: Cursor) -> Result<Self>
115	where
116		Iter: Iterator<Item = crate::Cursor> + Clone,
117	{
118		let c = p.peek_n(1);
119		Err(Diagnostic::new(c, Diagnostic::unexpected))?
120	}
121
122	/// Determines if the given [Cursor] begins a computed value (an arbitrary substitution function such as
123	/// `var()`/`env()`, or a typed math function such as `calc()`/`min()`).
124	///
125	/// This is used by [`parse_declaration_value`][DeclarationValue::parse_declaration_value] as the fallback check after
126	/// property-specific parsing fails or stops early: if this returns `true` the whole declaration is re-parsed via
127	/// [`parse_computed_declaration_value`][DeclarationValue::parse_computed_declaration_value].
128	///
129	/// The default implementation returns `false`, i.e. this DeclarationValue has no computed fallback.
130	fn is_computed_declaration_value<Iter>(_p: &Parser<'a, Iter>, _c: Cursor) -> bool
131	where
132		Iter: Iterator<Item = crate::Cursor> + Clone,
133	{
134		false
135	}
136
137	/// Like `parse()` but with the additional context of the `name` [Cursor]. This is only called before verifying that
138	/// the next token was peeked to be a ComputedValue, therefore this should return a `Self` reflecting a Computed
139	/// property. Alternatively, if this DeclarationValue disallows computed declarations then this is the right place to
140	/// return a parse Error.
141	///
142	/// The default implementation of this method is to return an Unexpected Err.
143	fn parse_computed_declaration_value<Iter>(p: &mut Parser<'a, Iter>, _name: Cursor) -> Result<Self>
144	where
145		Iter: Iterator<Item = crate::Cursor> + Clone,
146	{
147		let c = p.peek_n(1);
148		Err(Diagnostic::new(c, Diagnostic::unexpected))?
149	}
150
151	/// Like `parse()` but with the additional context of the `name` [Cursor]. This is only called on values that are
152	/// assumed to be _specified_, that is, they're not custom and not computed. Therefore this should return a `Self`
153	/// reflecting a specified value. If this results in a Parse error then ComputedValue will be checked to see if the
154	/// parser stopped because it saw a computed value function. If this results in a success, the next token is still
155	/// checked as it may be a ComputedValue, which - if so - the parsed value will be discarded, and the parser rewound
156	/// to re-parse this as a ComputedValue.
157	///
158	/// The default implementation of this method is to return an Unexpected Err.
159	fn parse_specified_declaration_value<Iter>(p: &mut Parser<'a, Iter>, _name: Cursor) -> Result<Self>
160	where
161		Iter: Iterator<Item = crate::Cursor> + Clone,
162	{
163		let c = p.peek_n(1);
164		Err(Diagnostic::new(c, Diagnostic::unexpected))?
165	}
166
167	/// Like `parse()` but with the additional context of the `name` [Cursor]. This is only called on values that are
168	/// didn't parse as either a Custom, Computed or Specified value therefore this should return a `Self` reflecting an
169	/// unknown property, or alternatively the right place to return a parse error.
170	///
171	/// The default implementation of this method is to return an Unexpected Err.
172	fn parse_unknown_declaration_value<Iter>(p: &mut Parser<'a, Iter>, _name: Cursor) -> Result<Self>
173	where
174		Iter: Iterator<Item = crate::Cursor> + Clone,
175	{
176		let c = p.peek_n(1);
177		Err(Diagnostic::new(c, Diagnostic::unexpected))?
178	}
179
180	// Like `parse()` but with the additional context of the `name` [Cursor] - the same [Cursor]
181	// passed to [DeclarationValue::valid_declaration_name()].
182	//
183	// Parsing order:
184	// 1. Custom properties (--dashed-ident)
185	// 2. Unknown property names
186	// 3. Property-specific parsing (via parse_specified_declaration_value)
187	// 4. Fallback to Computed for var/calc if property parsing failed/stopped early
188	// 5. Unknown as final fallback
189	fn parse_declaration_value<Iter>(p: &mut Parser<'a, Iter>, name: Cursor) -> Result<Self>
190	where
191		Iter: Iterator<Item = crate::Cursor> + Clone,
192	{
193		if name.token().is_dashed_ident() {
194			return Self::parse_custom_declaration_value(p, name);
195		}
196		if !Self::valid_declaration_name(p, name) {
197			return Self::parse_unknown_declaration_value(p, name);
198		}
199
200		let checkpoint = p.checkpoint();
201		if let Ok(val) = Self::parse_specified_declaration_value(p, name) {
202			let c = p.peek_n(1);
203			if p.at_end() || c == KindSet::RIGHT_CURLY_SEMICOLON_OR_RIGHT_PAREN || <T![!]>::peek(p, c) {
204				return Ok(val);
205			}
206		}
207		p.rewind(checkpoint.clone());
208		if Self::is_computed_declaration_value(p, p.peek_n(1))
209			&& let Ok(val) = Self::parse_computed_declaration_value(p, name)
210		{
211			return Ok(val);
212		}
213		p.rewind(checkpoint);
214		Self::parse_unknown_declaration_value(p, name)
215	}
216}