diff options
| author | Kevin Ballard <kevin@sb.org> | 2014-08-24 19:08:48 -0700 |
|---|---|---|
| committer | Jakub Wieczorek <jakub@jakub.cc> | 2014-09-30 18:54:02 +0200 |
| commit | 0e6ff432dc83e5675163b1c29ce73dbc5e18ba24 (patch) | |
| tree | 032c5323eb135364686c52ab01695e397f4a7c94 /src/libsyntax | |
| parent | 5d8cfd53b513d999ffff22f17e3066a30a8ed949 (diff) | |
| download | rust-0e6ff432dc83e5675163b1c29ce73dbc5e18ba24.tar.gz rust-0e6ff432dc83e5675163b1c29ce73dbc5e18ba24.zip | |
Desugar 'if let' into the appropriate 'match'
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 91 |
1 files changed, 90 insertions, 1 deletions
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 9f3df1a7623..341be15b739 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -39,7 +39,7 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> { e.and_then(|ast::Expr {id, node, span}| match node { // expr_mac should really be expr_ext or something; it's the // entry-point for all syntax extensions. - ExprMac(mac) => { + ast::ExprMac(mac) => { let expanded_expr = match expand_mac_invoc(mac, span, |r| r.make_expr(), mark_expr, fld) { @@ -67,6 +67,95 @@ 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 ExprIfLet + // From: `if let <pat> = <expr> <body> [<elseopt>]` + ast::ExprIfLet(pat, expr, body, mut elseopt) => { + let span = e.span; + + // to: + // + // match <expr> { + // <pat> => <body>, + // [_ if <elseopt_if_cond> => <elseopt_if_body>,] + // _ => [<elseopt> | ()] + // } + + // `<pat> => <body>` + let pat_arm = { + let body_expr = fld.cx.expr_block(body); + fld.cx.arm(pat.span, vec![pat], body_expr) + }; + + // `[_ if <elseopt_if_cond> => <elseopt_if_body>,]` + let else_if_arms = { + let mut arms = vec![]; + loop { + // NOTE: replace with 'if let' after snapshot + match elseopt { + Some(els) => match els.node { + // else if + ast::ExprIf(cond, then, elseopt_) => { + let pat_under = fld.cx.pat_wild(span); + elseopt = elseopt_; + arms.push(ast::Arm { + attrs: vec![], + pats: vec![pat_under], + guard: Some(cond), + body: fld.cx.expr_block(then) + }); + } + _ => break + }, + None => break + } + } + arms + }; + + // `_ => [<elseopt> | ()]` + let else_arm = { + let pat_under = fld.cx.pat_wild(span); + let else_expr = match elseopt { + Some(els) => els, + None => fld.cx.expr_lit(span, ast::LitNil) + }; + fld.cx.arm(span, vec![pat_under], else_expr) + }; + + let mut arms = Vec::with_capacity(else_if_arms.len() + 2); + arms.push(pat_arm); + arms.push_all_move(else_if_arms); + arms.push(else_arm); + + let match_expr = fld.cx.expr_match(span, expr, arms); + fld.fold_expr(match_expr) + } + + // Desugar support for ExprIfLet in the ExprIf else position + ast::ExprIf(cond, blk, mut elseopt) => { + // NOTE: replace with 'if let' after snapshot + match elseopt { + Some(els) => match els.node { + ast::ExprIfLet(..) => { + // wrap the if-let expr in a block + let blk = P(ast::Block { + view_items: vec![], + stmts: vec![], + expr: Some(els), + id: ast::DUMMY_NODE_ID, + rules: ast::DefaultBlock, + span: els.span + }); + elseopt = Some(fld.cx.expr_block(blk)); + } + _ => () + }, + None => () + }; + let if_expr = fld.cx.expr(e.span, ast::ExprIf(cond, blk, elseopt)); + noop_fold_expr(if_expr, fld) + } + ast::ExprLoop(loop_block, opt_ident) => { let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld); fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident)) |
