Skip to content

Commit

Permalink
if-let: Add support for multiple patterns
Browse files Browse the repository at this point in the history
This commit adds support for multiple patterns in if-let statements:

```rust
let x = Some(0);
if let Some(0) | Some(1) = x {
    println!("Got 0 or 1");
}
```
  • Loading branch information
Munksgaard committed Mar 4, 2015
1 parent 6e055c3 commit 3da6cf5
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 16 deletions.
2 changes: 1 addition & 1 deletion src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ pub enum Expr_ {
ExprLit(P<Lit>),
ExprCast(P<Expr>, P<Ty>),
ExprIf(P<Expr>, P<Block>, Option<P<Expr>>),
ExprIfLet(P<Pat>, P<Expr>, P<Block>, Option<P<Expr>>),
ExprIfLet(Vec<P<Pat>>, P<Expr>, P<Block>, Option<P<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.
Expand Down
6 changes: 3 additions & 3 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
}

// Desugar ExprIfLet
// From: `if let <pat> = <expr> <body> [<elseopt>]`
ast::ExprIfLet(pat, expr, body, mut elseopt) => {
// From: `if let <pats> = <expr> <body> [<elseopt>]`
ast::ExprIfLet(pats, expr, body, mut elseopt) => {
// to:
//
// match <expr> {
Expand All @@ -140,7 +140,7 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
// `<pat> => <body>`
let pat_arm = {
let body_expr = fld.cx.expr_block(body);
fld.cx.arm(pat.span, vec![pat], body_expr)
fld.cx.arm(span, pats, body_expr)
};

// `[_ if <elseopt_if_cond> => <elseopt_if_body>,]`
Expand Down
4 changes: 2 additions & 2 deletions src/libsyntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1288,8 +1288,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
folder.fold_block(tr),
fl.map(|x| folder.fold_expr(x)))
}
ExprIfLet(pat, expr, tr, fl) => {
ExprIfLet(folder.fold_pat(pat),
ExprIfLet(pats, expr, tr, fl) => {
ExprIfLet(pats.move_map(|x| folder.fold_pat(x)),
folder.fold_expr(expr),
folder.fold_block(tr),
fl.map(|x| folder.fold_expr(x)))
Expand Down
4 changes: 2 additions & 2 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3065,7 +3065,7 @@ impl<'a> Parser<'a> {
pub fn parse_if_let_expr(&mut self) -> P<Expr> {
let lo = self.last_span.lo;
self.expect_keyword(keywords::Let);
let pat = self.parse_pat();
let pats = self.parse_pats();
self.expect(&token::Eq);
let expr = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL);
let thn = self.parse_block();
Expand All @@ -3075,7 +3075,7 @@ impl<'a> Parser<'a> {
} else {
(thn.span.hi, None)
};
self.mk_expr(lo, hi, ExprIfLet(pat, expr, thn, els))
self.mk_expr(lo, hi, ExprIfLet(pats, expr, thn, els))
}

// `|args| expr`
Expand Down
25 changes: 19 additions & 6 deletions src/libsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1459,11 +1459,11 @@ impl<'a> State<'a> {
self.print_else(e.as_ref().map(|e| &**e))
}
// "another else-if-let"
ast::ExprIfLet(ref pat, ref expr, ref then, ref e) => {
ast::ExprIfLet(ref pats, ref expr, ref then, ref e) => {
try!(self.cbox(indent_unit - 1));
try!(self.ibox(0));
try!(word(&mut self.s, " else if let "));
try!(self.print_pat(&**pat));
try!(self.print_pats(pats));
try!(space(&mut self.s));
try!(self.word_space("="));
try!(self.print_expr(&**expr));
Expand Down Expand Up @@ -1497,10 +1497,10 @@ impl<'a> State<'a> {
self.print_else(elseopt)
}

pub fn print_if_let(&mut self, pat: &ast::Pat, expr: &ast::Expr, blk: &ast::Block,
pub fn print_if_let(&mut self, pats: &[P<ast::Pat>], expr: &ast::Expr, blk: &ast::Block,
elseopt: Option<&ast::Expr>) -> IoResult<()> {
try!(self.head("if let"));
try!(self.print_pat(pat));
try!(self.print_pats(pats));
try!(space(&mut self.s));
try!(self.word_space("="));
try!(self.print_expr(expr));
Expand Down Expand Up @@ -1721,8 +1721,8 @@ impl<'a> State<'a> {
ast::ExprIf(ref test, ref blk, ref elseopt) => {
try!(self.print_if(&**test, &**blk, elseopt.as_ref().map(|e| &**e)));
}
ast::ExprIfLet(ref pat, ref expr, ref blk, ref elseopt) => {
try!(self.print_if_let(&**pat, &**expr, &** blk, elseopt.as_ref().map(|e| &**e)));
ast::ExprIfLet(ref pats, ref expr, ref blk, ref elseopt) => {
try!(self.print_if_let(&**pats, &**expr, &** blk, elseopt.as_ref().map(|e| &**e)));
}
ast::ExprWhile(ref test, ref blk, opt_ident) => {
if let Some(ident) = opt_ident {
Expand Down Expand Up @@ -2253,6 +2253,19 @@ impl<'a> State<'a> {
self.ann.post(self, NodePat(pat))
}

pub fn print_pats(&mut self, pats: &[ast::Pat]) -> IoResult<()> {
let mut first = true;
for ref p in pats {
if first {
first = false;
} else {
try!(space(&mut self.s));
try!(self.word_space("|"));

This comment has been minimized.

Copy link
@Manishearth

Manishearth Mar 4, 2015

Should there be a space here on either side?

This comment has been minimized.

Copy link
@Munksgaard

Munksgaard Mar 4, 2015

Author Owner

I think self.word_space already does that for us.

This comment has been minimized.

Copy link
@Manishearth

Manishearth Mar 4, 2015

Oh, okay. Just play around with the pretty printer (maybe write some pretty tests?) and ensure that it does look like what you want it to

This comment has been minimized.

Copy link
@Munksgaard

Munksgaard Mar 4, 2015

Author Owner

I tried running my tests through with --pretty normal, and the output looks normal.

This comment has been minimized.

Copy link
@Munksgaard

Munksgaard Mar 4, 2015

Author Owner

I did manage to screw this function up though, it doesn't compile right now, as print_pats doesn't return an IoResult. Will fix in a minute.

}
try!(self.print_pat(&**p));
}
}

fn print_arm(&mut self, arm: &ast::Arm) -> IoResult<()> {
// I have no idea why this check is necessary, but here it
// is :(
Expand Down
6 changes: 4 additions & 2 deletions src/libsyntax/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -805,8 +805,10 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
visitor.visit_expr(&**subexpression);
visitor.visit_block(&**block)
}
ExprIfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => {
visitor.visit_pat(&**pattern);
ExprIfLet(ref patterns, ref subexpression, ref if_block, ref optional_else) => {
for pattern in patterns {
visitor.visit_pat(&**pattern)
}
visitor.visit_expr(&**subexpression);
visitor.visit_block(&**if_block);
walk_expr_opt(visitor, optional_else);
Expand Down

0 comments on commit 3da6cf5

Please sign in to comment.