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/macros.rs b/src/macros.rs
new file mode 100644
index 0000000..656fe90
--- /dev/null
+++ b/src/macros.rs
@@ -0,0 +1,101 @@
+macro_rules! ast_struct {
+    (
+        $(#[$attr:meta])*
+        pub struct $name:ident {
+            $(
+                $(#[$field_attr:meta])*
+                pub $field:ident: $ty:ty,
+            )*
+        }
+    ) => {
+        $(#[$attr])*
+        #[derive(Debug, Clone, Eq, PartialEq, Hash)]
+        pub struct $name {
+            $(
+                $(#[$field_attr])*
+                pub $field: $ty,
+            )*
+        }
+    }
+}
+
+macro_rules! ast_enum {
+    (
+        $(#[$enum_attr:meta])*
+        pub enum $name:ident { $($variants:tt)* }
+    ) => (
+        $(#[$enum_attr])*
+        #[derive(Debug, Clone, Eq, PartialEq, Hash)]
+        pub enum $name {
+            $($variants)*
+        }
+    )
+}
+
+macro_rules! ast_enum_of_structs {
+    (
+        $(#[$enum_attr:meta])*
+        pub enum $name:ident {
+            $(
+                $(#[$variant_attr:meta])*
+                pub $variant:ident($member:ident $($rest:tt)*),
+            )*
+        }
+
+        $($remaining:tt)*
+    ) => (
+        ast_enum! {
+            $(#[$enum_attr])*
+            pub enum $name {
+                $(
+                    $(#[$variant_attr])*
+                    $variant($member),
+                )*
+            }
+        }
+
+        $(
+            maybe_ast_struct! {
+                $(#[$variant_attr])*
+                pub struct $member $($rest)*
+            }
+
+            impl From<$member> for $name {
+                fn from(e: $member) -> $name {
+                    $name::$variant(e)
+                }
+            }
+        )*
+
+        generate_to_tokens! {
+            $($remaining)*
+            enum $name { $($variant,)* }
+        }
+    )
+}
+
+macro_rules! generate_to_tokens {
+    (do_not_generate_to_tokens $($foo:tt)*) => ();
+
+    (enum $name:ident { $($variant:ident,)* }) => (
+        #[cfg(feature = "printing")]
+        impl ::quote::ToTokens for $name {
+            fn to_tokens(&self, tokens: &mut ::quote::Tokens) {
+                match *self {
+                    $(
+                        $name::$variant(ref e) => e.to_tokens(tokens),
+                    )*
+                }
+            }
+        }
+    )
+}
+
+macro_rules! maybe_ast_struct {
+    (
+        $(#[$attr:meta])*
+        pub struct $name:ident
+    ) => ();
+
+    ($($rest:tt)*) => (ast_struct! { $($rest)* });
+}