Make ToTokens more lenient when generating tokens for invalid ASTs
diff --git a/src/expr.rs b/src/expr.rs
index db3fb55..3d4fbb3 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -527,7 +527,7 @@
             pub hi: Box<Expr>,
             pub limits: RangeLimits,
         }),
-        /// `[a, b, ..i, y, z]` is represented as:
+        /// `[a, b, i.., y, z]` is represented as:
         pub Slice(PatSlice {
             pub front: Delimited<Pat, tokens::Comma>,
             pub middle: Option<Box<Pat>>,
@@ -622,6 +622,16 @@
     }
 }
 
+#[cfg(any(feature = "parsing", feature = "printing"))]
+#[cfg(feature = "full")]
+fn arm_requires_comma(arm: &Arm) -> bool {
+    if let ExprKind::Block(ExprBlock { unsafety: Unsafety::Normal, .. }) = arm.body.node {
+        false
+    } else {
+        true
+    }
+}
+
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
@@ -1497,15 +1507,6 @@
     }
 
     #[cfg(feature = "full")]
-    fn arm_requires_comma(arm: &Arm) -> bool {
-        if let ExprKind::Block(ExprBlock { unsafety: Unsafety::Normal, .. }) = arm.body.node {
-            false
-        } else {
-            true
-        }
-    }
-
-    #[cfg(feature = "full")]
     impl Synom for Arm {
         named!(parse -> Self, do_parse!(
             attrs: many0!(call!(Attribute::parse_outer)) >>
@@ -2265,6 +2266,19 @@
     use attr::FilterAttrs;
     use quote::{Tokens, ToTokens};
 
+    /// If the given expression is a bare `ExprStruct`, wraps it in parenthesis
+    /// before appending it to `Tokens`.
+    #[cfg(feature = "full")]
+    fn wrap_bare_struct(tokens: &mut Tokens, e: &Expr) {
+        if let ExprKind::Struct(_) = e.node {
+            tokens::Paren::default().surround(tokens, |tokens| {
+                e.to_tokens(tokens);
+            });
+        } else {
+            e.to_tokens(tokens);
+        }
+    }
+
     impl ToTokens for Expr {
         #[cfg(feature = "full")]
         fn to_tokens(&self, tokens: &mut Tokens) {
@@ -2298,7 +2312,15 @@
                 InPlaceKind::In(ref _in) => {
                     _in.to_tokens(tokens);
                     self.place.to_tokens(tokens);
-                    self.value.to_tokens(tokens);
+                    // NOTE: The second operand must be in a block, add one if
+                    // it is not present.
+                    if let ExprKind::Block(_) = self.value.node {
+                        self.value.to_tokens(tokens);
+                    } else {
+                        tokens::Brace::default().surround(tokens, |tokens| {
+                            self.value.to_tokens(tokens);
+                        })
+                    }
                 }
             }
         }
@@ -2328,10 +2350,12 @@
             self.expr.to_tokens(tokens);
             self.dot_token.to_tokens(tokens);
             self.method.to_tokens(tokens);
-            self.colon2_token.to_tokens(tokens);
-            self.lt_token.to_tokens(tokens);
-            self.typarams.to_tokens(tokens);
-            self.gt_token.to_tokens(tokens);
+            if !self.typarams.is_empty() {
+                self.colon2_token.unwrap_or_default().to_tokens(tokens);
+                self.lt_token.unwrap_or_default().to_tokens(tokens);
+                self.typarams.to_tokens(tokens);
+                self.gt_token.unwrap_or_default().to_tokens(tokens);
+            }
             self.paren_token.surround(tokens, |tokens| {
                 self.args.to_tokens(tokens);
             });
@@ -2343,6 +2367,15 @@
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.paren_token.surround(tokens, |tokens| {
                 self.args.to_tokens(tokens);
+                // If we only have one argument, we need a trailing comma to
+                // distinguish ExprTup from ExprParen.
+                if self.args.len() == 1 && !self.args.trailing_delim() {
+                    tokens::Comma::default().to_tokens(tokens);
+                }
+                // XXX: Not sure how to handle this, but we never parse it yet.
+                // Is this for an expression like (0,)? Can't we use the
+                // trailing delimiter on Delimited for that? (,) isn't a valid
+                // expression as far as I know.
                 self.lone_comma.to_tokens(tokens);
             })
         }
@@ -2380,13 +2413,37 @@
     }
 
     #[cfg(feature = "full")]
+    fn maybe_wrap_else(tokens: &mut Tokens,
+                       else_token: &Option<tokens::Else>,
+                       if_false: &Option<Box<Expr>>)
+    {
+        if let Some(ref if_false) = *if_false {
+            else_token.unwrap_or_default().to_tokens(tokens);
+
+            // If we are not one of the valid expressions to exist in an else
+            // clause, wrap ourselves in a block.
+            match if_false.node {
+                ExprKind::If(_) |
+                ExprKind::IfLet(_) |
+                ExprKind::Block(_) => {
+                    if_false.to_tokens(tokens);
+                }
+                _ => {
+                    tokens::Brace::default().surround(tokens, |tokens| {
+                        if_false.to_tokens(tokens);
+                    });
+                }
+            }
+        }
+    }
+
+    #[cfg(feature = "full")]
     impl ToTokens for ExprIf {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.if_token.to_tokens(tokens);
-            self.cond.to_tokens(tokens);
+            wrap_bare_struct(tokens, &self.cond);
             self.if_true.to_tokens(tokens);
-            self.else_token.to_tokens(tokens);
-            self.if_false.to_tokens(tokens);
+            maybe_wrap_else(tokens, &self.else_token, &self.if_false);
         }
     }
 
@@ -2397,20 +2454,21 @@
             self.let_token.to_tokens(tokens);
             self.pat.to_tokens(tokens);
             self.eq_token.to_tokens(tokens);
-            self.expr.to_tokens(tokens);
+            wrap_bare_struct(tokens, &self.expr);
             self.if_true.to_tokens(tokens);
-            self.else_token.to_tokens(tokens);
-            self.if_false.to_tokens(tokens);
+            maybe_wrap_else(tokens, &self.else_token, &self.if_false);
         }
     }
 
     #[cfg(feature = "full")]
     impl ToTokens for ExprWhile {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            self.label.to_tokens(tokens);
-            self.colon_token.to_tokens(tokens);
+            if self.label.is_some() {
+                self.label.to_tokens(tokens);
+                self.colon_token.unwrap_or_default().to_tokens(tokens);
+            }
             self.while_token.to_tokens(tokens);
-            self.cond.to_tokens(tokens);
+            wrap_bare_struct(tokens, &self.cond);
             self.body.to_tokens(tokens);
         }
     }
@@ -2418,13 +2476,15 @@
     #[cfg(feature = "full")]
     impl ToTokens for ExprWhileLet {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            self.label.to_tokens(tokens);
-            self.colon_token.to_tokens(tokens);
+            if self.label.is_some() {
+                self.label.to_tokens(tokens);
+                self.colon_token.unwrap_or_default().to_tokens(tokens);
+            }
             self.while_token.to_tokens(tokens);
             self.let_token.to_tokens(tokens);
             self.pat.to_tokens(tokens);
             self.eq_token.to_tokens(tokens);
-            self.expr.to_tokens(tokens);
+            wrap_bare_struct(tokens, &self.expr);
             self.body.to_tokens(tokens);
         }
     }
@@ -2432,12 +2492,14 @@
     #[cfg(feature = "full")]
     impl ToTokens for ExprForLoop {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            self.label.to_tokens(tokens);
-            self.colon_token.to_tokens(tokens);
+            if self.label.is_some() {
+                self.label.to_tokens(tokens);
+                self.colon_token.unwrap_or_default().to_tokens(tokens);
+            }
             self.for_token.to_tokens(tokens);
             self.pat.to_tokens(tokens);
             self.in_token.to_tokens(tokens);
-            self.expr.to_tokens(tokens);
+            wrap_bare_struct(tokens, &self.expr);
             self.body.to_tokens(tokens);
         }
     }
@@ -2445,8 +2507,10 @@
     #[cfg(feature = "full")]
     impl ToTokens for ExprLoop {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            self.label.to_tokens(tokens);
-            self.colon_token.to_tokens(tokens);
+            if self.label.is_some() {
+                self.label.to_tokens(tokens);
+                self.colon_token.unwrap_or_default().to_tokens(tokens);
+            }
             self.loop_token.to_tokens(tokens);
             self.body.to_tokens(tokens);
         }
@@ -2456,9 +2520,17 @@
     impl ToTokens for ExprMatch {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.match_token.to_tokens(tokens);
-            self.expr.to_tokens(tokens);
+            wrap_bare_struct(tokens, &self.expr);
             self.brace_token.surround(tokens, |tokens| {
-                tokens.append_all(&self.arms);
+                for (i,  arm) in self.arms.iter().enumerate() {
+                    arm.to_tokens(tokens);
+                    // Ensure that we have a comma after a non-block arm, except
+                    // for the last one.
+                    let is_last = i == self.arms.len() - 1;
+                    if !is_last && arm_requires_comma(arm) && arm.comma.is_none() {
+                        tokens::Comma::default().to_tokens(tokens);
+                    }
+                }
             });
         }
     }
@@ -2531,6 +2603,8 @@
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.expr.to_tokens(tokens);
             self.dot_token.to_tokens(tokens);
+            // XXX: I don't think we can do anything if someone shoves a
+            // nonsense Lit in here.
             self.field.to_tokens(tokens);
         }
     }
@@ -2608,8 +2682,10 @@
             self.path.to_tokens(tokens);
             self.brace_token.surround(tokens, |tokens| {
                 self.fields.to_tokens(tokens);
-                self.dot2_token.to_tokens(tokens);
-                self.rest.to_tokens(tokens);
+                if self.rest.is_some() {
+                    self.dot2_token.unwrap_or_default().to_tokens(tokens);
+                    self.rest.to_tokens(tokens);
+                }
             })
         }
     }
@@ -2653,8 +2729,11 @@
     impl ToTokens for FieldValue {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.ident.to_tokens(tokens);
+            // XXX: Override self.is_shorthand if expr is not an IdentExpr with
+            // the ident self.ident?
             if !self.is_shorthand {
-                self.colon_token.to_tokens(tokens);
+                self.colon_token.unwrap_or_default()
+                    .to_tokens(tokens);
                 self.expr.to_tokens(tokens);
             }
         }
@@ -2665,8 +2744,10 @@
         fn to_tokens(&self, tokens: &mut Tokens) {
             tokens.append_all(&self.attrs);
             self.pats.to_tokens(tokens);
-            self.if_token.to_tokens(tokens);
-            self.guard.to_tokens(tokens);
+            if self.guard.is_some() {
+                self.if_token.unwrap_or_default().to_tokens(tokens);
+                self.guard.to_tokens(tokens);
+            }
             self.rocket_token.to_tokens(tokens);
             self.body.to_tokens(tokens);
             self.comma.to_tokens(tokens);
@@ -2685,8 +2766,10 @@
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.mode.to_tokens(tokens);
             self.ident.to_tokens(tokens);
-            self.at_token.to_tokens(tokens);
-            self.subpat.to_tokens(tokens);
+            if self.subpat.is_some() {
+                self.at_token.unwrap_or_default().to_tokens(tokens);
+                self.subpat.to_tokens(tokens);
+            }
         }
     }
 
@@ -2696,6 +2779,10 @@
             self.path.to_tokens(tokens);
             self.brace_token.surround(tokens, |tokens| {
                 self.fields.to_tokens(tokens);
+                // NOTE: We need a comma before the dot2 token if it is present.
+                if !self.fields.empty_or_trailing() && self.dot2_token.is_some() {
+                    tokens::Comma::default().to_tokens(tokens);
+                }
                 self.dot2_token.to_tokens(tokens);
             });
         }
@@ -2722,13 +2809,17 @@
             self.paren_token.surround(tokens, |tokens| {
                 for (i, token) in self.pats.iter().enumerate() {
                     if Some(i) == self.dots_pos {
-                        self.dot2_token.to_tokens(tokens);
-                        self.comma_token.to_tokens(tokens);
+                        self.dot2_token.unwrap_or_default().to_tokens(tokens);
+                        self.comma_token.unwrap_or_default().to_tokens(tokens);
                     }
                     token.to_tokens(tokens);
                 }
 
                 if Some(self.pats.len()) == self.dots_pos {
+                    // Ensure there is a comma before the .. token.
+                    if !self.pats.empty_or_trailing() {
+                        tokens::Comma::default().to_tokens(tokens);
+                    }
                     self.dot2_token.to_tokens(tokens);
                 }
             });
@@ -2771,12 +2862,34 @@
     #[cfg(feature = "full")]
     impl ToTokens for PatSlice {
         fn to_tokens(&self, tokens: &mut Tokens) {
+            // XXX: This is a mess, and it will be so easy to screw it up. How
+            // do we make this correct itself better?
             self.bracket_token.surround(tokens, |tokens| {
                 self.front.to_tokens(tokens);
-                self.middle.to_tokens(tokens);
-                self.dot2_token.to_tokens(tokens);
-                self.comma_token.to_tokens(tokens);
-                self.back.to_tokens(tokens);
+
+                // If we need a comma before the middle or standalone .. token,
+                // then make sure it's present.
+                if !self.front.empty_or_trailing() &&
+                    (self.middle.is_some() || self.dot2_token.is_some())
+                {
+                    tokens::Comma::default().to_tokens(tokens);
+                }
+
+                // If we have an identifier, we always need a .. token.
+                if self.middle.is_some() {
+                    self.middle.to_tokens(tokens);
+                    self.dot2_token.unwrap_or_default().to_tokens(tokens);
+                } else if self.dot2_token.is_some() {
+                    self.dot2_token.to_tokens(tokens);
+                }
+
+                // Make sure we have a comma before the back half.
+                if !self.back.is_empty() {
+                    self.comma_token.unwrap_or_default().to_tokens(tokens);
+                    self.back.to_tokens(tokens);
+                } else {
+                    self.comma_token.to_tokens(tokens);
+                }
             })
         }
     }
@@ -2794,9 +2907,10 @@
     #[cfg(feature = "full")]
     impl ToTokens for FieldPat {
         fn to_tokens(&self, tokens: &mut Tokens) {
+            // XXX: Override is_shorthand if it was wrong?
             if !self.is_shorthand {
                 self.ident.to_tokens(tokens);
-                self.colon_token.to_tokens(tokens);
+                self.colon_token.unwrap_or_default().to_tokens(tokens);
             }
             self.pat.to_tokens(tokens);
         }
@@ -2870,10 +2984,14 @@
             tokens.append_all(self.attrs.outer());
             self.let_token.to_tokens(tokens);
             self.pat.to_tokens(tokens);
-            self.colon_token.to_tokens(tokens);
-            self.ty.to_tokens(tokens);
-            self.eq_token.to_tokens(tokens);
-            self.init.to_tokens(tokens);
+            if self.ty.is_some() {
+                self.colon_token.unwrap_or_default().to_tokens(tokens);
+                self.ty.to_tokens(tokens);
+            }
+            if self.init.is_some() {
+                self.eq_token.unwrap_or_default().to_tokens(tokens);
+                self.init.to_tokens(tokens);
+            }
             self.semi_token.to_tokens(tokens);
         }
     }