Rewrite the AST to be a bit more user-friendly

This commit is a relatively large rewrite of the AST that `syn` exposes. The
main change is to expose enums-of-structs rather than
enums-with-huge-tuple-variants. The best example of this is `ItemKind::Fn` which
changed from:

    enum ItemKind {
        Fn(Box<FnDecl>, Unsafety, Constness, Option<Abi>, Generics, Box<Block>),
        ...
    }

to

    enum ItemKind {
        Fn(ItemFn),
        ...
    }

    struct ItemFn {
        decl: Box<FnDecl>,
        unsafety: Unsafety,
        constness: Constness,
        abi: Option<Abi>,
        generics: Generics,
        block: Box<Block>,
    }

This change serves a few purposes:

* It's now much easier to add fields to each variant of the ast, ast struct
  fields tend to be "by default ignored" in most contexts.
* It's much easier to document what each field is, as each field can have
  dedicated documentation.
* There's now canonicalized names for each field (the name of the field) which
  can help match `match` statements more consistent across a codebase.

A downside of this representation is that it can be a little more verbose to
work with in `match` statements and during constructions. Overall though I'd
feel at least that the readability improved significantly despite the extra
words required to do various operations.

Closes #136
diff --git a/src/attr.rs b/src/attr.rs
index 0a2b016..fecfd9a 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -2,24 +2,25 @@
 
 use std::iter;
 
-/// Doc-comments are promoted to attributes that have `is_sugared_doc` = true
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct Attribute {
-    pub style: AttrStyle,
+ast_struct! {
+    /// Doc-comments are promoted to attributes that have `is_sugared_doc` = true
+    pub struct Attribute {
+        pub style: AttrStyle,
 
-    /// The path of the attribute.
-    ///
-    /// E.g. `derive` in `#[derive(Copy)]`
-    /// E.g. `crate::precondition` in `#[crate::precondition x < 5]`
-    pub path: Path,
+        /// The path of the attribute.
+        ///
+        /// E.g. `derive` in `#[derive(Copy)]`
+        /// E.g. `crate::precondition` in `#[crate::precondition x < 5]`
+        pub path: Path,
 
-    /// Any tokens after the path.
-    ///
-    /// E.g. `( Copy )` in `#[derive(Copy)]`
-    /// E.g. `x < 5` in `#[crate::precondition x < 5]`
-    pub tts: Vec<TokenTree>,
+        /// Any tokens after the path.
+        ///
+        /// E.g. `( Copy )` in `#[derive(Copy)]`
+        /// E.g. `x < 5` in `#[crate::precondition x < 5]`
+        pub tts: Vec<TokenTree>,
 
-    pub is_sugared_doc: bool,
+        pub is_sugared_doc: bool,
+    }
 }
 
 impl Attribute {
@@ -49,7 +50,11 @@
                             if tts.len() >= 3 {
                                 if let TokenTree::Token(Token::Eq) = tts[1] {
                                     if let TokenTree::Token(Token::Literal(ref lit)) = tts[2] {
-                                        return Some((NestedMetaItem::MetaItem(MetaItem::NameValue(ident.clone(), lit.clone())), &tts[3..]));
+                                        let pair = MetaNameValue {
+                                            ident: ident.clone(),
+                                            lit: lit.clone(),
+                                        };
+                                        return Some((NestedMetaItem::MetaItem(MetaItem::NameValue(pair)), &tts[3..]));
                                     }
                                 }
                             }
@@ -58,7 +63,11 @@
                                 if let TokenTree::Delimited(Delimited { delim: DelimToken::Paren, tts: ref inner_tts }) = tts[1] {
                                     return match list_of_nested_meta_items_from_tokens(vec![], inner_tts) {
                                         Some(nested_meta_items) => {
-                                            Some((NestedMetaItem::MetaItem(MetaItem::List(ident.clone(), nested_meta_items)), &tts[2..]))
+                                            let list = MetaItemList {
+                                                ident: ident.clone(),
+                                                nested: nested_meta_items,
+                                            };
+                                            Some((NestedMetaItem::MetaItem(MetaItem::List(list)), &tts[2..]))
                                         }
 
                                         None => None
@@ -97,7 +106,10 @@
                 }
 
                 if let Some(nested_meta_items) = list_of_nested_meta_items_from_tokens(vec![], tts) {
-                    return Some(MetaItem::List(name.clone(), nested_meta_items));
+                    return Some(MetaItem::List(MetaItemList {
+                        ident: name.clone(),
+                        nested: nested_meta_items,
+                    }));
                 }
             }
         }
@@ -105,7 +117,10 @@
         if self.tts.len() == 2 {
             if let TokenTree::Token(Token::Eq) = self.tts[0] {
                 if let TokenTree::Token(Token::Literal(ref lit)) = self.tts[1] {
-                    return Some(MetaItem::NameValue(name.clone(), lit.clone()));
+                    return Some(MetaItem::NameValue(MetaNameValue {
+                        ident: name.clone(),
+                        lit: lit.clone(),
+                    }));
                 }
             }
         }
@@ -114,37 +129,60 @@
     }
 }
 
-/// Distinguishes between Attributes that decorate items and Attributes that
-/// are contained as statements within items. These two cases need to be
-/// distinguished for pretty-printing.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub enum AttrStyle {
-    /// Attribute of the form `#![...]`.
-    Outer,
+ast_enum! {
+    /// Distinguishes between Attributes that decorate items and Attributes that
+    /// are contained as statements within items. These two cases need to be
+    /// distinguished for pretty-printing.
+    #[derive(Copy)]
+    pub enum AttrStyle {
+        /// Attribute of the form `#![...]`.
+        Outer,
 
-    /// Attribute of the form `#[...]`.
-    Inner,
+        /// Attribute of the form `#[...]`.
+        Inner,
+    }
 }
 
-/// A compile-time attribute item.
-///
-/// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]`
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub enum MetaItem {
-    /// Word meta item.
+ast_enum_of_structs! {
+    /// A compile-time attribute item.
     ///
-    /// E.g. `test` as in `#[test]`
-    Word(Ident),
+    /// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]`
+    pub enum MetaItem {
+        /// Word meta item.
+        ///
+        /// E.g. `test` as in `#[test]`
+        pub Word(Ident),
 
-    /// List meta item.
-    ///
-    /// E.g. `derive(..)` as in `#[derive(..)]`
-    List(Ident, Vec<NestedMetaItem>),
+        /// List meta item.
+        ///
+        /// E.g. `derive(..)` as in `#[derive(..)]`
+        pub List(MetaItemList {
+            /// Name of this attribute.
+            ///
+            /// E.g. `derive` in `#[derive(..)]`
+            pub ident: Ident,
 
-    /// Name-value meta item.
-    ///
-    /// E.g. `feature = "foo"` as in `#[feature = "foo"]`
-    NameValue(Ident, Lit),
+            /// Arguments to this attribute
+            ///
+            /// E.g. `..` in `#[derive(..)]`
+            pub nested: Vec<NestedMetaItem>,
+        }),
+
+        /// Name-value meta item.
+        ///
+        /// E.g. `feature = "foo"` as in `#[feature = "foo"]`
+        pub NameValue(MetaNameValue {
+            /// Name of this attribute.
+            ///
+            /// E.g. `feature` in `#[feature = "foo"]`
+            pub ident: Ident,
+
+            /// Arguments to this attribute
+            ///
+            /// E.g. `"foo"` in `#[feature = "foo"]`
+            pub lit: Lit,
+        }),
+    }
 }
 
 impl MetaItem {
@@ -154,27 +192,28 @@
     /// `feature` as in `#[feature = "foo"]`.
     pub fn name(&self) -> &str {
         match *self {
-            MetaItem::Word(ref name) |
-            MetaItem::List(ref name, _) |
-            MetaItem::NameValue(ref name, _) => name.as_ref(),
+            MetaItem::Word(ref name) => name.as_ref(),
+            MetaItem::NameValue(ref pair) => pair.ident.as_ref(),
+            MetaItem::List(ref list) => list.ident.as_ref(),
         }
     }
 }
 
-/// Possible values inside of compile-time attribute lists.
-///
-/// E.g. the '..' in `#[name(..)]`.
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub enum NestedMetaItem {
-    /// A full `MetaItem`.
+ast_enum_of_structs! {
+    /// Possible values inside of compile-time attribute lists.
     ///
-    /// E.g. `Copy` in `#[derive(Copy)]` would be a `MetaItem::Word(Ident::from("Copy"))`.
-    MetaItem(MetaItem),
+    /// E.g. the '..' in `#[name(..)]`.
+    pub enum NestedMetaItem {
+        /// A full `MetaItem`.
+        ///
+        /// E.g. `Copy` in `#[derive(Copy)]` would be a `MetaItem::Word(Ident::from("Copy"))`.
+        pub MetaItem(MetaItem),
 
-    /// A Rust literal.
-    ///
-    /// E.g. `"name"` in `#[rename("name")]`.
-    Literal(Lit),
+        /// A Rust literal.
+        ///
+        /// E.g. `"name"` in `#[rename("name")]`.
+        pub Literal(Lit),
+    }
 }
 
 pub trait FilterAttrs<'a> {
@@ -378,37 +417,20 @@
         }
     }
 
-    impl ToTokens for MetaItem {
+    impl ToTokens for MetaItemList {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            match *self {
-                MetaItem::Word(ref ident) => {
-                    ident.to_tokens(tokens);
-                }
-                MetaItem::List(ref ident, ref inner) => {
-                    ident.to_tokens(tokens);
-                    tokens.append("(");
-                    tokens.append_separated(inner, ",");
-                    tokens.append(")");
-                }
-                MetaItem::NameValue(ref name, ref value) => {
-                    name.to_tokens(tokens);
-                    tokens.append("=");
-                    value.to_tokens(tokens);
-                }
-            }
+            self.ident.to_tokens(tokens);
+            tokens.append("(");
+            tokens.append_separated(&self.nested, ",");
+            tokens.append(")");
         }
     }
 
-    impl ToTokens for NestedMetaItem {
+    impl ToTokens for MetaNameValue {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            match *self {
-                NestedMetaItem::MetaItem(ref nested) => {
-                    nested.to_tokens(tokens);
-                }
-                NestedMetaItem::Literal(ref lit) => {
-                    lit.to_tokens(tokens);
-                }
-            }
+            self.ident.to_tokens(tokens);
+            tokens.append("=");
+            self.lit.to_tokens(tokens);
         }
     }
 }