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