summary refs log tree commit diff
path: root/src/libsyntax/ext
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-10-13 19:37:40 +0000
committerbors <bors@rust-lang.org>2014-10-13 19:37:40 +0000
commitc7e072427469ef50880a722b7b6cd00b052939f5 (patch)
treec87cb2f922c34bf1b6d9b6152ae466a31b817eff /src/libsyntax/ext
parentdaa71e40a98f32084539e7cfe893a3e94f83fe69 (diff)
parent16ccdba8512fc7ce397095cf5d62858ef2234c47 (diff)
downloadrust-c7e072427469ef50880a722b7b6cd00b052939f5.tar.gz
rust-c7e072427469ef50880a722b7b6cd00b052939f5.zip
auto merge of #17733 : jgallagher/rust/while-let, r=alexcrichton
This is *heavily* based on `if let` (#17634) by @jakub- and @kballard

This should close #17687
Diffstat (limited to 'src/libsyntax/ext')
-rw-r--r--src/libsyntax/ext/build.rs8
-rw-r--r--src/libsyntax/ext/expand.rs36
2 files changed, 44 insertions, 0 deletions
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 87983e1aea3..98ac6fe6a6c 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -147,6 +147,8 @@ pub trait AstBuilder {
     fn expr_some(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr>;
     fn expr_none(&self, sp: Span) -> P<ast::Expr>;
 
+    fn expr_break(&self, sp: Span) -> P<ast::Expr>;
+
     fn expr_tuple(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr>;
 
     fn expr_fail(&self, span: Span, msg: InternedString) -> P<ast::Expr>;
@@ -688,6 +690,12 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         self.expr_path(none)
     }
 
+
+    fn expr_break(&self, sp: Span) -> P<ast::Expr> {
+        self.expr(sp, ast::ExprBreak(None))
+    }
+
+
     fn expr_tuple(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
         self.expr(sp, ast::ExprTup(exprs))
     }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index efe4b76354f..575dcf32dd6 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -67,6 +67,42 @@ 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 ExprWhileLet
+        // From: `[opt_ident]: while let <pat> = <expr> <body>`
+        ast::ExprWhileLet(pat, expr, body, opt_ident) => {
+            // to:
+            //
+            //   [opt_ident]: loop {
+            //     match <expr> {
+            //       <pat> => <body>,
+            //       _ => break
+            //     }
+            //   }
+
+            // `<pat> => <body>`
+            let pat_arm = {
+                let body_expr = fld.cx.expr_block(body);
+                fld.cx.arm(pat.span, vec![pat], body_expr)
+            };
+
+            // `_ => break`
+            let break_arm = {
+                let pat_under = fld.cx.pat_wild(span);
+                let break_expr = fld.cx.expr_break(span);
+                fld.cx.arm(span, vec![pat_under], break_expr)
+            };
+
+            // `match <expr> { ... }`
+            let arms = vec![pat_arm, break_arm];
+            let match_expr = fld.cx.expr(span,
+                                         ast::ExprMatch(expr, arms, ast::MatchWhileLetDesugar));
+
+            // `[opt_ident]: loop { ... }`
+            let loop_block = fld.cx.block_expr(match_expr);
+            let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
+            fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident))
+        }
+
         // Desugar ExprIfLet
         // From: `if let <pat> = <expr> <body> [<elseopt>]`
         ast::ExprIfLet(pat, expr, body, mut elseopt) => {