Skip to content

Commit 34301b7

Browse files
committed
Teach libsyntax about if let
1 parent 9e8c30c commit 34301b7

File tree

6 files changed

+68
-12
lines changed

6 files changed

+68
-12
lines changed

src/libsyntax/ast.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,7 @@ pub enum Expr_ {
534534
ExprLit(Gc<Lit>),
535535
ExprCast(Gc<Expr>, P<Ty>),
536536
ExprIf(Gc<Expr>, P<Block>, Option<Gc<Expr>>),
537+
ExprIfLet(P<Pat>, P<Expr>, P<Block>, Option<P<Expr>>),
537538
ExprWhile(Gc<Expr>, P<Block>),
538539
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
539540
ExprForLoop(Gc<Pat>, Gc<Expr>, P<Block>, Option<Ident>),

src/libsyntax/fold.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,12 @@ pub fn noop_fold_expr<T: Folder>(e: Gc<Expr>, folder: &mut T) -> Gc<Expr> {
11291129
folder.fold_block(tr),
11301130
fl.map(|x| folder.fold_expr(x)))
11311131
}
1132+
ExprIfLet(pat, expr, tr, fl) => {
1133+
ExprIfLet(folder.fold_pat(pat),
1134+
folder.fold_expr(expr),
1135+
folder.fold_block(tr),
1136+
fl.map(|x| folder.fold_expr(x)))
1137+
}
11321138
ExprWhile(cond, body) => {
11331139
ExprWhile(folder.fold_expr(cond), folder.fold_block(body))
11341140
}

src/libsyntax/parse/classify.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use std::gc::Gc;
2525
pub fn expr_requires_semi_to_be_stmt(e: Gc<ast::Expr>) -> bool {
2626
match e.node {
2727
ast::ExprIf(..)
28+
| ast::ExprIfLet(..)
2829
| ast::ExprMatch(..)
2930
| ast::ExprBlock(_)
3031
| ast::ExprWhile(..)

src/libsyntax/parse/parser.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use ast::{DeclLocal, DefaultBlock, UnDeref, BiDiv, EMPTY_CTXT, EnumDef, Explicit
2323
use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
2424
use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox};
2525
use ast::{ExprBreak, ExprCall, ExprCast};
26-
use ast::{ExprField, ExprFnBlock, ExprIf, ExprIndex};
26+
use ast::{ExprField, ExprFnBlock, ExprIf, ExprIfLet, ExprIndex};
2727
use ast::{ExprLit, ExprLoop, ExprMac};
2828
use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc};
2929
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn};
@@ -569,13 +569,10 @@ impl<'a> Parser<'a> {
569569
/// If the next token is the given keyword, eat it and return
570570
/// true. Otherwise, return false.
571571
pub fn eat_keyword(&mut self, kw: keywords::Keyword) -> bool {
572-
match self.token {
573-
token::IDENT(sid, false) if kw.to_name() == sid.name => {
574-
self.bump();
575-
true
576-
}
577-
_ => false
578-
}
572+
if self.is_keyword(kw) {
573+
self.bump();
574+
true
575+
} else { false }
579576
}
580577

581578
/// If the given word is not a keyword, signal an error.
@@ -2714,8 +2711,11 @@ impl<'a> Parser<'a> {
27142711
}
27152712
}
27162713

2717-
/// Parse an 'if' expression ('if' token already eaten)
2714+
/// Parse an 'if' or 'if let' expression ('if' token already eaten)
27182715
pub fn parse_if_expr(&mut self) -> Gc<Expr> {
2716+
if self.is_keyword(keywords::Let) {
2717+
return self.parse_if_let_expr();
2718+
}
27192719
let lo = self.last_span.lo;
27202720
let cond = self.parse_expr_res(RESTRICT_NO_STRUCT_LITERAL);
27212721
let thn = self.parse_block();
@@ -2729,6 +2729,21 @@ impl<'a> Parser<'a> {
27292729
self.mk_expr(lo, hi, ExprIf(cond, thn, els))
27302730
}
27312731

2732+
/// Parse an 'if let' expression ('if' token already eaten)
2733+
pub fn parse_if_let_expr(&mut self) -> Gc<Expr> {
2734+
let lo = self.last_span.lo;
2735+
self.expect_keyword(keywords::Let);
2736+
let pat = self.parse_pat();
2737+
self.expect(&token::EQ);
2738+
let expr = self.parse_expr_res(RESTRICT_NO_STRUCT_LITERAL);
2739+
let thn = self.parse_block();
2740+
let els = if self.eat_keyword(keywords::Else) {
2741+
Some(self.parse_else_expr())
2742+
} else { None };
2743+
let hi = els.map_or(thn.span.hi, |expr| expr.span.hi);
2744+
self.mk_expr(lo, hi, ExprIfLet(pat, expr, thn, els))
2745+
}
2746+
27322747
// `|args| expr`
27332748
pub fn parse_lambda_expr(&mut self, capture_clause: CaptureClause)
27342749
-> Gc<Expr> {

src/libsyntax/print/pprust.rs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,6 +1281,19 @@ impl<'a> State<'a> {
12811281
try!(self.print_block(&**t));
12821282
self.print_else(e)
12831283
}
1284+
// "another else-if-let"
1285+
ast::ExprIfLet(ref pat, ref expr, ref blk, elseopt) => {
1286+
try!(self.cbox(indent_unit - 1u));
1287+
try!(self.ibox(0u));
1288+
try!(word(&mut self.s, " else if let "));
1289+
try!(self.print_pat(&**pat));
1290+
try!(space(&mut self.s));
1291+
try!(self.word_space("="));
1292+
try!(self.print_expr(&**expr));
1293+
try!(space(&mut self.s));
1294+
try!(self.print_block(&**blk));
1295+
self.print_else(elseopt)
1296+
}
12841297
// "final else"
12851298
ast::ExprBlock(ref b) => {
12861299
try!(self.cbox(indent_unit - 1u));
@@ -1299,15 +1312,26 @@ impl<'a> State<'a> {
12991312
}
13001313

13011314
pub fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block,
1302-
elseopt: Option<Gc<ast::Expr>>, chk: bool) -> IoResult<()> {
1315+
elseopt: Option<Gc<ast::Expr>>) -> IoResult<()> {
13031316
try!(self.head("if"));
1304-
if chk { try!(self.word_nbsp("check")); }
13051317
try!(self.print_expr(test));
13061318
try!(space(&mut self.s));
13071319
try!(self.print_block(blk));
13081320
self.print_else(elseopt)
13091321
}
13101322

1323+
pub fn print_if_let(&mut self, pat: &ast::Pat, expr: &ast::Expr, blk: &ast::Block,
1324+
elseopt: Option<P<ast::Expr>>) -> IoResult<()> {
1325+
try!(self.head("if let"));
1326+
try!(self.print_pat(pat));
1327+
try!(space(&mut self.s));
1328+
try!(self.word_space("="));
1329+
try!(self.print_expr(expr));
1330+
try!(space(&mut self.s));
1331+
try!(self.print_block(blk));
1332+
self.print_else(elseopt)
1333+
}
1334+
13111335
pub fn print_mac(&mut self, m: &ast::Mac) -> IoResult<()> {
13121336
match m.node {
13131337
// I think it's reasonable to hide the ctxt here:
@@ -1462,7 +1486,10 @@ impl<'a> State<'a> {
14621486
try!(self.print_type(&**ty));
14631487
}
14641488
ast::ExprIf(ref test, ref blk, elseopt) => {
1465-
try!(self.print_if(&**test, &**blk, elseopt, false));
1489+
try!(self.print_if(&**test, &**blk, elseopt));
1490+
}
1491+
ast::ExprIfLet(ref pat, ref expr, ref blk, elseopt) => {
1492+
try!(self.print_if_let(&**pat, &**expr, &** blk, elseopt));
14661493
}
14671494
ast::ExprWhile(ref test, ref blk) => {
14681495
try!(self.head("while"));

src/libsyntax/visit.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,12 @@ pub fn walk_expr<E: Clone, V: Visitor<E>>(visitor: &mut V, expression: &Expr, en
784784
visitor.visit_block(&**if_block, env.clone());
785785
walk_expr_opt(visitor, optional_else, env.clone())
786786
}
787+
ExprIfLet(ref pattern, ref subexpression, ref if_block, optional_else) => {
788+
visitor.visit_pat(&**pattern, env.clone());
789+
visitor.visit_expr(&**subexpression, env.clone());
790+
visitor.visit_block(&**if_block, env.clone());
791+
walk_expr_opt(visitor, optional_else, env.clone())
792+
}
787793
ExprWhile(ref subexpression, ref block) => {
788794
visitor.visit_expr(&**subexpression, env.clone());
789795
visitor.visit_block(&**block, env.clone())

0 commit comments

Comments
 (0)