Printing for attributes and types
diff --git a/src/attr.rs b/src/attr.rs
index 7b09b47..828006f 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -83,3 +83,41 @@
         map!(word, MetaItem::Word)
     ));
 }
+
+#[cfg(feature = "printing")]
+mod printing {
+    use super::*;
+    use quote::{Tokens, ToTokens};
+
+    impl ToTokens for Attribute {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            tokens.append("#[");
+            self.value.to_tokens(tokens);
+            tokens.append("]");
+        }
+    }
+
+    impl ToTokens for MetaItem {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            match *self {
+                MetaItem::Word(ref ident) => tokens.append(&ident),
+                MetaItem::List(ref ident, ref inner) => {
+                    tokens.append(&ident);
+                    tokens.append("(");
+                    for (i, meta_item) in inner.iter().enumerate() {
+                        if i > 0 {
+                            tokens.append(",");
+                        }
+                        meta_item.to_tokens(tokens);
+                    }
+                    tokens.append(")");
+                }
+                MetaItem::NameValue(ref name, ref value) => {
+                    tokens.append(&name);
+                    tokens.append("=");
+                    value.to_tokens(tokens);
+                }
+            }
+        }
+    }
+}
diff --git a/src/generics.rs b/src/generics.rs
index 80738ae..51f56b9 100644
--- a/src/generics.rs
+++ b/src/generics.rs
@@ -101,7 +101,9 @@
 
     named!(pub lifetime<&str, Lifetime>, preceded!(
         punct!("'"),
-        map!(word, |ident| Lifetime { ident: ident })
+        map!(word, |ident| Lifetime {
+            ident: format!("'{}", ident),
+        })
     ));
 
     named!(pub lifetime_def<&str, LifetimeDef>, do_parse!(
@@ -173,3 +175,40 @@
         )
     ));
 }
+
+#[cfg(feature = "printing")]
+mod printing {
+    use super::*;
+    use quote::{Tokens, ToTokens};
+
+    impl ToTokens for Lifetime {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            self.ident.to_tokens(tokens);
+        }
+    }
+
+    impl ToTokens for LifetimeDef {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            self.lifetime.to_tokens(tokens);
+            if !self.bounds.is_empty() {
+                tokens.append(":");
+                for (i, bound) in self.bounds.iter().enumerate() {
+                    if i > 0 {
+                        tokens.append("+");
+                    }
+                    bound.to_tokens(tokens);
+                }
+            }
+        }
+    }
+
+    impl ToTokens for TyParamBound {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            match *self {
+                TyParamBound::MaybeSized => tokens.append("?Sized"),
+                TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
+                TyParamBound::Trait(ref trait_ref) => trait_ref.to_tokens(tokens),
+            }
+        }
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 397b9e1..cd7b545 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,6 +2,9 @@
 #[macro_use]
 extern crate nom;
 
+#[cfg(feature = "printing")]
+extern crate quote;
+
 #[macro_use]
 mod do_parse;
 
diff --git a/src/ty.rs b/src/ty.rs
index cbc0bb1..3d1cb1d 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -410,3 +410,238 @@
         })
     ));
 }
+
+#[cfg(feature = "printing")]
+mod printing {
+    use super::*;
+    use quote::{Tokens, ToTokens};
+
+    impl ToTokens for Ty {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            match *self {
+                Ty::Vec(ref inner) => {
+                    tokens.append("[");
+                    inner.to_tokens(tokens);
+                    tokens.append("]");
+                }
+                Ty::FixedLengthVec(ref inner, len) => {
+                    tokens.append("[");
+                    inner.to_tokens(tokens);
+                    tokens.append(";");
+                    len.to_tokens(tokens);
+                    tokens.append("]");
+                }
+                Ty::Ptr(ref target) => {
+                    tokens.append("*");
+                    match target.mutability {
+                        Mutability::Mutable => tokens.append("mut"),
+                        Mutability::Immutable => tokens.append("const"),
+                    }
+                    target.ty.to_tokens(tokens);
+                }
+                Ty::Rptr(ref lifetime, ref target) => {
+                    tokens.append("&");
+                    lifetime.to_tokens(tokens);
+                    if let Mutability::Mutable = target.mutability {
+                        tokens.append("mut");
+                    }
+                    target.ty.to_tokens(tokens);
+                }
+                Ty::BareFn(ref func) => {
+                    func.to_tokens(tokens);
+                }
+                Ty::Never => {
+                    tokens.append("!");
+                }
+                Ty::Tup(ref elems) => {
+                    tokens.append("(");
+                    for (i, elem) in elems.iter().enumerate() {
+                        if i > 0 {
+                            tokens.append(",");
+                        }
+                        elem.to_tokens(tokens);
+                    }
+                    if elems.len() == 1 {
+                        tokens.append(",");
+                    }
+                    tokens.append(")");
+                }
+                Ty::Path(ref qself, ref path) => {
+                    match *qself {
+                        Some(ref qself) => {
+                            tokens.append("<");
+                            qself.ty.to_tokens(tokens);
+                            if qself.position > 0 {
+                                tokens.append("as");
+                                for (i, segment) in path.segments.iter()
+                                                        .take(qself.position)
+                                                        .enumerate()
+                                {
+                                    if i > 0 || path.global {
+                                        tokens.append("::");
+                                    }
+                                    segment.to_tokens(tokens);
+                                }
+                                for segment in path.segments.iter()
+                                                   .skip(qself.position)
+                                {
+                                    tokens.append("::");
+                                    segment.to_tokens(tokens);
+                                }
+                            }
+                            tokens.append(">");
+                        }
+                        None => path.to_tokens(tokens),
+                    }
+                }
+                Ty::ObjectSum(_, _) => unimplemented!(),
+                Ty::PolyTraitRef(_) => unimplemented!(),
+                Ty::ImplTrait(ref bounds) => {
+                    tokens.append("impl");
+                    for (i, bound) in bounds.iter().enumerate() {
+                        if i > 0 {
+                            tokens.append("+");
+                        }
+                        bound.to_tokens(tokens);
+                    }
+                }
+                Ty::Paren(ref inner) => {
+                    tokens.append("(");
+                    inner.to_tokens(tokens);
+                    tokens.append(")");
+                }
+                Ty::Infer => {
+                    tokens.append("_");
+                }
+            }
+        }
+    }
+
+    impl ToTokens for Path {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            for (i, segment) in self.segments.iter().enumerate() {
+                if i > 0 || self.global {
+                    tokens.append("::");
+                }
+                segment.to_tokens(tokens);
+            }
+        }
+    }
+
+    impl ToTokens for PathSegment {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            self.ident.to_tokens(tokens);
+            self.parameters.to_tokens(tokens);
+        }
+    }
+
+    impl ToTokens for PathParameters {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            match *self {
+                PathParameters::AngleBracketed(ref parameters) => {
+                    parameters.to_tokens(tokens);
+                }
+                PathParameters::Parenthesized(ref parameters) => {
+                    parameters.to_tokens(tokens);
+                }
+            }
+        }
+    }
+
+    impl ToTokens for AngleBracketedParameterData {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            let has_lifetimes = !self.lifetimes.is_empty();
+            let has_types = !self.types.is_empty();
+            let has_bindings = !self.bindings.is_empty();
+            if !has_lifetimes && !has_types && !has_bindings {
+                return;
+            }
+
+            tokens.append("<");
+
+            let mut first = true;
+            for lifetime in &self.lifetimes {
+                if !first {
+                    tokens.append(",");
+                }
+                lifetime.to_tokens(tokens);
+                first = false;
+            }
+            for ty in &self.types {
+                if !first {
+                    tokens.append(",");
+                }
+                ty.to_tokens(tokens);
+                first = false;
+            }
+            for binding in &self.bindings {
+                if !first {
+                    tokens.append(",");
+                }
+                binding.to_tokens(tokens);
+                first = false;
+            }
+
+            tokens.append(">");
+        }
+    }
+
+    impl ToTokens for TypeBinding {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            self.ident.to_tokens(tokens);
+            tokens.append("=");
+            self.ty.to_tokens(tokens);
+        }
+    }
+
+    impl ToTokens for ParenthesizedParameterData {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            tokens.append("(");
+            for (i, input) in self.inputs.iter().enumerate() {
+                if i > 0 {
+                    tokens.append(",");
+                }
+                input.to_tokens(tokens);
+            }
+            tokens.append(")");
+            if let Some(ref output) = self.output {
+                tokens.append("->");
+                output.to_tokens(tokens);
+            }
+        }
+    }
+
+    impl ToTokens for PolyTraitRef {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            if !self.bound_lifetimes.is_empty() {
+                tokens.append("<");
+                for (i, lifetime) in self.bound_lifetimes.iter().enumerate() {
+                    if i > 0 {
+                        tokens.append(",");
+                    }
+                    lifetime.to_tokens(tokens);
+                }
+                tokens.append(">");
+            }
+            self.trait_ref.to_tokens(tokens);
+        }
+    }
+
+    impl ToTokens for BareFnTy {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            tokens.append("fn");
+            if !self.lifetimes.is_empty() {
+                tokens.append("<");
+                for (i, lifetime) in self.lifetimes.iter().enumerate() {
+                    if i > 0 {
+                        tokens.append(",");
+                    }
+                    lifetime.to_tokens(tokens);
+                }
+                tokens.append(">");
+            }
+            tokens.append("(");
+            tokens.append(")");
+        }
+    }
+}