Implement atom_expr
diff --git a/src/expr.rs b/src/expr.rs
index 419a8c1..d4ce03a 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -1488,72 +1488,257 @@
     // Parse all atomic expressions which don't have to worry about precedence
     // interactions, as they are fully contained.
     #[cfg(feature = "full")]
-    named2!(atom_expr(allow_struct: AllowStruct, allow_block: AllowBlock) -> Expr, alt!(
-        syn!(ExprGroup) => { Expr::Group } // must be placed first
-        |
-        syn!(ExprLit) => { Expr::Lit } // must be before expr_struct
-        |
-        // must be before ExprStruct
-        syn!(ExprAsync) => { Expr::Async }
-        |
-        // must be before ExprStruct
-        syn!(ExprTryBlock) => { Expr::TryBlock }
-        |
-        // must be before expr_path
-        cond_reduce!(allow_struct.0, syn!(ExprStruct)) => { Expr::Struct }
-        |
-        syn!(ExprParen) => { Expr::Paren } // must be before expr_tup
-        |
-        syn!(ExprMacro) => { Expr::Macro } // must be before expr_path
-        |
-        shim!(expr_break, allow_struct) => { Expr::Break } // must be before expr_path
-        |
-        syn!(ExprContinue) => { Expr::Continue } // must be before expr_path
-        |
-        shim!(expr_ret, allow_struct) => { Expr::Return } // must be before expr_path
-        |
-        syn!(ExprArray) => { Expr::Array }
-        |
-        syn!(ExprTuple) => { Expr::Tuple }
-        |
-        syn!(ExprIf) => { Expr::If }
-        |
-        syn!(ExprIfLet) => { Expr::IfLet }
-        |
-        syn!(ExprWhile) => { Expr::While }
-        |
-        syn!(ExprWhileLet) => { Expr::WhileLet }
-        |
-        syn!(ExprForLoop) => { Expr::ForLoop }
-        |
-        syn!(ExprLoop) => { Expr::Loop }
-        |
-        syn!(ExprMatch) => { Expr::Match }
-        |
-        syn!(ExprYield) => { Expr::Yield }
-        |
-        syn!(ExprUnsafe) => { Expr::Unsafe }
-        |
-        shim!(expr_closure, allow_struct) => { Expr::Closure }
-        |
-        cond_reduce!(allow_block.0, syn!(ExprBlock)) => { Expr::Block }
-        |
-        // NOTE: This is the prefix-form of range
-        shim!(expr_range, allow_struct) => { Expr::Range }
-        |
-        syn!(ExprPath) => { Expr::Path }
-        |
-        syn!(ExprRepeat) => { Expr::Repeat }
-    ));
+    fn atom_expr(input: ParseStream, allow_struct: AllowStruct, allow_block: AllowBlock) -> Result<Expr> {
+        if input.peek(token::Group) {
+            return input.parse().map(Expr::Group);
+        }
+
+        let mut attrs = input.call(Attribute::parse_outer)?;
+
+        let mut expr = if input.peek(token::Group) {
+            Expr::Group(input.parse()?)
+        } else if input.peek(Lit) {
+            Expr::Lit(input.parse()?)
+        } else if input.peek(Token![async])
+            && (input.peek2(token::Brace) || input.peek2(Token![move]) && input.peek3(token::Brace))
+        {
+            Expr::Async(input.parse()?)
+        } else if input.peek(Token![try]) && input.peek2(token::Brace) {
+            Expr::TryBlock(input.parse()?)
+        } else if input.peek(Token![|])
+            || input.peek(Token![async]) && (input.peek2(Token![|]) || input.peek2(Token![move]))
+            || input.peek(Token![static])
+            || input.peek(Token![move])
+        {
+            Expr::Closure(expr_closure(input, allow_struct)?)
+        } else if input.peek(Ident)
+            || input.peek(Token![::])
+            || input.peek(Token![<])
+            || input.peek(Token![self])
+            || input.peek(Token![Self])
+            || input.peek(Token![super])
+            || input.peek(Token![extern])
+            || input.peek(Token![crate])
+        {
+            path_or_macro_or_struct(input, allow_struct)?
+        } else if input.peek(token::Paren) {
+            paren_or_tuple(input)?
+        } else if input.peek(Token![break]) {
+            Expr::Break(expr_break(input, allow_struct)?)
+        } else if input.peek(Token![continue]) {
+            Expr::Continue(input.parse()?)
+        } else if input.peek(Token![return]) {
+            Expr::Return(expr_ret(input, allow_struct)?)
+        } else if input.peek(token::Bracket) {
+            array_or_repeat(input)?
+        } else if input.peek(Token![if]) {
+            if input.peek2(Token![let]) {
+                Expr::IfLet(input.parse()?)
+            } else {
+                Expr::If(input.parse()?)
+            }
+        } else if input.peek(Token![while]) {
+            if input.peek2(Token![let]) {
+                Expr::WhileLet(input.parse()?)
+            } else {
+                Expr::While(input.parse()?)
+            }
+        } else if input.peek(Token![for]) {
+            Expr::ForLoop(input.parse()?)
+        } else if input.peek(Token![loop]) {
+            Expr::Loop(input.parse()?)
+        } else if input.peek(Token![match]) {
+            Expr::Match(input.parse()?)
+        } else if input.peek(Token![yield]) {
+            Expr::Yield(input.parse()?)
+        } else if input.peek(Token![unsafe]) {
+            Expr::Unsafe(input.parse()?)
+        } else if allow_block.0 && input.peek(token::Brace) {
+            Expr::Block(input.parse()?)
+        } else if input.peek(Token![..]) {
+            Expr::Range(expr_range(input, allow_struct)?)
+        } else if input.peek(Lifetime) {
+            let the_label: Label = input.parse()?;
+            let mut expr = if input.peek(Token![while]) {
+                if input.peek2(Token![let]) {
+                    Expr::WhileLet(input.parse()?)
+                } else {
+                    Expr::While(input.parse()?)
+                }
+            } else if input.peek(Token![for]) {
+                Expr::ForLoop(input.parse()?)
+            } else if input.peek(Token![loop]) {
+                Expr::Loop(input.parse()?)
+            } else if input.peek(token::Brace) {
+                Expr::Block(input.parse()?)
+            } else {
+                return Err(input.error("expected loop or block expression"));
+            };
+            match expr {
+                Expr::WhileLet(ExprWhileLet { ref mut label, .. }) |
+                Expr::While(ExprWhile { ref mut label, .. }) |
+                Expr::ForLoop(ExprForLoop { ref mut label, .. }) |
+                Expr::Loop(ExprLoop { ref mut label, .. }) |
+                Expr::Block(ExprBlock { ref mut label, .. }) => *label = Some(the_label),
+                _ => unreachable!(),
+            }
+            expr
+        } else {
+            return Err(input.error("expected expression"));
+        };
+
+        attrs.extend(expr.replace_attrs(Vec::new()));
+        expr.replace_attrs(attrs);
+        Ok(expr)
+    }
 
     #[cfg(not(feature = "full"))]
-    named2!(atom_expr(_allow_struct: AllowStruct, _allow_block: AllowBlock) -> Expr, alt!(
-        syn!(ExprLit) => { Expr::Lit }
-        |
-        syn!(ExprParen) => { Expr::Paren }
-        |
-        syn!(ExprPath) => { Expr::Path }
-    ));
+    fn atom_expr(input: ParseStream, allow_struct: AllowStruct, allow_block: AllowBlock) -> Result<Expr> {
+        if input.peek(Lit) {
+            input.parse().map(Expr::Lit)
+        } else if input.peek(token::Paren) {
+            input.parse().map(Expr::Paren)
+        } else if input.peek(Ident)
+            || input.peek(Token![::])
+            || input.peek(Token![<])
+            || input.peek(Token![self])
+            || input.peek(Token![Self])
+            || input.peek(Token![super])
+            || input.peek(Token![extern])
+            || input.peek(Token![crate])
+        {
+            input.parse().map(Expr::Path)
+        } else {
+            Err(input.error("unsupported expression; enable syn's features=[\"full\"]"))
+        }
+    }
+
+    #[cfg(feature = "full")]
+    fn path_or_macro_or_struct(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> {
+        let expr: ExprPath = input.parse()?;
+        if expr.qself.is_some() {
+            return Ok(Expr::Path(expr));
+        }
+
+        if input.peek(Token![!]) && !input.peek(Token![!=]) {
+            let mut contains_arguments = false;
+            for segment in &expr.path.segments {
+                match segment.arguments {
+                    PathArguments::None => {}
+                    PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => {
+                        contains_arguments = true;
+                    }
+                }
+            }
+
+            if !contains_arguments {
+                let bang_token: Token![!] = input.parse()?;
+                let (delimiter, tts) = mac::parse_delimiter(input)?;
+                return Ok(Expr::Macro(ExprMacro {
+                    attrs: Vec::new(),
+                    mac: Macro {
+                        path: expr.path,
+                        bang_token: bang_token,
+                        delimiter: delimiter,
+                        tts: tts,
+                    },
+                }));
+            }
+        }
+
+        if allow_struct.0 && input.peek(token::Brace) {
+            let outer_attrs = Vec::new();
+            expr_struct_helper(input, outer_attrs, expr.path).map(Expr::Struct)
+        } else {
+            Ok(Expr::Path(expr))
+        }
+    }
+
+    #[cfg(feature = "full")]
+    fn paren_or_tuple(input: ParseStream) -> Result<Expr> {
+        let content;
+        let paren_token = parenthesized!(content in input);
+        let inner_attrs = content.call(Attribute::parse_inner)?;
+        if content.is_empty() {
+            return Ok(Expr::Tuple(ExprTuple {
+                attrs: inner_attrs,
+                paren_token: paren_token,
+                elems: Punctuated::new(),
+            }));
+        }
+
+        let first: Expr = content.parse()?;
+        if content.is_empty() {
+            return Ok(Expr::Paren(ExprParen {
+                attrs: inner_attrs,
+                paren_token: paren_token,
+                expr: Box::new(first),
+            }));
+        }
+
+        let mut elems = Punctuated::new();
+        elems.push_value(first);
+        while !content.is_empty() {
+            let punct = content.parse()?;
+            elems.push_punct(punct);
+            if content.is_empty() {
+                break;
+            }
+            let value = content.parse()?;
+            elems.push_value(value);
+        }
+        Ok(Expr::Tuple(ExprTuple {
+            attrs: inner_attrs,
+            paren_token: paren_token,
+            elems: elems,
+        }))
+    }
+
+    #[cfg(feature = "full")]
+    fn array_or_repeat(input: ParseStream) -> Result<Expr> {
+        let content;
+        let bracket_token = bracketed!(content in input);
+        let inner_attrs = content.call(Attribute::parse_inner)?;
+        if content.is_empty() {
+            return Ok(Expr::Array(ExprArray {
+                attrs: inner_attrs,
+                bracket_token: bracket_token,
+                elems: Punctuated::new(),
+            }));
+        }
+
+        let first: Expr = content.parse()?;
+        if content.is_empty() || content.peek(Token![,]) {
+            let mut elems = Punctuated::new();
+            elems.push_value(first);
+            while !content.is_empty() {
+                let punct = content.parse()?;
+                elems.push_punct(punct);
+                if content.is_empty() {
+                    break;
+                }
+                let value = content.parse()?;
+                elems.push_value(value);
+            }
+            Ok(Expr::Array(ExprArray {
+                attrs: inner_attrs,
+                bracket_token: bracket_token,
+                elems: elems,
+            }))
+        } else if content.peek(Token![;]) {
+            let semi_token: Token![;] = content.parse()?;
+            let len: Expr = content.parse()?;
+            Ok(Expr::Repeat(ExprRepeat {
+                attrs: inner_attrs,
+                bracket_token: bracket_token,
+                expr: Box::new(first),
+                semi_token: semi_token,
+                len: Box::new(len),
+            }))
+        } else {
+            Err(content.error("expected `,` or `;`"))
+        }
+    }
 
     #[cfg(feature = "full")]
     fn expr_early(input: ParseStream) -> Result<Expr> {
@@ -2225,72 +2410,77 @@
             let outer_attrs = input.call(Attribute::parse_outer)?;
             let path: Path = input.parse()?;
 
-            let content;
-            let brace_token = braced!(content in input);
-            let inner_attrs = content.call(Attribute::parse_inner)?;
+            expr_struct_helper(input, outer_attrs, path)
+        }
+    }
 
-            let mut fields = Punctuated::new();
-            loop {
-                let attrs = content.call(Attribute::parse_outer)?;
-                if content.fork().parse::<Member>().is_err() {
-                    if attrs.is_empty() {
-                        break;
-                    } else {
-                        return Err(content.error("expected struct field"));
-                    }
-                }
+    #[cfg(feature = "full")]
+    fn expr_struct_helper(input: ParseStream, outer_attrs: Vec<Attribute>, path: Path) -> Result<ExprStruct> {
+        let content;
+        let brace_token = braced!(content in input);
+        let inner_attrs = content.call(Attribute::parse_inner)?;
 
-                let member: Member = content.parse()?;
-                let (colon_token, value) = if content.peek(Token![:]) || !member.is_named() {
-                    let colon_token: Token![:] = content.parse()?;
-                    let value: Expr = content.parse()?;
-                    (Some(colon_token), value)
-                } else if let Member::Named(ref ident) = member {
-                    let value = Expr::Path(ExprPath {
-                        attrs: Vec::new(),
-                        qself: None,
-                        path: Path::from(ident.clone()),
-                    });
-                    (None, value)
-                } else {
-                    unreachable!()
-                };
-
-                fields.push(FieldValue {
-                    attrs: attrs,
-                    member: member,
-                    colon_token: colon_token,
-                    expr: value,
-                });
-
-                if !content.peek(Token![,]) {
+        let mut fields = Punctuated::new();
+        loop {
+            let attrs = content.call(Attribute::parse_outer)?;
+            if content.fork().parse::<Member>().is_err() {
+                if attrs.is_empty() {
                     break;
+                } else {
+                    return Err(content.error("expected struct field"));
                 }
-                let punct: Token![,] = content.parse()?;
-                fields.push_punct(punct);
             }
 
-            let (dot2_token, rest) = if fields.empty_or_trailing() && content.peek(Token![..]) {
-                let dot2_token: Token![..] = content.parse()?;
-                let rest: Expr = content.parse()?;
-                (Some(dot2_token), Some(Box::new(rest)))
+            let member: Member = content.parse()?;
+            let (colon_token, value) = if content.peek(Token![:]) || !member.is_named() {
+                let colon_token: Token![:] = content.parse()?;
+                let value: Expr = content.parse()?;
+                (Some(colon_token), value)
+            } else if let Member::Named(ref ident) = member {
+                let value = Expr::Path(ExprPath {
+                    attrs: Vec::new(),
+                    qself: None,
+                    path: Path::from(ident.clone()),
+                });
+                (None, value)
             } else {
-                (None, None)
+                unreachable!()
             };
 
-            Ok(ExprStruct {
-                attrs: {
-                    let mut attrs = outer_attrs;
-                    attrs.extend(inner_attrs);
-                    attrs
-                },
-                brace_token: brace_token,
-                path: path,
-                fields: fields,
-                dot2_token: dot2_token,
-                rest: rest,
-            })
+            fields.push(FieldValue {
+                attrs: attrs,
+                member: member,
+                colon_token: colon_token,
+                expr: value,
+            });
+
+            if !content.peek(Token![,]) {
+                break;
+            }
+            let punct: Token![,] = content.parse()?;
+            fields.push_punct(punct);
         }
+
+        let (dot2_token, rest) = if fields.empty_or_trailing() && content.peek(Token![..]) {
+            let dot2_token: Token![..] = content.parse()?;
+            let rest: Expr = content.parse()?;
+            (Some(dot2_token), Some(Box::new(rest)))
+        } else {
+            (None, None)
+        };
+
+        Ok(ExprStruct {
+            attrs: {
+                let mut attrs = outer_attrs;
+                attrs.extend(inner_attrs);
+                attrs
+            },
+            brace_token: brace_token,
+            path: path,
+            fields: fields,
+            dot2_token: dot2_token,
+            rest: rest,
+        })
     }
 
     #[cfg(feature = "full")]