Skip to content

Commit 0c2c811

Browse files
committed
Teach libsyntax about while let
1 parent 78a7676 commit 0c2c811

File tree

7 files changed

+80
-1
lines changed

7 files changed

+80
-1
lines changed

src/libsyntax/ast.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,8 @@ pub enum Expr_ {
524524
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
525525
ExprWhile(P<Expr>, P<Block>, Option<Ident>),
526526
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
527+
ExprWhileLet(P<Pat>, P<Expr>, P<Block>, Option<Ident>),
528+
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
527529
ExprForLoop(P<Pat>, P<Expr>, P<Block>, Option<Ident>),
528530
// Conditionless loop (can be exited with break, cont, or ret)
529531
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.

src/libsyntax/ext/expand.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,42 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
6767
fld.cx.expr(span, ast::ExprWhile(cond, body, opt_ident))
6868
}
6969

70+
// Desugar ExprWhileLet
71+
// From: `[opt_ident]: while let <pat> = <expr> <body>`
72+
ast::ExprWhileLet(pat, expr, body, opt_ident) => {
73+
// to:
74+
//
75+
// [opt_ident]: loop {
76+
// match <expr> {
77+
// <pat> => <body>,
78+
// _ => break
79+
// }
80+
// }
81+
82+
// `<pat> => <body>`
83+
let pat_arm = {
84+
let body_expr = fld.cx.expr_block(body);
85+
fld.cx.arm(pat.span, vec![pat], body_expr)
86+
};
87+
88+
// `_ => break`
89+
let break_arm = {
90+
let pat_under = fld.cx.pat_wild(span);
91+
let break_expr = fld.cx.expr_break(span);
92+
fld.cx.arm(span, vec![pat_under], break_expr)
93+
};
94+
95+
// `match <expr> { ... }`
96+
let arms = vec![pat_arm, break_arm];
97+
let match_expr = fld.cx.expr(span,
98+
ast::ExprMatch(expr, arms, ast::MatchWhileLetDesugar));
99+
100+
// `[opt_ident]: loop { ... }`
101+
let loop_block = fld.cx.block_expr(match_expr);
102+
let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
103+
fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident))
104+
}
105+
70106
// Desugar ExprIfLet
71107
// From: `if let <pat> = <expr> <body> [<elseopt>]`
72108
ast::ExprIfLet(pat, expr, body, mut elseopt) => {

src/libsyntax/fold.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,6 +1218,12 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
12181218
folder.fold_block(body),
12191219
opt_ident.map(|i| folder.fold_ident(i)))
12201220
}
1221+
ExprWhileLet(pat, expr, body, opt_ident) => {
1222+
ExprWhileLet(folder.fold_pat(pat),
1223+
folder.fold_expr(expr),
1224+
folder.fold_block(body),
1225+
opt_ident.map(|i| folder.fold_ident(i)))
1226+
}
12211227
ExprForLoop(pat, iter, body, opt_ident) => {
12221228
ExprForLoop(folder.fold_pat(pat),
12231229
folder.fold_expr(iter),

src/libsyntax/parse/classify.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
2828
| ast::ExprMatch(..)
2929
| ast::ExprBlock(_)
3030
| ast::ExprWhile(..)
31+
| ast::ExprWhileLet(..)
3132
| ast::ExprLoop(..)
3233
| ast::ExprForLoop(..) => false,
3334
_ => true

src/libsyntax/parse/parser.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use ast::{ExprField, ExprTupField, ExprFnBlock, ExprIf, ExprIfLet, ExprIndex, Ex
2626
use ast::{ExprLit, ExprLoop, ExprMac};
2727
use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc};
2828
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn};
29-
use ast::{ExprVec, ExprWhile, ExprForLoop, Field, FnDecl};
29+
use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl};
3030
use ast::{Once, Many};
3131
use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind};
3232
use ast::{FnOnceUnboxedClosureKind};
@@ -2935,14 +2935,30 @@ impl<'a> Parser<'a> {
29352935
self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident))
29362936
}
29372937

2938+
/// Parse a 'while' or 'while let' expression ('while' token already eaten)
29382939
pub fn parse_while_expr(&mut self, opt_ident: Option<ast::Ident>) -> P<Expr> {
2940+
if self.is_keyword(keywords::Let) {
2941+
return self.parse_while_let_expr(opt_ident);
2942+
}
29392943
let lo = self.last_span.lo;
29402944
let cond = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL);
29412945
let body = self.parse_block();
29422946
let hi = body.span.hi;
29432947
return self.mk_expr(lo, hi, ExprWhile(cond, body, opt_ident));
29442948
}
29452949

2950+
/// Parse a 'while let' expression ('while' token already eaten)
2951+
pub fn parse_while_let_expr(&mut self, opt_ident: Option<ast::Ident>) -> P<Expr> {
2952+
let lo = self.last_span.lo;
2953+
self.expect_keyword(keywords::Let);
2954+
let pat = self.parse_pat();
2955+
self.expect(&token::EQ);
2956+
let expr = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL);
2957+
let body = self.parse_block();
2958+
let hi = body.span.hi;
2959+
return self.mk_expr(lo, hi, ExprWhileLet(pat, expr, body, opt_ident));
2960+
}
2961+
29462962
pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::Ident>) -> P<Expr> {
29472963
let lo = self.last_span.lo;
29482964
let body = self.parse_block();

src/libsyntax/print/pprust.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1525,6 +1525,19 @@ impl<'a> State<'a> {
15251525
try!(space(&mut self.s));
15261526
try!(self.print_block(&**blk));
15271527
}
1528+
ast::ExprWhileLet(ref pat, ref expr, ref blk, opt_ident) => {
1529+
for ident in opt_ident.iter() {
1530+
try!(self.print_ident(*ident));
1531+
try!(self.word_space(":"));
1532+
}
1533+
try!(self.head("while let"));
1534+
try!(self.print_pat(&**pat));
1535+
try!(space(&mut self.s));
1536+
try!(self.word_space("="));
1537+
try!(self.print_expr(&**expr));
1538+
try!(space(&mut self.s));
1539+
try!(self.print_block(&**blk));
1540+
}
15281541
ast::ExprForLoop(ref pat, ref iter, ref blk, opt_ident) => {
15291542
for ident in opt_ident.iter() {
15301543
try!(self.print_ident(*ident));

src/libsyntax/visit.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,11 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
737737
visitor.visit_block(&**if_block);
738738
walk_expr_opt(visitor, optional_else);
739739
}
740+
ExprWhileLet(ref pattern, ref subexpression, ref block, _) => {
741+
visitor.visit_pat(&**pattern);
742+
visitor.visit_expr(&**subexpression);
743+
visitor.visit_block(&**block);
744+
}
740745
ExprForLoop(ref pattern, ref subexpression, ref block, _) => {
741746
visitor.visit_pat(&**pattern);
742747
visitor.visit_expr(&**subexpression);

0 commit comments

Comments
 (0)