summaryrefslogtreecommitdiffstats
path: root/third_party/rust/glsl/src/visitor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/glsl/src/visitor.rs')
-rw-r--r--third_party/rust/glsl/src/visitor.rs1465
1 files changed, 1465 insertions, 0 deletions
diff --git a/third_party/rust/glsl/src/visitor.rs b/third_party/rust/glsl/src/visitor.rs
new file mode 100644
index 0000000000..5867c72ded
--- /dev/null
+++ b/third_party/rust/glsl/src/visitor.rs
@@ -0,0 +1,1465 @@
+//! AST visitors (i.e. on-the-fly mutation at different places in the AST).
+//!
+//! Visitors are mutable objects that can mutate parts of an AST while traversing it. You can see
+//! them as flexible mutations taking place on *patterns* representing your AST – they get called
+//! everytime an interesting node gets visited. Because of their mutable nature, you can accumulate
+//! a state as you traverse the AST and implement exotic filtering.
+//!
+//! Visitors must implement the [`Visitor`] trait in order to be usable.
+//!
+//! In order to visit any part of an AST (from its very top root or from any part of it), you must
+//! use the [`Host`] interface, that provides the [`Host::visit`] function.
+//!
+//! For instance, we can imagine visiting an AST to count how many variables are declared:
+//!
+//! ```
+//! use glsl::syntax::{CompoundStatement, Expr, SingleDeclaration, Statement, TypeSpecifierNonArray};
+//! use glsl::visitor::{Host, Visit, Visitor};
+//! use std::iter::FromIterator;
+//!
+//! let decl0 = Statement::declare_var(
+//! TypeSpecifierNonArray::Float,
+//! "x",
+//! None,
+//! Some(Expr::from(3.14).into())
+//! );
+//!
+//! let decl1 = Statement::declare_var(
+//! TypeSpecifierNonArray::Int,
+//! "y",
+//! None,
+//! None
+//! );
+//!
+//! let decl2 = Statement::declare_var(
+//! TypeSpecifierNonArray::Vec4,
+//! "z",
+//! None,
+//! None
+//! );
+//!
+//! let compound = CompoundStatement::from_iter(vec![decl0, decl1, decl2]);
+//!
+//! // our visitor that will count the number of variables it saw
+//! struct Counter {
+//! var_nb: usize
+//! }
+//!
+//! impl Visitor for Counter {
+//! // we are only interested in single declaration with a name
+//! fn visit_single_declaration(&mut self, declaration: &SingleDeclaration) -> Visit {
+//! if declaration.name.is_some() {
+//! self.var_nb += 1;
+//! }
+//!
+//! // do not go deeper
+//! Visit::Parent
+//! }
+//! }
+//!
+//! let mut counter = Counter { var_nb: 0 };
+//! compound.visit(&mut counter);
+//! assert_eq!(counter.var_nb, 3);
+//! ```
+//!
+//! [`Host`]: crate::visitor::Host
+//! [`Host::visit`]: crate::visitor::Host::visit
+//! [`Visitor`]: crate::visitor::Visitor
+
+use crate::syntax;
+
+/// Visit strategy after having visited an AST node.
+///
+/// Some AST nodes have *children* – in enum’s variants, in some fields as nested in [`Vec`], etc.
+/// Those nodes can be visited depending on the strategy you chose.
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub enum Visit {
+ /// The visitor will go deeper in the AST by visiting all the children, if any. If no children are
+ /// present or if having children doesn’t make sense for a specific part of the AST, this
+ /// strategy will be ignored.
+ Children,
+ /// The visitor won’t visit children nor siblings and will go up.
+ Parent,
+}
+
+macro_rules! make_visitor_trait {
+ ($t:ident, $($ref:tt)*) => {
+ /// Visitor object, visiting AST nodes.
+ ///
+ /// This trait exists in two flavors, depending on whether you want to mutate the AST or not: [`Visitor`] doesn’t
+ /// allow for mutation while [`VisitorMut`] does.
+ pub trait $t {
+ fn visit_translation_unit(&mut self, _: $($ref)* syntax::TranslationUnit) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_external_declaration(&mut self, _: $($ref)* syntax::ExternalDeclaration) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_identifier(&mut self, _: $($ref)* syntax::Identifier) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_arrayed_identifier(&mut self, _: $($ref)* syntax::ArrayedIdentifier) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_type_name(&mut self, _: $($ref)* syntax::TypeName) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_block(&mut self, _: $($ref)* syntax::Block) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_for_init_statement(&mut self, _: $($ref)* syntax::ForInitStatement) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_for_rest_statement(&mut self, _: $($ref)* syntax::ForRestStatement) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_function_definition(&mut self, _: $($ref)* syntax::FunctionDefinition) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_function_parameter_declarator(
+ &mut self,
+ _: $($ref)* syntax::FunctionParameterDeclarator,
+ ) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_function_prototype(&mut self, _: $($ref)* syntax::FunctionPrototype) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_init_declarator_list(&mut self, _: $($ref)* syntax::InitDeclaratorList) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_layout_qualifier(&mut self, _: $($ref)* syntax::LayoutQualifier) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_preprocessor(&mut self, _: $($ref)* syntax::Preprocessor) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_preprocessor_define(&mut self, _: $($ref)* syntax::PreprocessorDefine) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_preprocessor_elseif(&mut self, _: $($ref)* syntax::PreprocessorElseIf) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_preprocessor_error(&mut self, _: $($ref)* syntax::PreprocessorError) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_preprocessor_extension(&mut self, _: $($ref)* syntax::PreprocessorExtension) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_preprocessor_extension_behavior(
+ &mut self,
+ _: $($ref)* syntax::PreprocessorExtensionBehavior,
+ ) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_preprocessor_extension_name(
+ &mut self,
+ _: $($ref)* syntax::PreprocessorExtensionName,
+ ) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_preprocessor_if(&mut self, _: $($ref)* syntax::PreprocessorIf) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_preprocessor_ifdef(&mut self, _: $($ref)* syntax::PreprocessorIfDef) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_preprocessor_ifndef(&mut self, _: $($ref)* syntax::PreprocessorIfNDef) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_preprocessor_include(&mut self, _: $($ref)* syntax::PreprocessorInclude) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_preprocessor_line(&mut self, _: $($ref)* syntax::PreprocessorLine) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_preprocessor_pragma(&mut self, _: $($ref)* syntax::PreprocessorPragma) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_preprocessor_undef(&mut self, _: $($ref)* syntax::PreprocessorUndef) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_preprocessor_version(&mut self, _: $($ref)* syntax::PreprocessorVersion) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_preprocessor_version_profile(
+ &mut self,
+ _: $($ref)* syntax::PreprocessorVersionProfile,
+ ) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_selection_statement(&mut self, _: $($ref)* syntax::SelectionStatement) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_selection_rest_statement(&mut self, _: $($ref)* syntax::SelectionRestStatement) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_single_declaration(&mut self, _: $($ref)* syntax::SingleDeclaration) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_single_declaration_no_type(&mut self, _: $($ref)* syntax::SingleDeclarationNoType) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_struct_field_specifier(&mut self, _: $($ref)* syntax::StructFieldSpecifier) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_struct_specifier(&mut self, _: $($ref)* syntax::StructSpecifier) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_switch_statement(&mut self, _: $($ref)* syntax::SwitchStatement) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_type_qualifier(&mut self, _: $($ref)* syntax::TypeQualifier) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_type_specifier(&mut self, _: $($ref)* syntax::TypeSpecifier) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_full_specified_type(&mut self, _: $($ref)* syntax::FullySpecifiedType) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_array_specifier(&mut self, _: $($ref)* syntax::ArraySpecifier) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_array_specifier_dimension(&mut self, _: $($ref)* syntax::ArraySpecifierDimension) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_assignment_op(&mut self, _: $($ref)* syntax::AssignmentOp) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_binary_op(&mut self, _: $($ref)* syntax::BinaryOp) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_case_label(&mut self, _: $($ref)* syntax::CaseLabel) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_condition(&mut self, _: $($ref)* syntax::Condition) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_declaration(&mut self, _: $($ref)* syntax::Declaration) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_expr(&mut self, _: $($ref)* syntax::Expr) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_fun_identifier(&mut self, _: $($ref)* syntax::FunIdentifier) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_function_parameter_declaration(
+ &mut self,
+ _: $($ref)* syntax::FunctionParameterDeclaration,
+ ) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_initializer(&mut self, _: $($ref)* syntax::Initializer) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_interpolation_qualifier(&mut self, _: $($ref)* syntax::InterpolationQualifier) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_iteration_statement(&mut self, _: $($ref)* syntax::IterationStatement) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_jump_statement(&mut self, _: $($ref)* syntax::JumpStatement) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_layout_qualifier_spec(&mut self, _: $($ref)* syntax::LayoutQualifierSpec) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_precision_qualifier(&mut self, _: $($ref)* syntax::PrecisionQualifier) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_statement(&mut self, _: $($ref)* syntax::Statement) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_compound_statement(&mut self, _: $($ref)* syntax::CompoundStatement) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_simple_statement(&mut self, _: $($ref)* syntax::SimpleStatement) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_storage_qualifier(&mut self, _: $($ref)* syntax::StorageQualifier) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_type_qualifier_spec(&mut self, _: $($ref)* syntax::TypeQualifierSpec) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_type_specifier_non_array(&mut self, _: $($ref)* syntax::TypeSpecifierNonArray) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_unary_op(&mut self, _: $($ref)* syntax::UnaryOp) -> Visit {
+ Visit::Children
+ }
+
+ fn visit_expr_statement(&mut self, _: $($ref)* syntax::ExprStatement) -> Visit {
+ Visit::Children
+ }
+ }
+ }
+}
+
+macro_rules! make_host_trait {
+ ($host_ty:ident, $visitor_ty:ident, $mthd_name:ident, $($ref:tt)*) => {
+ /// Part of the AST that can be visited.
+ ///
+ /// You shouldn’t have to worry about this type nor how to implement it – it’s completely
+ /// implemented for you. However, it works in a pretty simple way: any implementor of the host trait can
+ /// be used with a visitor.
+ ///
+ /// The idea is that visiting an AST node is a two-step process:
+ ///
+ /// - First, you *can* get your visitor called once as soon as an interesting node gets visited.
+ /// For instance, if your visitor has an implementation for visiting expressions, everytime an
+ /// expression gets visited, your visitor will run.
+ /// - If your implementation of visiting an AST node returns [`Visit::Children`] and if the given
+ /// node has children, the visitor will go deeper, invoking other calls if you have defined any.
+ /// A typical pattern you might want to do is to implement your visitor to gets run on all
+ /// typenames. Since expressions contains variables, you will get your visitor called once again
+ /// there.
+ /// - Notice that since visitors are mutable, you can accumulate a state as you go deeper in the
+ /// AST to implement various checks and validations.
+ ///
+ /// Note that this trait exists in two versions: an immutable one, [`Host`], which doesn’t allow you to mutate the
+ /// AST (but takes a `&`), and a mutable one, [`HostMut`], which allows for AST mutation.
+ pub trait $host_ty {
+ /// Visit an AST node.
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty;
+ }
+
+ impl<T> $host_ty for Option<T>
+ where
+ T: $host_ty,
+ {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ if let Some(x) = self {
+ x.$mthd_name(visitor);
+ }
+ }
+ }
+
+ impl<T> $host_ty for Box<T>
+ where
+ T: $host_ty,
+ {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ (**self).$mthd_name(visitor);
+ }
+ }
+
+ impl $host_ty for syntax::TranslationUnit {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_translation_unit(self);
+
+ if visit == Visit::Children {
+ for ed in $($ref)* (self.0).0 {
+ ed.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::ExternalDeclaration {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_external_declaration(self);
+
+ if visit == Visit::Children {
+ match self {
+ syntax::ExternalDeclaration::Preprocessor(p) => p.$mthd_name(visitor),
+ syntax::ExternalDeclaration::FunctionDefinition(fd) => fd.$mthd_name(visitor),
+ syntax::ExternalDeclaration::Declaration(d) => d.$mthd_name(visitor),
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::Preprocessor {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_preprocessor(self);
+
+ if visit == Visit::Children {
+ match self {
+ syntax::Preprocessor::Define(pd) => pd.$mthd_name(visitor),
+ syntax::Preprocessor::Else => (),
+ syntax::Preprocessor::ElseIf(pei) => pei.$mthd_name(visitor),
+ syntax::Preprocessor::EndIf => (),
+ syntax::Preprocessor::Error(pe) => pe.$mthd_name(visitor),
+ syntax::Preprocessor::If(pi) => pi.$mthd_name(visitor),
+ syntax::Preprocessor::IfDef(pid) => pid.$mthd_name(visitor),
+ syntax::Preprocessor::IfNDef(pind) => pind.$mthd_name(visitor),
+ syntax::Preprocessor::Include(pi) => pi.$mthd_name(visitor),
+ syntax::Preprocessor::Line(pl) => pl.$mthd_name(visitor),
+ syntax::Preprocessor::Pragma(pp) => pp.$mthd_name(visitor),
+ syntax::Preprocessor::Undef(pu) => pu.$mthd_name(visitor),
+ syntax::Preprocessor::Version(pv) => pv.$mthd_name(visitor),
+ syntax::Preprocessor::Extension(ext) => ext.$mthd_name(visitor),
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::PreprocessorDefine {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_preprocessor_define(self);
+
+ if visit == Visit::Children {
+ match self {
+ syntax::PreprocessorDefine::ObjectLike { ident, .. } => {
+ ident.$mthd_name(visitor);
+ }
+
+ syntax::PreprocessorDefine::FunctionLike {
+ ident,
+ args,
+ ..
+ } => {
+ ident.$mthd_name(visitor);
+
+ for arg in args {
+ arg.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::PreprocessorElseIf {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let _ = visitor.visit_preprocessor_elseif(self);
+ }
+ }
+
+ impl $host_ty for syntax::PreprocessorError {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let _ = visitor.visit_preprocessor_error(self);
+ }
+ }
+
+ impl $host_ty for syntax::PreprocessorIf {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let _ = visitor.visit_preprocessor_if(self);
+ }
+ }
+
+ impl $host_ty for syntax::PreprocessorIfDef {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_preprocessor_ifdef(self);
+
+ if visit == Visit::Children {
+ self.ident.$mthd_name(visitor);
+ }
+ }
+ }
+
+ impl $host_ty for syntax::PreprocessorIfNDef {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_preprocessor_ifndef(self);
+
+ if visit == Visit::Children {
+ self.ident.$mthd_name(visitor);
+ }
+ }
+ }
+
+ impl $host_ty for syntax::PreprocessorInclude {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let _ = visitor.visit_preprocessor_include(self);
+ }
+ }
+
+ impl $host_ty for syntax::PreprocessorLine {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let _ = visitor.visit_preprocessor_line(self);
+ }
+ }
+
+ impl $host_ty for syntax::PreprocessorPragma {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let _ = visitor.visit_preprocessor_pragma(self);
+ }
+ }
+
+ impl $host_ty for syntax::PreprocessorUndef {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_preprocessor_undef(self);
+
+ if visit == Visit::Children {
+ self.name.$mthd_name(visitor);
+ }
+ }
+ }
+
+ impl $host_ty for syntax::PreprocessorVersion {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_preprocessor_version(self);
+
+ if visit == Visit::Children {
+ self.profile.$mthd_name(visitor);
+ }
+ }
+ }
+
+ impl $host_ty for syntax::PreprocessorVersionProfile {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let _ = visitor.visit_preprocessor_version_profile(self);
+ }
+ }
+
+ impl $host_ty for syntax::PreprocessorExtension {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_preprocessor_extension(self);
+
+ if visit == Visit::Children {
+ self.name.$mthd_name(visitor);
+ self.behavior.$mthd_name(visitor);
+ }
+ }
+ }
+
+ impl $host_ty for syntax::PreprocessorExtensionBehavior {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let _ = visitor.visit_preprocessor_extension_behavior(self);
+ }
+ }
+
+ impl $host_ty for syntax::PreprocessorExtensionName {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let _ = visitor.visit_preprocessor_extension_name(self);
+ }
+ }
+
+ impl $host_ty for syntax::FunctionPrototype {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_function_prototype(self);
+
+ if visit == Visit::Children {
+ self.ty.$mthd_name(visitor);
+ self.name.$mthd_name(visitor);
+
+ for param in $($ref)* self.parameters {
+ param.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::FunctionParameterDeclaration {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_function_parameter_declaration(self);
+
+ if visit == Visit::Children {
+ match self {
+ syntax::FunctionParameterDeclaration::Named(tq, fpd) => {
+ tq.$mthd_name(visitor);
+ fpd.$mthd_name(visitor);
+ }
+
+ syntax::FunctionParameterDeclaration::Unnamed(tq, ty) => {
+ tq.$mthd_name(visitor);
+ ty.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::FunctionParameterDeclarator {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_function_parameter_declarator(self);
+
+ if visit == Visit::Children {
+ self.ty.$mthd_name(visitor);
+ self.ident.$mthd_name(visitor);
+ }
+ }
+ }
+
+ impl $host_ty for syntax::FunctionDefinition {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_function_definition(self);
+
+ if visit == Visit::Children {
+ self.prototype.$mthd_name(visitor);
+ self.statement.$mthd_name(visitor);
+ }
+ }
+ }
+
+ impl $host_ty for syntax::Declaration {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_declaration(self);
+
+ if visit == Visit::Children {
+ match self {
+ syntax::Declaration::FunctionPrototype(fp) => fp.$mthd_name(visitor),
+
+ syntax::Declaration::InitDeclaratorList(idl) => idl.$mthd_name(visitor),
+
+ syntax::Declaration::Precision(pq, ty) => {
+ pq.$mthd_name(visitor);
+ ty.$mthd_name(visitor);
+ }
+
+ syntax::Declaration::Block(block) => block.$mthd_name(visitor),
+
+ syntax::Declaration::Global(tq, idents) => {
+ tq.$mthd_name(visitor);
+
+ for ident in idents {
+ ident.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::Block {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_block(self);
+
+ if visit == Visit::Children {
+ self.qualifier.$mthd_name(visitor);
+ self.name.$mthd_name(visitor);
+
+ for field in $($ref)* self.fields {
+ field.$mthd_name(visitor);
+ }
+
+ self.identifier.$mthd_name(visitor);
+ }
+ }
+ }
+
+ impl $host_ty for syntax::InitDeclaratorList {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_init_declarator_list(self);
+
+ if visit == Visit::Children {
+ self.head.$mthd_name(visitor);
+
+ for d in $($ref)* self.tail {
+ d.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::SingleDeclaration {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_single_declaration(self);
+
+ if visit == Visit::Children {
+ self.ty.$mthd_name(visitor);
+ self.name.$mthd_name(visitor);
+ self.array_specifier.$mthd_name(visitor);
+ self.initializer.$mthd_name(visitor);
+ }
+ }
+ }
+
+ impl $host_ty for syntax::SingleDeclarationNoType {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_single_declaration_no_type(self);
+
+ if visit == Visit::Children {
+ self.ident.$mthd_name(visitor);
+ self.initializer.$mthd_name(visitor);
+ }
+ }
+ }
+
+ impl $host_ty for syntax::FullySpecifiedType {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_full_specified_type(self);
+
+ if visit == Visit::Children {
+ self.qualifier.$mthd_name(visitor);
+ self.ty.$mthd_name(visitor);
+ }
+ }
+ }
+
+ impl $host_ty for syntax::TypeSpecifier {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_type_specifier(self);
+
+ if visit == Visit::Children {
+ self.ty.$mthd_name(visitor);
+ self.array_specifier.$mthd_name(visitor);
+ }
+ }
+ }
+
+ impl $host_ty for syntax::TypeSpecifierNonArray {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_type_specifier_non_array(self);
+
+ if visit == Visit::Children {
+ match self {
+ syntax::TypeSpecifierNonArray::Struct(ss) => ss.$mthd_name(visitor),
+ syntax::TypeSpecifierNonArray::TypeName(tn) => tn.$mthd_name(visitor),
+ _ => (),
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::TypeQualifier {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_type_qualifier(self);
+
+ if visit == Visit::Children {
+ for tqs in $($ref)* self.qualifiers.0 {
+ tqs.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::TypeQualifierSpec {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_type_qualifier_spec(self);
+
+ if visit == Visit::Children {
+ match self {
+ syntax::TypeQualifierSpec::Storage(sq) => sq.$mthd_name(visitor),
+ syntax::TypeQualifierSpec::Layout(lq) => lq.$mthd_name(visitor),
+ syntax::TypeQualifierSpec::Precision(pq) => pq.$mthd_name(visitor),
+ syntax::TypeQualifierSpec::Interpolation(iq) => iq.$mthd_name(visitor),
+ _ => (),
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::StorageQualifier {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_storage_qualifier(self);
+
+ if visit == Visit::Children {
+ if let syntax::StorageQualifier::Subroutine(names) = self {
+ for name in names {
+ name.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::LayoutQualifier {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_layout_qualifier(self);
+
+ if visit == Visit::Children {
+ for lqs in $($ref)* self.ids.0 {
+ lqs.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::LayoutQualifierSpec {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_layout_qualifier_spec(self);
+
+ if visit == Visit::Children {
+ if let syntax::LayoutQualifierSpec::Identifier(ident, expr) = self {
+ ident.$mthd_name(visitor);
+
+ if let Some(e) = expr {
+ e.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::PrecisionQualifier {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let _ = visitor.visit_precision_qualifier(self);
+ }
+ }
+
+ impl $host_ty for syntax::InterpolationQualifier {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let _ = visitor.visit_interpolation_qualifier(self);
+ }
+ }
+
+ impl $host_ty for syntax::TypeName {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let _ = visitor.visit_type_name(self);
+ }
+ }
+
+ impl $host_ty for syntax::Identifier {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let _ = visitor.visit_identifier(self);
+ }
+ }
+
+ impl $host_ty for syntax::ArrayedIdentifier {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_arrayed_identifier(self);
+
+ if visit == Visit::Children {
+ self.ident.$mthd_name(visitor);
+ self.array_spec.$mthd_name(visitor);
+ }
+ }
+ }
+
+ impl $host_ty for syntax::Expr {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_expr(self);
+
+ if visit == Visit::Children {
+ match self {
+ syntax::Expr::Variable(ident) => ident.$mthd_name(visitor),
+
+ syntax::Expr::Unary(op, e) => {
+ op.$mthd_name(visitor);
+ e.$mthd_name(visitor);
+ }
+
+ syntax::Expr::Binary(op, a, b) => {
+ op.$mthd_name(visitor);
+ a.$mthd_name(visitor);
+ b.$mthd_name(visitor);
+ }
+
+ syntax::Expr::Ternary(a, b, c) => {
+ a.$mthd_name(visitor);
+ b.$mthd_name(visitor);
+ c.$mthd_name(visitor);
+ }
+
+ syntax::Expr::Assignment(lhs, op, rhs) => {
+ lhs.$mthd_name(visitor);
+ op.$mthd_name(visitor);
+ rhs.$mthd_name(visitor);
+ }
+
+ syntax::Expr::Bracket(e, arr_spec) => {
+ e.$mthd_name(visitor);
+ arr_spec.$mthd_name(visitor);
+ }
+
+ syntax::Expr::FunCall(fi, params) => {
+ fi.$mthd_name(visitor);
+
+ for param in params {
+ param.$mthd_name(visitor);
+ }
+ }
+
+ syntax::Expr::Dot(e, i) => {
+ e.$mthd_name(visitor);
+ i.$mthd_name(visitor);
+ }
+
+ syntax::Expr::PostInc(e) => e.$mthd_name(visitor),
+
+ syntax::Expr::PostDec(e) => e.$mthd_name(visitor),
+
+ syntax::Expr::Comma(a, b) => {
+ a.$mthd_name(visitor);
+ b.$mthd_name(visitor);
+ }
+
+ _ => (),
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::UnaryOp {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let _ = visitor.visit_unary_op(self);
+ }
+ }
+
+ impl $host_ty for syntax::BinaryOp {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let _ = visitor.visit_binary_op(self);
+ }
+ }
+
+ impl $host_ty for syntax::AssignmentOp {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let _ = visitor.visit_assignment_op(self);
+ }
+ }
+
+ impl $host_ty for syntax::ArraySpecifier {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_array_specifier(self);
+
+ if visit == Visit::Children {
+ for dimension in $($ref)* self.dimensions {
+ dimension.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::ArraySpecifierDimension {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_array_specifier_dimension(self);
+
+ if visit == Visit::Children {
+ if let syntax::ArraySpecifierDimension::ExplicitlySized(e) = self {
+ e.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::FunIdentifier {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_fun_identifier(self);
+
+ if visit == Visit::Children {
+ match self {
+ syntax::FunIdentifier::Identifier(i) => i.$mthd_name(visitor),
+ syntax::FunIdentifier::Expr(e) => e.$mthd_name(visitor),
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::StructSpecifier {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_struct_specifier(self);
+
+ if visit == Visit::Children {
+ self.name.$mthd_name(visitor);
+
+ for field in $($ref)* self.fields.0 {
+ field.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::StructFieldSpecifier {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_struct_field_specifier(self);
+
+ if visit == Visit::Children {
+ self.qualifier.$mthd_name(visitor);
+ self.ty.$mthd_name(visitor);
+
+ for identifier in $($ref)* self.identifiers.0 {
+ identifier.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::Statement {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_statement(self);
+
+ if visit == Visit::Children {
+ match self {
+ syntax::Statement::Compound(cs) => cs.$mthd_name(visitor),
+ syntax::Statement::Simple(ss) => ss.$mthd_name(visitor),
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::SimpleStatement {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_simple_statement(self);
+
+ if visit == Visit::Children {
+ match self {
+ syntax::SimpleStatement::Declaration(d) => d.$mthd_name(visitor),
+ syntax::SimpleStatement::Expression(e) => e.$mthd_name(visitor),
+ syntax::SimpleStatement::Selection(s) => s.$mthd_name(visitor),
+ syntax::SimpleStatement::Switch(s) => s.$mthd_name(visitor),
+ syntax::SimpleStatement::CaseLabel(cl) => cl.$mthd_name(visitor),
+ syntax::SimpleStatement::Iteration(i) => i.$mthd_name(visitor),
+ syntax::SimpleStatement::Jump(j) => j.$mthd_name(visitor),
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::CompoundStatement {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_compound_statement(self);
+
+ if visit == Visit::Children {
+ for stmt in $($ref)* self.statement_list {
+ stmt.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::SelectionStatement {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_selection_statement(self);
+
+ if visit == Visit::Children {
+ self.cond.$mthd_name(visitor);
+ self.rest.$mthd_name(visitor);
+ }
+ }
+ }
+
+ impl $host_ty for syntax::SelectionRestStatement {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_selection_rest_statement(self);
+
+ if visit == Visit::Children {
+ match self {
+ syntax::SelectionRestStatement::Statement(s) => s.$mthd_name(visitor),
+
+ syntax::SelectionRestStatement::Else(a, b) => {
+ a.$mthd_name(visitor);
+ b.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::SwitchStatement {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_switch_statement(self);
+
+ if visit == Visit::Children {
+ self.head.$mthd_name(visitor);
+
+ for s in $($ref)* self.body {
+ s.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::CaseLabel {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_case_label(self);
+
+ if visit == Visit::Children {
+ if let syntax::CaseLabel::Case(e) = self {
+ e.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::IterationStatement {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_iteration_statement(self);
+
+ if visit == Visit::Children {
+ match self {
+ syntax::IterationStatement::While(c, s) => {
+ c.$mthd_name(visitor);
+ s.$mthd_name(visitor);
+ }
+
+ syntax::IterationStatement::DoWhile(s, e) => {
+ s.$mthd_name(visitor);
+ e.$mthd_name(visitor);
+ }
+
+ syntax::IterationStatement::For(fis, frs, s) => {
+ fis.$mthd_name(visitor);
+ frs.$mthd_name(visitor);
+ s.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::ForInitStatement {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_for_init_statement(self);
+
+ if visit == Visit::Children {
+ match self {
+ syntax::ForInitStatement::Expression(e) => e.$mthd_name(visitor),
+ syntax::ForInitStatement::Declaration(d) => d.$mthd_name(visitor),
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::ForRestStatement {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_for_rest_statement(self);
+
+ if visit == Visit::Children {
+ self.condition.$mthd_name(visitor);
+ self.post_expr.$mthd_name(visitor);
+ }
+ }
+ }
+
+ impl $host_ty for syntax::JumpStatement {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_jump_statement(self);
+
+ if visit == Visit::Children {
+ if let syntax::JumpStatement::Return(r) = self {
+ r.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::Condition {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_condition(self);
+
+ if visit == Visit::Children {
+ match self {
+ syntax::Condition::Expr(e) => e.$mthd_name(visitor),
+
+ syntax::Condition::Assignment(fst, ident, init) => {
+ fst.$mthd_name(visitor);
+ ident.$mthd_name(visitor);
+ init.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+ }
+
+ impl $host_ty for syntax::Initializer {
+ fn $mthd_name<V>($($ref)* self, visitor: &mut V)
+ where
+ V: $visitor_ty,
+ {
+ let visit = visitor.visit_initializer(self);
+
+ if visit == Visit::Children {
+ match self {
+ syntax::Initializer::Simple(e) => e.$mthd_name(visitor),
+
+ syntax::Initializer::List(i) => {
+ for i in $($ref)* i.0 {
+ i.$mthd_name(visitor);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+// immutable
+make_visitor_trait!(Visitor, &);
+make_host_trait!(Host, Visitor, visit, &);
+
+// mutable
+make_visitor_trait!(VisitorMut, &mut);
+make_host_trait!(HostMut, VisitorMut, visit_mut, &mut);
+
+#[cfg(test)]
+mod tests {
+ use std::iter::FromIterator;
+
+ use super::*;
+ use syntax;
+
+ #[test]
+ fn count_variables() {
+ let decl0 = syntax::Statement::declare_var(
+ syntax::TypeSpecifierNonArray::Float,
+ "x",
+ None,
+ Some(syntax::Expr::from(3.14).into()),
+ );
+
+ let decl1 = syntax::Statement::declare_var(syntax::TypeSpecifierNonArray::Int, "y", None, None);
+
+ let decl2 =
+ syntax::Statement::declare_var(syntax::TypeSpecifierNonArray::Vec4, "z", None, None);
+
+ let compound = syntax::CompoundStatement::from_iter(vec![decl0, decl1, decl2]);
+
+ // our visitor that will count the number of variables it saw
+ struct Counter {
+ var_nb: usize,
+ }
+
+ impl Visitor for Counter {
+ // we are only interested in single declaration with a name
+ fn visit_single_declaration(&mut self, declaration: &syntax::SingleDeclaration) -> Visit {
+ if declaration.name.is_some() {
+ self.var_nb += 1;
+ }
+
+ // do not go deeper
+ Visit::Parent
+ }
+ }
+
+ let mut counter = Counter { var_nb: 0 };
+ compound.visit(&mut counter);
+ assert_eq!(counter.var_nb, 3);
+ }
+}