glsl_lang/
visitor.rs

1//! AST visitors (i.e. on-the-fly mutation at different places in the AST).
2//!
3//! Visitors are mutable objects that can mutate parts of an AST while traversing it. You can see
4//! them as flexible mutations taking place on *patterns* representing your AST – they get called
5//! everytime an interesting node gets visited. Because of their mutable nature, you can accumulate
6//! a state as you traverse the AST and implement exotic filtering.
7//!
8//! Visitors must implement the [`Visitor`] trait in order to be usable.
9//!
10//! In order to visit any part of an AST (from its very top root or from any part of it), you must
11//! use the [`Host`] interface, that provides the [`Host::visit`] function.
12//!
13//! For instance, we can imagine visiting an AST to count how many variables are declared:
14//!
15//! ```
16//! use glsl_lang::ast::{CompoundStatement, CompoundStatementData, ExprData, SingleDeclaration, StatementData, TypeSpecifierNonArrayData, NodeContent};
17//! use glsl_lang::visitor::{Host, Visit, Visitor};
18//! use std::iter::FromIterator;
19//!
20//! let decl0 = StatementData::declare_var(
21//!   TypeSpecifierNonArrayData::Float,
22//!   "x",
23//!   None,
24//!   Some(ExprData::from(3.14).into_node())
25//! );
26//!
27//! let decl1 = StatementData::declare_var(
28//!   TypeSpecifierNonArrayData::Int,
29//!   "y",
30//!   None,
31//!   None
32//! );
33//!
34//! let decl2 = StatementData::declare_var(
35//!   TypeSpecifierNonArrayData::Vec4,
36//!   "z",
37//!   None,
38//!   None
39//! );
40//!
41//! let compound: CompoundStatement = CompoundStatementData::from_iter(
42//!   vec![decl0.into(), decl1.into(), decl2.into()]
43//! ).into();
44//!
45//! // our visitor that will count the number of variables it saw
46//! struct Counter {
47//!   var_nb: usize
48//! }
49//!
50//! impl Visitor for Counter {
51//!   // we are only interested in single declaration with a name
52//!   fn visit_single_declaration(&mut self, declaration: &SingleDeclaration) -> Visit {
53//!     if declaration.name.is_some() {
54//!       self.var_nb += 1;
55//!     }
56//!
57//!     // do not go deeper
58//!     Visit::Parent
59//!   }
60//! }
61//!
62//! let mut counter = Counter { var_nb: 0 };
63//! compound.visit(&mut counter);
64//! assert_eq!(counter.var_nb, 3);
65//! ```
66//!
67//! [`Host`]: crate::visitor::Host
68//! [`Host::visit`]: crate::visitor::Host::visit
69//! [`Visitor`]: crate::visitor::Visitor
70
71use crate::ast;
72
73/// Visit strategy after having visited an AST node.
74///
75/// Some AST nodes have *children* – in enum’s variants, in some fields as nested in [`Vec`], etc.
76/// Those nodes can be visited depending on the strategy you chose.
77#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
78pub enum Visit {
79    /// The visitor will go deeper in the AST by visiting all the children, if any. If no children are
80    /// present or if having children doesn’t make sense for a specific part of the AST, this
81    /// strategy will be ignored.
82    Children,
83    /// The visitor won’t visit children nor siblings and will go up.
84    Parent,
85}
86
87macro_rules! make_visitor_trait {
88  ($t:ident, $($ref:tt)*) => {
89    /// Visitor object, visiting AST nodes.
90    ///
91    /// This trait exists in two flavors, depending on whether you want to mutate the AST or not: [`Visitor`] doesn’t
92    /// allow for mutation while [`VisitorMut`] does.
93    #[allow(missing_docs)]
94    pub trait $t {
95      fn visit_translation_unit(&mut self, _: $($ref)* ast::TranslationUnit) -> Visit {
96        Visit::Children
97      }
98
99      fn visit_external_declaration(&mut self, _: $($ref)* ast::ExternalDeclaration) -> Visit {
100        Visit::Children
101      }
102
103      fn visit_identifier(&mut self, _: $($ref)* ast::Identifier) -> Visit {
104        Visit::Children
105      }
106
107      fn visit_arrayed_identifier(&mut self, _: $($ref)* ast::ArrayedIdentifier) -> Visit {
108        Visit::Children
109      }
110
111      fn visit_type_name(&mut self, _: $($ref)* ast::TypeName) -> Visit {
112        Visit::Children
113      }
114
115      fn visit_block(&mut self, _: $($ref)* ast::Block) -> Visit {
116        Visit::Children
117      }
118
119      fn visit_for_init_statement(&mut self, _: $($ref)* ast::ForInitStatement) -> Visit {
120        Visit::Children
121      }
122
123      fn visit_for_rest_statement(&mut self, _: $($ref)* ast::ForRestStatement) -> Visit {
124        Visit::Children
125      }
126
127      fn visit_function_definition(&mut self, _: $($ref)* ast::FunctionDefinition) -> Visit {
128        Visit::Children
129      }
130
131      fn visit_function_parameter_declarator(
132        &mut self,
133        _: $($ref)* ast::FunctionParameterDeclarator,
134      ) -> Visit {
135        Visit::Children
136      }
137
138      fn visit_function_prototype(&mut self, _: $($ref)* ast::FunctionPrototype) -> Visit {
139        Visit::Children
140      }
141
142      fn visit_init_declarator_list(&mut self, _: $($ref)* ast::InitDeclaratorList) -> Visit {
143        Visit::Children
144      }
145
146      fn visit_layout_qualifier(&mut self, _: $($ref)* ast::LayoutQualifier) -> Visit {
147        Visit::Children
148      }
149
150      fn visit_preprocessor(&mut self, _: $($ref)* ast::Preprocessor) -> Visit {
151        Visit::Children
152      }
153
154      fn visit_preprocessor_define(&mut self, _: $($ref)* ast::PreprocessorDefine) -> Visit {
155        Visit::Children
156      }
157
158      fn visit_preprocessor_elseif(&mut self, _: $($ref)* ast::PreprocessorElseIf) -> Visit {
159        Visit::Children
160      }
161
162      fn visit_preprocessor_error(&mut self, _: $($ref)* ast::PreprocessorError) -> Visit {
163        Visit::Children
164      }
165
166      fn visit_preprocessor_extension(&mut self, _: $($ref)* ast::PreprocessorExtension) -> Visit {
167        Visit::Children
168      }
169
170      fn visit_preprocessor_extension_behavior(
171        &mut self,
172        _: $($ref)* ast::PreprocessorExtensionBehavior,
173      ) -> Visit {
174        Visit::Children
175      }
176
177      fn visit_preprocessor_extension_name(
178        &mut self,
179        _: $($ref)* ast::PreprocessorExtensionName,
180      ) -> Visit {
181        Visit::Children
182      }
183
184      fn visit_preprocessor_if(&mut self, _: $($ref)* ast::PreprocessorIf) -> Visit {
185        Visit::Children
186      }
187
188      fn visit_preprocessor_ifdef(&mut self, _: $($ref)* ast::PreprocessorIfDef) -> Visit {
189        Visit::Children
190      }
191
192      fn visit_preprocessor_ifndef(&mut self, _: $($ref)* ast::PreprocessorIfNDef) -> Visit {
193        Visit::Children
194      }
195
196      fn visit_preprocessor_include(&mut self, _: $($ref)* ast::PreprocessorInclude) -> Visit {
197        Visit::Children
198      }
199
200      fn visit_preprocessor_line(&mut self, _: $($ref)* ast::PreprocessorLine) -> Visit {
201        Visit::Children
202      }
203
204      fn visit_preprocessor_pragma(&mut self, _: $($ref)* ast::PreprocessorPragma) -> Visit {
205        Visit::Children
206      }
207
208      fn visit_preprocessor_undef(&mut self, _: $($ref)* ast::PreprocessorUndef) -> Visit {
209        Visit::Children
210      }
211
212      fn visit_preprocessor_version(&mut self, _: $($ref)* ast::PreprocessorVersion) -> Visit {
213        Visit::Children
214      }
215
216      fn visit_preprocessor_version_profile(
217        &mut self,
218        _: $($ref)* ast::PreprocessorVersionProfile,
219      ) -> Visit {
220        Visit::Children
221      }
222
223      fn visit_selection_statement(&mut self, _: $($ref)* ast::SelectionStatement) -> Visit {
224        Visit::Children
225      }
226
227      fn visit_selection_rest_statement(&mut self, _: $($ref)* ast::SelectionRestStatement) -> Visit {
228        Visit::Children
229      }
230
231      fn visit_single_declaration(&mut self, _: $($ref)* ast::SingleDeclaration) -> Visit {
232        Visit::Children
233      }
234
235      fn visit_single_declaration_no_type(&mut self, _: $($ref)* ast::SingleDeclarationNoType) -> Visit {
236        Visit::Children
237      }
238
239      fn visit_struct_field_specifier(&mut self, _: $($ref)* ast::StructFieldSpecifier) -> Visit {
240        Visit::Children
241      }
242
243      fn visit_struct_specifier(&mut self, _: $($ref)* ast::StructSpecifier) -> Visit {
244        Visit::Children
245      }
246
247      fn visit_switch_statement(&mut self, _: $($ref)* ast::SwitchStatement) -> Visit {
248        Visit::Children
249      }
250
251      fn visit_type_qualifier(&mut self, _: $($ref)* ast::TypeQualifier) -> Visit {
252        Visit::Children
253      }
254
255      fn visit_type_specifier(&mut self, _: $($ref)* ast::TypeSpecifier) -> Visit {
256        Visit::Children
257      }
258
259      fn visit_full_specified_type(&mut self, _: $($ref)* ast::FullySpecifiedType) -> Visit {
260        Visit::Children
261      }
262
263      fn visit_array_specifier(&mut self, _: $($ref)* ast::ArraySpecifier) -> Visit {
264        Visit::Children
265      }
266
267      fn visit_array_specifier_dimension(&mut self, _: $($ref)* ast::ArraySpecifierDimension) -> Visit {
268        Visit::Children
269      }
270
271      fn visit_assignment_op(&mut self, _: $($ref)* ast::AssignmentOp) -> Visit {
272        Visit::Children
273      }
274
275      fn visit_binary_op(&mut self, _: $($ref)* ast::BinaryOp) -> Visit {
276        Visit::Children
277      }
278
279      fn visit_case_label(&mut self, _: $($ref)* ast::CaseLabel) -> Visit {
280        Visit::Children
281      }
282
283      fn visit_condition(&mut self, _: $($ref)* ast::Condition) -> Visit {
284        Visit::Children
285      }
286
287      fn visit_declaration(&mut self, _: $($ref)* ast::Declaration) -> Visit {
288        Visit::Children
289      }
290
291      fn visit_expr(&mut self, _: $($ref)* ast::Expr) -> Visit {
292        Visit::Children
293      }
294
295      fn visit_fun_identifier(&mut self, _: $($ref)* ast::FunIdentifier) -> Visit {
296        Visit::Children
297      }
298
299      fn visit_function_parameter_declaration(
300        &mut self,
301        _: $($ref)* ast::FunctionParameterDeclaration,
302      ) -> Visit {
303        Visit::Children
304      }
305
306      fn visit_initializer(&mut self, _: $($ref)* ast::Initializer) -> Visit {
307        Visit::Children
308      }
309
310      fn visit_interpolation_qualifier(&mut self, _: $($ref)* ast::InterpolationQualifier) -> Visit {
311        Visit::Children
312      }
313
314      fn visit_iteration_statement(&mut self, _: $($ref)* ast::IterationStatement) -> Visit {
315        Visit::Children
316      }
317
318      fn visit_jump_statement(&mut self, _: $($ref)* ast::JumpStatement) -> Visit {
319        Visit::Children
320      }
321
322      fn visit_layout_qualifier_spec(&mut self, _: $($ref)* ast::LayoutQualifierSpec) -> Visit {
323        Visit::Children
324      }
325
326      fn visit_precision_qualifier(&mut self, _: $($ref)* ast::PrecisionQualifier) -> Visit {
327        Visit::Children
328      }
329
330      fn visit_statement(&mut self, _: $($ref)* ast::Statement) -> Visit {
331        Visit::Children
332      }
333
334      fn visit_compound_statement(&mut self, _: $($ref)* ast::CompoundStatement) -> Visit {
335        Visit::Children
336      }
337
338      fn visit_storage_qualifier(&mut self, _: $($ref)* ast::StorageQualifier) -> Visit {
339        Visit::Children
340      }
341
342      fn visit_type_qualifier_spec(&mut self, _: $($ref)* ast::TypeQualifierSpec) -> Visit {
343        Visit::Children
344      }
345
346      fn visit_type_specifier_non_array(&mut self, _: $($ref)* ast::TypeSpecifierNonArray) -> Visit {
347        Visit::Children
348      }
349
350      fn visit_unary_op(&mut self, _: $($ref)* ast::UnaryOp) -> Visit {
351        Visit::Children
352      }
353
354      fn visit_expr_statement(&mut self, _: $($ref)* ast::ExprStatement) -> Visit {
355        Visit::Children
356      }
357    }
358  }
359}
360
361macro_rules! make_host_trait {
362  ($host_ty:ident, $visitor_ty:ident, $mthd_name:ident, $iter:ident, $($ref:tt)*) => {
363    /// Part of the AST that can be visited.
364    ///
365    /// You shouldn’t have to worry about this type nor how to implement it – it’s completely
366    /// implemented for you. However, it works in a pretty simple way: any implementor of the host trait can
367    /// be used with a visitor.
368    ///
369    /// The idea is that visiting an AST node is a two-step process:
370    ///
371    ///   - First, you *can* get your visitor called once as soon as an interesting node gets visited.
372    ///     For instance, if your visitor has an implementation for visiting expressions, everytime an
373    ///     expression gets visited, your visitor will run.
374    ///   - If your implementation of visiting an AST node returns [`Visit::Children`] and if the given
375    ///     node has children, the visitor will go deeper, invoking other calls if you have defined any.
376    ///     A typical pattern you might want to do is to implement your visitor to gets run on all
377    ///     typenames. Since expressions contains variables, you will get your visitor called once again
378    ///     there.
379    ///   - Notice that since visitors are mutable, you can accumulate a state as you go deeper in the
380    ///     AST to implement various checks and validations.
381    ///
382    /// Note that this trait exists in two versions: an immutable one, [`Host`], which doesn’t allow you to mutate the
383    /// AST (but takes a `&`), and a mutable one, [`HostMut`], which allows for AST mutation.
384    pub trait $host_ty {
385      /// Visit an AST node.
386      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
387      where
388          V: $visitor_ty;
389    }
390
391    impl<T> $host_ty for Option<T>
392      where
393          T: $host_ty,
394      {
395        fn $mthd_name<V>($($ref)* self, visitor: &mut V)
396        where
397            V: $visitor_ty,
398        {
399          if let Some(x) = self {
400            x.$mthd_name(visitor);
401          }
402        }
403      }
404
405    impl<T> $host_ty for Box<T>
406      where
407          T: $host_ty,
408      {
409        fn $mthd_name<V>($($ref)* self, visitor: &mut V)
410        where
411            V: $visitor_ty,
412        {
413          (**self).$mthd_name(visitor);
414        }
415      }
416
417    impl $host_ty for ast::TranslationUnit {
418      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
419      where
420          V: $visitor_ty,
421      {
422        let visit = visitor.visit_translation_unit(self);
423
424        if visit == Visit::Children {
425          for ed in $($ref)* self.0 {
426            ed.$mthd_name(visitor);
427          }
428        }
429      }
430    }
431
432    impl $host_ty for ast::ExternalDeclaration {
433      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
434      where
435          V: $visitor_ty,
436      {
437        let visit = visitor.visit_external_declaration(self);
438
439        if visit == Visit::Children {
440          match $($ref)* **self {
441            ast::ExternalDeclarationData::Preprocessor(p) => p.$mthd_name(visitor),
442            ast::ExternalDeclarationData::FunctionDefinition(fd) => fd.$mthd_name(visitor),
443            ast::ExternalDeclarationData::Declaration(d) => d.$mthd_name(visitor),
444          }
445        }
446      }
447    }
448
449    impl $host_ty for ast::Preprocessor {
450      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
451      where
452          V: $visitor_ty,
453      {
454        let visit = visitor.visit_preprocessor(self);
455
456        if visit == Visit::Children {
457          match $($ref)* **self {
458            ast::PreprocessorData::Define(pd) => pd.$mthd_name(visitor),
459            ast::PreprocessorData::Else => (),
460            ast::PreprocessorData::ElseIf(pei) => pei.$mthd_name(visitor),
461            ast::PreprocessorData::EndIf => (),
462            ast::PreprocessorData::Error(pe) => pe.$mthd_name(visitor),
463            ast::PreprocessorData::If(pi) => pi.$mthd_name(visitor),
464            ast::PreprocessorData::IfDef(pid) => pid.$mthd_name(visitor),
465            ast::PreprocessorData::IfNDef(pind) => pind.$mthd_name(visitor),
466            ast::PreprocessorData::Include(pi) => pi.$mthd_name(visitor),
467            ast::PreprocessorData::Line(pl) => pl.$mthd_name(visitor),
468            ast::PreprocessorData::Pragma(pp) => pp.$mthd_name(visitor),
469            ast::PreprocessorData::Undef(pu) => pu.$mthd_name(visitor),
470            ast::PreprocessorData::Version(pv) => pv.$mthd_name(visitor),
471            ast::PreprocessorData::Extension(ext) => ext.$mthd_name(visitor),
472          }
473        }
474      }
475    }
476
477    impl $host_ty for ast::PreprocessorDefine {
478      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
479      where
480          V: $visitor_ty,
481      {
482        let visit = visitor.visit_preprocessor_define(self);
483
484        if visit == Visit::Children {
485          match $($ref)* **self {
486            ast::PreprocessorDefineData::ObjectLike { ident, .. } => {
487              ident.$mthd_name(visitor);
488            }
489
490            ast::PreprocessorDefineData::FunctionLike {
491              ident,
492              args,
493              ..
494            } => {
495              ident.$mthd_name(visitor);
496
497              for arg in args {
498                arg.$mthd_name(visitor);
499              }
500            }
501          }
502        }
503      }
504    }
505
506    impl $host_ty for ast::PreprocessorElseIf {
507      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
508      where
509          V: $visitor_ty,
510      {
511        let _ = visitor.visit_preprocessor_elseif(self);
512      }
513    }
514
515    impl $host_ty for ast::PreprocessorError {
516      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
517      where
518          V: $visitor_ty,
519      {
520        let _ = visitor.visit_preprocessor_error(self);
521      }
522    }
523
524    impl $host_ty for ast::PreprocessorIf {
525      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
526      where
527          V: $visitor_ty,
528      {
529        let _ = visitor.visit_preprocessor_if(self);
530      }
531    }
532
533    impl $host_ty for ast::PreprocessorIfDef {
534      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
535      where
536          V: $visitor_ty,
537      {
538        let visit = visitor.visit_preprocessor_ifdef(self);
539
540        if visit == Visit::Children {
541          self.ident.$mthd_name(visitor);
542        }
543      }
544    }
545
546    impl $host_ty for ast::PreprocessorIfNDef {
547      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
548      where
549          V: $visitor_ty,
550      {
551        let visit = visitor.visit_preprocessor_ifndef(self);
552
553        if visit == Visit::Children {
554          self.ident.$mthd_name(visitor);
555        }
556      }
557    }
558
559    impl $host_ty for ast::PreprocessorInclude {
560      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
561      where
562          V: $visitor_ty,
563      {
564        let _ = visitor.visit_preprocessor_include(self);
565      }
566    }
567
568    impl $host_ty for ast::PreprocessorLine {
569      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
570      where
571          V: $visitor_ty,
572      {
573        let _ = visitor.visit_preprocessor_line(self);
574      }
575    }
576
577    impl $host_ty for ast::PreprocessorPragma {
578      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
579      where
580          V: $visitor_ty,
581      {
582        let _ = visitor.visit_preprocessor_pragma(self);
583      }
584    }
585
586    impl $host_ty for ast::PreprocessorUndef {
587      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
588      where
589          V: $visitor_ty,
590      {
591        let visit = visitor.visit_preprocessor_undef(self);
592
593        if visit == Visit::Children {
594          self.name.$mthd_name(visitor);
595        }
596      }
597    }
598
599    impl $host_ty for ast::PreprocessorVersion {
600      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
601      where
602          V: $visitor_ty,
603      {
604        let visit = visitor.visit_preprocessor_version(self);
605
606        if visit == Visit::Children {
607          self.profile.$mthd_name(visitor);
608        }
609      }
610    }
611
612    impl $host_ty for ast::PreprocessorVersionProfile {
613      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
614      where
615          V: $visitor_ty,
616      {
617        let _ = visitor.visit_preprocessor_version_profile(self);
618      }
619    }
620
621    impl $host_ty for ast::PreprocessorExtension {
622      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
623      where
624          V: $visitor_ty,
625      {
626        let visit = visitor.visit_preprocessor_extension(self);
627
628        if visit == Visit::Children {
629          self.name.$mthd_name(visitor);
630          self.behavior.$mthd_name(visitor);
631        }
632      }
633    }
634
635    impl $host_ty for ast::PreprocessorExtensionBehavior {
636      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
637      where
638          V: $visitor_ty,
639      {
640        let _ = visitor.visit_preprocessor_extension_behavior(self);
641      }
642    }
643
644    impl $host_ty for ast::PreprocessorExtensionName {
645      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
646      where
647          V: $visitor_ty,
648      {
649        let _ = visitor.visit_preprocessor_extension_name(self);
650      }
651    }
652
653    impl $host_ty for ast::FunctionPrototype {
654      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
655      where
656          V: $visitor_ty,
657      {
658        let visit = visitor.visit_function_prototype(self);
659
660        if visit == Visit::Children {
661          self.ty.$mthd_name(visitor);
662          self.name.$mthd_name(visitor);
663
664          for param in $($ref)* self.parameters {
665            param.$mthd_name(visitor);
666          }
667        }
668      }
669    }
670
671    impl $host_ty for ast::FunctionParameterDeclaration {
672      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
673      where
674          V: $visitor_ty,
675      {
676        let visit = visitor.visit_function_parameter_declaration(self);
677
678        if visit == Visit::Children {
679          match $($ref)* **self {
680            ast::FunctionParameterDeclarationData::Named(tq, fpd) => {
681              tq.$mthd_name(visitor);
682              fpd.$mthd_name(visitor);
683            }
684
685            ast::FunctionParameterDeclarationData::Unnamed(tq, ty) => {
686              tq.$mthd_name(visitor);
687              ty.$mthd_name(visitor);
688            }
689          }
690        }
691      }
692    }
693
694    impl $host_ty for ast::FunctionParameterDeclarator {
695      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
696      where
697          V: $visitor_ty,
698      {
699        let visit = visitor.visit_function_parameter_declarator(self);
700
701        if visit == Visit::Children {
702          self.ty.$mthd_name(visitor);
703          self.ident.$mthd_name(visitor);
704        }
705      }
706    }
707
708    impl $host_ty for ast::FunctionDefinition {
709      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
710      where
711          V: $visitor_ty,
712      {
713        let visit = visitor.visit_function_definition(self);
714
715        if visit == Visit::Children {
716          self.prototype.$mthd_name(visitor);
717          self.statement.$mthd_name(visitor);
718        }
719      }
720    }
721
722    impl $host_ty for ast::Declaration {
723      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
724      where
725          V: $visitor_ty,
726      {
727        let visit = visitor.visit_declaration(self);
728
729        if visit == Visit::Children {
730          match $($ref)* **self {
731            ast::DeclarationData::FunctionPrototype(fp) => fp.$mthd_name(visitor),
732
733            ast::DeclarationData::InitDeclaratorList(idl) => idl.$mthd_name(visitor),
734
735            ast::DeclarationData::Precision(pq, ty) => {
736              pq.$mthd_name(visitor);
737              ty.$mthd_name(visitor);
738            }
739
740            ast::DeclarationData::Block(block) => block.$mthd_name(visitor),
741
742            ast::DeclarationData::Invariant(ident) => ident.$mthd_name(visitor),
743
744            ast::DeclarationData::TypeOnly(q) => q.$mthd_name(visitor),
745          }
746        }
747      }
748    }
749
750    impl $host_ty for ast::Block {
751      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
752      where
753          V: $visitor_ty,
754      {
755        let visit = visitor.visit_block(self);
756
757        if visit == Visit::Children {
758          self.qualifier.$mthd_name(visitor);
759          self.name.$mthd_name(visitor);
760
761          for field in $($ref)* self.fields {
762            field.$mthd_name(visitor);
763          }
764
765          self.identifier.$mthd_name(visitor);
766        }
767      }
768    }
769
770    impl $host_ty for ast::InitDeclaratorList {
771      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
772      where
773          V: $visitor_ty,
774      {
775        let visit = visitor.visit_init_declarator_list(self);
776
777        if visit == Visit::Children {
778          self.head.$mthd_name(visitor);
779
780          for d in $($ref)* self.tail {
781            d.$mthd_name(visitor);
782          }
783        }
784      }
785    }
786
787    impl $host_ty for ast::SingleDeclaration {
788      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
789      where
790          V: $visitor_ty,
791      {
792        let visit = visitor.visit_single_declaration(self);
793
794        if visit == Visit::Children {
795          self.ty.$mthd_name(visitor);
796          self.name.$mthd_name(visitor);
797          self.array_specifier.$mthd_name(visitor);
798          self.initializer.$mthd_name(visitor);
799        }
800      }
801    }
802
803    impl $host_ty for ast::SingleDeclarationNoType {
804      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
805      where
806          V: $visitor_ty,
807      {
808        let visit = visitor.visit_single_declaration_no_type(self);
809
810        if visit == Visit::Children {
811          self.ident.$mthd_name(visitor);
812          self.initializer.$mthd_name(visitor);
813        }
814      }
815    }
816
817    impl $host_ty for ast::FullySpecifiedType {
818      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
819      where
820          V: $visitor_ty,
821      {
822        let visit = visitor.visit_full_specified_type(self);
823
824        if visit == Visit::Children {
825          self.qualifier.$mthd_name(visitor);
826          self.ty.$mthd_name(visitor);
827        }
828      }
829    }
830
831    impl $host_ty for ast::TypeSpecifier {
832      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
833      where
834          V: $visitor_ty,
835      {
836        let visit = visitor.visit_type_specifier(self);
837
838        if visit == Visit::Children {
839          self.ty.$mthd_name(visitor);
840          self.array_specifier.$mthd_name(visitor);
841        }
842      }
843    }
844
845    impl $host_ty for ast::TypeSpecifierNonArray {
846      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
847      where
848          V: $visitor_ty,
849      {
850        let visit = visitor.visit_type_specifier_non_array(self);
851
852        if visit == Visit::Children {
853          match $($ref)* **self {
854            ast::TypeSpecifierNonArrayData::Struct(ss) => ss.$mthd_name(visitor),
855            ast::TypeSpecifierNonArrayData::TypeName(tn) => tn.$mthd_name(visitor),
856            _ => (),
857          }
858        }
859      }
860    }
861
862    impl $host_ty for ast::TypeQualifier {
863      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
864      where
865          V: $visitor_ty,
866      {
867        let visit = visitor.visit_type_qualifier(self);
868
869        if visit == Visit::Children {
870          for tqs in $($ref)* self.qualifiers {
871            tqs.$mthd_name(visitor);
872          }
873        }
874      }
875    }
876
877    impl $host_ty for ast::TypeQualifierSpec {
878      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
879      where
880          V: $visitor_ty,
881      {
882        let visit = visitor.visit_type_qualifier_spec(self);
883
884        if visit == Visit::Children {
885          match $($ref)* **self {
886            ast::TypeQualifierSpecData::Storage(sq) => sq.$mthd_name(visitor),
887            ast::TypeQualifierSpecData::Layout(lq) => lq.$mthd_name(visitor),
888            ast::TypeQualifierSpecData::Precision(pq) => pq.$mthd_name(visitor),
889            ast::TypeQualifierSpecData::Interpolation(iq) => iq.$mthd_name(visitor),
890            _ => (),
891          }
892        }
893      }
894    }
895
896    impl $host_ty for ast::StorageQualifier {
897      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
898      where
899          V: $visitor_ty,
900      {
901        let visit = visitor.visit_storage_qualifier(self);
902
903        if visit == Visit::Children {
904          if let ast::StorageQualifierData::Subroutine(names) = $($ref)* **self {
905            for name in names {
906              name.$mthd_name(visitor);
907            }
908          }
909        }
910      }
911    }
912
913    impl $host_ty for ast::LayoutQualifier {
914      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
915      where
916          V: $visitor_ty,
917      {
918        let visit = visitor.visit_layout_qualifier(self);
919
920        if visit == Visit::Children {
921          for lqs in $($ref)* self.ids {
922            lqs.$mthd_name(visitor);
923          }
924        }
925      }
926    }
927
928    impl $host_ty for ast::LayoutQualifierSpec {
929      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
930      where
931          V: $visitor_ty,
932      {
933        let visit = visitor.visit_layout_qualifier_spec(self);
934
935        if visit == Visit::Children {
936          if let ast::LayoutQualifierSpecData::Identifier(ident, expr) = $($ref)* **self {
937            ident.$mthd_name(visitor);
938
939            if let Some(e) = expr {
940              e.$mthd_name(visitor);
941            }
942          }
943        }
944      }
945    }
946
947    impl $host_ty for ast::PrecisionQualifier {
948      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
949      where
950          V: $visitor_ty,
951      {
952        let _ = visitor.visit_precision_qualifier(self);
953      }
954    }
955
956    impl $host_ty for ast::InterpolationQualifier {
957      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
958      where
959          V: $visitor_ty,
960      {
961        let _ = visitor.visit_interpolation_qualifier(self);
962      }
963    }
964
965    impl $host_ty for ast::TypeName {
966      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
967      where
968          V: $visitor_ty,
969      {
970        let _ = visitor.visit_type_name(self);
971      }
972    }
973
974    impl $host_ty for ast::Identifier {
975      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
976      where
977          V: $visitor_ty,
978      {
979        let _ = visitor.visit_identifier(self);
980      }
981    }
982
983    impl $host_ty for ast::ArrayedIdentifier {
984      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
985      where
986          V: $visitor_ty,
987      {
988        let visit = visitor.visit_arrayed_identifier(self);
989
990        if visit == Visit::Children {
991          self.ident.$mthd_name(visitor);
992          self.array_spec.$mthd_name(visitor);
993        }
994      }
995    }
996
997    impl $host_ty for ast::Expr {
998      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
999      where
1000          V: $visitor_ty,
1001      {
1002        let visit = visitor.visit_expr(self);
1003
1004        if visit == Visit::Children {
1005          match $($ref)* **self {
1006            ast::ExprData::Variable(ident) => ident.$mthd_name(visitor),
1007
1008            ast::ExprData::Unary(op, e) => {
1009              op.$mthd_name(visitor);
1010              e.$mthd_name(visitor);
1011            }
1012
1013            ast::ExprData::Binary(op, a, b) => {
1014              op.$mthd_name(visitor);
1015              a.$mthd_name(visitor);
1016              b.$mthd_name(visitor);
1017            }
1018
1019            ast::ExprData::Ternary(a, b, c) => {
1020              a.$mthd_name(visitor);
1021              b.$mthd_name(visitor);
1022              c.$mthd_name(visitor);
1023            }
1024
1025            ast::ExprData::Assignment(lhs, op, rhs) => {
1026              lhs.$mthd_name(visitor);
1027              op.$mthd_name(visitor);
1028              rhs.$mthd_name(visitor);
1029            }
1030
1031            ast::ExprData::Bracket(e, arr_spec) => {
1032              e.$mthd_name(visitor);
1033              arr_spec.$mthd_name(visitor);
1034            }
1035
1036            ast::ExprData::FunCall(fi, params) => {
1037              fi.$mthd_name(visitor);
1038
1039              for param in params {
1040                param.$mthd_name(visitor);
1041              }
1042            }
1043
1044            ast::ExprData::Dot(e, i) => {
1045              e.$mthd_name(visitor);
1046              i.$mthd_name(visitor);
1047            }
1048
1049            ast::ExprData::PostInc(e) => e.$mthd_name(visitor),
1050
1051            ast::ExprData::PostDec(e) => e.$mthd_name(visitor),
1052
1053            ast::ExprData::Comma(a, b) => {
1054              a.$mthd_name(visitor);
1055              b.$mthd_name(visitor);
1056            }
1057
1058            _ => (),
1059          }
1060        }
1061      }
1062    }
1063
1064    impl $host_ty for ast::UnaryOp {
1065      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1066      where
1067          V: $visitor_ty,
1068      {
1069        let _ = visitor.visit_unary_op(self);
1070      }
1071    }
1072
1073    impl $host_ty for ast::BinaryOp {
1074      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1075      where
1076          V: $visitor_ty,
1077      {
1078        let _ = visitor.visit_binary_op(self);
1079      }
1080    }
1081
1082    impl $host_ty for ast::AssignmentOp {
1083      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1084      where
1085          V: $visitor_ty,
1086      {
1087        let _ = visitor.visit_assignment_op(self);
1088      }
1089    }
1090
1091    impl $host_ty for ast::ArraySpecifier {
1092      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1093      where
1094          V: $visitor_ty,
1095      {
1096        let visit = visitor.visit_array_specifier(self);
1097
1098        if visit == Visit::Children {
1099          for dimension in $($ref)* self.dimensions {
1100            dimension.$mthd_name(visitor);
1101          }
1102        }
1103      }
1104    }
1105
1106    impl $host_ty for ast::ArraySpecifierDimension {
1107      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1108      where
1109          V: $visitor_ty,
1110      {
1111        let visit = visitor.visit_array_specifier_dimension(self);
1112
1113        if visit == Visit::Children {
1114          if let ast::ArraySpecifierDimensionData::ExplicitlySized(e) = $($ref)* **self {
1115            e.$mthd_name(visitor);
1116          }
1117        }
1118      }
1119    }
1120
1121    impl $host_ty for ast::FunIdentifier {
1122      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1123      where
1124          V: $visitor_ty,
1125      {
1126        let visit = visitor.visit_fun_identifier(self);
1127
1128        if visit == Visit::Children {
1129          match $($ref)* **self {
1130            ast::FunIdentifierData::TypeSpecifier(t) => t.$mthd_name(visitor),
1131            ast::FunIdentifierData::Expr(e) => e.$mthd_name(visitor),
1132          }
1133        }
1134      }
1135    }
1136
1137    impl $host_ty for ast::StructSpecifier {
1138      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1139      where
1140          V: $visitor_ty,
1141      {
1142        let visit = visitor.visit_struct_specifier(self);
1143
1144        if visit == Visit::Children {
1145          self.name.$mthd_name(visitor);
1146
1147          for field in $($ref)* self.fields {
1148            field.$mthd_name(visitor);
1149          }
1150        }
1151      }
1152    }
1153
1154    impl $host_ty for ast::StructFieldSpecifier {
1155      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1156      where
1157          V: $visitor_ty,
1158      {
1159        let visit = visitor.visit_struct_field_specifier(self);
1160
1161        if visit == Visit::Children {
1162          self.qualifier.$mthd_name(visitor);
1163          self.ty.$mthd_name(visitor);
1164
1165          for identifier in $($ref)* self.identifiers {
1166            identifier.$mthd_name(visitor);
1167          }
1168        }
1169      }
1170    }
1171
1172    impl $host_ty for ast::Statement {
1173      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1174      where
1175          V: $visitor_ty,
1176      {
1177        let visit = visitor.visit_statement(self);
1178
1179        if visit == Visit::Children {
1180          match $($ref)* **self {
1181            ast::StatementData::Declaration(d) => d.$mthd_name(visitor),
1182            ast::StatementData::Expression(e) => e.$mthd_name(visitor),
1183            ast::StatementData::Selection(s) => s.$mthd_name(visitor),
1184            ast::StatementData::Switch(s) => s.$mthd_name(visitor),
1185            ast::StatementData::CaseLabel(cl) => cl.$mthd_name(visitor),
1186            ast::StatementData::Iteration(i) => i.$mthd_name(visitor),
1187            ast::StatementData::Jump(j) => j.$mthd_name(visitor),
1188            ast::StatementData::Compound(cs) => cs.$mthd_name(visitor),
1189          }
1190        }
1191      }
1192    }
1193
1194    impl $host_ty for ast::CompoundStatement {
1195      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1196      where
1197          V: $visitor_ty,
1198      {
1199        let visit = visitor.visit_compound_statement(self);
1200
1201        if visit == Visit::Children {
1202          for stmt in $($ref)* self.statement_list {
1203            stmt.$mthd_name(visitor);
1204          }
1205        }
1206      }
1207    }
1208
1209    impl $host_ty for ast::ExprStatement {
1210      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1211      where
1212          V: $visitor_ty,
1213      {
1214        let visit = visitor.visit_expr_statement(self);
1215
1216        if visit == Visit::Children {
1217          self.0.$mthd_name(visitor);
1218        }
1219      }
1220    }
1221
1222    impl $host_ty for ast::SelectionStatement {
1223      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1224      where
1225          V: $visitor_ty,
1226      {
1227        let visit = visitor.visit_selection_statement(self);
1228
1229        if visit == Visit::Children {
1230          self.cond.$mthd_name(visitor);
1231          self.rest.$mthd_name(visitor);
1232        }
1233      }
1234    }
1235
1236    impl $host_ty for ast::SelectionRestStatement {
1237      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1238      where
1239          V: $visitor_ty,
1240      {
1241        let visit = visitor.visit_selection_rest_statement(self);
1242
1243        if visit == Visit::Children {
1244          match $($ref)* **self {
1245            ast::SelectionRestStatementData::Statement(s) => s.$mthd_name(visitor),
1246
1247            ast::SelectionRestStatementData::Else(a, b) => {
1248              a.$mthd_name(visitor);
1249              b.$mthd_name(visitor);
1250            }
1251          }
1252        }
1253      }
1254    }
1255
1256    impl $host_ty for ast::SwitchStatement {
1257      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1258      where
1259          V: $visitor_ty,
1260      {
1261        let visit = visitor.visit_switch_statement(self);
1262
1263        if visit == Visit::Children {
1264          self.head.$mthd_name(visitor);
1265
1266          for s in $($ref)* self.body {
1267            s.$mthd_name(visitor);
1268          }
1269        }
1270      }
1271    }
1272
1273    impl $host_ty for ast::CaseLabel {
1274      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1275      where
1276          V: $visitor_ty,
1277      {
1278        let visit = visitor.visit_case_label(self);
1279
1280        if visit == Visit::Children {
1281          if let ast::CaseLabelData::Case(e) = $($ref)* **self {
1282            e.$mthd_name(visitor);
1283          }
1284        }
1285      }
1286    }
1287
1288    impl $host_ty for ast::IterationStatement {
1289      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1290      where
1291          V: $visitor_ty,
1292      {
1293        let visit = visitor.visit_iteration_statement(self);
1294
1295        if visit == Visit::Children {
1296          match $($ref)* **self {
1297            ast::IterationStatementData::While(c, s) => {
1298              c.$mthd_name(visitor);
1299              s.$mthd_name(visitor);
1300            }
1301
1302            ast::IterationStatementData::DoWhile(s, e) => {
1303              s.$mthd_name(visitor);
1304              e.$mthd_name(visitor);
1305            }
1306
1307            ast::IterationStatementData::For(fis, frs, s) => {
1308              fis.$mthd_name(visitor);
1309              frs.$mthd_name(visitor);
1310              s.$mthd_name(visitor);
1311            }
1312          }
1313        }
1314      }
1315    }
1316
1317    impl $host_ty for ast::ForInitStatement {
1318      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1319      where
1320          V: $visitor_ty,
1321      {
1322        let visit = visitor.visit_for_init_statement(self);
1323
1324        if visit == Visit::Children {
1325          match $($ref)* **self {
1326            ast::ForInitStatementData::Expression(e) => e.$mthd_name(visitor),
1327            ast::ForInitStatementData::Declaration(d) => d.$mthd_name(visitor),
1328          }
1329        }
1330      }
1331    }
1332
1333    impl $host_ty for ast::ForRestStatement {
1334      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1335      where
1336          V: $visitor_ty,
1337      {
1338        let visit = visitor.visit_for_rest_statement(self);
1339
1340        if visit == Visit::Children {
1341          self.condition.$mthd_name(visitor);
1342          self.post_expr.$mthd_name(visitor);
1343        }
1344      }
1345    }
1346
1347    impl $host_ty for ast::JumpStatement {
1348      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1349      where
1350          V: $visitor_ty,
1351      {
1352        let visit = visitor.visit_jump_statement(self);
1353
1354        if visit == Visit::Children {
1355          if let ast::JumpStatementData::Return(r) = $($ref)* **self {
1356            r.$mthd_name(visitor);
1357          }
1358        }
1359      }
1360    }
1361
1362    impl $host_ty for ast::Condition {
1363      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1364      where
1365          V: $visitor_ty,
1366      {
1367        let visit = visitor.visit_condition(self);
1368
1369        if visit == Visit::Children {
1370          match $($ref)* **self {
1371            ast::ConditionData::Expr(e) => e.$mthd_name(visitor),
1372
1373            ast::ConditionData::Assignment(fst, ident, init) => {
1374              fst.$mthd_name(visitor);
1375              ident.$mthd_name(visitor);
1376              init.$mthd_name(visitor);
1377            }
1378          }
1379        }
1380      }
1381    }
1382
1383    impl $host_ty for ast::Initializer {
1384      fn $mthd_name<V>($($ref)* self, visitor: &mut V)
1385      where
1386          V: $visitor_ty,
1387      {
1388        let visit = visitor.visit_initializer(self);
1389
1390        if visit == Visit::Children {
1391          match $($ref)* **self {
1392            ast::InitializerData::Simple(e) => e.$mthd_name(visitor),
1393
1394            ast::InitializerData::List(i) => {
1395              for i in i.$iter() {
1396                i.$mthd_name(visitor);
1397              }
1398            }
1399          }
1400        }
1401      }
1402    }
1403  }
1404}
1405
1406// immutable
1407make_visitor_trait!(Visitor, &);
1408make_host_trait!(Host, Visitor, visit, iter, &);
1409
1410// mutable
1411make_visitor_trait!(VisitorMut, &mut);
1412make_host_trait!(HostMut, VisitorMut, visit_mut, iter_mut, &mut);
1413
1414#[cfg(test)]
1415mod tests {
1416    use lang_util::NodeContent;
1417    use std::iter::FromIterator;
1418
1419    use super::*;
1420
1421    #[test]
1422    #[allow(clippy::approx_constant)]
1423    fn count_variables() {
1424        let decl0 = ast::StatementData::declare_var(
1425            ast::TypeSpecifierNonArrayData::Float,
1426            "x",
1427            None,
1428            Some(ast::ExprData::from(3.14).into_node()),
1429        );
1430
1431        let decl1 =
1432            ast::StatementData::declare_var(ast::TypeSpecifierNonArrayData::Int, "y", None, None);
1433
1434        let decl2 =
1435            ast::StatementData::declare_var(ast::TypeSpecifierNonArrayData::Vec4, "z", None, None);
1436
1437        let compound: ast::CompoundStatement =
1438            ast::CompoundStatementData::from_iter(vec![decl0.into(), decl1.into(), decl2.into()])
1439                .into();
1440
1441        // our visitor that will count the number of variables it saw
1442        struct Counter {
1443            var_nb: usize,
1444        }
1445
1446        impl Visitor for Counter {
1447            // we are only interested in single declaration with a name
1448            fn visit_single_declaration(&mut self, declaration: &ast::SingleDeclaration) -> Visit {
1449                if declaration.name.is_some() {
1450                    self.var_nb += 1;
1451                }
1452
1453                // do not go deeper
1454                Visit::Parent
1455            }
1456        }
1457
1458        let mut counter = Counter { var_nb: 0 };
1459        compound.visit(&mut counter);
1460        assert_eq!(counter.var_nb, 3);
1461    }
1462}