Skip to main content

css_ast/visit/
mod.rs

1include!(concat!(env!("OUT_DIR"), "/css_node_kind.rs"));
2include!(concat!(env!("OUT_DIR"), "/css_apply_visit_methods.rs"));
3
4use css_parse::Vec;
5use css_parse::{
6	Block, Box, CommaSeparated, Comparison, ComponentValue, ComponentValues, Cursor, Declaration, DeclarationGroup,
7	DeclarationList, DeclarationOrBad, DeclarationValue, Either, NoBlockAllowed, NodeMetadata, NodeWithMetadata,
8	Optionals2, Optionals3, Optionals4, Optionals5, Parse, Peek, QualifiedRule, RuleList, ToCursors, ToSpan,
9	syntax::BadDeclaration, token_macros,
10};
11use visit_flow::{VisitFlow, try_visit};
12
13/// The `#[visitor]` attribute: observer methods without a return type
14/// auto-descend. Re-exported so visitor consumers need only depend on `css_ast`.
15pub use csskit_derives::visitor;
16pub use visit_flow::{VisitAction, VisitBreak, VisitFlowExt};
17
18mod root;
19mod visit_node;
20pub use root::{ErasedNode, ParsedRoot, parse_root};
21pub(crate) use visit_node::QueryNodeData;
22pub use visit_node::{NodeKey, VisitNode};
23
24use crate::*;
25
26macro_rules! visit_mut_trait {
27	( $(
28		$name: ident$(<$($gen:tt),+>)?($obj: ty),
29	)+ ) => {
30		pub trait VisitMut: Sized {
31			fn visit_declaration<'a, T: DeclarationValue<'a, CssMetadata>>(&mut self, _rule: &mut Declaration<'a, T, CssMetadata>) {}
32			fn exit_declaration<'a, T: DeclarationValue<'a, CssMetadata>>(&mut self, _rule: &mut Declaration<'a, T, CssMetadata>) {}
33			fn visit_bad_declaration<'a>(&mut self, _rule: &mut BadDeclaration<'a>) {}
34			fn exit_bad_declaration<'a>(&mut self, _rule: &mut BadDeclaration<'a>) {}
35			fn visit_string(&mut self, _str: &mut token_macros::String) {}
36			fn exit_string(&mut self, _str: &mut token_macros::String) {}
37			fn visit_comparison(&mut self, _comparison: &mut Comparison) {}
38			fn exit_comparison(&mut self, _comparison: &mut Comparison) {}
39			$(
40				fn $name$(<$($gen),+>)?(&mut self, _rule: &mut $obj) {}
41			)+
42		}
43	}
44}
45apply_visit_methods!(visit_mut_trait);
46
47/// The object-safe core of [`Visit`].
48///
49/// [`Visit`] has methods that are type-specific. A visitor that needs the node kind and the span can implement just
50/// this trait, and can then walk a node whose type is erased, such as an [`ErasedNode`].
51///
52/// The methods have no defaults, thus an implementation cannot drop one by mistake.
53pub trait NodeVisitor {
54	/// Called before entering a node.
55	///
56	/// Return [`VisitFlow::SKIP_CHILDREN`] to prune the node and its entire subtree (it is never entered). Return
57	/// [`VisitFlow::STOP`] to halt the whole traversal.
58	fn consider_node(&self, node: VisitNode) -> VisitFlow;
59
60	/// Called on entry to every queryable node.
61	///
62	/// Receives a [`VisitNode`]; per-node metadata and properties are available via its methods. Return
63	/// [`VisitFlow::SKIP_CHILDREN`] to skip the typed `visit_*` call and children.
64	fn enter_node(&mut self, node: VisitNode) -> VisitFlow;
65
66	/// Called on exit from every queryable node.
67	fn exit_node(&mut self, node: VisitNode) -> VisitFlow;
68}
69
70impl NodeVisitor for &mut (dyn NodeVisitor + '_) {
71	fn consider_node(&self, node: VisitNode) -> VisitFlow {
72		(**self).consider_node(node)
73	}
74
75	fn enter_node(&mut self, node: VisitNode) -> VisitFlow {
76		(**self).enter_node(node)
77	}
78
79	fn exit_node(&mut self, node: VisitNode) -> VisitFlow {
80		(**self).exit_node(node)
81	}
82}
83
84impl Visit for &mut (dyn NodeVisitor + '_) {}
85
86macro_rules! visit_trait {
87	( $(
88		$name: ident$(<$($gen:tt),+>)?($obj: ty),
89	)+ ) => {
90		pub trait Visit: NodeVisitor + Sized {
91
92			fn enter_declaration<'a, T: DeclarationValue<'a, CssMetadata>>(&mut self, _rule: &Declaration<'a, T, CssMetadata>, _node: VisitNode) -> VisitFlow {
93				VisitFlow::DESCEND
94			}
95			fn exit_declaration<'a, T: DeclarationValue<'a, CssMetadata>>(&mut self, _rule: &Declaration<'a, T, CssMetadata>, _node: VisitNode) -> VisitFlow {
96				VisitFlow::DESCEND
97			}
98			fn visit_bad_declaration<'a>(&mut self, _rule: &BadDeclaration<'a>) -> VisitFlow {
99				VisitFlow::DESCEND
100			}
101			fn exit_bad_declaration<'a>(&mut self, _rule: &BadDeclaration<'a>) -> VisitFlow {
102				VisitFlow::DESCEND
103			}
104			fn visit_string(&mut self, _str: &token_macros::String) -> VisitFlow {
105				VisitFlow::DESCEND
106			}
107			fn exit_string(&mut self, _str: &token_macros::String) -> VisitFlow {
108				VisitFlow::DESCEND
109			}
110			fn visit_comparison(&mut self, _comparison: &Comparison) -> VisitFlow {
111				VisitFlow::DESCEND
112			}
113			fn exit_comparison(&mut self, _comparison: &Comparison) -> VisitFlow {
114				VisitFlow::DESCEND
115			}
116
117			fn visit_feature<T: FeatureMetadata>(&mut self, _node: &T) {}
118			fn exit_feature<T: FeatureMetadata>(&mut self, _node: &T) {}
119
120			$(
121				fn $name$(<$($gen),+>)?(&mut self, _rule: &$obj) -> VisitFlow {
122					VisitFlow::DESCEND
123				}
124			)+
125		}
126	}
127}
128apply_visit_methods!(visit_trait);
129
130pub trait VisitableMut {
131	fn accept_mut<V: VisitMut>(&mut self, v: &mut V);
132}
133
134pub trait Visitable {
135	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow;
136}
137
138/// Marker trait for AST nodes that can be queried with selectors.
139///
140/// Implemented by `#[derive(Visitable)]` for queryable nodes, and manually for nodes
141/// with `get_property` overrides (named at-rules, declarations).
142/// Not part of the `Visit` public API - visitors receive a [`VisitNode`] instead.
143pub(crate) trait QueryableNode: ToSpan + NodeWithMetadata<CssMetadata> {
144	/// Unique identifier for this node type.
145	const NODE_ID: NodeId;
146
147	/// Returns a cursor for the given property kind, if the node has that property.
148	/// Used by attribute selectors to extract values from nodes.
149	///
150	/// For `PropertyKind::Name`, returns a cursor to the node's name (e.g., property
151	/// name for declarations, animation name for `@keyframes`).
152	fn get_property(&self, _kind: PropertyKind) -> Option<Cursor> {
153		None
154	}
155
156	/// Builds the [`VisitNode`] passed to every `Visit` callback for this node.
157	///
158	/// Metadata and properties are reached through `&dyn` accessors, so they only cost anything
159	/// when a visitor actually reads them - `subtree_metadata` in particular walks the subtree.
160	fn visit_node(&self) -> VisitNode<'_>
161	where
162		Self: Sized,
163	{
164		VisitNode::new(self.to_span(), Self::NODE_ID, self)
165	}
166}
167
168/// Blanket bridge so any [`QueryableNode`] can be held as a `&dyn` in [`VisitNode`].
169impl<T: QueryableNode> QueryNodeData for T {
170	#[inline]
171	fn self_metadata(&self) -> CssMetadata {
172		NodeWithMetadata::self_metadata(self)
173	}
174	#[inline]
175	fn subtree_metadata(&self) -> CssMetadata {
176		NodeWithMetadata::metadata(self)
177	}
178	#[inline]
179	fn get_property(&self, kind: PropertyKind) -> Option<Cursor> {
180		QueryableNode::get_property(self, kind)
181	}
182}
183
184impl<T> VisitableMut for Option<T>
185where
186	T: VisitableMut,
187{
188	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
189		if let Some(node) = self {
190			node.accept_mut(v)
191		}
192	}
193}
194
195macro_rules! impl_optionals {
196	($N:ident, $($T:ident),+) => {
197		impl<$($T),*> Visitable for $N<$($T),+>
198		where
199			$($T: Visitable,)+
200		{
201			#[allow(non_snake_case)]
202			#[allow(unused)]
203			fn accept<VI: Visit>(&self, v: &mut VI) -> VisitFlow {
204				let $N($($T),+) = self;
205				$(try_visit!($T.accept(v));)+;
206				VisitFlow::DESCEND
207			}
208		}
209
210		impl<$($T),*> VisitableMut for $N<$($T),+>
211		where
212			$($T: VisitableMut,)+
213		{
214			#[allow(non_snake_case)]
215			#[allow(unused)]
216			fn accept_mut<VI: VisitMut>(&mut self, v: &mut VI) {
217				let $N($($T),+) = self;
218				$($T.accept_mut(v);)+;
219			}
220		}
221	};
222}
223
224impl_optionals!(Optionals2, T, U);
225impl_optionals!(Optionals3, T, U, V);
226impl_optionals!(Optionals4, T, U, V, W);
227impl_optionals!(Optionals5, T, U, V, W, X);
228
229impl Visitable for token_macros::Ident {
230	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
231		VisitFlow::DESCEND
232	}
233}
234
235impl VisitableMut for token_macros::Ident {
236	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
237}
238
239impl Visitable for token_macros::Function {
240	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
241		VisitFlow::DESCEND
242	}
243}
244
245impl VisitableMut for token_macros::Function {
246	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
247}
248
249impl Visitable for token_macros::Comma {
250	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
251		VisitFlow::DESCEND
252	}
253}
254
255impl VisitableMut for token_macros::Comma {
256	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
257}
258
259impl Visitable for token_macros::LeftParen {
260	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
261		VisitFlow::DESCEND
262	}
263}
264
265impl VisitableMut for token_macros::LeftParen {
266	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
267}
268
269impl Visitable for token_macros::RightParen {
270	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
271		VisitFlow::DESCEND
272	}
273}
274
275impl VisitableMut for token_macros::RightParen {
276	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
277}
278
279impl Visitable for token_macros::Colon {
280	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
281		VisitFlow::DESCEND
282	}
283}
284
285impl VisitableMut for token_macros::Colon {
286	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
287}
288
289impl Visitable for token_macros::Semicolon {
290	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
291		VisitFlow::DESCEND
292	}
293}
294
295impl VisitableMut for token_macros::Semicolon {
296	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
297}
298
299impl Visitable for Comparison {
300	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
301		try_visit!(v.visit_comparison(self));
302		try_visit!(v.exit_comparison(self));
303		VisitFlow::DESCEND
304	}
305}
306
307impl VisitableMut for Comparison {
308	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
309		v.visit_comparison(self);
310		v.exit_comparison(self);
311	}
312}
313
314impl Visitable for token_macros::delim::Dash {
315	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
316		VisitFlow::DESCEND
317	}
318}
319
320impl VisitableMut for token_macros::delim::Dash {
321	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
322}
323
324impl Visitable for token_macros::delim::Slash {
325	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
326		VisitFlow::DESCEND
327	}
328}
329
330impl VisitableMut for token_macros::delim::Slash {
331	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
332}
333
334impl Visitable for token_macros::Number {
335	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
336		VisitFlow::DESCEND
337	}
338}
339
340impl VisitableMut for token_macros::Number {
341	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
342}
343
344impl Visitable for token_macros::Any {
345	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
346		VisitFlow::DESCEND
347	}
348}
349
350impl VisitableMut for token_macros::Any {
351	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
352}
353
354impl Visitable for token_macros::String {
355	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
356		try_visit!(v.visit_string(self));
357		try_visit!(v.exit_string(self));
358		VisitFlow::DESCEND
359	}
360}
361
362impl VisitableMut for token_macros::String {
363	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
364		v.visit_string(self);
365		v.exit_string(self);
366	}
367}
368
369impl<T> Visitable for Option<T>
370where
371	T: Visitable,
372{
373	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
374		if let Some(node) = self {
375			try_visit!(node.accept(v));
376		}
377		VisitFlow::DESCEND
378	}
379}
380
381impl<'a, T: VisitableMut> VisitableMut for Box<'a, T> {
382	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
383		(**self).accept_mut(v)
384	}
385}
386
387impl<'a, T: Visitable> Visitable for Box<'a, T> {
388	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
389		(**self).accept(v)
390	}
391}
392
393impl<'a, T, const MIN: usize> VisitableMut for CommaSeparated<'a, T, MIN>
394where
395	T: VisitableMut,
396{
397	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
398		for (node, _) in self {
399			node.accept_mut(v)
400		}
401	}
402}
403
404impl<'a, T, const MIN: usize> Visitable for CommaSeparated<'a, T, MIN>
405where
406	T: Visitable,
407{
408	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
409		for (node, _) in self {
410			try_visit!(node.accept(v));
411		}
412		VisitFlow::DESCEND
413	}
414}
415
416impl<Left, Right> VisitableMut for Either<Left, Right>
417where
418	Left: VisitableMut,
419	Right: VisitableMut,
420{
421	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
422		match self {
423			Self::Left(t) => t.accept_mut(v),
424			Self::Right(t) => t.accept_mut(v),
425		}
426	}
427}
428
429impl<Left, Right> Visitable for Either<Left, Right>
430where
431	Left: Visitable,
432	Right: Visitable,
433{
434	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
435		match self {
436			Self::Left(t) => t.accept(v),
437			Self::Right(t) => t.accept(v),
438		}
439	}
440}
441
442impl<'a, T> VisitableMut for Declaration<'a, T, CssMetadata>
443where
444	T: VisitableMut + DeclarationValue<'a, CssMetadata>,
445{
446	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
447		v.visit_declaration(self);
448		self.value.accept_mut(v);
449		v.exit_declaration(self);
450	}
451}
452
453impl<'a, T> QueryableNode for Declaration<'a, T, CssMetadata>
454where
455	T: DeclarationValue<'a, CssMetadata> + QueryableNode,
456{
457	const NODE_ID: NodeId = NodeId::StyleValue;
458
459	fn get_property(&self, kind: PropertyKind) -> Option<Cursor> {
460		match kind {
461			PropertyKind::Name => Some(self.name.into()),
462			_ => None,
463		}
464	}
465
466	fn visit_node(&self) -> VisitNode<'_> {
467		// Use T::NODE_ID so each declaration type has its own identity.
468		VisitNode::new(self.to_span(), T::NODE_ID, self)
469	}
470}
471
472impl<'a, T> Visitable for Declaration<'a, T, CssMetadata>
473where
474	T: Visitable + DeclarationValue<'a, CssMetadata> + QueryableNode,
475{
476	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
477		let node = self.visit_node();
478		if let visit_flow::VisitAction::SkipChildren = try_visit!(v.consider_node(node)) {
479			return VisitFlow::DESCEND;
480		}
481		if let visit_flow::VisitAction::Descend = visit_flow::try_visit!(v.enter_node(node)) {
482			if let visit_flow::VisitAction::Descend = visit_flow::try_visit!(v.enter_declaration::<T>(self, node)) {
483				try_visit!(self.value.accept(v));
484			}
485			try_visit!(v.exit_declaration::<T>(self, node));
486		}
487		try_visit!(v.exit_node(node));
488		VisitFlow::DESCEND
489	}
490}
491
492impl<'a, T> VisitableMut for DeclarationList<'a, T, CssMetadata>
493where
494	T: VisitableMut + DeclarationValue<'a, CssMetadata>,
495{
496	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
497		for declaration in &mut self.declarations {
498			declaration.accept_mut(v);
499		}
500	}
501}
502
503impl<'a, T> Visitable for DeclarationList<'a, T, CssMetadata>
504where
505	T: Visitable + DeclarationValue<'a, CssMetadata> + QueryableNode,
506{
507	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
508		for declaration in &self.declarations {
509			try_visit!(declaration.accept(v));
510		}
511		VisitFlow::DESCEND
512	}
513}
514
515impl<'a, T, M> VisitableMut for RuleList<'a, T, M>
516where
517	T: VisitableMut + Parse<'a> + ToCursors + ToSpan + NodeWithMetadata<M>,
518	M: NodeMetadata,
519{
520	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
521		self.rules.accept_mut(v);
522	}
523}
524
525impl<'a, T, M> Visitable for RuleList<'a, T, M>
526where
527	T: Visitable + Parse<'a> + ToCursors + ToSpan + NodeWithMetadata<M>,
528	M: NodeMetadata,
529{
530	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
531		self.rules.accept(v)
532	}
533}
534
535impl<'a, P, D, R> VisitableMut for QualifiedRule<'a, P, D, R, CssMetadata>
536where
537	P: VisitableMut + Peek<'a> + Parse<'a> + ToCursors + ToSpan,
538	D: VisitableMut + DeclarationValue<'a, CssMetadata>,
539	R: VisitableMut + Parse<'a> + ToCursors + ToSpan,
540	Block<'a, D, R, CssMetadata>: Parse<'a> + ToCursors + ToSpan,
541{
542	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
543		self.prelude.accept_mut(v);
544		self.block.accept_mut(v);
545	}
546}
547
548impl<'a, P, D, R> Visitable for QualifiedRule<'a, P, D, R, CssMetadata>
549where
550	P: Visitable + Peek<'a> + Parse<'a> + ToCursors + ToSpan,
551	D: Visitable + DeclarationValue<'a, CssMetadata> + QueryableNode,
552	R: Visitable + Parse<'a> + ToCursors + ToSpan,
553	Block<'a, D, R, CssMetadata>: Parse<'a> + ToCursors + ToSpan,
554{
555	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
556		try_visit!(self.prelude.accept(v));
557		self.block.accept(v)
558	}
559}
560
561impl<'a, D, R> VisitableMut for Block<'a, D, R, CssMetadata>
562where
563	D: VisitableMut + DeclarationValue<'a, CssMetadata>,
564	R: VisitableMut + Parse<'a> + ToCursors + ToSpan,
565{
566	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
567		for declaration in &mut self.declarations {
568			declaration.accept_mut(v);
569		}
570		for rule in &mut self.rules {
571			rule.accept_mut(v);
572		}
573	}
574}
575
576impl<'a, D, R> Visitable for Block<'a, D, R, CssMetadata>
577where
578	D: Visitable + DeclarationValue<'a, CssMetadata> + QueryableNode,
579	R: Visitable + Parse<'a> + ToCursors + ToSpan,
580{
581	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
582		for declaration in &self.declarations {
583			try_visit!(declaration.accept(v));
584		}
585		for rule in &self.rules {
586			try_visit!(rule.accept(v));
587		}
588		VisitFlow::DESCEND
589	}
590}
591
592impl<'a, T> VisitableMut for Vec<'a, T>
593where
594	T: VisitableMut,
595{
596	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
597		for node in self {
598			node.accept_mut(v);
599		}
600	}
601}
602
603impl<'a, T> Visitable for Vec<'a, T>
604where
605	T: Visitable,
606{
607	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
608		for node in self {
609			try_visit!(node.accept(v));
610		}
611		VisitFlow::DESCEND
612	}
613}
614
615impl<'a> VisitableMut for BadDeclaration<'a> {
616	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
617		v.visit_bad_declaration(self);
618		v.exit_bad_declaration(self);
619	}
620}
621
622impl<'a> Visitable for BadDeclaration<'a> {
623	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
624		try_visit!(v.visit_bad_declaration(self));
625		try_visit!(v.exit_bad_declaration(self));
626		VisitFlow::DESCEND
627	}
628}
629
630impl<'a> VisitableMut for ComponentValues<'a> {
631	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
632		v.visit_component_values(self);
633		for value in &mut self.values {
634			value.accept_mut(v);
635		}
636		v.exit_component_values(self);
637	}
638}
639
640impl<'a> QueryableNode for ComponentValues<'a> {
641	const NODE_ID: NodeId = NodeId::ComponentValues;
642}
643
644impl<'a> Visitable for ComponentValues<'a> {
645	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
646		let node = QueryableNode::visit_node(self);
647		if let VisitAction::SkipChildren = try_visit!(v.consider_node(node)) {
648			return VisitFlow::DESCEND;
649		}
650		if let VisitAction::Descend = try_visit!(v.enter_node(node)) {
651			if let VisitAction::Descend = try_visit!(v.visit_component_values(self)) {
652				for value in &self.values {
653					try_visit!(value.accept(v));
654				}
655			}
656			try_visit!(v.exit_component_values(self));
657		}
658		try_visit!(v.exit_node(node));
659		VisitFlow::DESCEND
660	}
661}
662
663impl<'a> VisitableMut for ComponentValue<'a> {
664	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
665		v.visit_component_value(self);
666		match self {
667			ComponentValue::SimpleBlock(block) => block.values.accept_mut(v),
668			ComponentValue::Function(function) => function.params.accept_mut(v),
669			_ => {}
670		}
671		v.exit_component_value(self);
672	}
673}
674
675impl<'a> QueryableNode for ComponentValue<'a> {
676	const NODE_ID: NodeId = NodeId::ComponentValue;
677}
678
679impl<'a> Visitable for ComponentValue<'a> {
680	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
681		let node = QueryableNode::visit_node(self);
682		if let VisitAction::SkipChildren = try_visit!(v.consider_node(node)) {
683			return VisitFlow::DESCEND;
684		}
685		if let VisitAction::Descend = try_visit!(v.enter_node(node)) {
686			if let VisitAction::Descend = try_visit!(v.visit_component_value(self)) {
687				match self {
688					ComponentValue::SimpleBlock(block) => {
689						try_visit!(block.values.accept(v));
690					}
691					ComponentValue::Function(function) => {
692						try_visit!(function.params.accept(v));
693					}
694					_ => {}
695				}
696			}
697			try_visit!(v.exit_component_value(self));
698		}
699		try_visit!(v.exit_node(node));
700		VisitFlow::DESCEND
701	}
702}
703
704impl<'a> VisitableMut for Unresolved<'a> {
705	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
706}
707
708impl<'a> Visitable for Unresolved<'a> {
709	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
710		VisitFlow::DESCEND
711	}
712}
713
714impl<D, M> VisitableMut for NoBlockAllowed<D, M> {
715	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
716}
717
718impl<D, M> Visitable for NoBlockAllowed<D, M> {
719	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
720		VisitFlow::DESCEND
721	}
722}
723
724impl<'a, D> VisitableMut for DeclarationGroup<'a, D, CssMetadata>
725where
726	D: VisitableMut + DeclarationValue<'a, CssMetadata>,
727{
728	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
729		for declaration in &mut self.declarations {
730			declaration.accept_mut(v)
731		}
732	}
733}
734
735impl<'a, D> Visitable for DeclarationGroup<'a, D, CssMetadata>
736where
737	D: Visitable + DeclarationValue<'a, CssMetadata> + QueryableNode,
738{
739	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
740		for declaration in &self.declarations {
741			try_visit!(declaration.accept(v));
742		}
743		VisitFlow::DESCEND
744	}
745}
746
747impl<'a, D> VisitableMut for DeclarationOrBad<'a, D, CssMetadata>
748where
749	D: VisitableMut + DeclarationValue<'a, CssMetadata>,
750{
751	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
752		match self {
753			Self::Declaration(d) => d.accept_mut(v),
754			Self::Bad(b) => b.accept_mut(v),
755		}
756	}
757}
758
759impl<'a, D> Visitable for DeclarationOrBad<'a, D, CssMetadata>
760where
761	D: Visitable + DeclarationValue<'a, CssMetadata> + QueryableNode,
762{
763	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
764		match self {
765			Self::Declaration(d) => d.accept(v),
766			Self::Bad(b) => b.accept(v),
767		}
768	}
769}
770
771macro_rules! impl_tuple_mut {
772    ($($T:ident),*) => {
773				impl<$($T),*> VisitableMut for ($($T),*)
774        where
775            $($T: VisitableMut,)*
776        {
777            #[allow(non_snake_case)]
778            #[allow(unused)]
779						fn accept_mut<VI: VisitMut>(&mut self, v: &mut VI) {
780                let ($($T),*) = self;
781                $($T.accept_mut(v);)*
782            }
783        }
784    };
785}
786
787impl_tuple_mut!(T, U);
788impl_tuple_mut!(T, U, V);
789impl_tuple_mut!(T, U, V, W);
790impl_tuple_mut!(T, U, V, W, X);
791impl_tuple_mut!(T, U, V, W, X, Y);
792impl_tuple_mut!(T, U, V, W, X, Y, Z);
793impl_tuple_mut!(T, U, V, W, X, Y, Z, A);
794impl_tuple_mut!(T, U, V, W, X, Y, Z, A, B);
795impl_tuple_mut!(T, U, V, W, X, Y, Z, A, B, C);
796impl_tuple_mut!(T, U, V, W, X, Y, Z, A, B, C, D);
797impl_tuple_mut!(T, U, V, W, X, Y, Z, A, B, C, D, E);
798
799macro_rules! impl_tuple {
800    ($($T:ident),*) => {
801			impl<$($T),*> Visitable for ($($T),*)
802        where
803            $($T: Visitable,)*
804        {
805            #[allow(non_snake_case)]
806            #[allow(unused)]
807					fn accept<VI: Visit>(&self, v: &mut VI) -> VisitFlow {
808                let ($($T),*) = self;
809                $(try_visit!($T.accept(v));)*
810                VisitFlow::DESCEND
811            }
812        }
813    };
814}
815impl_tuple!(T, U);
816impl_tuple!(T, U, V);
817impl_tuple!(T, U, V, W);
818impl_tuple!(T, U, V, W, X);
819impl_tuple!(T, U, V, W, X, Y);
820impl_tuple!(T, U, V, W, X, Y, Z);
821impl_tuple!(T, U, V, W, X, Y, Z, A);
822impl_tuple!(T, U, V, W, X, Y, Z, A, B);
823impl_tuple!(T, U, V, W, X, Y, Z, A, B, C);
824impl_tuple!(T, U, V, W, X, Y, Z, A, B, C, D);
825impl_tuple!(T, U, V, W, X, Y, Z, A, B, C, D, E);