about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorJohn Gallagher <jgallagher@bignerdranch.com>2014-10-02 22:45:46 -0400
committerJohn Gallagher <jgallagher@bignerdranch.com>2014-10-10 20:30:31 -0400
commit0c2c8116a307e88f8327e0ea846d2c9c135193b7 (patch)
treeb9f17f6dc86f3e98b77b0eaf18a7d5ecb05bd7a4 /src
parent78a7676898d9f80ab540c6df5d4c9ce35bb50463 (diff)
downloadrust-0c2c8116a307e88f8327e0ea846d2c9c135193b7.tar.gz
rust-0c2c8116a307e88f8327e0ea846d2c9c135193b7.zip
Teach libsyntax about `while let`
Diffstat (limited to 'src')
-rw-r--r--src/libsyntax/ast.rs2
-rw-r--r--src/libsyntax/ext/expand.rs36
-rw-r--r--src/libsyntax/fold.rs6
-rw-r--r--src/libsyntax/parse/classify.rs1
-rw-r--r--src/libsyntax/parse/parser.rs18
-rw-r--r--src/libsyntax/print/pprust.rs13
-rw-r--r--src/libsyntax/visit.rs5
7 files changed, 80 insertions, 1 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 274bb2e39e0..675249b2591 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -524,6 +524,8 @@ pub enum Expr_ {
     // FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
     ExprWhile(P<Expr>, P<Block>, Option<Ident>),
     // FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
+    ExprWhileLet(P<Pat>, P<Expr>, P<Block>, Option<Ident>),
+    // FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
     ExprForLoop(P<Pat>, P<Expr>, P<Block>, Option<Ident>),
     // Conditionless loop (can be exited with break, cont, or ret)
     // FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
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) => {
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 32e226361e9..6ecb4d3208d 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1218,6 +1218,12 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
                           folder.fold_block(body),
                           opt_ident.map(|i| folder.fold_ident(i)))
             }
+            ExprWhileLet(pat, expr, body, opt_ident) => {
+                ExprWhileLet(folder.fold_pat(pat),
+                             folder.fold_expr(expr),
+                             folder.fold_block(body),
+                             opt_ident.map(|i| folder.fold_ident(i)))
+            }
             ExprForLoop(pat, iter, body, opt_ident) => {
                 ExprForLoop(folder.fold_pat(pat),
                             folder.fold_expr(iter),
diff --git a/src/libsyntax/parse/classify.rs b/src/libsyntax/parse/classify.rs
index cb57318445e..d46d078c776 100644
--- a/src/libsyntax/parse/classify.rs
+++ b/src/libsyntax/parse/classify.rs
@@ -28,6 +28,7 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
         | ast::ExprMatch(..)
         | ast::ExprBlock(_)
         | ast::ExprWhile(..)
+        | ast::ExprWhileLet(..)
         | ast::ExprLoop(..)
         | ast::ExprForLoop(..) => false,
         _ => true
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index e7f40cf0722..5f304fb0aeb 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -26,7 +26,7 @@ use ast::{ExprField, ExprTupField, ExprFnBlock, ExprIf, ExprIfLet, ExprIndex, Ex
 use ast::{ExprLit, ExprLoop, ExprMac};
 use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc};
 use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn};
-use ast::{ExprVec, ExprWhile, ExprForLoop, Field, FnDecl};
+use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl};
 use ast::{Once, Many};
 use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind};
 use ast::{FnOnceUnboxedClosureKind};
@@ -2935,7 +2935,11 @@ impl<'a> Parser<'a> {
         self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident))
     }
 
+    /// Parse a 'while' or 'while let' expression ('while' token already eaten)
     pub fn parse_while_expr(&mut self, opt_ident: Option<ast::Ident>) -> P<Expr> {
+        if self.is_keyword(keywords::Let) {
+            return self.parse_while_let_expr(opt_ident);
+        }
         let lo = self.last_span.lo;
         let cond = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL);
         let body = self.parse_block();
@@ -2943,6 +2947,18 @@ impl<'a> Parser<'a> {
         return self.mk_expr(lo, hi, ExprWhile(cond, body, opt_ident));
     }
 
+    /// Parse a 'while let' expression ('while' token already eaten)
+    pub fn parse_while_let_expr(&mut self, opt_ident: Option<ast::Ident>) -> P<Expr> {
+        let lo = self.last_span.lo;
+        self.expect_keyword(keywords::Let);
+        let pat = self.parse_pat();
+        self.expect(&token::EQ);
+        let expr = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL);
+        let body = self.parse_block();
+        let hi = body.span.hi;
+        return self.mk_expr(lo, hi, ExprWhileLet(pat, expr, body, opt_ident));
+    }
+
     pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::Ident>) -> P<Expr> {
         let lo = self.last_span.lo;
         let body = self.parse_block();
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index e1a2b2aeefe..fd3dd1c5a2c 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1525,6 +1525,19 @@ impl<'a> State<'a> {
                 try!(space(&mut self.s));
                 try!(self.print_block(&**blk));
             }
+            ast::ExprWhileLet(ref pat, ref expr, ref blk, opt_ident) => {
+                for ident in opt_ident.iter() {
+                    try!(self.print_ident(*ident));
+                    try!(self.word_space(":"));
+                }
+                try!(self.head("while let"));
+                try!(self.print_pat(&**pat));
+                try!(space(&mut self.s));
+                try!(self.word_space("="));
+                try!(self.print_expr(&**expr));
+                try!(space(&mut self.s));
+                try!(self.print_block(&**blk));
+            }
             ast::ExprForLoop(ref pat, ref iter, ref blk, opt_ident) => {
                 for ident in opt_ident.iter() {
                     try!(self.print_ident(*ident));
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 5c7b144f4ab..ce316ef5766 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -737,6 +737,11 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             visitor.visit_block(&**if_block);
             walk_expr_opt(visitor, optional_else);
         }
+        ExprWhileLet(ref pattern, ref subexpression, ref block, _) => {
+            visitor.visit_pat(&**pattern);
+            visitor.visit_expr(&**subexpression);
+            visitor.visit_block(&**block);
+        }
         ExprForLoop(ref pattern, ref subexpression, ref block, _) => {
             visitor.visit_pat(&**pattern);
             visitor.visit_expr(&**subexpression);