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	AttributeOperator, Block, Box, CommaSeparated, Comparison, ComponentValue, ComponentValues, Cursor, Declaration,
7	DeclarationGroup, DeclarationList, DeclarationOrBad, DeclarationValue, Either, NoBlockAllowed, NodeMetadata,
8	NodeWithMetadata, Optionals2, Optionals3, Optionals4, Optionals5, Parse, Peek, QualifiedRule, RuleList, Span,
9	ToCursors, ToSpan, 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::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 span(&self) -> Span {
172		ToSpan::to_span(self)
173	}
174
175	#[inline]
176	fn self_metadata(&self) -> CssMetadata {
177		NodeWithMetadata::self_metadata(self)
178	}
179
180	#[inline]
181	fn subtree_metadata(&self) -> CssMetadata {
182		NodeWithMetadata::metadata(self)
183	}
184
185	#[inline]
186	fn get_property(&self, kind: PropertyKind) -> Option<Cursor> {
187		QueryableNode::get_property(self, kind)
188	}
189}
190
191impl<T> VisitableMut for Option<T>
192where
193	T: VisitableMut,
194{
195	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
196		if let Some(node) = self {
197			node.accept_mut(v)
198		}
199	}
200}
201
202macro_rules! impl_optionals {
203	($N:ident, $($T:ident),+) => {
204		impl<$($T),*> Visitable for $N<$($T),+>
205		where
206			$($T: Visitable,)+
207		{
208			#[allow(non_snake_case)]
209			#[allow(unused)]
210			fn accept<VI: Visit>(&self, v: &mut VI) -> VisitFlow {
211				let $N($($T),+) = self;
212				$(try_visit!($T.accept(v));)+;
213				VisitFlow::DESCEND
214			}
215		}
216
217		impl<$($T),*> VisitableMut for $N<$($T),+>
218		where
219			$($T: VisitableMut,)+
220		{
221			#[allow(non_snake_case)]
222			#[allow(unused)]
223			fn accept_mut<VI: VisitMut>(&mut self, v: &mut VI) {
224				let $N($($T),+) = self;
225				$($T.accept_mut(v);)+;
226			}
227		}
228	};
229}
230
231impl_optionals!(Optionals2, T, U);
232impl_optionals!(Optionals3, T, U, V);
233impl_optionals!(Optionals4, T, U, V, W);
234impl_optionals!(Optionals5, T, U, V, W, X);
235
236impl Visitable for token_macros::Ident {
237	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
238		VisitFlow::DESCEND
239	}
240}
241
242impl VisitableMut for token_macros::Ident {
243	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
244}
245
246impl Visitable for token_macros::Function {
247	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
248		VisitFlow::DESCEND
249	}
250}
251
252impl VisitableMut for token_macros::Function {
253	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
254}
255
256impl Visitable for token_macros::Comma {
257	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
258		VisitFlow::DESCEND
259	}
260}
261
262impl VisitableMut for token_macros::Comma {
263	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
264}
265
266impl Visitable for token_macros::LeftParen {
267	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
268		VisitFlow::DESCEND
269	}
270}
271
272impl VisitableMut for token_macros::LeftParen {
273	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
274}
275
276impl Visitable for token_macros::RightParen {
277	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
278		VisitFlow::DESCEND
279	}
280}
281
282impl VisitableMut for token_macros::RightParen {
283	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
284}
285
286impl Visitable for token_macros::Colon {
287	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
288		VisitFlow::DESCEND
289	}
290}
291
292impl VisitableMut for token_macros::Colon {
293	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
294}
295
296impl Visitable for token_macros::Semicolon {
297	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
298		VisitFlow::DESCEND
299	}
300}
301
302impl VisitableMut for token_macros::Semicolon {
303	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
304}
305
306impl Visitable for Comparison {
307	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
308		try_visit!(v.visit_comparison(self));
309		try_visit!(v.exit_comparison(self));
310		VisitFlow::DESCEND
311	}
312}
313
314impl VisitableMut for Comparison {
315	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
316		v.visit_comparison(self);
317		v.exit_comparison(self);
318	}
319}
320
321impl Visitable for token_macros::delim::Dash {
322	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
323		VisitFlow::DESCEND
324	}
325}
326
327impl VisitableMut for token_macros::delim::Dash {
328	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
329}
330
331impl Visitable for token_macros::delim::Slash {
332	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
333		VisitFlow::DESCEND
334	}
335}
336
337impl VisitableMut for token_macros::delim::Slash {
338	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
339}
340
341impl Visitable for token_macros::Number {
342	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
343		VisitFlow::DESCEND
344	}
345}
346
347impl VisitableMut for token_macros::Number {
348	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
349}
350
351impl Visitable for token_macros::Any {
352	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
353		VisitFlow::DESCEND
354	}
355}
356
357impl VisitableMut for token_macros::Any {
358	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
359}
360
361impl Visitable for token_macros::String {
362	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
363		try_visit!(v.visit_string(self));
364		try_visit!(v.exit_string(self));
365		VisitFlow::DESCEND
366	}
367}
368
369impl VisitableMut for token_macros::String {
370	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
371		v.visit_string(self);
372		v.exit_string(self);
373	}
374}
375
376impl<T> Visitable for Option<T>
377where
378	T: Visitable,
379{
380	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
381		if let Some(node) = self {
382			try_visit!(node.accept(v));
383		}
384		VisitFlow::DESCEND
385	}
386}
387
388impl<'a, T: VisitableMut> VisitableMut for Box<'a, T> {
389	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
390		(**self).accept_mut(v)
391	}
392}
393
394impl<'a, T: Visitable> Visitable for Box<'a, T> {
395	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
396		(**self).accept(v)
397	}
398}
399
400impl<'a, T, const MIN: usize> VisitableMut for CommaSeparated<'a, T, MIN>
401where
402	T: VisitableMut,
403{
404	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
405		for (node, _) in self {
406			node.accept_mut(v)
407		}
408	}
409}
410
411impl<'a, T, const MIN: usize> Visitable for CommaSeparated<'a, T, MIN>
412where
413	T: Visitable,
414{
415	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
416		for (node, _) in self {
417			try_visit!(node.accept(v));
418		}
419		VisitFlow::DESCEND
420	}
421}
422
423impl<Left, Right> VisitableMut for Either<Left, Right>
424where
425	Left: VisitableMut,
426	Right: VisitableMut,
427{
428	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
429		match self {
430			Self::Left(t) => t.accept_mut(v),
431			Self::Right(t) => t.accept_mut(v),
432		}
433	}
434}
435
436impl<Left, Right> Visitable for Either<Left, Right>
437where
438	Left: Visitable,
439	Right: Visitable,
440{
441	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
442		match self {
443			Self::Left(t) => t.accept(v),
444			Self::Right(t) => t.accept(v),
445		}
446	}
447}
448
449impl<'a, T> VisitableMut for Declaration<'a, T, CssMetadata>
450where
451	T: VisitableMut + DeclarationValue<'a, CssMetadata>,
452{
453	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
454		v.visit_declaration(self);
455		self.value.accept_mut(v);
456		v.exit_declaration(self);
457	}
458}
459
460impl<'a, T> QueryableNode for Declaration<'a, T, CssMetadata>
461where
462	T: DeclarationValue<'a, CssMetadata> + QueryableNode,
463{
464	const NODE_ID: NodeId = NodeId::StyleValue;
465
466	fn get_property(&self, kind: PropertyKind) -> Option<Cursor> {
467		match kind {
468			PropertyKind::Name => Some(self.name.into()),
469			_ => None,
470		}
471	}
472
473	fn visit_node(&self) -> VisitNode<'_> {
474		// Use T::NODE_ID so each declaration type has its own identity.
475		VisitNode::new(T::NODE_ID, self)
476	}
477}
478
479impl<'a, T> Visitable for Declaration<'a, T, CssMetadata>
480where
481	T: Visitable + DeclarationValue<'a, CssMetadata> + QueryableNode,
482{
483	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
484		let node = self.visit_node();
485		if let visit_flow::VisitAction::SkipChildren = try_visit!(v.consider_node(node)) {
486			return VisitFlow::DESCEND;
487		}
488		if let visit_flow::VisitAction::Descend = visit_flow::try_visit!(v.enter_node(node)) {
489			if let visit_flow::VisitAction::Descend = visit_flow::try_visit!(v.enter_declaration::<T>(self, node)) {
490				try_visit!(self.value.accept(v));
491			}
492			try_visit!(v.exit_declaration::<T>(self, node));
493		}
494		try_visit!(v.exit_node(node));
495		VisitFlow::DESCEND
496	}
497}
498
499impl<'a, T> VisitableMut for DeclarationList<'a, T, CssMetadata>
500where
501	T: VisitableMut + DeclarationValue<'a, CssMetadata>,
502{
503	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
504		for declaration in &mut self.declarations {
505			declaration.accept_mut(v);
506		}
507	}
508}
509
510impl<'a, T> Visitable for DeclarationList<'a, T, CssMetadata>
511where
512	T: Visitable + DeclarationValue<'a, CssMetadata> + QueryableNode,
513{
514	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
515		for declaration in &self.declarations {
516			try_visit!(declaration.accept(v));
517		}
518		VisitFlow::DESCEND
519	}
520}
521
522impl<'a, T, M> VisitableMut for RuleList<'a, T, M>
523where
524	T: VisitableMut + Parse<'a> + ToCursors + ToSpan + NodeWithMetadata<M>,
525	M: NodeMetadata,
526{
527	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
528		self.rules.accept_mut(v);
529	}
530}
531
532impl<'a, T, M> Visitable for RuleList<'a, T, M>
533where
534	T: Visitable + Parse<'a> + ToCursors + ToSpan + NodeWithMetadata<M>,
535	M: NodeMetadata,
536{
537	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
538		self.rules.accept(v)
539	}
540}
541
542impl<'a, P, D, R> VisitableMut for QualifiedRule<'a, P, D, R, CssMetadata>
543where
544	P: VisitableMut + Peek<'a> + Parse<'a> + ToCursors + ToSpan,
545	D: VisitableMut + DeclarationValue<'a, CssMetadata>,
546	R: VisitableMut + Parse<'a> + ToCursors + ToSpan,
547	Block<'a, D, R, CssMetadata>: Parse<'a> + ToCursors + ToSpan,
548{
549	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
550		self.prelude.accept_mut(v);
551		self.block.accept_mut(v);
552	}
553}
554
555impl<'a, P, D, R> Visitable for QualifiedRule<'a, P, D, R, CssMetadata>
556where
557	P: Visitable + Peek<'a> + Parse<'a> + ToCursors + ToSpan,
558	D: Visitable + DeclarationValue<'a, CssMetadata> + QueryableNode,
559	R: Visitable + Parse<'a> + ToCursors + ToSpan,
560	Block<'a, D, R, CssMetadata>: Parse<'a> + ToCursors + ToSpan,
561{
562	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
563		try_visit!(self.prelude.accept(v));
564		self.block.accept(v)
565	}
566}
567
568impl<'a, D, R> VisitableMut for Block<'a, D, R, CssMetadata>
569where
570	D: VisitableMut + DeclarationValue<'a, CssMetadata>,
571	R: VisitableMut + Parse<'a> + ToCursors + ToSpan,
572{
573	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
574		for declaration in &mut self.declarations {
575			declaration.accept_mut(v);
576		}
577		for rule in &mut self.rules {
578			rule.accept_mut(v);
579		}
580	}
581}
582
583impl<'a, D, R> Visitable for Block<'a, D, R, CssMetadata>
584where
585	D: Visitable + DeclarationValue<'a, CssMetadata> + QueryableNode,
586	R: Visitable + Parse<'a> + ToCursors + ToSpan,
587{
588	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
589		for declaration in &self.declarations {
590			try_visit!(declaration.accept(v));
591		}
592		for rule in &self.rules {
593			try_visit!(rule.accept(v));
594		}
595		VisitFlow::DESCEND
596	}
597}
598
599impl<'a, T> VisitableMut for Vec<'a, T>
600where
601	T: VisitableMut,
602{
603	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
604		for node in self {
605			node.accept_mut(v);
606		}
607	}
608}
609
610impl<'a, T> Visitable for Vec<'a, T>
611where
612	T: Visitable,
613{
614	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
615		for node in self {
616			try_visit!(node.accept(v));
617		}
618		VisitFlow::DESCEND
619	}
620}
621
622impl<'a> VisitableMut for BadDeclaration<'a> {
623	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
624		v.visit_bad_declaration(self);
625		v.exit_bad_declaration(self);
626	}
627}
628
629impl<'a> Visitable for BadDeclaration<'a> {
630	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
631		try_visit!(v.visit_bad_declaration(self));
632		try_visit!(v.exit_bad_declaration(self));
633		VisitFlow::DESCEND
634	}
635}
636
637impl<'a> VisitableMut for ComponentValues<'a> {
638	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
639		v.visit_component_values(self);
640		for value in &mut self.values {
641			value.accept_mut(v);
642		}
643		v.exit_component_values(self);
644	}
645}
646
647impl<'a> QueryableNode for ComponentValues<'a> {
648	const NODE_ID: NodeId = NodeId::ComponentValues;
649}
650
651impl<'a> Visitable for ComponentValues<'a> {
652	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
653		let node = QueryableNode::visit_node(self);
654		if let VisitAction::SkipChildren = try_visit!(v.consider_node(node)) {
655			return VisitFlow::DESCEND;
656		}
657		if let VisitAction::Descend = try_visit!(v.enter_node(node)) {
658			if let VisitAction::Descend = try_visit!(v.visit_component_values(self)) {
659				for value in &self.values {
660					try_visit!(value.accept(v));
661				}
662			}
663			try_visit!(v.exit_component_values(self));
664		}
665		try_visit!(v.exit_node(node));
666		VisitFlow::DESCEND
667	}
668}
669
670impl<'a> VisitableMut for ComponentValue<'a> {
671	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
672		v.visit_component_value(self);
673		match self {
674			ComponentValue::SimpleBlock(block) => block.values.accept_mut(v),
675			ComponentValue::Function(function) => function.params.accept_mut(v),
676			_ => {}
677		}
678		v.exit_component_value(self);
679	}
680}
681
682impl<'a> QueryableNode for ComponentValue<'a> {
683	const NODE_ID: NodeId = NodeId::ComponentValue;
684}
685
686impl<'a> Visitable for ComponentValue<'a> {
687	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
688		let node = QueryableNode::visit_node(self);
689		if let VisitAction::SkipChildren = try_visit!(v.consider_node(node)) {
690			return VisitFlow::DESCEND;
691		}
692		if let VisitAction::Descend = try_visit!(v.enter_node(node)) {
693			if let VisitAction::Descend = try_visit!(v.visit_component_value(self)) {
694				match self {
695					ComponentValue::SimpleBlock(block) => {
696						try_visit!(block.values.accept(v));
697					}
698					ComponentValue::Function(function) => {
699						try_visit!(function.params.accept(v));
700					}
701					_ => {}
702				}
703			}
704			try_visit!(v.exit_component_value(self));
705		}
706		try_visit!(v.exit_node(node));
707		VisitFlow::DESCEND
708	}
709}
710
711impl VisitableMut for AttributeOperator {
712	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
713		v.visit_attribute_operator(self);
714		v.exit_attribute_operator(self);
715	}
716}
717
718impl QueryableNode for AttributeOperator {
719	const NODE_ID: NodeId = NodeId::AttributeOperator;
720}
721
722impl Visitable for AttributeOperator {
723	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
724		let node = QueryableNode::visit_node(self);
725		if let VisitAction::SkipChildren = try_visit!(v.consider_node(node)) {
726			return VisitFlow::DESCEND;
727		}
728		if let VisitAction::Descend = try_visit!(v.enter_node(node)) {
729			try_visit!(v.visit_attribute_operator(self));
730			try_visit!(v.exit_attribute_operator(self));
731		}
732		try_visit!(v.exit_node(node));
733		VisitFlow::DESCEND
734	}
735}
736
737impl<'a> VisitableMut for Unresolved<'a> {
738	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
739}
740
741impl<'a> Visitable for Unresolved<'a> {
742	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
743		VisitFlow::DESCEND
744	}
745}
746
747impl<D, M> VisitableMut for NoBlockAllowed<D, M> {
748	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
749}
750
751impl<D, M> Visitable for NoBlockAllowed<D, M> {
752	fn accept<V: Visit>(&self, _: &mut V) -> VisitFlow {
753		VisitFlow::DESCEND
754	}
755}
756
757impl<'a, D> VisitableMut for DeclarationGroup<'a, D, CssMetadata>
758where
759	D: VisitableMut + DeclarationValue<'a, CssMetadata>,
760{
761	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
762		for declaration in &mut self.declarations {
763			declaration.accept_mut(v)
764		}
765	}
766}
767
768impl<'a, D> Visitable for DeclarationGroup<'a, D, CssMetadata>
769where
770	D: Visitable + DeclarationValue<'a, CssMetadata> + QueryableNode,
771{
772	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
773		for declaration in &self.declarations {
774			try_visit!(declaration.accept(v));
775		}
776		VisitFlow::DESCEND
777	}
778}
779
780impl<'a, D> VisitableMut for DeclarationOrBad<'a, D, CssMetadata>
781where
782	D: VisitableMut + DeclarationValue<'a, CssMetadata>,
783{
784	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
785		match self {
786			Self::Declaration(d) => d.accept_mut(v),
787			Self::Bad(b) => b.accept_mut(v),
788		}
789	}
790}
791
792impl<'a, D> Visitable for DeclarationOrBad<'a, D, CssMetadata>
793where
794	D: Visitable + DeclarationValue<'a, CssMetadata> + QueryableNode,
795{
796	fn accept<V: Visit>(&self, v: &mut V) -> VisitFlow {
797		match self {
798			Self::Declaration(d) => d.accept(v),
799			Self::Bad(b) => b.accept(v),
800		}
801	}
802}
803
804macro_rules! impl_tuple_mut {
805    ($($T:ident),*) => {
806				impl<$($T),*> VisitableMut for ($($T),*)
807        where
808            $($T: VisitableMut,)*
809        {
810            #[allow(non_snake_case)]
811            #[allow(unused)]
812						fn accept_mut<VI: VisitMut>(&mut self, v: &mut VI) {
813                let ($($T),*) = self;
814                $($T.accept_mut(v);)*
815            }
816        }
817    };
818}
819
820impl_tuple_mut!(T, U);
821impl_tuple_mut!(T, U, V);
822impl_tuple_mut!(T, U, V, W);
823impl_tuple_mut!(T, U, V, W, X);
824impl_tuple_mut!(T, U, V, W, X, Y);
825impl_tuple_mut!(T, U, V, W, X, Y, Z);
826impl_tuple_mut!(T, U, V, W, X, Y, Z, A);
827impl_tuple_mut!(T, U, V, W, X, Y, Z, A, B);
828impl_tuple_mut!(T, U, V, W, X, Y, Z, A, B, C);
829impl_tuple_mut!(T, U, V, W, X, Y, Z, A, B, C, D);
830impl_tuple_mut!(T, U, V, W, X, Y, Z, A, B, C, D, E);
831
832macro_rules! impl_tuple {
833    ($($T:ident),*) => {
834			impl<$($T),*> Visitable for ($($T),*)
835        where
836            $($T: Visitable,)*
837        {
838            #[allow(non_snake_case)]
839            #[allow(unused)]
840					fn accept<VI: Visit>(&self, v: &mut VI) -> VisitFlow {
841                let ($($T),*) = self;
842                $(try_visit!($T.accept(v));)*
843                VisitFlow::DESCEND
844            }
845        }
846    };
847}
848impl_tuple!(T, U);
849impl_tuple!(T, U, V);
850impl_tuple!(T, U, V, W);
851impl_tuple!(T, U, V, W, X);
852impl_tuple!(T, U, V, W, X, Y);
853impl_tuple!(T, U, V, W, X, Y, Z);
854impl_tuple!(T, U, V, W, X, Y, Z, A);
855impl_tuple!(T, U, V, W, X, Y, Z, A, B);
856impl_tuple!(T, U, V, W, X, Y, Z, A, B, C);
857impl_tuple!(T, U, V, W, X, Y, Z, A, B, C, D);
858impl_tuple!(T, U, V, W, X, Y, Z, A, B, C, D, E);