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/tests/test_expr.rs b/tests/test_expr.rs
index dca8603..1fe0180 100644
--- a/tests/test_expr.rs
+++ b/tests/test_expr.rs
@@ -90,45 +90,45 @@
 
     assert_let!(ItemKind::Struct(..) = actual.items[0].node);
 
-    assert_let!(Item { node: ItemKind::Fn(_, _, _, _, _, ref body), .. } = actual.items[1]; {
-        assert_let!(Stmt::Local(ref local) = body.stmts[0]; {
+    assert_let!(Item { node: ItemKind::Fn(ItemFn { ref block, .. }), .. } = actual.items[1]; {
+        assert_let!(Stmt::Local(ref local) = block.stmts[0]; {
             assert_let!(Local { init: Some(ref init_expr), .. } = **local; {
                 assert_let!(Expr { node: ExprKind::Catch(..), .. } = **init_expr);
             });
         });
 
-        assert_let!(Stmt::Local(ref local) = body.stmts[2]; {
+        assert_let!(Stmt::Local(ref local) = block.stmts[2]; {
             assert_let!(Pat::Ident(BindingMode::ByValue(Mutability::Mutable), ref ident, None) = *local.pat; {
                 assert_eq!(ident, "catch");
             });
         });
 
-        assert_let!(Stmt::Expr(ref expr) = body.stmts[3]; {
-            assert_let!(Expr { node: ExprKind::While(ref loop_expr, _, None), .. } = **expr; {
-                assert_let!(Expr { node: ExprKind::Path(None, ref loop_var), .. } = **loop_expr; {
-                    assert_eq!(*loop_var, "catch".into());
+        assert_let!(Stmt::Expr(ref expr) = block.stmts[3]; {
+            assert_let!(Expr { node: ExprKind::While(ExprWhile { ref cond, .. }), .. } = **expr; {
+                assert_let!(Expr { node: ExprKind::Path(ExprPath { qself: None, ref path }), .. } = **cond; {
+                    assert_eq!(*path, "catch".into());
                 });
             });
         });
 
-        assert_let!(Stmt::Semi(ref expr) = body.stmts[5]; {
-            assert_let!(Expr { node: ExprKind::Assign(ref left, ref right), .. } = **expr; {
-                assert_let!(Expr { node: ExprKind::Path(None, ref loop_var), .. } = **left; {
-                    assert_eq!(*loop_var, "catch".into());
+        assert_let!(Stmt::Semi(ref expr) = block.stmts[5]; {
+            assert_let!(Expr { node: ExprKind::Assign(ExprAssign { ref left, ref right }), .. } = **expr; {
+                assert_let!(Expr { node: ExprKind::Path(ExprPath { qself: None, ref path }), .. } = **left; {
+                    assert_eq!(*path, "catch".into());
                 });
 
-                assert_let!(Expr { node: ExprKind::If(ref if_expr, _, _), .. } = **right; {
-                    assert_let!(Expr { node: ExprKind::Path(None, ref if_var), .. } = **if_expr; {
-                        assert_eq!(*if_var, "catch".into());
+                assert_let!(Expr { node: ExprKind::If(ExprIf { ref cond, .. }), .. } = **right; {
+                    assert_let!(Expr { node: ExprKind::Path(ExprPath { qself: None, ref path }), .. } = **cond; {
+                        assert_eq!(*path, "catch".into());
                     });
                 });
             });
         });
 
-        assert_let!(Stmt::Semi(ref expr) = body.stmts[7]; {
-            assert_let!(Expr { node: ExprKind::Match(ref match_expr, _), .. } = **expr; {
-                assert_let!(Expr { node: ExprKind::Path(None, ref match_var), .. } = **match_expr; {
-                    assert_eq!(*match_var, "catch".into());
+        assert_let!(Stmt::Semi(ref expr) = block.stmts[7]; {
+            assert_let!(Expr { node: ExprKind::Match(ExprMatch { ref expr, .. }), .. } = **expr; {
+                assert_let!(Expr { node: ExprKind::Path(ExprPath { qself: None, ref path }), .. } = **expr; {
+                    assert_eq!(*path, "catch".into());
                 });
             });
         });
diff --git a/tests/test_generics.rs b/tests/test_generics.rs
index 800daa7..08886bb 100644
--- a/tests/test_generics.rs
+++ b/tests/test_generics.rs
@@ -27,13 +27,15 @@
                                         }],
                             ident: Ident::new("T"),
                             bounds: vec![TyParamBound::Region(Lifetime::new("'a"))],
-                            default: Some(Ty::Tup(Vec::new())),
+                            default: Some(TyTup { tys: Vec::new() }.into()),
                         }],
         where_clause: WhereClause {
             predicates: vec![WherePredicate::BoundPredicate(WhereBoundPredicate {
                                                                 bound_lifetimes: Vec::new(),
-                                                                bounded_ty:
-                                                                    Ty::Path(None, "T".into()),
+                                                                bounded_ty: TyPath {
+                                                                    qself: None,
+                                                                    path: "T".into(),
+                                                                }.into(),
                                                                 bounds: vec![
                         TyParamBound::Trait(
                             PolyTraitRef {
diff --git a/tests/test_macro_input.rs b/tests/test_macro_input.rs
index d45ead3..4e6bbd8 100644
--- a/tests/test_macro_input.rs
+++ b/tests/test_macro_input.rs
@@ -1,4 +1,4 @@
-//! Test the now-deprecated `parse_macro_input` function. 
+//! Test the now-deprecated `parse_macro_input` function.
 //!
 //! Deprecation warnings are suppressed to keep the output clean.
 #![allow(deprecated)]
@@ -47,43 +47,56 @@
             is_sugared_doc: false,
         }],
         generics: Generics::default(),
-        body: Body::Struct(VariantData::Struct(vec![Field {
-                                                        ident: Some("ident".into()),
-                                                        vis: Visibility::Public,
-                                                        attrs: Vec::new(),
-                                                        ty: Ty::Path(None, "Ident".into()),
-                                                    },
-                                                    Field {
-                                                        ident: Some("attrs".into()),
-                                                        vis: Visibility::Public,
-                                                        attrs: Vec::new(),
-                                                        ty: Ty::Path(None,
-                                                                     Path {
-                                                                         global: false,
-                                                                         segments: vec![
-                        PathSegment {
-                            ident: "Vec".into(),
-                            parameters: PathParameters::AngleBracketed(
-                                AngleBracketedParameterData {
-                                    lifetimes: Vec::new(),
-                                    types: vec![Ty::Path(None, "Attribute".into())],
-                                    bindings: Vec::new(),
-                                },
-                            ),
-                        }
-                    ],
-                                                                     }),
-                                                    }])),
+        body: Body::Struct(VariantData::Struct(vec![
+            Field {
+                ident: Some("ident".into()),
+                vis: Visibility::Public,
+                attrs: Vec::new(),
+                ty: TyPath {
+                    qself: None,
+                    path: "Ident".into(),
+                }.into(),
+            },
+            Field {
+                ident: Some("attrs".into()),
+                vis: Visibility::Public,
+                attrs: Vec::new(),
+                ty: TyPath {
+                    qself: None,
+                    path: Path {
+                        global: false,
+                        segments: vec![
+                            PathSegment {
+                                ident: "Vec".into(),
+                                parameters: PathParameters::AngleBracketed(
+                                    AngleBracketedParameterData {
+                                        lifetimes: Vec::new(),
+                                        types: vec![TyPath {
+                                            qself: None,
+                                            path: "Attribute".into(),
+                                        }.into()],
+                                        bindings: Vec::new(),
+                                    },
+                                ),
+                            }
+                        ],
+                    },
+                }.into(),
+            },
+        ]))
     };
 
     let actual = parse_macro_input(raw).unwrap();
 
     assert_eq!(expected, actual);
 
-    let expected_meta_item = MetaItem::List("derive".into(), vec![
-        NestedMetaItem::MetaItem(MetaItem::Word("Debug".into())),
-        NestedMetaItem::MetaItem(MetaItem::Word("Clone".into())),
-    ]);
+    let expected_meta_item: MetaItem = MetaItemList {
+        ident: "derive".into(),
+        nested: vec![
+            NestedMetaItem::MetaItem(MetaItem::Word("Debug".into())),
+            NestedMetaItem::MetaItem(MetaItem::Word("Clone".into())),
+        ],
+    }.into();
 
     assert_eq!(expected_meta_item, actual.attrs[0].meta_item().unwrap());
 }
@@ -153,7 +166,7 @@
                         ident: None,
                         vis: Visibility::Inherited,
                         attrs: Vec::new(),
-                        ty: Ty::Path(None, "T".into()),
+                        ty: TyPath { qself: None, path: "T".into() }.into(),
                     },
                 ]),
                 discriminant: None,
@@ -166,7 +179,7 @@
                         ident: None,
                         vis: Visibility::Inherited,
                         attrs: Vec::new(),
-                        ty: Ty::Path(None, "E".into()),
+                        ty: TyPath { qself: None, path: "E".into() }.into(),
                     },
                 ]),
                 discriminant: None,
@@ -182,22 +195,24 @@
                 attrs: Vec::new(),
                 data: VariantData::Unit,
                 discriminant: Some(ConstExpr::Other(Expr {
-                    node: ExprKind::TupField(
-                        Box::new(Expr {
-                            node: ExprKind::Tup(vec![
-                                Expr {
-                                    node: ExprKind::Lit(Lit::Int(0, IntTy::Unsuffixed)),
-                                    attrs: Vec::new(),
-                                },
-                                Expr {
-                                    node: ExprKind::Lit(Lit::Str("data".into(), StrStyle::Cooked)),
-                                    attrs: Vec::new(),
-                                },
-                            ]),
+                    node: ExprTupField {
+                        expr: Box::new(Expr {
+                            node: ExprTup {
+                                args: vec![
+                                    Expr {
+                                        node: ExprKind::Lit(Lit::Int(0, IntTy::Unsuffixed)),
+                                        attrs: Vec::new(),
+                                    },
+                                    Expr {
+                                        node: ExprKind::Lit(Lit::Str("data".into(), StrStyle::Cooked)),
+                                        attrs: Vec::new(),
+                                    },
+                                ],
+                            }.into(),
                             attrs: Vec::new(),
                         }),
-                        0
-                    ),
+                        field: 0
+                    }.into(),
                     attrs: Vec::new(),
                 })),
             },
@@ -209,10 +224,13 @@
     assert_eq!(expected, actual);
 
     let expected_meta_items = vec![
-        MetaItem::NameValue("doc".into(), Lit::Str(
-            "/// See the std::result module documentation for details.".into(),
-            StrStyle::Cooked,
-        )),
+        MetaNameValue {
+            ident: "doc".into(),
+            lit: Lit::Str(
+                "/// See the std::result module documentation for details.".into(),
+                StrStyle::Cooked,
+            ),
+        }.into(),
         MetaItem::Word("must_use".into()),
     ];
 
@@ -338,7 +356,7 @@
             ident: None,
             vis: Visibility::Restricted(Box::new(Path { global: false, segments: vec!["m".into(), "n".into()] })),
             attrs: vec![],
-            ty: Ty::Path(None, "u8".into()),
+            ty: TyPath { qself: None, path: "u8".into() }.into(),
         }])),
     };
 
diff --git a/tests/test_meta_item.rs b/tests/test_meta_item.rs
index 58a8eff..735c9a2 100644
--- a/tests/test_meta_item.rs
+++ b/tests/test_meta_item.rs
@@ -3,52 +3,75 @@
 
 #[test]
 fn test_meta_item_word() {
-    run_test("#[foo]", &MetaItem::Word("foo".into()))
+    run_test("#[foo]", MetaItem::Word("foo".into()))
 }
 
 #[test]
 fn test_meta_item_name_value() {
-    run_test("#[foo = 5]", &MetaItem::NameValue("foo".into(),
-        Lit::Int(5, IntTy::Unsuffixed)))
+    run_test("#[foo = 5]", MetaNameValue {
+        ident: "foo".into(),
+        lit: Lit::Int(5, IntTy::Unsuffixed),
+    })
 }
 
 #[test]
 fn test_meta_item_list_lit() {
-    run_test("#[foo(5)]", &MetaItem::List("foo".into(), vec![
-        NestedMetaItem::Literal(Lit::Int(5, IntTy::Unsuffixed)),
-    ]))
+    run_test("#[foo(5)]", MetaItemList {
+        ident: "foo".into(),
+        nested: vec![
+            NestedMetaItem::Literal(Lit::Int(5, IntTy::Unsuffixed)),
+        ],
+    })
 }
 
 #[test]
 fn test_meta_item_list_word() {
-    run_test("#[foo(bar)]", &MetaItem::List("foo".into(), vec![
-        NestedMetaItem::MetaItem(MetaItem::Word("bar".into())),
-    ]))
+    run_test("#[foo(bar)]", MetaItemList {
+        ident: "foo".into(),
+        nested: vec![
+            NestedMetaItem::MetaItem(MetaItem::Word("bar".into())),
+        ],
+    })
 }
 
 #[test]
 fn test_meta_item_list_name_value() {
-    run_test("#[foo(bar = 5)]", &MetaItem::List("foo".into(), vec![
-        NestedMetaItem::MetaItem(MetaItem::NameValue("bar".into(),
-            Lit::Int(5, IntTy::Unsuffixed))),
-    ]))
+    run_test("#[foo(bar = 5)]", MetaItemList {
+        ident: "foo".into(),
+        nested: vec![
+            NestedMetaItem::MetaItem(MetaNameValue {
+                ident: "bar".into(),
+                lit: Lit::Int(5, IntTy::Unsuffixed),
+            }.into()),
+        ],
+    })
 }
 
 #[test]
 fn test_meta_item_multiple() {
-    run_test("#[foo(word, name = 5, list(name2 = 6), word2)]", &MetaItem::List("foo".into(), vec![
-        NestedMetaItem::MetaItem(MetaItem::Word("word".into())),
-        NestedMetaItem::MetaItem(MetaItem::NameValue("name".into(),
-            Lit::Int(5, IntTy::Unsuffixed))),
-        NestedMetaItem::MetaItem(MetaItem::List("list".into(), vec![
-            NestedMetaItem::MetaItem(MetaItem::NameValue("name2".into(),
-                Lit::Int(6, IntTy::Unsuffixed)))
-        ])),
-        NestedMetaItem::MetaItem(MetaItem::Word("word2".into())),
-    ]))
+    run_test("#[foo(word, name = 5, list(name2 = 6), word2)]", MetaItemList {
+        ident: "foo".into(),
+        nested: vec![
+            NestedMetaItem::MetaItem(MetaItem::Word("word".into())),
+            NestedMetaItem::MetaItem(MetaNameValue {
+                ident: "name".into(),
+                lit: Lit::Int(5, IntTy::Unsuffixed),
+            }.into()),
+            NestedMetaItem::MetaItem(MetaItemList {
+                ident: "list".into(),
+                nested: vec![
+                    NestedMetaItem::MetaItem(MetaNameValue {
+                        ident: "name2".into(),
+                        lit: Lit::Int(6, IntTy::Unsuffixed),
+                    }.into())
+                ],
+            }.into()),
+            NestedMetaItem::MetaItem(MetaItem::Word("word2".into())),
+        ],
+    })
 }
 
-fn run_test(input: &str, expected: &MetaItem) {
+fn run_test<T: Into<MetaItem>>(input: &str, expected: T) {
     let attr = parse_outer_attr(input).unwrap();
-    assert_eq!(expected, &attr.meta_item().unwrap());
+    assert_eq!(expected.into(), attr.meta_item().unwrap());
 }