Closure parsing
diff --git a/src/expr.rs b/src/expr.rs
index c3c90ea..65a3902 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -39,39 +39,39 @@
     /// An `if` block, with an optional else block
     ///
     /// `if expr { block } else { expr }`
-    If(Box<Expr>, Box<Block>, Option<Box<Expr>>),
+    If(Box<Expr>, Block, Option<Box<Expr>>),
     /// An `if let` expression with an optional else block
     ///
     /// `if let pat = expr { block } else { expr }`
     ///
     /// This is desugared to a `match` expression.
-    IfLet(Box<Pat>, Box<Expr>, Box<Block>, Option<Box<Expr>>),
+    IfLet(Box<Pat>, Box<Expr>, Block, Option<Box<Expr>>),
     /// A while loop, with an optional label
     ///
     /// `'label: while expr { block }`
-    While(Box<Expr>, Box<Block>, Option<Ident>),
+    While(Box<Expr>, Block, Option<Ident>),
     /// A while-let loop, with an optional label
     ///
     /// `'label: while let pat = expr { block }`
     ///
     /// This is desugared to a combination of `loop` and `match` expressions.
-    WhileLet(Box<Pat>, Box<Expr>, Box<Block>, Option<Ident>),
+    WhileLet(Box<Pat>, Box<Expr>, Block, Option<Ident>),
     /// A for loop, with an optional label
     ///
     /// `'label: for pat in expr { block }`
     ///
     /// This is desugared to a combination of `loop` and `match` expressions.
-    ForLoop(Box<Pat>, Box<Expr>, Box<Block>, Option<Ident>),
+    ForLoop(Box<Pat>, Box<Expr>, Block, Option<Ident>),
     /// Conditionless loop (can be exited with break, continue, or return)
     ///
     /// `'label: loop { block }`
-    Loop(Box<Block>, Option<Ident>),
+    Loop(Block, Option<Ident>),
     /// A `match` block.
     Match(Box<Expr>, Vec<Arm>),
     /// A closure (for example, `move |a, b, c| {a + b + c}`)
-    Closure(CaptureBy, Box<FnDecl>, Box<Block>),
-    /// A block (`{ ... }`)
-    Block(Box<Block>),
+    Closure(CaptureBy, Box<FnDecl>, Block),
+    /// A block (`{ ... }` or `unsafe { ... }`)
+    Block(BlockCheckMode, Block),
 
     /// An assignment (`a = foo()`)
     Assign(Box<Expr>, Box<Expr>),
@@ -135,8 +135,6 @@
 pub struct Block {
     /// Statements in a block
     pub stmts: Vec<Stmt>,
-    /// Distinguishes between `unsafe { ... }` and `{ ... }`
-    pub rules: BlockCheckMode,
 }
 
 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
@@ -336,15 +334,17 @@
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
-    use {Ident, Lifetime, Ty};
+    use {FnArg, FnDecl, FunctionRetTy, Ident, Lifetime, Path, QSelf, Ty};
     use attr::parsing::outer_attr;
     use generics::parsing::lifetime;
     use ident::parsing::ident;
     use lit::parsing::lit;
-    use ty::parsing::{mutability, ty};
+    use ty::parsing::{mutability, path, path_segment, ty};
 
     named!(pub expr -> Expr, do_parse!(
         mut e: alt!(
+            expr_paren
+            |
             expr_box
             |
             expr_vec
@@ -367,10 +367,14 @@
             expr_loop
             |
             expr_match
-            // TODO: Closure
+            |
+            expr_closure
             |
             expr_block
-            // TODO: Path
+            |
+            expr_path
+            |
+            expr_qpath
             // TODO: AddrOf
             |
             expr_break
@@ -381,7 +385,6 @@
             // TODO: Mac
             // TODO: Struct
             // TODO: Repeat
-            // TODO: Pparen
         ) >>
         many0!(alt!(
             tap!(args: and_call => {
@@ -417,6 +420,13 @@
         (e)
     ));
 
+    named!(expr_paren -> Expr, do_parse!(
+        punct!("(") >>
+        e: expr >>
+        punct!(")") >>
+        (Expr::Paren(Box::new(e)))
+    ));
+
     named!(expr_box -> Expr, do_parse!(
         keyword!("box") >>
         inner: expr >>
@@ -454,6 +464,7 @@
     named!(expr_tup -> Expr, do_parse!(
         punct!("(") >>
         elems: separated_list!(punct!(","), expr) >>
+        option!(punct!(",")) >>
         punct!(")") >>
         (Expr::Tup(elems))
     ));
@@ -536,19 +547,17 @@
                     punct!("{") >>
                     else_block: within_block >>
                     punct!("}") >>
-                    (Expr::Block(Box::new(Block {
+                    (Expr::Block(BlockCheckMode::Default, Block {
                         stmts: else_block,
-                        rules: BlockCheckMode::Default,
-                    })))
+                    }))
                 )
             )
         )) >>
         (Expr::If(
             Box::new(cond),
-            Box::new(Block {
+            Block {
                 stmts: then_block,
-                rules: BlockCheckMode::Default,
-            }),
+            },
             else_block.map(Box::new),
         ))
     ));
@@ -557,10 +566,7 @@
         lbl: option!(terminated!(label, punct!(":"))) >>
         keyword!("loop") >>
         loop_block: block >>
-        (Expr::Loop(
-            Box::new(loop_block),
-            lbl,
-        ))
+        (Expr::Loop(loop_block, lbl))
     ));
 
     named!(expr_match -> Expr, do_parse!(
@@ -575,7 +581,7 @@
             body: alt!(
                 terminated!(expr, punct!(","))
                 |
-                map!(block, |blk| Expr::Block(Box::new(blk)))
+                map!(block, |blk| Expr::Block(BlockCheckMode::Default, blk))
             ) >>
             (Arm {
                 attrs: attrs,
@@ -588,6 +594,45 @@
         (Expr::Match(Box::new(obj), arms))
     ));
 
+    named!(expr_closure -> Expr, do_parse!(
+        capture: capture_by >>
+        punct!("|") >>
+        inputs: separated_list!(punct!(","), closure_arg) >>
+        punct!("|") >>
+        ret_and_body: alt!(
+            do_parse!(
+                punct!("->") >>
+                ty: ty >>
+                body: block >>
+                ((FunctionRetTy::Ty(ty), body))
+            )
+            |
+            map!(expr, |e| (
+                FunctionRetTy::Default,
+                Block {
+                    stmts: vec![Stmt::Expr(Box::new(e))],
+                },
+            ))
+        ) >>
+        (Expr::Closure(
+            capture,
+            Box::new(FnDecl {
+                inputs: inputs,
+                output: ret_and_body.0,
+            }),
+            ret_and_body.1,
+        ))
+    ));
+
+    named!(closure_arg -> FnArg, do_parse!(
+        pat: pat >>
+        ty: option!(preceded!(punct!(":"), ty)) >>
+        (FnArg {
+            pat: pat,
+            ty: ty.unwrap_or(Ty::Infer),
+        })
+    ));
+
     named!(expr_while -> Expr, do_parse!(
         lbl: option!(terminated!(label, punct!(":"))) >>
         keyword!("while") >>
@@ -595,7 +640,7 @@
         while_block: block >>
         (Expr::While(
             Box::new(cond),
-            Box::new(while_block),
+            while_block,
             lbl,
         ))
     ));
@@ -627,10 +672,38 @@
     named!(expr_block -> Expr, do_parse!(
         rules: block_check_mode >>
         b: block >>
-        (Expr::Block(Box::new(Block {
+        (Expr::Block(rules, Block {
             stmts: b.stmts,
-            rules: rules,
-        })))
+        }))
+    ));
+
+    named!(expr_path -> Expr, map!(path, |p| Expr::Path(None, p)));
+
+    named!(expr_qpath -> Expr, do_parse!(
+        punct!("<") >>
+        this: map!(ty, Box::new) >>
+        path: option!(preceded!(
+            keyword!("as"),
+            path
+        )) >>
+        punct!(">") >>
+        punct!("::") >>
+        rest: separated_nonempty_list!(punct!("::"), path_segment) >>
+        ({
+            match path {
+                Some(mut path) => {
+                    let pos = path.segments.len();
+                    path.segments.extend(rest);
+                    Expr::Path(Some(QSelf { ty: this, position: pos }), path)
+                }
+                None => {
+                    Expr::Path(Some(QSelf { ty: this, position: 0 }), Path {
+                        global: false,
+                        segments: rest,
+                    })
+                }
+            }
+        })
     ));
 
     named!(pub block -> Block, do_parse!(
@@ -639,7 +712,6 @@
         punct!("}") >>
         (Block {
             stmts: stmts,
-            rules: BlockCheckMode::Default,
         })
     ));
 
@@ -709,13 +781,19 @@
         ))
     ));
 
+    named!(capture_by -> CaptureBy, alt!(
+        keyword!("move") => { |_| CaptureBy::Value }
+        |
+        epsilon!() => { |_| CaptureBy::Ref }
+    ));
+
     named!(label -> Ident, map!(lifetime, |lt: Lifetime| lt.ident));
 }
 
 #[cfg(feature = "printing")]
 mod printing {
     use super::*;
-    use Mutability;
+    use {FunctionRetTy, Mutability, Ty};
     use quote::{Tokens, ToTokens};
 
     impl ToTokens for Expr {
@@ -733,7 +811,11 @@
                     }
                     tokens.append(")");
                 }
-                Expr::Binary(_op, ref _left, ref _right) => unimplemented!(),
+                Expr::Binary(op, ref left, ref right) => {
+                    left.to_tokens(tokens);
+                    op.to_tokens(tokens);
+                    right.to_tokens(tokens);
+                }
                 Expr::Unary(_op, ref _expr) => unimplemented!(),
                 Expr::Lit(ref lit) => lit.to_tokens(tokens),
                 Expr::Cast(ref _expr, ref _ty) => unimplemented!(),
@@ -751,15 +833,76 @@
                     tokens.append_separated(arms, ",");
                     tokens.append("}");
                 }
-                Expr::Closure(_capture, ref _decl, ref _body) => unimplemented!(),
-                Expr::Block(ref _block) => unimplemented!(),
+                Expr::Closure(capture, ref decl, ref body) => {
+                    capture.to_tokens(tokens);
+                    tokens.append("|");
+                    for (i, input) in decl.inputs.iter().enumerate() {
+                        if i > 0 {
+                            tokens.append(",");
+                        }
+                        input.pat.to_tokens(tokens);
+                        match input.ty {
+                            Ty::Infer => { /* nothing */ }
+                            _ => {
+                                tokens.append(":");
+                                input.ty.to_tokens(tokens);
+                            }
+                        }
+                    }
+                    tokens.append("|");
+                    match decl.output {
+                        FunctionRetTy::Default => {
+                            if body.stmts.len() == 1 {
+                                if let Stmt::Expr(ref expr) = body.stmts[0] {
+                                    expr.to_tokens(tokens);
+                                } else {
+                                    body.to_tokens(tokens);
+                                }
+                            } else {
+                                body.to_tokens(tokens);
+                            }
+                        }
+                        FunctionRetTy::Ty(ref ty) => {
+                            tokens.append("->");
+                            ty.to_tokens(tokens);
+                            body.to_tokens(tokens);
+                        }
+                    }
+                }
+                Expr::Block(rules, ref block) => {
+                    rules.to_tokens(tokens);
+                    block.to_tokens(tokens);
+                }
                 Expr::Assign(ref _var, ref _expr) => unimplemented!(),
                 Expr::AssignOp(_op, ref _var, ref _expr) => unimplemented!(),
                 Expr::Field(ref _expr, ref _field) => unimplemented!(),
                 Expr::TupField(ref _expr, _field) => unimplemented!(),
                 Expr::Index(ref _expr, ref _index) => unimplemented!(),
                 Expr::Range(ref _from, ref _to, _limits) => unimplemented!(),
-                Expr::Path(ref _qself, ref _path) => unimplemented!(),
+                Expr::Path(None, ref path) => {
+                    path.to_tokens(tokens);
+                }
+                Expr::Path(Some(ref qself), ref path) => {
+                    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);
+                        }
+                    }
+                    tokens.append(">");
+                    for segment in path.segments.iter().skip(qself.position) {
+                        tokens.append("::");
+                        segment.to_tokens(tokens);
+                    }
+                }
                 Expr::AddrOf(_mutability, ref _expr) => unimplemented!(),
                 Expr::Break(ref _label) => unimplemented!(),
                 Expr::Continue(ref _label) => unimplemented!(),
@@ -770,12 +913,41 @@
                 Expr::Mac(ref _mac) => unimplemented!(),
                 Expr::Struct(ref _path, ref _fields, ref _base) => unimplemented!(),
                 Expr::Repeat(ref _expr, ref _times) => unimplemented!(),
-                Expr::Paren(ref _inner) => unimplemented!(),
+                Expr::Paren(ref expr) => {
+                    tokens.append("(");
+                    expr.to_tokens(tokens);
+                    tokens.append(")");
+                }
                 Expr::Try(ref _expr) => unimplemented!(),
             }
         }
     }
 
+    impl ToTokens for BinOp {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            match *self {
+                BinOp::Add => tokens.append("+"),
+                BinOp::Sub => tokens.append("-"),
+                BinOp::Mul => tokens.append("*"),
+                BinOp::Div => tokens.append("/"),
+                BinOp::Rem => tokens.append("%"),
+                BinOp::And => tokens.append("&&"),
+                BinOp::Or => tokens.append("||"),
+                BinOp::BitXor => tokens.append("^"),
+                BinOp::BitAnd => tokens.append("&"),
+                BinOp::BitOr => tokens.append("|"),
+                BinOp::Shl => tokens.append("<<"),
+                BinOp::Shr => tokens.append(">>"),
+                BinOp::Eq => tokens.append("=="),
+                BinOp::Lt => tokens.append("<"),
+                BinOp::Le => tokens.append("<="),
+                BinOp::Ne => tokens.append("!="),
+                BinOp::Ge => tokens.append(">="),
+                BinOp::Gt => tokens.append(">"),
+            }
+        }
+    }
+
     impl ToTokens for Arm {
         fn to_tokens(&self, tokens: &mut Tokens) {
             for attr in &self.attrs {
@@ -789,7 +961,7 @@
             tokens.append("=>");
             self.body.to_tokens(tokens);
             match *self.body {
-                Expr::Block(_) => { /* no comma */ }
+                Expr::Block(_, _) => { /* no comma */ }
                 _ => tokens.append(","),
             }
         }
@@ -839,9 +1011,17 @@
         }
     }
 
+    impl ToTokens for CaptureBy {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            match *self {
+                CaptureBy::Value => tokens.append("move"),
+                CaptureBy::Ref => { /* nothing */ }
+            }
+        }
+    }
+
     impl ToTokens for Block {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            self.rules.to_tokens(tokens);
             tokens.append("{");
             for stmt in &self.stmts {
                 stmt.to_tokens(tokens);
@@ -853,7 +1033,7 @@
     impl ToTokens for BlockCheckMode {
         fn to_tokens(&self, tokens: &mut Tokens) {
             match *self {
-                BlockCheckMode::Default => { /* nothing */ },
+                BlockCheckMode::Default => { /* nothing */ }
                 BlockCheckMode::Unsafe => tokens.append("unsafe"),
             }
         }