css_ast/visit/
mod.rs

1include!(concat!(env!("OUT_DIR"), "/css_node_kind.rs"));
2include!(concat!(env!("OUT_DIR"), "/css_apply_visit_methods.rs"));
3include!(concat!(env!("OUT_DIR"), "/css_apply_queryable_visit_methods.rs"));
4include!(concat!(env!("OUT_DIR"), "/css_apply_queryable_exit_methods.rs"));
5pub use apply_queryable_exit_methods;
6pub use apply_queryable_visit_methods;
7pub use apply_visit_methods;
8
9use bumpalo::collections::Vec;
10use css_parse::{
11	Block, CommaSeparated, Comparison, ComponentValues, Cursor, Declaration, DeclarationGroup, DeclarationList,
12	DeclarationOrBad, DeclarationValue, NoBlockAllowed, NodeMetadata, NodeWithMetadata, Optionals2, Optionals3,
13	Optionals4, Optionals5, QualifiedRule, RuleList, syntax::BadDeclaration, token_macros,
14};
15
16use crate::*;
17
18macro_rules! visit_mut_trait {
19	( $(
20		$name: ident$(<$($gen:tt),+>)?($obj: ty),
21	)+ ) => {
22		pub trait VisitMut: Sized {
23			fn visit_declaration<'a, T: DeclarationValue<'a, CssMetadata>>(&mut self, _rule: &mut Declaration<'a, T, CssMetadata>) {}
24			fn exit_declaration<'a, T: DeclarationValue<'a, CssMetadata>>(&mut self, _rule: &mut Declaration<'a, T, CssMetadata>) {}
25			fn visit_bad_declaration<'a>(&mut self, _rule: &mut BadDeclaration<'a>) {}
26			fn exit_bad_declaration<'a>(&mut self, _rule: &mut BadDeclaration<'a>) {}
27			fn visit_string(&mut self, _str: &mut token_macros::String) {}
28			fn exit_string(&mut self, _str: &mut token_macros::String) {}
29			fn visit_comparison(&mut self, _comparison: &mut Comparison) {}
30			fn exit_comparison(&mut self, _comparison: &mut Comparison) {}
31			$(
32				fn $name$(<$($gen),+>)?(&mut self, _rule: &mut $obj) {}
33			)+
34		}
35	}
36}
37apply_visit_methods!(visit_mut_trait);
38
39macro_rules! visit_trait {
40	( $(
41		$name: ident$(<$($gen:tt),+>)?($obj: ty),
42	)+ ) => {
43		pub trait Visit: Sized {
44			/// Generic method for visiting queryable nodes. Override this to handle all queryable nodes uniformly.
45			/// Individual visit methods will delegate to this by default.
46			fn visit_queryable_node<T: QueryableNode>(&mut self, _node: &T) {}
47
48			/// Generic method for exiting queryable nodes. Override this to handle all queryable nodes uniformly.
49			/// Individual exit methods will delegate to this by default.
50			fn exit_queryable_node<T: QueryableNode>(&mut self, _node: &T) {}
51
52			fn visit_declaration<'a, T: DeclarationValue<'a, CssMetadata> + QueryableNode>(&mut self, _rule: &Declaration<'a, T, CssMetadata>) {}
53			fn exit_declaration<'a, T: DeclarationValue<'a, CssMetadata> + QueryableNode>(&mut self, _rule: &Declaration<'a, T, CssMetadata>) {}
54			fn visit_bad_declaration<'a>(&mut self, _rule: &BadDeclaration<'a>) {}
55			fn exit_bad_declaration<'a>(&mut self, _rule: &BadDeclaration<'a>) {}
56			fn visit_string(&mut self, _str: &token_macros::String) {}
57			fn exit_string(&mut self, _str: &token_macros::String) {}
58			fn visit_comparison(&mut self, _comparison: &Comparison) {}
59			fn exit_comparison(&mut self, _comparison: &Comparison) {}
60			$(
61				fn $name$(<$($gen),+>)?(&mut self, _rule: &$obj) {}
62			)+
63		}
64	}
65}
66apply_visit_methods!(visit_trait);
67
68pub trait VisitableMut {
69	fn accept_mut<V: VisitMut>(&mut self, v: &mut V);
70}
71
72pub trait Visitable {
73	fn accept<V: Visit>(&self, v: &mut V);
74}
75
76/// Marker trait for AST nodes that can be queried with selectors.
77///
78/// This trait extends `Visitable` and adds a unique identifier for the node type.
79/// It is automatically implemented by `#[derive(Visitable)]` for all nodes that
80/// are not marked with `#[visit(skip)]` or `#[visit(children)]`.
81pub trait QueryableNode: Visitable + NodeWithMetadata<CssMetadata> + ToSpan {
82	/// Unique identifier for this node type.
83	const NODE_ID: NodeId;
84
85	fn node_id(&self) -> NodeId {
86		Self::NODE_ID
87	}
88
89	/// Returns a cursor for the given property kind, if the node has that property.
90	/// Used by attribute selectors to extract values from nodes.
91	///
92	/// For `PropertyKind::Name`, returns a cursor to the node's name (e.g., property
93	/// name for declarations, animation name for `@keyframes`).
94	fn get_property(&self, _kind: PropertyKind) -> Option<Cursor> {
95		None
96	}
97}
98
99impl<T> VisitableMut for Option<T>
100where
101	T: VisitableMut,
102{
103	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
104		if let Some(node) = self {
105			node.accept_mut(v)
106		}
107	}
108}
109
110macro_rules! impl_optionals {
111	($N:ident, $($T:ident),+) => {
112		impl<$($T),*> Visitable for $N<$($T),+>
113		where
114			$($T: Visitable,)+
115		{
116			#[allow(non_snake_case)]
117			#[allow(unused)]
118			fn accept<VI: Visit>(&self, v: &mut VI) {
119				let $N($($T),+) = self;
120				$($T.accept(v);)+;
121			}
122		}
123
124		impl<$($T),*> VisitableMut for $N<$($T),+>
125		where
126			$($T: VisitableMut,)+
127		{
128			#[allow(non_snake_case)]
129			#[allow(unused)]
130			fn accept_mut<VI: VisitMut>(&mut self, v: &mut VI) {
131				let $N($($T),+) = self;
132				$($T.accept_mut(v);)+;
133			}
134		}
135	};
136}
137
138impl_optionals!(Optionals2, T, U);
139impl_optionals!(Optionals3, T, U, V);
140impl_optionals!(Optionals4, T, U, V, W);
141impl_optionals!(Optionals5, T, U, V, W, X);
142
143impl Visitable for token_macros::Ident {
144	fn accept<V: Visit>(&self, _: &mut V) {}
145}
146
147impl VisitableMut for token_macros::Ident {
148	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
149}
150
151impl Visitable for token_macros::Comma {
152	fn accept<V: Visit>(&self, _: &mut V) {}
153}
154
155impl VisitableMut for token_macros::Comma {
156	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
157}
158
159impl Visitable for token_macros::LeftParen {
160	fn accept<V: Visit>(&self, _: &mut V) {}
161}
162
163impl VisitableMut for token_macros::LeftParen {
164	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
165}
166
167impl Visitable for token_macros::RightParen {
168	fn accept<V: Visit>(&self, _: &mut V) {}
169}
170
171impl VisitableMut for token_macros::RightParen {
172	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
173}
174
175impl Visitable for token_macros::Colon {
176	fn accept<V: Visit>(&self, _: &mut V) {}
177}
178
179impl VisitableMut for token_macros::Colon {
180	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
181}
182
183impl Visitable for Comparison {
184	fn accept<V: Visit>(&self, v: &mut V) {
185		v.visit_comparison(self);
186		v.exit_comparison(self);
187	}
188}
189
190impl VisitableMut for Comparison {
191	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
192		v.visit_comparison(self);
193		v.exit_comparison(self);
194	}
195}
196
197impl Visitable for token_macros::delim::Slash {
198	fn accept<V: Visit>(&self, _: &mut V) {}
199}
200
201impl VisitableMut for token_macros::delim::Slash {
202	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
203}
204
205impl Visitable for token_macros::Number {
206	fn accept<V: Visit>(&self, _: &mut V) {}
207}
208
209impl VisitableMut for token_macros::Number {
210	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
211}
212
213impl Visitable for token_macros::String {
214	fn accept<V: Visit>(&self, v: &mut V) {
215		v.visit_string(self);
216		v.exit_string(self);
217	}
218}
219
220impl VisitableMut for token_macros::String {
221	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
222		v.visit_string(self);
223		v.exit_string(self);
224	}
225}
226
227impl<T> Visitable for Option<T>
228where
229	T: Visitable,
230{
231	fn accept<V: Visit>(&self, v: &mut V) {
232		if let Some(node) = self {
233			node.accept(v)
234		}
235	}
236}
237
238impl<'a, T, const MIN: usize> VisitableMut for CommaSeparated<'a, T, MIN>
239where
240	T: VisitableMut + Peek<'a> + Parse<'a> + ToCursors + ToSpan,
241{
242	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
243		for (node, _) in self {
244			node.accept_mut(v)
245		}
246	}
247}
248
249impl<'a, T, const MIN: usize> Visitable for CommaSeparated<'a, T, MIN>
250where
251	T: Visitable + Peek<'a> + Parse<'a> + ToCursors + ToSpan,
252{
253	fn accept<V: Visit>(&self, v: &mut V) {
254		for (node, _) in self {
255			node.accept(v)
256		}
257	}
258}
259
260impl<'a, T> VisitableMut for Declaration<'a, T, CssMetadata>
261where
262	T: VisitableMut + DeclarationValue<'a, CssMetadata>,
263{
264	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
265		v.visit_declaration(self);
266		self.value.accept_mut(v);
267		v.exit_declaration(self);
268	}
269}
270
271impl<'a, T> QueryableNode for Declaration<'a, T, CssMetadata>
272where
273	T: DeclarationValue<'a, CssMetadata> + QueryableNode,
274{
275	const NODE_ID: NodeId = NodeId::StyleValue;
276
277	fn node_id(&self) -> NodeId {
278		T::NODE_ID
279	}
280
281	fn get_property(&self, kind: PropertyKind) -> Option<Cursor> {
282		match kind {
283			PropertyKind::Name => Some(self.name.into()),
284			_ => None,
285		}
286	}
287}
288
289impl<'a, T> Visitable for Declaration<'a, T, CssMetadata>
290where
291	T: Visitable + DeclarationValue<'a, CssMetadata> + QueryableNode,
292{
293	fn accept<V: Visit>(&self, v: &mut V) {
294		v.visit_queryable_node(self);
295		v.visit_declaration::<T>(self);
296		self.value.accept(v);
297		v.exit_declaration::<T>(self);
298		v.exit_queryable_node(self);
299	}
300}
301
302impl<'a, T> VisitableMut for DeclarationList<'a, T, CssMetadata>
303where
304	T: VisitableMut + DeclarationValue<'a, CssMetadata>,
305{
306	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
307		for declaration in &mut self.declarations {
308			declaration.accept_mut(v);
309		}
310	}
311}
312
313impl<'a, T> Visitable for DeclarationList<'a, T, CssMetadata>
314where
315	T: Visitable + DeclarationValue<'a, CssMetadata> + QueryableNode,
316{
317	fn accept<V: Visit>(&self, v: &mut V) {
318		for declaration in &self.declarations {
319			declaration.accept(v);
320		}
321	}
322}
323
324impl<'a, T, M> VisitableMut for RuleList<'a, T, M>
325where
326	T: VisitableMut + Parse<'a> + ToCursors + ToSpan + NodeWithMetadata<M>,
327	M: NodeMetadata,
328{
329	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
330		self.rules.accept_mut(v);
331	}
332}
333
334impl<'a, T, M> Visitable for RuleList<'a, T, M>
335where
336	T: Visitable + Parse<'a> + ToCursors + ToSpan + NodeWithMetadata<M>,
337	M: NodeMetadata,
338{
339	fn accept<V: Visit>(&self, v: &mut V) {
340		self.rules.accept(v);
341	}
342}
343
344impl<'a, P, D, R> VisitableMut for QualifiedRule<'a, P, D, R, CssMetadata>
345where
346	P: VisitableMut + Peek<'a> + Parse<'a> + ToCursors + ToSpan,
347	D: VisitableMut + DeclarationValue<'a, CssMetadata>,
348	R: VisitableMut + Parse<'a> + ToCursors + ToSpan,
349	Block<'a, D, R, CssMetadata>: Parse<'a> + ToCursors + ToSpan,
350{
351	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
352		self.prelude.accept_mut(v);
353		self.block.accept_mut(v);
354	}
355}
356
357impl<'a, P, D, R> Visitable for QualifiedRule<'a, P, D, R, CssMetadata>
358where
359	P: Visitable + Peek<'a> + Parse<'a> + ToCursors + ToSpan,
360	D: Visitable + DeclarationValue<'a, CssMetadata> + QueryableNode,
361	R: Visitable + Parse<'a> + ToCursors + ToSpan,
362	Block<'a, D, R, CssMetadata>: Parse<'a> + ToCursors + ToSpan,
363{
364	fn accept<V: Visit>(&self, v: &mut V) {
365		self.prelude.accept(v);
366		self.block.accept(v);
367	}
368}
369
370impl<'a, D, R> VisitableMut for Block<'a, D, R, CssMetadata>
371where
372	D: VisitableMut + DeclarationValue<'a, CssMetadata>,
373	R: VisitableMut + Parse<'a> + ToCursors + ToSpan,
374{
375	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
376		for declaration in &mut self.declarations {
377			declaration.accept_mut(v);
378		}
379		for rule in &mut self.rules {
380			rule.accept_mut(v);
381		}
382	}
383}
384
385impl<'a, D, R> Visitable for Block<'a, D, R, CssMetadata>
386where
387	D: Visitable + DeclarationValue<'a, CssMetadata> + QueryableNode,
388	R: Visitable + Parse<'a> + ToCursors + ToSpan,
389{
390	fn accept<V: Visit>(&self, v: &mut V) {
391		for declaration in &self.declarations {
392			declaration.accept(v);
393		}
394		for rule in &self.rules {
395			rule.accept(v);
396		}
397	}
398}
399
400impl<'a, T> VisitableMut for Vec<'a, T>
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> Visitable for Vec<'a, T>
412where
413	T: Visitable,
414{
415	fn accept<V: Visit>(&self, v: &mut V) {
416		for node in self {
417			node.accept(v)
418		}
419	}
420}
421
422impl<'a> VisitableMut for BadDeclaration<'a> {
423	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
424		v.visit_bad_declaration(self);
425		v.exit_bad_declaration(self);
426	}
427}
428
429impl<'a> Visitable for BadDeclaration<'a> {
430	fn accept<V: Visit>(&self, v: &mut V) {
431		v.visit_bad_declaration(self);
432		v.exit_bad_declaration(self);
433	}
434}
435
436impl<'a> VisitableMut for ComponentValues<'a> {
437	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
438}
439
440impl<'a> Visitable for ComponentValues<'a> {
441	fn accept<V: Visit>(&self, _: &mut V) {}
442}
443
444impl<D, M> VisitableMut for NoBlockAllowed<D, M> {
445	fn accept_mut<V: VisitMut>(&mut self, _: &mut V) {}
446}
447
448impl<D, M> Visitable for NoBlockAllowed<D, M> {
449	fn accept<V: Visit>(&self, _: &mut V) {}
450}
451
452impl<'a, D> VisitableMut for DeclarationGroup<'a, D, CssMetadata>
453where
454	D: VisitableMut + DeclarationValue<'a, CssMetadata>,
455{
456	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
457		for declaration in &mut self.declarations {
458			declaration.accept_mut(v)
459		}
460	}
461}
462
463impl<'a, D> Visitable for DeclarationGroup<'a, D, CssMetadata>
464where
465	D: Visitable + DeclarationValue<'a, CssMetadata> + QueryableNode,
466{
467	fn accept<V: Visit>(&self, v: &mut V) {
468		for declaration in &self.declarations {
469			declaration.accept(v)
470		}
471	}
472}
473
474impl<'a, D> VisitableMut for DeclarationOrBad<'a, D, CssMetadata>
475where
476	D: VisitableMut + DeclarationValue<'a, CssMetadata>,
477{
478	fn accept_mut<V: VisitMut>(&mut self, v: &mut V) {
479		match self {
480			Self::Declaration(d) => d.accept_mut(v),
481			Self::Bad(b) => b.accept_mut(v),
482		}
483	}
484}
485
486impl<'a, D> Visitable for DeclarationOrBad<'a, D, CssMetadata>
487where
488	D: Visitable + DeclarationValue<'a, CssMetadata> + QueryableNode,
489{
490	fn accept<V: Visit>(&self, v: &mut V) {
491		match self {
492			Self::Declaration(d) => d.accept(v),
493			Self::Bad(b) => b.accept(v),
494		}
495	}
496}
497
498macro_rules! impl_tuple_mut {
499    ($($T:ident),*) => {
500				impl<$($T),*> VisitableMut for ($($T),*)
501        where
502            $($T: VisitableMut,)*
503        {
504            #[allow(non_snake_case)]
505            #[allow(unused)]
506						fn accept_mut<VI: VisitMut>(&mut self, v: &mut VI) {
507                let ($($T),*) = self;
508                $($T.accept_mut(v);)*
509            }
510        }
511    };
512}
513
514impl_tuple_mut!(T, U);
515impl_tuple_mut!(T, U, V);
516impl_tuple_mut!(T, U, V, W);
517
518macro_rules! impl_tuple {
519    ($($T:ident),*) => {
520				impl<$($T),*> Visitable for ($($T),*)
521        where
522            $($T: Visitable,)*
523        {
524            #[allow(non_snake_case)]
525            #[allow(unused)]
526						fn accept<VI: Visit>(&self, v: &mut VI) {
527                let ($($T),*) = self;
528                $($T.accept(v);)*
529            }
530        }
531    };
532}
533impl_tuple!(T, U);
534impl_tuple!(T, U, V);
535impl_tuple!(T, U, V, W);