Add a Synom description to everything for better error messages
diff --git a/src/data.rs b/src/data.rs
index a860ce4..3db0307 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -195,6 +195,10 @@
             |
             epsilon!() => { |_| Visibility::Inherited }
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("visibility qualifier, e.g. `pub`")
+        }
     }
 }
 
diff --git a/src/derive.rs b/src/derive.rs
index 5442a7c..04d7599 100644
--- a/src/derive.rs
+++ b/src/derive.rs
@@ -144,6 +144,10 @@
                 discriminant: disr,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("enum variant")
+        }
     }
 
     named!(struct_like_body -> (Delimited<Field, Token![,]>, token::Brace),
diff --git a/src/expr.rs b/src/expr.rs
index 101cc9d..863492c 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -1445,6 +1445,10 @@
                 bracket_token: elems.1,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("array")
+        }
     }
 
     named!(and_call -> (Delimited<Expr, Token![,]>, token::Paren),
@@ -1503,6 +1507,10 @@
                 paren_token: elems.1,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("tuple")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -1529,6 +1537,10 @@
                 else_branch: else_block,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("`if let` expression")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -1549,6 +1561,10 @@
                 else_branch: else_block,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("`if` expression")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -1592,6 +1608,10 @@
                 label: label,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("`for` loop")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -1607,6 +1627,10 @@
                 label: label,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("`loop`")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -1626,6 +1650,10 @@
                 }
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("`match` expression")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -1641,6 +1669,10 @@
                 catch_token: catch_,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("`catch` expression")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -1654,6 +1686,10 @@
                 expr: expr.map(Box::new),
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("`yield` expression")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -1685,6 +1721,10 @@
                 comma: body.1,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("`match` arm")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -1750,6 +1790,10 @@
                 label: label,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("`while` expression")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -1785,6 +1829,10 @@
                 colon_token: colon,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("`while let` expression")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -1798,6 +1846,10 @@
                 label: label,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("`continue`")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -1860,6 +1912,10 @@
                 }
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("struct literal expression")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -1888,6 +1944,10 @@
                 colon_token: None,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("field-value pair: `field: value`")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -1907,6 +1967,10 @@
                 semi_token: (data.0).1,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("repeated array literal: `[val; N]`")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -1920,6 +1984,10 @@
                 block: b,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("unsafe block: `unsafe { .. }`")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -1931,6 +1999,10 @@
                 block: b,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("block: `{ .. }`")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -1956,6 +2028,10 @@
             |
             punct!(..) => { RangeLimits::HalfOpen }
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("range limit: `..`, `...` or `..=`")
+        }
     }
 
     impl Synom for ExprPath {
@@ -1967,6 +2043,10 @@
                 path: pair.1,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("path: `a::b::c`")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -1983,6 +2063,10 @@
                 brace_token: stmts.1,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("block: `{ .. }`")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -2025,6 +2109,10 @@
             |
             stmt_expr
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("statement")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -2127,6 +2215,10 @@
             |
             syn!(PatSlice) => { Pat::Slice }
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("pattern")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -2135,6 +2227,10 @@
             punct!(_),
             |u| PatWild { underscore_token: u }
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("wild pattern: `_`")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -2147,6 +2243,10 @@
                 box_token: boxed,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("box pattern")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -2169,6 +2269,10 @@
                 subpat: subpat.map(|(at, pat)| (at, Box::new(pat))),
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("pattern identifier binding")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -2181,6 +2285,10 @@
                 pat: tuple,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("tuple struct pattern")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -2199,6 +2307,10 @@
                 dot2_token: (data.0).1.and_then(|m| m),
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("struct pattern")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -2243,6 +2355,10 @@
                 })
             )
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("field pattern")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -2252,6 +2368,10 @@
             |
             syn!(Index) => { Member::Unnamed }
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("field member")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -2266,6 +2386,10 @@
                 }
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("field index")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -2274,6 +2398,10 @@
             syn!(ExprPath),
             |p| PatPath { qself: p.qself, path: p.path }
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("path pattern")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -2306,6 +2434,10 @@
                 }
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("tuple pattern")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -2320,6 +2452,10 @@
                 and_token: and,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("reference pattern")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -2334,6 +2470,10 @@
                 }
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("literal pattern")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -2348,6 +2488,10 @@
                 limits: limits,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("range pattern")
+        }
     }
 
     #[cfg(feature = "full")]
@@ -2410,11 +2554,19 @@
                 }
             }
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("slice pattern")
+        }
     }
 
     #[cfg(feature = "full")]
     impl Synom for PatMacro {
         named!(parse -> Self, map!(syn!(Macro), |mac| PatMacro { mac: mac }));
+
+        fn description() -> Option<&'static str> {
+            Some("macro pattern")
+        }
     }
 }
 
diff --git a/src/generics.rs b/src/generics.rs
index 70b3da4..9caf750 100644
--- a/src/generics.rs
+++ b/src/generics.rs
@@ -228,6 +228,10 @@
                 where_clause: None,
             }
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("generic parameters in declaration")
+        }
     }
 
     impl Synom for LifetimeDef {
@@ -246,6 +250,10 @@
                 colon_token: colon,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("lifetime definition")
+        }
     }
 
     impl Synom for BoundLifetimes {
@@ -261,6 +269,10 @@
                 lifetimes: lifetimes,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("bound lifetimes")
+        }
     }
 
     impl Synom for TypeParam {
@@ -286,6 +298,10 @@
                 default: default.map(|d| d.1),
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("type parameter")
+        }
     }
 
     impl Synom for TypeParamBound {
@@ -336,6 +352,10 @@
                 }
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("generic `const` parameter")
+        }
     }
 
     impl Synom for WhereClause {
@@ -382,6 +402,10 @@
                 }))
             )
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("predicate in where clause")
+        }
     }
 }
 
diff --git a/src/item.rs b/src/item.rs
index 1953756..82712d3 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -845,6 +845,10 @@
             |
             syn!(Type) => { FnArg::Ignored }
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("function argument")
+        }
     }
 
     impl_synom!(ItemMod "mod item" do_parse!(
diff --git a/src/lifetime.rs b/src/lifetime.rs
index 44359de..dabe581 100644
--- a/src/lifetime.rs
+++ b/src/lifetime.rs
@@ -115,6 +115,10 @@
                 },
             ))
         }
+
+        fn description() -> Option<&'static str> {
+            Some("lifetime")
+        }
     }
 }
 
diff --git a/src/lit.rs b/src/lit.rs
index 948a96c..83d9f9d 100644
--- a/src/lit.rs
+++ b/src/lit.rs
@@ -134,6 +134,10 @@
                 },
             }
         }
+
+        fn description() -> Option<&'static str> {
+            Some("literal")
+        }
     }
 }
 
diff --git a/src/mac.rs b/src/mac.rs
index a43c311..0f0b28d 100644
--- a/src/mac.rs
+++ b/src/mac.rs
@@ -185,6 +185,10 @@
                 tts: body.1,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("macro invocation")
+        }
     }
 }
 
diff --git a/src/op.rs b/src/op.rs
index 93c6073..275657d 100644
--- a/src/op.rs
+++ b/src/op.rs
@@ -148,6 +148,10 @@
             |
             punct!(-) => { UnOp::Neg }
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("unary operator: `*`, `!`, or `-`")
+        }
     }
 }
 
diff --git a/src/synom.rs b/src/synom.rs
index 5d2d1a4..cd2b622 100644
--- a/src/synom.rs
+++ b/src/synom.rs
@@ -39,4 +39,8 @@
     fn parse(input: Cursor) -> PResult<Self> {
         Ok((Cursor::empty(), input.token_stream()))
     }
+
+    fn description() -> Option<&'static str> {
+        Some("arbitrary token stream")
+    }
 }
diff --git a/src/token.rs b/src/token.rs
index 228396b..5419fe7 100644
--- a/src/token.rs
+++ b/src/token.rs
@@ -74,6 +74,10 @@
             fn parse(tokens: $crate::synom::Cursor) -> $crate::synom::PResult<$name> {
                 parsing::op($s, tokens, $name)
             }
+
+            fn description() -> Option<&'static str> {
+                Some(concat!("`", $s, "`"))
+            }
         }
     }
 }
diff --git a/src/ty.rs b/src/ty.rs
index 2aefaaa..9d2fa01 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -403,6 +403,10 @@
                 bracket_token: b,
             }
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("slice type")
+        }
     }
 
     impl Synom for TypeArray {
@@ -422,6 +426,10 @@
                 }
             }
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("array type")
+        }
     }
 
     impl Synom for TypePtr {
@@ -440,6 +448,10 @@
                 elem: Box::new(target),
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("raw pointer type")
+        }
     }
 
     impl Synom for TypeReference {
@@ -456,6 +468,10 @@
                 and_token: amp,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("reference type")
+        }
     }
 
     impl Synom for TypeBareFn {
@@ -481,6 +497,10 @@
                 inputs: (parens.0).0,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("`fn` type")
+        }
     }
 
     impl Synom for TypeNever {
@@ -488,6 +508,10 @@
             punct!(!),
             |b| TypeNever { bang_token: b }
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("never type: `!`")
+        }
     }
 
     impl Synom for TypeInfer {
@@ -495,6 +519,10 @@
             punct!(_),
             |u| TypeInfer { underscore_token: u }
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("inferred type: `_`")
+        }
     }
 
     impl Synom for TypeTuple {
@@ -505,6 +533,10 @@
                 paren_token: data.1,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("tuple type")
+        }
     }
 
     impl Synom for TypeMacro {
@@ -586,6 +618,10 @@
                 output: output,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("parenthesized generic arguments: `Foo(A, B, ..) -> T`")
+        }
     }
 
     impl Synom for ReturnType {
@@ -598,10 +634,18 @@
             |
             epsilon!() => { |_| ReturnType::Default }
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("return type")
+        }
     }
 
     impl Synom for TypeTraitObject {
         named!(parse -> Self, call!(Self::parse, true));
+
+        fn description() -> Option<&'static str> {
+            Some("trait object type")
+        }
     }
 
     impl TypeTraitObject {
@@ -633,6 +677,10 @@
                 bounds: elem,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("`impl Trait` type")
+        }
     }
 
     impl Synom for TypeGroup {
@@ -700,6 +748,10 @@
             |
             syn!(ExprBlock) => { |b| GenericArgument::Const(Expr::Block(b).into()) }
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("generic argument")
+        }
     }
 
     impl Synom for AngleBracketedGenericArguments {
@@ -715,6 +767,10 @@
                 gt_token: gt,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("angle bracketed generic arguments")
+        }
     }
 
     impl Synom for PathSegment {
@@ -730,6 +786,10 @@
             |
             mod_style_path_segment
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("path segment")
+        }
     }
 
     named!(pub ty_no_eq_after -> Type, do_parse!(
@@ -773,6 +833,10 @@
                 ty: ty,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("associated type binding")
+        }
     }
 
     impl Synom for PolyTraitRef {
@@ -796,6 +860,10 @@
                 }
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("poly trait reference")
+        }
     }
 
     impl Synom for BareFnArg {
@@ -812,6 +880,10 @@
                 ty: ty,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("function type argument")
+        }
     }
 
     impl Synom for BareFnArgName {
@@ -820,6 +892,10 @@
             |
             map!(punct!(_), BareFnArgName::Wild)
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("function argument name")
+        }
     }
 
     impl Synom for Abi {
@@ -832,6 +908,10 @@
                 name: name,
             })
         ));
+
+        fn description() -> Option<&'static str> {
+            Some("ABI qualifier")
+        }
     }
 }