Skip to main content

css_parse/traits/
declaration_value.rs

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