Reorganize DeriveInput
diff --git a/src/derive.rs b/src/derive.rs
index cf4a3d1..7b58523 100644
--- a/src/derive.rs
+++ b/src/derive.rs
@@ -2,7 +2,7 @@
 use delimited::Delimited;
 
 ast_struct! {
-    /// Struct or enum sent to a `proc_macro_derive` macro.
+    /// Data structure sent to a `proc_macro_derive` macro.
     pub struct DeriveInput {
         /// Attributes tagged on the whole struct or enum.
         pub attrs: Vec<Attribute>,
@@ -17,25 +17,31 @@
         pub generics: Generics,
 
         /// Data within the struct or enum.
-        pub body: Body,
+        pub data: Data,
     }
 }
 
 ast_enum_of_structs! {
-    /// Body of a derived struct or enum.
-    pub enum Body {
+    /// The storage of a struct, enum or union data structure.
+    pub enum Data {
+        /// It's a struct.
+        pub Struct(DataStruct {
+            pub struct_token: Token![struct],
+            pub fields: Fields,
+            pub semi_token: Option<Token![;]>,
+        }),
+
         /// It's an enum.
-        pub Enum(BodyEnum {
+        pub Enum(DataEnum {
             pub enum_token: Token![enum],
             pub brace_token: token::Brace,
             pub variants: Delimited<Variant, Token![,]>,
         }),
 
-        /// It's a struct.
-        pub Struct(BodyStruct {
-            pub data: VariantData,
-            pub struct_token: Token![struct],
-            pub semi_token: Option<Token![;]>,
+        /// It's an untagged union.
+        pub Union(DataUnion {
+            pub union_token: Token![union],
+            pub fields: FieldsNamed,
         }),
     }
 
@@ -60,7 +66,7 @@
             id: syn!(Ident) >>
             generics: syn!(Generics) >>
             item: switch!(value!(which),
-                Ok(s) => map!(struct_body, move |(wh, body, semi)| DeriveInput {
+                Ok(s) => map!(data_struct, move |(wh, fields, semi)| DeriveInput {
                     ident: id,
                     vis: vis,
                     attrs: attrs,
@@ -68,14 +74,14 @@
                         where_clause: wh,
                         .. generics
                     },
-                    body: Body::Struct(BodyStruct {
+                    data: Data::Struct(DataStruct {
                         struct_token: s,
-                        data: body,
+                        fields: fields,
                         semi_token: semi,
                     }),
                 })
                 |
-                Err(e) => map!(enum_body, move |(wh, brace, body)| DeriveInput {
+                Err(e) => map!(data_enum, move |(wh, brace, variants)| DeriveInput {
                     ident: id,
                     vis: vis,
                     attrs: attrs,
@@ -83,8 +89,8 @@
                         where_clause: wh,
                         .. generics
                     },
-                    body: Body::Enum(BodyEnum {
-                        variants: body,
+                    data: Data::Enum(DataEnum {
+                        variants: variants,
                         brace_token: brace,
                         enum_token: e,
                     }),
@@ -98,70 +104,38 @@
         }
     }
 
-    named!(struct_body -> (Option<WhereClause>, VariantData, Option<Token![;]>), alt!(
+    named!(data_struct -> (Option<WhereClause>, Fields, Option<Token![;]>), alt!(
         do_parse!(
             wh: option!(syn!(WhereClause)) >>
-            body: struct_like_body >>
-            (wh, VariantData::Struct(body.0, body.1), None)
+            fields: syn!(FieldsNamed) >>
+            (wh, Fields::Named(fields), None)
         )
         |
         do_parse!(
-            body: tuple_like_body >>
+            fields: syn!(FieldsUnnamed) >>
             wh: option!(syn!(WhereClause)) >>
             semi: punct!(;) >>
-            (wh, VariantData::Tuple(body.0, body.1), Some(semi))
+            (wh, Fields::Unnamed(fields), Some(semi))
         )
         |
         do_parse!(
             wh: option!(syn!(WhereClause)) >>
             semi: punct!(;) >>
-            (wh, VariantData::Unit, Some(semi))
+            (wh, Fields::Unit, Some(semi))
         )
     ));
 
-    named!(enum_body -> (Option<WhereClause>, token::Brace, Delimited<Variant, Token![,]>), do_parse!(
+    named!(data_enum -> (Option<WhereClause>, token::Brace, Delimited<Variant, Token![,]>), do_parse!(
         wh: option!(syn!(WhereClause)) >>
         data: braces!(Delimited::parse_terminated) >>
         (wh, data.0, data.1)
     ));
-
-    impl Synom for Variant {
-        named!(parse -> Self, do_parse!(
-            attrs: many0!(Attribute::parse_outer) >>
-            id: syn!(Ident) >>
-            data: alt!(
-                struct_like_body => { |(b, d)| VariantData::Struct(b, d) }
-                |
-                tuple_like_body => { |(b, d)| VariantData::Tuple(b, d) }
-                |
-                epsilon!() => { |_| VariantData::Unit }
-            ) >>
-            disr: option!(tuple!(punct!(=), syn!(Expr))) >>
-            (Variant {
-                ident: id,
-                attrs: attrs,
-                data: data,
-                discriminant: disr,
-            })
-        ));
-
-        fn description() -> Option<&'static str> {
-            Some("enum variant")
-        }
-    }
-
-    named!(struct_like_body -> (token::Brace, Delimited<Field, Token![,]>),
-           braces!(call!(Delimited::parse_terminated_with, Field::parse_struct)));
-
-    named!(tuple_like_body -> (token::Paren, Delimited<Field, Token![,]>),
-           parens!(call!(Delimited::parse_terminated_with, Field::parse_tuple)));
 }
 
 #[cfg(feature = "printing")]
 mod printing {
     use super::*;
     use attr::FilterAttrs;
-    use data::VariantData;
     use quote::{ToTokens, Tokens};
 
     impl ToTokens for DeriveInput {
@@ -170,34 +144,40 @@
                 attr.to_tokens(tokens);
             }
             self.vis.to_tokens(tokens);
-            match self.body {
-                Body::Enum(ref d) => d.enum_token.to_tokens(tokens),
-                Body::Struct(ref d) => d.struct_token.to_tokens(tokens),
+            match self.data {
+                Data::Struct(ref d) => d.struct_token.to_tokens(tokens),
+                Data::Enum(ref d) => d.enum_token.to_tokens(tokens),
+                Data::Union(ref d) => d.union_token.to_tokens(tokens),
             }
             self.ident.to_tokens(tokens);
             self.generics.to_tokens(tokens);
-            match self.body {
-                Body::Enum(ref data) => {
+            match self.data {
+                Data::Struct(ref data) => {
+                    match data.fields {
+                        Fields::Named(ref fields) => {
+                            self.generics.where_clause.to_tokens(tokens);
+                            fields.to_tokens(tokens);
+                        }
+                        Fields::Unnamed(ref fields) => {
+                            fields.to_tokens(tokens);
+                            self.generics.where_clause.to_tokens(tokens);
+                            TokensOrDefault(&data.semi_token).to_tokens(tokens);
+                        }
+                        Fields::Unit => {
+                            self.generics.where_clause.to_tokens(tokens);
+                            TokensOrDefault(&data.semi_token).to_tokens(tokens);
+                        }
+                    }
+                }
+                Data::Enum(ref data) => {
                     self.generics.where_clause.to_tokens(tokens);
                     data.brace_token.surround(tokens, |tokens| {
                         data.variants.to_tokens(tokens);
                     });
                 }
-                Body::Struct(ref data) => {
-                    match data.data {
-                        VariantData::Struct(..) => {
-                            self.generics.where_clause.to_tokens(tokens);
-                            data.data.to_tokens(tokens);
-                        }
-                        VariantData::Tuple(..) => {
-                            data.data.to_tokens(tokens);
-                            self.generics.where_clause.to_tokens(tokens);
-                        }
-                        VariantData::Unit => {
-                            self.generics.where_clause.to_tokens(tokens);
-                        }
-                    }
-                    data.semi_token.to_tokens(tokens);
+                Data::Union(ref data) => {
+                    self.generics.where_clause.to_tokens(tokens);
+                    data.fields.to_tokens(tokens);
                 }
             }
         }