css_parse/traits/
declaration_value.rs

1use crate::{Cursor, KindSet, Parser, Peek, Result, T, diagnostics};
2
3/// A trait that can be used for AST nodes representing a Declaration's Value. It offers some
4/// convenience functions for handling such values.
5pub trait DeclarationValue<'a>: Sized {
6	type ComputedValue: Peek<'a>;
7
8	/// Determines if the given [Cursor] represents a valid [Ident][crate::token_macros::Ident] matching a known property
9	/// name.
10	///
11	/// If implementing a set of declarations where ony limited property-ids are valid (such as the declarations allowed
12	/// by an at-rule) then it might be worthwhile changing this to sometimes return `false`, which consumers of this
13	/// trait can use to error early without having to do too much backtracking.
14	fn valid_declaration_name(_p: &Parser<'a>, _c: Cursor) -> bool {
15		true
16	}
17
18	/// Determines if the parsed Self was parsed as an unknown value.
19	///
20	/// If implementing a set of declarations where any name is accepted, or where the value might result in re-parsing
21	/// as unknown, this method can be used to signal that to upstream consumers of this trait. By default this returns
22	/// `false` because `valid_declaration_name` returns `true`, the assumption being that any successful construction of
23	/// Self is indeed a valid and known declaration.
24	fn is_unknown(&self) -> bool {
25		false
26	}
27
28	/// Determines if the parsed Self was parsed as a Custom value.
29	///
30	/// If implementing a set of declarations where custom names are accepted, or where the value might result in
31	/// re-parsing as unknown, this method can be used to signal that to upstream consumers of this trait. By default
32	/// this returns `false` because `valid_declaration_name` returns `true`, the assumption being that any successful
33	/// construction of Self is indeed a valid and known declaration.
34	fn is_custom(&self) -> bool {
35		false
36	}
37
38	/// Determines if the parsed Self was parsed as the "initial" keyword.
39	///
40	/// If implementing a set of declarations where the "initial" keyword is accepted this method can be used to signal
41	/// that to upstream consumers of this trait.
42	fn is_initial(&self) -> bool;
43
44	/// Determines if the parsed Self was parsed as the "inherit" keyword.
45	///
46	/// If implementing a set of declarations where the "inherit" keyword is accepted this method can be used to signal
47	/// that to upstream consumers of this trait.
48	fn is_inherit(&self) -> bool;
49
50	/// Determines if the parsed Self was parsed as the "unset" keyword.
51	///
52	/// If implementing a set of declarations where the "unset" keyword is accepted this method can be used to signal
53	/// that to upstream consumers of this trait.
54	fn is_unset(&self) -> bool;
55
56	/// Determines if the parsed Self was parsed as the "revert" keyword.
57	///
58	/// If implementing a set of declarations where the "revert" keyword is accepted this method can be used to signal
59	/// that to upstream consumers of this trait.
60	fn is_revert(&self) -> bool;
61
62	/// Determines if the parsed Self was parsed as the "revert" keyword.
63	///
64	/// If implementing a set of declarations where the "revert" keyword is accepted this method can be used to signal
65	/// that to upstream consumers of this trait.
66	fn is_revert_layer(&self) -> bool;
67
68	/// Determines if the parsed Self is not a valid literal production of the grammar, and instead some of its
69	/// constituent parts will need additional computation to reify into a known value.
70	///
71	/// CSS properties are allowed to include substitutions, such as `calc()` or `var()`. These are not defined in the
72	/// declaration's grammar but are instead stored so that when a style object is reified the declarations that had
73	/// those tokens can be recomputed against the context of their node.
74	fn needs_computing(&self) -> bool;
75
76	/// Like `parse()` but with the additional context of the `name` [Cursor]. This cursor is known to be dashed ident,
77	/// therefore this should return a `Self` reflecting a Custom property. Alternatively, if this DeclarationValue
78	/// disallows custom declarations then this is the right place to return a parse Error.
79	///
80	/// The default implementation of this method is to return an Unexpected Err.
81	fn parse_custom_declaration_value(p: &mut Parser<'a>, _name: Cursor) -> Result<Self> {
82		let c = p.peek_n(1);
83		Err(diagnostics::Unexpected(c))?
84	}
85
86	/// Like `parse()` but with the additional context of the `name` [Cursor]. This is only called before verifying that
87	/// the next token was peeked to be a ComputedValue, therefore this should return a `Self` reflecting a Computed
88	/// property. Alternatively, if this DeclarationValue disallows computed declarations then this is the right place to
89	/// return a parse Error.
90	///
91	/// The default implementation of this method is to return an Unexpected Err.
92	fn parse_computed_declaration_value(p: &mut Parser<'a>, _name: Cursor) -> Result<Self> {
93		let c = p.peek_n(1);
94		Err(diagnostics::Unexpected(c))?
95	}
96
97	/// Like `parse()` but with the additional context of the `name` [Cursor]. This is only called on values that are
98	/// assumed to be _specified_, that is, they're not custom and not computed. Therefore this should return a `Self`
99	/// reflecting a specified value. If this results in a Parse error then ComputedValue will be checked to see if the
100	/// parser stopped because it saw a computed value function. If this results in a success, the next token is still
101	/// checked as it may be a ComputedValue, which - if so - the parsed value will be discarded, and the parser rewound
102	/// to re-parse this as a ComputedValue.
103	///
104	/// The default implementation of this method is to return an Unexpected Err.
105	fn parse_specified_declaration_value(p: &mut Parser<'a>, _name: Cursor) -> Result<Self> {
106		let c = p.peek_n(1);
107		Err(diagnostics::Unexpected(c))?
108	}
109
110	/// Like `parse()` but with the additional context of the `name` [Cursor]. This is only called on values that are
111	/// didn't parse as either a Custom, Computed or Specified value therefore this should return a `Self` reflecting an
112	/// unknown property, or alternatively the right place to return a parse error.
113	///
114	/// The default implementation of this method is to return an Unexpected Err.
115	fn parse_unknown_declaration_value(p: &mut Parser<'a>, _name: Cursor) -> Result<Self> {
116		let c = p.peek_n(1);
117		Err(diagnostics::Unexpected(c))?
118	}
119
120	// Like `parse()` but with the additional context of the `name` [Cursor] - the same [Cursor]
121	// passed to [DeclarationValue::valid_declaration_name()].
122	fn parse_declaration_value(p: &mut Parser<'a>, name: Cursor) -> Result<Self> {
123		if name.token().is_dashed_ident() {
124			return Self::parse_custom_declaration_value(p, name);
125		}
126		if !Self::valid_declaration_name(p, name) {
127			return Self::parse_unknown_declaration_value(p, name);
128		}
129		if p.peek::<Self::ComputedValue>() {
130			return Self::parse_computed_declaration_value(p, name);
131		}
132		let checkpoint = p.checkpoint();
133		if let Ok(val) = Self::parse_specified_declaration_value(p, name) {
134			if p.at_end() || p.peek_n(1) == KindSet::RIGHT_CURLY_OR_SEMICOLON || p.peek::<T![!]>() {
135				return Ok(val);
136			}
137		}
138		if p.peek::<Self::ComputedValue>() {
139			p.rewind(checkpoint);
140			if let Ok(val) = Self::parse_computed_declaration_value(p, name) {
141				return Ok(val);
142			}
143		}
144		p.rewind(checkpoint);
145		Self::parse_unknown_declaration_value(p, name)
146	}
147}