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