summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorKevin Ballard <kevin@sb.org>2014-08-24 19:08:48 -0700
committerJakub Wieczorek <jakub@jakub.cc>2014-09-30 18:54:02 +0200
commit0e6ff432dc83e5675163b1c29ce73dbc5e18ba24 (patch)
tree032c5323eb135364686c52ab01695e397f4a7c94 /src/libsyntax
parent5d8cfd53b513d999ffff22f17e3066a30a8ed949 (diff)
downloadrust-0e6ff432dc83e5675163b1c29ce73dbc5e18ba24.tar.gz
rust-0e6ff432dc83e5675163b1c29ce73dbc5e18ba24.zip
Desugar 'if let' into the appropriate 'match'
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/expand.rs91
1 files changed, 90 insertions, 1 deletions
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 9f3df1a7623..341be15b739 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -39,7 +39,7 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
     e.and_then(|ast::Expr {id, node, span}| match node {
         // expr_mac should really be expr_ext or something; it's the
         // entry-point for all syntax extensions.
-        ExprMac(mac) => {
+        ast::ExprMac(mac) => {
             let expanded_expr = match expand_mac_invoc(mac, span,
                                                        |r| r.make_expr(),
                                                        mark_expr, fld) {
@@ -67,6 +67,95 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
             fld.cx.expr(span, ast::ExprWhile(cond, body, opt_ident))
         }
 
+        // Desugar ExprIfLet
+        // From: `if let <pat> = <expr> <body> [<elseopt>]`
+        ast::ExprIfLet(pat, expr, body, mut elseopt) => {
+            let span = e.span;
+
+            // to:
+            //
+            //   match <expr> {
+            //     <pat> => <body>,
+            //     [_ if <elseopt_if_cond> => <elseopt_if_body>,]
+            //     _ => [<elseopt> | ()]
+            //   }
+
+            // `<pat> => <body>`
+            let pat_arm = {
+                let body_expr = fld.cx.expr_block(body);
+                fld.cx.arm(pat.span, vec![pat], body_expr)
+            };
+
+            // `[_ if <elseopt_if_cond> => <elseopt_if_body>,]`
+            let else_if_arms = {
+                let mut arms = vec![];
+                loop {
+                    // NOTE: replace with 'if let' after snapshot
+                    match elseopt {
+                        Some(els) => match els.node {
+                            // else if
+                            ast::ExprIf(cond, then, elseopt_) => {
+                                let pat_under = fld.cx.pat_wild(span);
+                                elseopt = elseopt_;
+                                arms.push(ast::Arm {
+                                    attrs: vec![],
+                                    pats: vec![pat_under],
+                                    guard: Some(cond),
+                                    body: fld.cx.expr_block(then)
+                                });
+                            }
+                            _ => break
+                        },
+                        None => break
+                    }
+                }
+                arms
+            };
+
+            // `_ => [<elseopt> | ()]`
+            let else_arm = {
+                let pat_under = fld.cx.pat_wild(span);
+                let else_expr = match elseopt {
+                    Some(els) => els,
+                    None => fld.cx.expr_lit(span, ast::LitNil)
+                };
+                fld.cx.arm(span, vec![pat_under], else_expr)
+            };
+
+            let mut arms = Vec::with_capacity(else_if_arms.len() + 2);
+            arms.push(pat_arm);
+            arms.push_all_move(else_if_arms);
+            arms.push(else_arm);
+
+            let match_expr = fld.cx.expr_match(span, expr, arms);
+            fld.fold_expr(match_expr)
+        }
+
+        // Desugar support for ExprIfLet in the ExprIf else position
+        ast::ExprIf(cond, blk, mut elseopt) => {
+            // NOTE: replace with 'if let' after snapshot
+            match elseopt {
+                Some(els) => match els.node {
+                    ast::ExprIfLet(..) => {
+                        // wrap the if-let expr in a block
+                        let blk = P(ast::Block {
+                            view_items: vec![],
+                            stmts: vec![],
+                            expr: Some(els),
+                            id: ast::DUMMY_NODE_ID,
+                            rules: ast::DefaultBlock,
+                            span: els.span
+                        });
+                        elseopt = Some(fld.cx.expr_block(blk));
+                    }
+                    _ => ()
+                },
+                None => ()
+            };
+            let if_expr = fld.cx.expr(e.span, ast::ExprIf(cond, blk, elseopt));
+            noop_fold_expr(if_expr, fld)
+        }
+
         ast::ExprLoop(loop_block, opt_ident) => {
             let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
             fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident))