diff options
| author | bors <bors@rust-lang.org> | 2014-10-13 19:37:40 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2014-10-13 19:37:40 +0000 |
| commit | c7e072427469ef50880a722b7b6cd00b052939f5 (patch) | |
| tree | c87cb2f922c34bf1b6d9b6152ae466a31b817eff /src/libsyntax | |
| parent | daa71e40a98f32084539e7cfe893a3e94f83fe69 (diff) | |
| parent | 16ccdba8512fc7ce397095cf5d62858ef2234c47 (diff) | |
| download | rust-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')
| -rw-r--r-- | src/libsyntax/ast.rs | 5 | ||||
| -rw-r--r-- | src/libsyntax/ext/build.rs | 8 | ||||
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 36 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 5 | ||||
| -rw-r--r-- | src/libsyntax/fold.rs | 6 | ||||
| -rw-r--r-- | src/libsyntax/parse/classify.rs | 1 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 18 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 13 | ||||
| -rw-r--r-- | src/libsyntax/visit.rs | 5 |
9 files changed, 95 insertions, 2 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 44b327745ed..bf4734529a2 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. @@ -579,7 +581,8 @@ pub struct QPath { #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum MatchSource { MatchNormal, - MatchIfLetDesugar + MatchIfLetDesugar, + MatchWhileLetDesugar, } #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] 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) => { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 590157d677d..c1877c827a4 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -73,6 +73,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[ ("slicing_syntax", Active), ("if_let", Active), + ("while_let", Active), // if you change this list without updating src/doc/reference.md, cmr will be sad @@ -345,6 +346,10 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { e.span, "slicing syntax is experimental"); } + ast::ExprWhileLet(..) => { + self.gate_feature("while_let", e.span, + "`while let` syntax is experimental"); + } _ => {} } visit::walk_expr(self, e); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 3e16bca72ef..8faecd407a8 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1216,6 +1216,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 460e96a6ad8..d5253cff6cb 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 c9a6354bf97..d32828192e9 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1515,6 +1515,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 c98c3bffcb6..00377a324a7 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -733,6 +733,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); |
