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