Flatten private codegen modules
diff --git a/codegen/src/fold.rs b/codegen/src/fold.rs
index adcde21..fabe598 100644
--- a/codegen/src/fold.rs
+++ b/codegen/src/fold.rs
@@ -1,280 +1,259 @@
 use crate::{file, full, gen};
-use quote::quote;
+use inflections::Inflect;
+use proc_macro2::{Span, TokenStream};
+use quote::{quote, TokenStreamExt};
+use syn::*;
 use syn_codegen as types;
 
 const FOLD_SRC: &str = "../src/gen/fold.rs";
 
-mod codegen {
-    use crate::gen;
-    use inflections::Inflect;
-    use proc_macro2::{Span, TokenStream};
-    use quote::{quote, TokenStreamExt};
-    use syn::*;
-    use syn_codegen as types;
+#[derive(Default)]
+struct State {
+    fold_trait: TokenStream,
+    fold_impl: TokenStream,
+}
 
-    #[derive(Default)]
-    pub struct State {
-        pub fold_trait: TokenStream,
-        pub fold_impl: TokenStream,
+fn under_name(name: &str) -> Ident {
+    Ident::new(&name.to_snake_case(), Span::call_site())
+}
+
+fn simple_visit(item: &str, name: &TokenStream) -> TokenStream {
+    let ident = under_name(item);
+
+    let method = Ident::new(&format!("fold_{}", ident), Span::call_site());
+    quote! {
+        _visitor.#method(#name)
+    }
+}
+
+fn box_visit(
+    elem: &types::Type,
+    features: &types::Features,
+    defs: &types::Definitions,
+    name: &TokenStream,
+) -> Option<TokenStream> {
+    let res = visit(elem, features, defs, &quote!(*#name))?;
+    Some(quote! {
+        Box::new(#res)
+    })
+}
+
+fn vec_visit(
+    elem: &types::Type,
+    features: &types::Features,
+    defs: &types::Definitions,
+    name: &TokenStream,
+) -> Option<TokenStream> {
+    let operand = quote!(it);
+    let val = visit(elem, features, defs, &operand)?;
+    Some(quote! {
+        FoldHelper::lift(#name, |it| { #val })
+    })
+}
+
+fn punctuated_visit(
+    elem: &types::Type,
+    features: &types::Features,
+    defs: &types::Definitions,
+    name: &TokenStream,
+) -> Option<TokenStream> {
+    let operand = quote!(it);
+    let val = visit(elem, features, defs, &operand)?;
+    Some(quote! {
+        FoldHelper::lift(#name, |it| { #val })
+    })
+}
+
+fn option_visit(
+    elem: &types::Type,
+    features: &types::Features,
+    defs: &types::Definitions,
+    name: &TokenStream,
+) -> Option<TokenStream> {
+    let it = quote!(it);
+    let val = visit(elem, features, defs, &it)?;
+    Some(quote! {
+        (#name).map(|it| { #val })
+    })
+}
+
+fn tuple_visit(
+    elems: &[types::Type],
+    features: &types::Features,
+    defs: &types::Definitions,
+    name: &TokenStream,
+) -> Option<TokenStream> {
+    if elems.is_empty() {
+        return None;
     }
 
-    fn under_name(name: &str) -> Ident {
-        Ident::new(&name.to_snake_case(), Span::call_site())
+    let mut code = TokenStream::new();
+    for (i, elem) in elems.iter().enumerate() {
+        let i = Index::from(i);
+        let it = quote!((#name).#i);
+        let val = visit(elem, features, defs, &it).unwrap_or(it);
+        code.append_all(val);
+        code.append_all(quote!(,));
     }
+    Some(quote! {
+        (#code)
+    })
+}
 
-    fn simple_visit(item: &str, name: &TokenStream) -> TokenStream {
-        let ident = under_name(item);
+fn token_punct_visit(repr: &str, name: &TokenStream) -> TokenStream {
+    let ty: TokenStream = syn::parse_str(&format!("Token![{}]", repr)).unwrap();
+    quote! {
+        #ty(tokens_helper(_visitor, &#name.spans))
+    }
+}
 
-        let method = Ident::new(&format!("fold_{}", ident), Span::call_site());
-        quote! {
-            _visitor.#method(#name)
+fn token_keyword_visit(repr: &str, name: &TokenStream) -> TokenStream {
+    let ty: TokenStream = syn::parse_str(&format!("Token![{}]", repr)).unwrap();
+    quote! {
+        #ty(tokens_helper(_visitor, &#name.span))
+    }
+}
+
+fn token_group_visit(ty: &str, name: &TokenStream) -> TokenStream {
+    let ty = Ident::new(ty, Span::call_site());
+    quote! {
+        #ty(tokens_helper(_visitor, &#name.span))
+    }
+}
+
+fn visit(
+    ty: &types::Type,
+    features: &types::Features,
+    defs: &types::Definitions,
+    name: &TokenStream,
+) -> Option<TokenStream> {
+    match ty {
+        types::Type::Box(t) => box_visit(&*t, features, defs, name),
+        types::Type::Vec(t) => vec_visit(&*t, features, defs, name),
+        types::Type::Punctuated(p) => punctuated_visit(&p.element, features, defs, name),
+        types::Type::Option(t) => option_visit(&*t, features, defs, name),
+        types::Type::Tuple(t) => tuple_visit(t, features, defs, name),
+        types::Type::Token(t) => {
+            let repr = &defs.tokens[t];
+            let is_keyword = repr.chars().next().unwrap().is_alphabetic();
+            if is_keyword {
+                Some(token_keyword_visit(repr, name))
+            } else {
+                Some(token_punct_visit(repr, name))
+            }
         }
-    }
+        types::Type::Group(t) => Some(token_group_visit(&t[..], name)),
+        types::Type::Syn(t) => {
+            fn requires_full(features: &types::Features) -> bool {
+                features.any.contains("full") && features.any.len() == 1
+            }
 
-    fn box_visit(
-        elem: &types::Type,
-        features: &types::Features,
-        defs: &types::Definitions,
-        name: &TokenStream,
-    ) -> Option<TokenStream> {
-        let res = visit(elem, features, defs, &quote!(*#name))?;
-        Some(quote! {
-            Box::new(#res)
-        })
-    }
+            let res = simple_visit(t, name);
 
-    fn vec_visit(
-        elem: &types::Type,
-        features: &types::Features,
-        defs: &types::Definitions,
-        name: &TokenStream,
-    ) -> Option<TokenStream> {
-        let operand = quote!(it);
-        let val = visit(elem, features, defs, &operand)?;
-        Some(quote! {
-            FoldHelper::lift(#name, |it| { #val })
-        })
-    }
+            let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap();
 
-    fn punctuated_visit(
-        elem: &types::Type,
-        features: &types::Features,
-        defs: &types::Definitions,
-        name: &TokenStream,
-    ) -> Option<TokenStream> {
-        let operand = quote!(it);
-        let val = visit(elem, features, defs, &operand)?;
-        Some(quote! {
-            FoldHelper::lift(#name, |it| { #val })
-        })
-    }
-
-    fn option_visit(
-        elem: &types::Type,
-        features: &types::Features,
-        defs: &types::Definitions,
-        name: &TokenStream,
-    ) -> Option<TokenStream> {
-        let it = quote!(it);
-        let val = visit(elem, features, defs, &it)?;
-        Some(quote! {
-            (#name).map(|it| { #val })
-        })
-    }
-
-    fn tuple_visit(
-        elems: &[types::Type],
-        features: &types::Features,
-        defs: &types::Definitions,
-        name: &TokenStream,
-    ) -> Option<TokenStream> {
-        if elems.is_empty() {
-            return None;
-        }
-
-        let mut code = TokenStream::new();
-        for (i, elem) in elems.iter().enumerate() {
-            let i = Index::from(i);
-            let it = quote!((#name).#i);
-            let val = visit(elem, features, defs, &it).unwrap_or(it);
-            code.append_all(val);
-            code.append_all(quote!(,));
-        }
-        Some(quote! {
-            (#code)
-        })
-    }
-
-    fn token_punct_visit(repr: &str, name: &TokenStream) -> TokenStream {
-        let ty: TokenStream = syn::parse_str(&format!("Token![{}]", repr)).unwrap();
-        quote! {
-            #ty(tokens_helper(_visitor, &#name.spans))
-        }
-    }
-
-    fn token_keyword_visit(repr: &str, name: &TokenStream) -> TokenStream {
-        let ty: TokenStream = syn::parse_str(&format!("Token![{}]", repr)).unwrap();
-        quote! {
-            #ty(tokens_helper(_visitor, &#name.span))
-        }
-    }
-
-    fn token_group_visit(ty: &str, name: &TokenStream) -> TokenStream {
-        let ty = Ident::new(ty, Span::call_site());
-        quote! {
-            #ty(tokens_helper(_visitor, &#name.span))
-        }
-    }
-
-    fn visit(
-        ty: &types::Type,
-        features: &types::Features,
-        defs: &types::Definitions,
-        name: &TokenStream,
-    ) -> Option<TokenStream> {
-        match ty {
-            types::Type::Box(t) => box_visit(&*t, features, defs, name),
-            types::Type::Vec(t) => vec_visit(&*t, features, defs, name),
-            types::Type::Punctuated(p) => punctuated_visit(&p.element, features, defs, name),
-            types::Type::Option(t) => option_visit(&*t, features, defs, name),
-            types::Type::Tuple(t) => tuple_visit(t, features, defs, name),
-            types::Type::Token(t) => {
-                let repr = &defs.tokens[t];
-                let is_keyword = repr.chars().next().unwrap().is_alphabetic();
-                if is_keyword {
-                    Some(token_keyword_visit(repr, name))
+            Some(
+                if requires_full(&target.features) && !requires_full(features) {
+                    quote! {
+                        full!(#res)
+                    }
                 } else {
-                    Some(token_punct_visit(repr, name))
-                }
-            }
-            types::Type::Group(t) => Some(token_group_visit(&t[..], name)),
-            types::Type::Syn(t) => {
-                fn requires_full(features: &types::Features) -> bool {
-                    features.any.contains("full") && features.any.len() == 1
-                }
-
-                let res = simple_visit(t, name);
-
-                let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap();
-
-                Some(
-                    if requires_full(&target.features) && !requires_full(features) {
-                        quote! {
-                            full!(#res)
-                        }
-                    } else {
-                        res
-                    },
-                )
-            }
-            types::Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => {
-                Some(simple_visit(t, name))
-            }
-            types::Type::Ext(_) | types::Type::Std(_) => None,
+                    res
+                },
+            )
         }
+        types::Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => Some(simple_visit(t, name)),
+        types::Type::Ext(_) | types::Type::Std(_) => None,
     }
+}
 
-    fn visit_features(features: &types::Features) -> TokenStream {
-        let features = &features.any;
-        match features.len() {
-            0 => quote!(),
-            1 => quote!(#[cfg(feature = #(#features)*)]),
-            _ => quote!(#[cfg(any(#(feature = #features),*))]),
-        }
+fn visit_features(features: &types::Features) -> TokenStream {
+    let features = &features.any;
+    match features.len() {
+        0 => quote!(),
+        1 => quote!(#[cfg(feature = #(#features)*)]),
+        _ => quote!(#[cfg(any(#(feature = #features),*))]),
     }
+}
 
-    pub fn generate(state: &mut State, s: &types::Node, defs: &types::Definitions) {
-        let features = visit_features(&s.features);
-        let under_name = under_name(&s.ident);
-        let ty = Ident::new(&s.ident, Span::call_site());
-        let fold_fn = Ident::new(&format!("fold_{}", under_name), Span::call_site());
+fn node(state: &mut State, s: &types::Node, defs: &types::Definitions) {
+    let features = visit_features(&s.features);
+    let under_name = under_name(&s.ident);
+    let ty = Ident::new(&s.ident, Span::call_site());
+    let fold_fn = Ident::new(&format!("fold_{}", under_name), Span::call_site());
 
-        let mut fold_impl = TokenStream::new();
+    let mut fold_impl = TokenStream::new();
 
-        match &s.data {
-            types::Data::Enum(variants) => {
-                let mut fold_variants = TokenStream::new();
+    match &s.data {
+        types::Data::Enum(variants) => {
+            let mut fold_variants = TokenStream::new();
 
-                for (variant, fields) in variants {
-                    let variant_ident = Ident::new(variant, Span::call_site());
+            for (variant, fields) in variants {
+                let variant_ident = Ident::new(variant, Span::call_site());
 
-                    if fields.is_empty() {
-                        fold_variants.append_all(quote! {
-                            #ty::#variant_ident => {
-                                #ty::#variant_ident
-                            }
-                        });
-                    } else {
-                        let mut bind_fold_fields = TokenStream::new();
-                        let mut fold_fields = TokenStream::new();
-
-                        for (idx, ty) in fields.iter().enumerate() {
-                            let name = format!("_binding_{}", idx);
-                            let binding = Ident::new(&name, Span::call_site());
-
-                            bind_fold_fields.append_all(quote! {
-                                #binding,
-                            });
-
-                            let owned_binding = quote!(#binding);
-
-                            fold_fields.append_all(
-                                visit(ty, &s.features, defs, &owned_binding)
-                                    .unwrap_or(owned_binding),
-                            );
-
-                            fold_fields.append_all(quote!(,));
+                if fields.is_empty() {
+                    fold_variants.append_all(quote! {
+                        #ty::#variant_ident => {
+                            #ty::#variant_ident
                         }
+                    });
+                } else {
+                    let mut bind_fold_fields = TokenStream::new();
+                    let mut fold_fields = TokenStream::new();
 
-                        fold_variants.append_all(quote! {
-                            #ty::#variant_ident(#bind_fold_fields) => {
-                                #ty::#variant_ident(
-                                    #fold_fields
-                                )
-                            }
+                    for (idx, ty) in fields.iter().enumerate() {
+                        let name = format!("_binding_{}", idx);
+                        let binding = Ident::new(&name, Span::call_site());
+
+                        bind_fold_fields.append_all(quote! {
+                            #binding,
                         });
-                    }
-                }
 
-                fold_impl.append_all(quote! {
-                    match _i {
-                        #fold_variants
+                        let owned_binding = quote!(#binding);
+
+                        fold_fields.append_all(
+                            visit(ty, &s.features, defs, &owned_binding).unwrap_or(owned_binding),
+                        );
+
+                        fold_fields.append_all(quote!(,));
                     }
+
+                    fold_variants.append_all(quote! {
+                        #ty::#variant_ident(#bind_fold_fields) => {
+                            #ty::#variant_ident(
+                                #fold_fields
+                            )
+                        }
+                    });
+                }
+            }
+
+            fold_impl.append_all(quote! {
+                match _i {
+                    #fold_variants
+                }
+            });
+        }
+        types::Data::Struct(fields) => {
+            let mut fold_fields = TokenStream::new();
+
+            for (field, ty) in fields {
+                let id = Ident::new(&field, Span::call_site());
+                let ref_toks = quote!(_i.#id);
+                let fold = visit(&ty, &s.features, defs, &ref_toks).unwrap_or(ref_toks);
+
+                fold_fields.append_all(quote! {
+                    #id: #fold,
                 });
             }
-            types::Data::Struct(fields) => {
-                let mut fold_fields = TokenStream::new();
 
-                for (field, ty) in fields {
-                    let id = Ident::new(&field, Span::call_site());
-                    let ref_toks = quote!(_i.#id);
-                    let fold = visit(&ty, &s.features, defs, &ref_toks).unwrap_or(ref_toks);
-
-                    fold_fields.append_all(quote! {
-                        #id: #fold,
-                    });
-                }
-
-                if !fields.is_empty() {
-                    fold_impl.append_all(quote! {
-                        #ty {
-                            #fold_fields
-                        }
-                    })
-                } else {
-                    if ty == "Ident" {
-                        fold_impl.append_all(quote! {
-                            let mut _i = _i;
-                            let span = _visitor.fold_span(_i.span());
-                            _i.set_span(span);
-                        });
+            if !fields.is_empty() {
+                fold_impl.append_all(quote! {
+                    #ty {
+                        #fold_fields
                     }
-                    fold_impl.append_all(quote! {
-                        _i
-                    });
-                }
-            }
-            types::Data::Private => {
+                })
+            } else {
                 if ty == "Ident" {
                     fold_impl.append_all(quote! {
                         let mut _i = _i;
@@ -287,34 +266,46 @@
                 });
             }
         }
-
-        let include_fold_impl = match &s.data {
-            types::Data::Private => gen::TERMINAL_TYPES.contains(&s.ident.as_str()),
-            types::Data::Struct(_) | types::Data::Enum(_) => true,
-        };
-
-        state.fold_trait.append_all(quote! {
-            #features
-            fn #fold_fn(&mut self, i: #ty) -> #ty {
-                #fold_fn(self, i)
+        types::Data::Private => {
+            if ty == "Ident" {
+                fold_impl.append_all(quote! {
+                    let mut _i = _i;
+                    let span = _visitor.fold_span(_i.span());
+                    _i.set_span(span);
+                });
             }
-        });
-
-        if include_fold_impl {
-            state.fold_impl.append_all(quote! {
-                #features
-                pub fn #fold_fn<V: Fold + ?Sized>(
-                    _visitor: &mut V, _i: #ty
-                ) -> #ty {
-                    #fold_impl
-                }
+            fold_impl.append_all(quote! {
+                _i
             });
         }
     }
+
+    let include_fold_impl = match &s.data {
+        types::Data::Private => gen::TERMINAL_TYPES.contains(&s.ident.as_str()),
+        types::Data::Struct(_) | types::Data::Enum(_) => true,
+    };
+
+    state.fold_trait.append_all(quote! {
+        #features
+        fn #fold_fn(&mut self, i: #ty) -> #ty {
+            #fold_fn(self, i)
+        }
+    });
+
+    if include_fold_impl {
+        state.fold_impl.append_all(quote! {
+            #features
+            pub fn #fold_fn<V: Fold + ?Sized>(
+                _visitor: &mut V, _i: #ty
+            ) -> #ty {
+                #fold_impl
+            }
+        });
+    }
 }
 
 pub fn generate(defs: &types::Definitions) {
-    let state = gen::traverse(defs, codegen::generate);
+    let state = gen::traverse(defs, node);
     let full_macro = full::get_macro();
     let fold_trait = state.fold_trait;
     let fold_impl = state.fold_impl;
diff --git a/codegen/src/gen.rs b/codegen/src/gen.rs
index c0bd4d1..30cee0d 100644
--- a/codegen/src/gen.rs
+++ b/codegen/src/gen.rs
@@ -2,14 +2,14 @@
 
 pub const TERMINAL_TYPES: &[&str] = &["Span", "Ident"];
 
-pub fn traverse<S, F>(defs: &types::Definitions, generate: F) -> S
+pub fn traverse<S, F>(defs: &types::Definitions, node: F) -> S
 where
     S: Default,
     F: Fn(&mut S, &types::Node, &types::Definitions),
 {
     let mut state = S::default();
     for s in &defs.types {
-        generate(&mut state, s, defs);
+        node(&mut state, s, defs);
     }
     for tt in TERMINAL_TYPES {
         let s = types::Node {
@@ -17,7 +17,7 @@
             features: types::Features::default(),
             data: types::Data::Private,
         };
-        generate(&mut state, &s, defs);
+        node(&mut state, &s, defs);
     }
     state
 }
diff --git a/codegen/src/visit.rs b/codegen/src/visit.rs
index 4679c9f..24c7f76 100644
--- a/codegen/src/visit.rs
+++ b/codegen/src/visit.rs
@@ -1,321 +1,313 @@
 use crate::{file, full, gen};
-use quote::quote;
+use inflections::Inflect;
+use proc_macro2::{Span, TokenStream};
+use quote::{quote, TokenStreamExt};
+use syn::*;
 use syn_codegen as types;
 
 const VISIT_SRC: &str = "../src/gen/visit.rs";
 
-mod codegen {
-    use crate::gen;
-    use inflections::Inflect;
-    use proc_macro2::{Span, TokenStream};
-    use quote::{quote, TokenStreamExt};
-    use syn::*;
-    use syn_codegen as types;
+#[derive(Default)]
+struct State {
+    visit_trait: TokenStream,
+    visit_impl: TokenStream,
+}
 
-    #[derive(Default)]
-    pub struct State {
-        pub visit_trait: TokenStream,
-        pub visit_impl: TokenStream,
-    }
+fn under_name(name: &str) -> Ident {
+    Ident::new(&name.to_snake_case(), Span::call_site())
+}
 
-    fn under_name(name: &str) -> Ident {
-        Ident::new(&name.to_snake_case(), Span::call_site())
-    }
+enum Operand {
+    Borrowed(TokenStream),
+    Owned(TokenStream),
+}
 
-    enum Operand {
-        Borrowed(TokenStream),
-        Owned(TokenStream),
-    }
+use self::Operand::*;
 
-    use self::Operand::*;
-
-    impl Operand {
-        fn tokens(&self) -> &TokenStream {
-            match *self {
-                Borrowed(ref n) | Owned(ref n) => n,
-            }
-        }
-
-        fn ref_tokens(&self) -> TokenStream {
-            match *self {
-                Borrowed(ref n) => n.clone(),
-                Owned(ref n) => quote!(&#n),
-            }
-        }
-
-        fn owned_tokens(&self) -> TokenStream {
-            match *self {
-                Borrowed(ref n) => quote!(*#n),
-                Owned(ref n) => n.clone(),
-            }
+impl Operand {
+    fn tokens(&self) -> &TokenStream {
+        match *self {
+            Borrowed(ref n) | Owned(ref n) => n,
         }
     }
 
-    fn simple_visit(item: &str, name: &Operand) -> TokenStream {
-        let ident = under_name(item);
-        let method = Ident::new(&format!("visit_{}", ident), Span::call_site());
-        let name = name.ref_tokens();
-        quote! {
-            _visitor.#method(#name)
+    fn ref_tokens(&self) -> TokenStream {
+        match *self {
+            Borrowed(ref n) => n.clone(),
+            Owned(ref n) => quote!(&#n),
         }
     }
 
-    fn box_visit(
-        elem: &types::Type,
-        features: &types::Features,
-        defs: &types::Definitions,
-        name: &Operand,
-    ) -> Option<TokenStream> {
-        let name = name.owned_tokens();
-        let res = visit(elem, features, defs, &Owned(quote!(*#name)))?;
-        Some(res)
-    }
-
-    fn vec_visit(
-        elem: &types::Type,
-        features: &types::Features,
-        defs: &types::Definitions,
-        name: &Operand,
-    ) -> Option<TokenStream> {
-        let operand = Borrowed(quote!(it));
-        let val = visit(elem, features, defs, &operand)?;
-        let name = name.ref_tokens();
-        Some(quote! {
-            for it in #name {
-                #val
-            }
-        })
-    }
-
-    fn punctuated_visit(
-        elem: &types::Type,
-        features: &types::Features,
-        defs: &types::Definitions,
-        name: &Operand,
-    ) -> Option<TokenStream> {
-        let operand = Borrowed(quote!(it));
-        let val = visit(elem, features, defs, &operand)?;
-        let name = name.ref_tokens();
-        Some(quote! {
-            for el in Punctuated::pairs(#name) {
-                let it = el.value();
-                #val
-            }
-        })
-    }
-
-    fn option_visit(
-        elem: &types::Type,
-        features: &types::Features,
-        defs: &types::Definitions,
-        name: &Operand,
-    ) -> Option<TokenStream> {
-        let it = Borrowed(quote!(it));
-        let val = visit(elem, features, defs, &it)?;
-        let name = name.owned_tokens();
-        Some(quote! {
-            if let Some(ref it) = #name {
-                #val
-            }
-        })
-    }
-
-    fn tuple_visit(
-        elems: &[types::Type],
-        features: &types::Features,
-        defs: &types::Definitions,
-        name: &Operand,
-    ) -> Option<TokenStream> {
-        if elems.is_empty() {
-            return None;
+    fn owned_tokens(&self) -> TokenStream {
+        match *self {
+            Borrowed(ref n) => quote!(*#n),
+            Owned(ref n) => n.clone(),
         }
-
-        let mut code = TokenStream::new();
-        for (i, elem) in elems.iter().enumerate() {
-            let name = name.tokens();
-            let i = Index::from(i);
-            let it = Owned(quote!((#name).#i));
-            let val = visit(elem, features, defs, &it).unwrap_or_else(|| noop_visit(&it));
-            code.append_all(val);
-            code.append_all(quote!(;));
-        }
-        Some(code)
-    }
-
-    fn token_punct_visit(name: &Operand) -> TokenStream {
-        let name = name.tokens();
-        quote! {
-            tokens_helper(_visitor, &#name.spans)
-        }
-    }
-
-    fn token_keyword_visit(name: &Operand) -> TokenStream {
-        let name = name.tokens();
-        quote! {
-            tokens_helper(_visitor, &#name.span)
-        }
-    }
-
-    fn token_group_visit(name: &Operand) -> TokenStream {
-        let name = name.tokens();
-        quote! {
-            tokens_helper(_visitor, &#name.span)
-        }
-    }
-
-    fn noop_visit(name: &Operand) -> TokenStream {
-        let name = name.tokens();
-        quote! {
-            skip!(#name)
-        }
-    }
-
-    fn visit(
-        ty: &types::Type,
-        features: &types::Features,
-        defs: &types::Definitions,
-        name: &Operand,
-    ) -> Option<TokenStream> {
-        match ty {
-            types::Type::Box(t) => box_visit(&*t, features, defs, name),
-            types::Type::Vec(t) => vec_visit(&*t, features, defs, name),
-            types::Type::Punctuated(p) => punctuated_visit(&p.element, features, defs, name),
-            types::Type::Option(t) => option_visit(&*t, features, defs, name),
-            types::Type::Tuple(t) => tuple_visit(t, features, defs, name),
-            types::Type::Token(t) => {
-                let repr = &defs.tokens[t];
-                let is_keyword = repr.chars().next().unwrap().is_alphabetic();
-                if is_keyword {
-                    Some(token_keyword_visit(name))
-                } else {
-                    Some(token_punct_visit(name))
-                }
-            }
-            types::Type::Group(_) => Some(token_group_visit(name)),
-            types::Type::Syn(t) => {
-                fn requires_full(features: &types::Features) -> bool {
-                    features.any.contains("full") && features.any.len() == 1
-                }
-
-                let res = simple_visit(t, name);
-
-                let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap();
-
-                Some(
-                    if requires_full(&target.features) && !requires_full(features) {
-                        quote! {
-                            full!(#res)
-                        }
-                    } else {
-                        res
-                    },
-                )
-            }
-            types::Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => {
-                Some(simple_visit(t, name))
-            }
-            types::Type::Ext(_) | types::Type::Std(_) => None,
-        }
-    }
-
-    fn visit_features(features: &types::Features) -> TokenStream {
-        let features = &features.any;
-        match features.len() {
-            0 => quote!(),
-            1 => quote!(#[cfg(feature = #(#features)*)]),
-            _ => quote!(#[cfg(any(#(feature = #features),*))]),
-        }
-    }
-
-    pub fn generate(state: &mut State, s: &types::Node, defs: &types::Definitions) {
-        let features = visit_features(&s.features);
-        let under_name = under_name(&s.ident);
-        let ty = Ident::new(&s.ident, Span::call_site());
-        let visit_fn = Ident::new(&format!("visit_{}", under_name), Span::call_site());
-
-        let mut visit_impl = TokenStream::new();
-
-        match &s.data {
-            types::Data::Enum(variants) => {
-                let mut visit_variants = TokenStream::new();
-
-                for (variant, fields) in variants {
-                    let variant_ident = Ident::new(variant, Span::call_site());
-
-                    if fields.is_empty() {
-                        visit_variants.append_all(quote! {
-                            #ty::#variant_ident => {}
-                        });
-                    } else {
-                        let mut bind_visit_fields = TokenStream::new();
-                        let mut visit_fields = TokenStream::new();
-
-                        for (idx, ty) in fields.iter().enumerate() {
-                            let name = format!("_binding_{}", idx);
-                            let binding = Ident::new(&name, Span::call_site());
-
-                            bind_visit_fields.append_all(quote! {
-                                ref #binding,
-                            });
-
-                            let borrowed_binding = Borrowed(quote!(#binding));
-
-                            visit_fields.append_all(
-                                visit(ty, &s.features, defs, &borrowed_binding)
-                                    .unwrap_or_else(|| noop_visit(&borrowed_binding)),
-                            );
-
-                            visit_fields.append_all(quote!(;));
-                        }
-
-                        visit_variants.append_all(quote! {
-                            #ty::#variant_ident(#bind_visit_fields) => {
-                                #visit_fields
-                            }
-                        });
-                    }
-                }
-
-                visit_impl.append_all(quote! {
-                    match *_i {
-                        #visit_variants
-                    }
-                });
-            }
-            types::Data::Struct(fields) => {
-                for (field, ty) in fields {
-                    let id = Ident::new(&field, Span::call_site());
-                    let ref_toks = Owned(quote!(_i.#id));
-                    let visit_field = visit(&ty, &s.features, defs, &ref_toks)
-                        .unwrap_or_else(|| noop_visit(&ref_toks));
-                    visit_impl.append_all(quote! {
-                        #visit_field;
-                    });
-                }
-            }
-            types::Data::Private => {}
-        }
-
-        state.visit_trait.append_all(quote! {
-            #features
-            fn #visit_fn(&mut self, i: &'ast #ty) {
-                #visit_fn(self, i)
-            }
-        });
-
-        state.visit_impl.append_all(quote! {
-            #features
-            pub fn #visit_fn<'ast, V: Visit<'ast> + ?Sized>(
-                _visitor: &mut V, _i: &'ast #ty
-            ) {
-                #visit_impl
-            }
-        });
     }
 }
 
+fn simple_visit(item: &str, name: &Operand) -> TokenStream {
+    let ident = under_name(item);
+    let method = Ident::new(&format!("visit_{}", ident), Span::call_site());
+    let name = name.ref_tokens();
+    quote! {
+        _visitor.#method(#name)
+    }
+}
+
+fn box_visit(
+    elem: &types::Type,
+    features: &types::Features,
+    defs: &types::Definitions,
+    name: &Operand,
+) -> Option<TokenStream> {
+    let name = name.owned_tokens();
+    let res = visit(elem, features, defs, &Owned(quote!(*#name)))?;
+    Some(res)
+}
+
+fn vec_visit(
+    elem: &types::Type,
+    features: &types::Features,
+    defs: &types::Definitions,
+    name: &Operand,
+) -> Option<TokenStream> {
+    let operand = Borrowed(quote!(it));
+    let val = visit(elem, features, defs, &operand)?;
+    let name = name.ref_tokens();
+    Some(quote! {
+        for it in #name {
+            #val
+        }
+    })
+}
+
+fn punctuated_visit(
+    elem: &types::Type,
+    features: &types::Features,
+    defs: &types::Definitions,
+    name: &Operand,
+) -> Option<TokenStream> {
+    let operand = Borrowed(quote!(it));
+    let val = visit(elem, features, defs, &operand)?;
+    let name = name.ref_tokens();
+    Some(quote! {
+        for el in Punctuated::pairs(#name) {
+            let it = el.value();
+            #val
+        }
+    })
+}
+
+fn option_visit(
+    elem: &types::Type,
+    features: &types::Features,
+    defs: &types::Definitions,
+    name: &Operand,
+) -> Option<TokenStream> {
+    let it = Borrowed(quote!(it));
+    let val = visit(elem, features, defs, &it)?;
+    let name = name.owned_tokens();
+    Some(quote! {
+        if let Some(ref it) = #name {
+            #val
+        }
+    })
+}
+
+fn tuple_visit(
+    elems: &[types::Type],
+    features: &types::Features,
+    defs: &types::Definitions,
+    name: &Operand,
+) -> Option<TokenStream> {
+    if elems.is_empty() {
+        return None;
+    }
+
+    let mut code = TokenStream::new();
+    for (i, elem) in elems.iter().enumerate() {
+        let name = name.tokens();
+        let i = Index::from(i);
+        let it = Owned(quote!((#name).#i));
+        let val = visit(elem, features, defs, &it).unwrap_or_else(|| noop_visit(&it));
+        code.append_all(val);
+        code.append_all(quote!(;));
+    }
+    Some(code)
+}
+
+fn token_punct_visit(name: &Operand) -> TokenStream {
+    let name = name.tokens();
+    quote! {
+        tokens_helper(_visitor, &#name.spans)
+    }
+}
+
+fn token_keyword_visit(name: &Operand) -> TokenStream {
+    let name = name.tokens();
+    quote! {
+        tokens_helper(_visitor, &#name.span)
+    }
+}
+
+fn token_group_visit(name: &Operand) -> TokenStream {
+    let name = name.tokens();
+    quote! {
+        tokens_helper(_visitor, &#name.span)
+    }
+}
+
+fn noop_visit(name: &Operand) -> TokenStream {
+    let name = name.tokens();
+    quote! {
+        skip!(#name)
+    }
+}
+
+fn visit(
+    ty: &types::Type,
+    features: &types::Features,
+    defs: &types::Definitions,
+    name: &Operand,
+) -> Option<TokenStream> {
+    match ty {
+        types::Type::Box(t) => box_visit(&*t, features, defs, name),
+        types::Type::Vec(t) => vec_visit(&*t, features, defs, name),
+        types::Type::Punctuated(p) => punctuated_visit(&p.element, features, defs, name),
+        types::Type::Option(t) => option_visit(&*t, features, defs, name),
+        types::Type::Tuple(t) => tuple_visit(t, features, defs, name),
+        types::Type::Token(t) => {
+            let repr = &defs.tokens[t];
+            let is_keyword = repr.chars().next().unwrap().is_alphabetic();
+            if is_keyword {
+                Some(token_keyword_visit(name))
+            } else {
+                Some(token_punct_visit(name))
+            }
+        }
+        types::Type::Group(_) => Some(token_group_visit(name)),
+        types::Type::Syn(t) => {
+            fn requires_full(features: &types::Features) -> bool {
+                features.any.contains("full") && features.any.len() == 1
+            }
+
+            let res = simple_visit(t, name);
+
+            let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap();
+
+            Some(
+                if requires_full(&target.features) && !requires_full(features) {
+                    quote! {
+                        full!(#res)
+                    }
+                } else {
+                    res
+                },
+            )
+        }
+        types::Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => Some(simple_visit(t, name)),
+        types::Type::Ext(_) | types::Type::Std(_) => None,
+    }
+}
+
+fn visit_features(features: &types::Features) -> TokenStream {
+    let features = &features.any;
+    match features.len() {
+        0 => quote!(),
+        1 => quote!(#[cfg(feature = #(#features)*)]),
+        _ => quote!(#[cfg(any(#(feature = #features),*))]),
+    }
+}
+
+fn node(state: &mut State, s: &types::Node, defs: &types::Definitions) {
+    let features = visit_features(&s.features);
+    let under_name = under_name(&s.ident);
+    let ty = Ident::new(&s.ident, Span::call_site());
+    let visit_fn = Ident::new(&format!("visit_{}", under_name), Span::call_site());
+
+    let mut visit_impl = TokenStream::new();
+
+    match &s.data {
+        types::Data::Enum(variants) => {
+            let mut visit_variants = TokenStream::new();
+
+            for (variant, fields) in variants {
+                let variant_ident = Ident::new(variant, Span::call_site());
+
+                if fields.is_empty() {
+                    visit_variants.append_all(quote! {
+                        #ty::#variant_ident => {}
+                    });
+                } else {
+                    let mut bind_visit_fields = TokenStream::new();
+                    let mut visit_fields = TokenStream::new();
+
+                    for (idx, ty) in fields.iter().enumerate() {
+                        let name = format!("_binding_{}", idx);
+                        let binding = Ident::new(&name, Span::call_site());
+
+                        bind_visit_fields.append_all(quote! {
+                            ref #binding,
+                        });
+
+                        let borrowed_binding = Borrowed(quote!(#binding));
+
+                        visit_fields.append_all(
+                            visit(ty, &s.features, defs, &borrowed_binding)
+                                .unwrap_or_else(|| noop_visit(&borrowed_binding)),
+                        );
+
+                        visit_fields.append_all(quote!(;));
+                    }
+
+                    visit_variants.append_all(quote! {
+                        #ty::#variant_ident(#bind_visit_fields) => {
+                            #visit_fields
+                        }
+                    });
+                }
+            }
+
+            visit_impl.append_all(quote! {
+                match *_i {
+                    #visit_variants
+                }
+            });
+        }
+        types::Data::Struct(fields) => {
+            for (field, ty) in fields {
+                let id = Ident::new(&field, Span::call_site());
+                let ref_toks = Owned(quote!(_i.#id));
+                let visit_field = visit(&ty, &s.features, defs, &ref_toks)
+                    .unwrap_or_else(|| noop_visit(&ref_toks));
+                visit_impl.append_all(quote! {
+                    #visit_field;
+                });
+            }
+        }
+        types::Data::Private => {}
+    }
+
+    state.visit_trait.append_all(quote! {
+        #features
+        fn #visit_fn(&mut self, i: &'ast #ty) {
+            #visit_fn(self, i)
+        }
+    });
+
+    state.visit_impl.append_all(quote! {
+        #features
+        pub fn #visit_fn<'ast, V: Visit<'ast> + ?Sized>(
+            _visitor: &mut V, _i: &'ast #ty
+        ) {
+            #visit_impl
+        }
+    });
+}
+
 pub fn generate(defs: &types::Definitions) {
-    let state = gen::traverse(defs, codegen::generate);
+    let state = gen::traverse(defs, node);
     let full_macro = full::get_macro();
     let visit_trait = state.visit_trait;
     let visit_impl = state.visit_impl;
diff --git a/codegen/src/visit_mut.rs b/codegen/src/visit_mut.rs
index f32d1c9..3388665 100644
--- a/codegen/src/visit_mut.rs
+++ b/codegen/src/visit_mut.rs
@@ -1,321 +1,313 @@
 use crate::{file, full, gen};
-use quote::quote;
+use inflections::Inflect;
+use proc_macro2::{Span, TokenStream};
+use quote::{quote, TokenStreamExt};
+use syn::*;
 use syn_codegen as types;
 
 const VISIT_MUT_SRC: &str = "../src/gen/visit_mut.rs";
 
-mod codegen {
-    use crate::gen;
-    use inflections::Inflect;
-    use proc_macro2::{Span, TokenStream};
-    use quote::{quote, TokenStreamExt};
-    use syn::*;
-    use syn_codegen as types;
+#[derive(Default)]
+struct State {
+    visit_mut_trait: TokenStream,
+    visit_mut_impl: TokenStream,
+}
 
-    #[derive(Default)]
-    pub struct State {
-        pub visit_mut_trait: TokenStream,
-        pub visit_mut_impl: TokenStream,
-    }
+fn under_name(name: &str) -> Ident {
+    Ident::new(&name.to_snake_case(), Span::call_site())
+}
 
-    fn under_name(name: &str) -> Ident {
-        Ident::new(&name.to_snake_case(), Span::call_site())
-    }
+enum Operand {
+    Borrowed(TokenStream),
+    Owned(TokenStream),
+}
 
-    enum Operand {
-        Borrowed(TokenStream),
-        Owned(TokenStream),
-    }
+use self::Operand::*;
 
-    use self::Operand::*;
-
-    impl Operand {
-        fn tokens(&self) -> &TokenStream {
-            match *self {
-                Borrowed(ref n) | Owned(ref n) => n,
-            }
-        }
-
-        fn ref_mut_tokens(&self) -> TokenStream {
-            match *self {
-                Borrowed(ref n) => n.clone(),
-                Owned(ref n) => quote!(&mut #n),
-            }
-        }
-
-        fn owned_tokens(&self) -> TokenStream {
-            match *self {
-                Borrowed(ref n) => quote!(*#n),
-                Owned(ref n) => n.clone(),
-            }
+impl Operand {
+    fn tokens(&self) -> &TokenStream {
+        match *self {
+            Borrowed(ref n) | Owned(ref n) => n,
         }
     }
 
-    fn simple_visit(item: &str, name: &Operand) -> TokenStream {
-        let ident = under_name(item);
-        let method = Ident::new(&format!("visit_{}_mut", ident), Span::call_site());
-        let name = name.ref_mut_tokens();
-        quote! {
-            _visitor.#method(#name)
+    fn ref_mut_tokens(&self) -> TokenStream {
+        match *self {
+            Borrowed(ref n) => n.clone(),
+            Owned(ref n) => quote!(&mut #n),
         }
     }
 
-    fn box_visit(
-        elem: &types::Type,
-        features: &types::Features,
-        defs: &types::Definitions,
-        name: &Operand,
-    ) -> Option<TokenStream> {
-        let name = name.owned_tokens();
-        let res = visit(elem, features, defs, &Owned(quote!(*#name)))?;
-        Some(res)
-    }
-
-    fn vec_visit(
-        elem: &types::Type,
-        features: &types::Features,
-        defs: &types::Definitions,
-        name: &Operand,
-    ) -> Option<TokenStream> {
-        let operand = Borrowed(quote!(it));
-        let val = visit(elem, features, defs, &operand)?;
-        let name = name.ref_mut_tokens();
-        Some(quote! {
-            for it in #name {
-                #val
-            }
-        })
-    }
-
-    fn punctuated_visit(
-        elem: &types::Type,
-        features: &types::Features,
-        defs: &types::Definitions,
-        name: &Operand,
-    ) -> Option<TokenStream> {
-        let operand = Borrowed(quote!(it));
-        let val = visit(elem, features, defs, &operand)?;
-        let name = name.ref_mut_tokens();
-        Some(quote! {
-            for mut el in Punctuated::pairs_mut(#name) {
-                let it = el.value_mut();
-                #val
-            }
-        })
-    }
-
-    fn option_visit(
-        elem: &types::Type,
-        features: &types::Features,
-        defs: &types::Definitions,
-        name: &Operand,
-    ) -> Option<TokenStream> {
-        let it = Borrowed(quote!(it));
-        let val = visit(elem, features, defs, &it)?;
-        let name = name.owned_tokens();
-        Some(quote! {
-            if let Some(ref mut it) = #name {
-                #val
-            }
-        })
-    }
-
-    fn tuple_visit(
-        elems: &[types::Type],
-        features: &types::Features,
-        defs: &types::Definitions,
-        name: &Operand,
-    ) -> Option<TokenStream> {
-        if elems.is_empty() {
-            return None;
+    fn owned_tokens(&self) -> TokenStream {
+        match *self {
+            Borrowed(ref n) => quote!(*#n),
+            Owned(ref n) => n.clone(),
         }
-
-        let mut code = TokenStream::new();
-        for (i, elem) in elems.iter().enumerate() {
-            let name = name.tokens();
-            let i = Index::from(i);
-            let it = Owned(quote!((#name).#i));
-            let val = visit(elem, features, defs, &it).unwrap_or_else(|| noop_visit(&it));
-            code.append_all(val);
-            code.append_all(quote!(;));
-        }
-        Some(code)
-    }
-
-    fn token_punct_visit(name: &Operand) -> TokenStream {
-        let name = name.tokens();
-        quote! {
-            tokens_helper(_visitor, &mut #name.spans)
-        }
-    }
-
-    fn token_keyword_visit(name: &Operand) -> TokenStream {
-        let name = name.tokens();
-        quote! {
-            tokens_helper(_visitor, &mut #name.span)
-        }
-    }
-
-    fn token_group_visit(name: &Operand) -> TokenStream {
-        let name = name.tokens();
-        quote! {
-            tokens_helper(_visitor, &mut #name.span)
-        }
-    }
-
-    fn noop_visit(name: &Operand) -> TokenStream {
-        let name = name.tokens();
-        quote! {
-            skip!(#name)
-        }
-    }
-
-    fn visit(
-        ty: &types::Type,
-        features: &types::Features,
-        defs: &types::Definitions,
-        name: &Operand,
-    ) -> Option<TokenStream> {
-        match ty {
-            types::Type::Box(t) => box_visit(&*t, features, defs, name),
-            types::Type::Vec(t) => vec_visit(&*t, features, defs, name),
-            types::Type::Punctuated(p) => punctuated_visit(&p.element, features, defs, name),
-            types::Type::Option(t) => option_visit(&*t, features, defs, name),
-            types::Type::Tuple(t) => tuple_visit(t, features, defs, name),
-            types::Type::Token(t) => {
-                let repr = &defs.tokens[t];
-                let is_keyword = repr.chars().next().unwrap().is_alphabetic();
-                if is_keyword {
-                    Some(token_keyword_visit(name))
-                } else {
-                    Some(token_punct_visit(name))
-                }
-            }
-            types::Type::Group(_) => Some(token_group_visit(name)),
-            types::Type::Syn(t) => {
-                fn requires_full(features: &types::Features) -> bool {
-                    features.any.contains("full") && features.any.len() == 1
-                }
-
-                let res = simple_visit(t, name);
-
-                let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap();
-
-                Some(
-                    if requires_full(&target.features) && !requires_full(features) {
-                        quote! {
-                            full!(#res)
-                        }
-                    } else {
-                        res
-                    },
-                )
-            }
-            types::Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => {
-                Some(simple_visit(t, name))
-            }
-            types::Type::Ext(_) | types::Type::Std(_) => None,
-        }
-    }
-
-    fn visit_features(features: &types::Features) -> TokenStream {
-        let features = &features.any;
-        match features.len() {
-            0 => quote!(),
-            1 => quote!(#[cfg(feature = #(#features)*)]),
-            _ => quote!(#[cfg(any(#(feature = #features),*))]),
-        }
-    }
-
-    pub fn generate(state: &mut State, s: &types::Node, defs: &types::Definitions) {
-        let features = visit_features(&s.features);
-        let under_name = under_name(&s.ident);
-        let ty = Ident::new(&s.ident, Span::call_site());
-        let visit_mut_fn = Ident::new(&format!("visit_{}_mut", under_name), Span::call_site());
-
-        let mut visit_mut_impl = TokenStream::new();
-
-        match &s.data {
-            types::Data::Enum(variants) => {
-                let mut visit_mut_variants = TokenStream::new();
-
-                for (variant, fields) in variants {
-                    let variant_ident = Ident::new(variant, Span::call_site());
-
-                    if fields.is_empty() {
-                        visit_mut_variants.append_all(quote! {
-                            #ty::#variant_ident => {}
-                        });
-                    } else {
-                        let mut bind_visit_mut_fields = TokenStream::new();
-                        let mut visit_mut_fields = TokenStream::new();
-
-                        for (idx, ty) in fields.iter().enumerate() {
-                            let name = format!("_binding_{}", idx);
-                            let binding = Ident::new(&name, Span::call_site());
-
-                            bind_visit_mut_fields.append_all(quote! {
-                                ref mut #binding,
-                            });
-
-                            let borrowed_binding = Borrowed(quote!(#binding));
-
-                            visit_mut_fields.append_all(
-                                visit(ty, &s.features, defs, &borrowed_binding)
-                                    .unwrap_or_else(|| noop_visit(&borrowed_binding)),
-                            );
-
-                            visit_mut_fields.append_all(quote!(;));
-                        }
-
-                        visit_mut_variants.append_all(quote! {
-                            #ty::#variant_ident(#bind_visit_mut_fields) => {
-                                #visit_mut_fields
-                            }
-                        });
-                    }
-                }
-
-                visit_mut_impl.append_all(quote! {
-                    match *_i {
-                        #visit_mut_variants
-                    }
-                });
-            }
-            types::Data::Struct(fields) => {
-                for (field, ty) in fields {
-                    let id = Ident::new(&field, Span::call_site());
-                    let ref_toks = Owned(quote!(_i.#id));
-                    let visit_mut_field = visit(&ty, &s.features, defs, &ref_toks)
-                        .unwrap_or_else(|| noop_visit(&ref_toks));
-                    visit_mut_impl.append_all(quote! {
-                        #visit_mut_field;
-                    });
-                }
-            }
-            types::Data::Private => {}
-        }
-
-        state.visit_mut_trait.append_all(quote! {
-            #features
-            fn #visit_mut_fn(&mut self, i: &mut #ty) {
-                #visit_mut_fn(self, i)
-            }
-        });
-
-        state.visit_mut_impl.append_all(quote! {
-            #features
-            pub fn #visit_mut_fn<V: VisitMut + ?Sized>(
-                _visitor: &mut V, _i: &mut #ty
-            ) {
-                #visit_mut_impl
-            }
-        });
     }
 }
 
+fn simple_visit(item: &str, name: &Operand) -> TokenStream {
+    let ident = under_name(item);
+    let method = Ident::new(&format!("visit_{}_mut", ident), Span::call_site());
+    let name = name.ref_mut_tokens();
+    quote! {
+        _visitor.#method(#name)
+    }
+}
+
+fn box_visit(
+    elem: &types::Type,
+    features: &types::Features,
+    defs: &types::Definitions,
+    name: &Operand,
+) -> Option<TokenStream> {
+    let name = name.owned_tokens();
+    let res = visit(elem, features, defs, &Owned(quote!(*#name)))?;
+    Some(res)
+}
+
+fn vec_visit(
+    elem: &types::Type,
+    features: &types::Features,
+    defs: &types::Definitions,
+    name: &Operand,
+) -> Option<TokenStream> {
+    let operand = Borrowed(quote!(it));
+    let val = visit(elem, features, defs, &operand)?;
+    let name = name.ref_mut_tokens();
+    Some(quote! {
+        for it in #name {
+            #val
+        }
+    })
+}
+
+fn punctuated_visit(
+    elem: &types::Type,
+    features: &types::Features,
+    defs: &types::Definitions,
+    name: &Operand,
+) -> Option<TokenStream> {
+    let operand = Borrowed(quote!(it));
+    let val = visit(elem, features, defs, &operand)?;
+    let name = name.ref_mut_tokens();
+    Some(quote! {
+        for mut el in Punctuated::pairs_mut(#name) {
+            let it = el.value_mut();
+            #val
+        }
+    })
+}
+
+fn option_visit(
+    elem: &types::Type,
+    features: &types::Features,
+    defs: &types::Definitions,
+    name: &Operand,
+) -> Option<TokenStream> {
+    let it = Borrowed(quote!(it));
+    let val = visit(elem, features, defs, &it)?;
+    let name = name.owned_tokens();
+    Some(quote! {
+        if let Some(ref mut it) = #name {
+            #val
+        }
+    })
+}
+
+fn tuple_visit(
+    elems: &[types::Type],
+    features: &types::Features,
+    defs: &types::Definitions,
+    name: &Operand,
+) -> Option<TokenStream> {
+    if elems.is_empty() {
+        return None;
+    }
+
+    let mut code = TokenStream::new();
+    for (i, elem) in elems.iter().enumerate() {
+        let name = name.tokens();
+        let i = Index::from(i);
+        let it = Owned(quote!((#name).#i));
+        let val = visit(elem, features, defs, &it).unwrap_or_else(|| noop_visit(&it));
+        code.append_all(val);
+        code.append_all(quote!(;));
+    }
+    Some(code)
+}
+
+fn token_punct_visit(name: &Operand) -> TokenStream {
+    let name = name.tokens();
+    quote! {
+        tokens_helper(_visitor, &mut #name.spans)
+    }
+}
+
+fn token_keyword_visit(name: &Operand) -> TokenStream {
+    let name = name.tokens();
+    quote! {
+        tokens_helper(_visitor, &mut #name.span)
+    }
+}
+
+fn token_group_visit(name: &Operand) -> TokenStream {
+    let name = name.tokens();
+    quote! {
+        tokens_helper(_visitor, &mut #name.span)
+    }
+}
+
+fn noop_visit(name: &Operand) -> TokenStream {
+    let name = name.tokens();
+    quote! {
+        skip!(#name)
+    }
+}
+
+fn visit(
+    ty: &types::Type,
+    features: &types::Features,
+    defs: &types::Definitions,
+    name: &Operand,
+) -> Option<TokenStream> {
+    match ty {
+        types::Type::Box(t) => box_visit(&*t, features, defs, name),
+        types::Type::Vec(t) => vec_visit(&*t, features, defs, name),
+        types::Type::Punctuated(p) => punctuated_visit(&p.element, features, defs, name),
+        types::Type::Option(t) => option_visit(&*t, features, defs, name),
+        types::Type::Tuple(t) => tuple_visit(t, features, defs, name),
+        types::Type::Token(t) => {
+            let repr = &defs.tokens[t];
+            let is_keyword = repr.chars().next().unwrap().is_alphabetic();
+            if is_keyword {
+                Some(token_keyword_visit(name))
+            } else {
+                Some(token_punct_visit(name))
+            }
+        }
+        types::Type::Group(_) => Some(token_group_visit(name)),
+        types::Type::Syn(t) => {
+            fn requires_full(features: &types::Features) -> bool {
+                features.any.contains("full") && features.any.len() == 1
+            }
+
+            let res = simple_visit(t, name);
+
+            let target = defs.types.iter().find(|ty| ty.ident == *t).unwrap();
+
+            Some(
+                if requires_full(&target.features) && !requires_full(features) {
+                    quote! {
+                        full!(#res)
+                    }
+                } else {
+                    res
+                },
+            )
+        }
+        types::Type::Ext(t) if gen::TERMINAL_TYPES.contains(&&t[..]) => Some(simple_visit(t, name)),
+        types::Type::Ext(_) | types::Type::Std(_) => None,
+    }
+}
+
+fn visit_features(features: &types::Features) -> TokenStream {
+    let features = &features.any;
+    match features.len() {
+        0 => quote!(),
+        1 => quote!(#[cfg(feature = #(#features)*)]),
+        _ => quote!(#[cfg(any(#(feature = #features),*))]),
+    }
+}
+
+fn node(state: &mut State, s: &types::Node, defs: &types::Definitions) {
+    let features = visit_features(&s.features);
+    let under_name = under_name(&s.ident);
+    let ty = Ident::new(&s.ident, Span::call_site());
+    let visit_mut_fn = Ident::new(&format!("visit_{}_mut", under_name), Span::call_site());
+
+    let mut visit_mut_impl = TokenStream::new();
+
+    match &s.data {
+        types::Data::Enum(variants) => {
+            let mut visit_mut_variants = TokenStream::new();
+
+            for (variant, fields) in variants {
+                let variant_ident = Ident::new(variant, Span::call_site());
+
+                if fields.is_empty() {
+                    visit_mut_variants.append_all(quote! {
+                        #ty::#variant_ident => {}
+                    });
+                } else {
+                    let mut bind_visit_mut_fields = TokenStream::new();
+                    let mut visit_mut_fields = TokenStream::new();
+
+                    for (idx, ty) in fields.iter().enumerate() {
+                        let name = format!("_binding_{}", idx);
+                        let binding = Ident::new(&name, Span::call_site());
+
+                        bind_visit_mut_fields.append_all(quote! {
+                            ref mut #binding,
+                        });
+
+                        let borrowed_binding = Borrowed(quote!(#binding));
+
+                        visit_mut_fields.append_all(
+                            visit(ty, &s.features, defs, &borrowed_binding)
+                                .unwrap_or_else(|| noop_visit(&borrowed_binding)),
+                        );
+
+                        visit_mut_fields.append_all(quote!(;));
+                    }
+
+                    visit_mut_variants.append_all(quote! {
+                        #ty::#variant_ident(#bind_visit_mut_fields) => {
+                            #visit_mut_fields
+                        }
+                    });
+                }
+            }
+
+            visit_mut_impl.append_all(quote! {
+                match *_i {
+                    #visit_mut_variants
+                }
+            });
+        }
+        types::Data::Struct(fields) => {
+            for (field, ty) in fields {
+                let id = Ident::new(&field, Span::call_site());
+                let ref_toks = Owned(quote!(_i.#id));
+                let visit_mut_field = visit(&ty, &s.features, defs, &ref_toks)
+                    .unwrap_or_else(|| noop_visit(&ref_toks));
+                visit_mut_impl.append_all(quote! {
+                    #visit_mut_field;
+                });
+            }
+        }
+        types::Data::Private => {}
+    }
+
+    state.visit_mut_trait.append_all(quote! {
+        #features
+        fn #visit_mut_fn(&mut self, i: &mut #ty) {
+            #visit_mut_fn(self, i)
+        }
+    });
+
+    state.visit_mut_impl.append_all(quote! {
+        #features
+        pub fn #visit_mut_fn<V: VisitMut + ?Sized>(
+            _visitor: &mut V, _i: &mut #ty
+        ) {
+            #visit_mut_impl
+        }
+    });
+}
+
 pub fn generate(defs: &types::Definitions) {
-    let state = gen::traverse(defs, codegen::generate);
+    let state = gen::traverse(defs, node);
     let full_macro = full::get_macro();
     let visit_mut_trait = state.visit_mut_trait;
     let visit_mut_impl = state.visit_mut_impl;