diff options
| author | Jorge Aparicio <japaricious@gmail.com> | 2015-01-08 18:04:26 -0500 |
|---|---|---|
| committer | Jorge Aparicio <japaricious@gmail.com> | 2015-01-30 10:36:31 -0500 |
| commit | 9fdc0effd292b097ae487ec4d927ca15102c5791 (patch) | |
| tree | c6f0cc475b0fe7cee697fdda83714965e33bed01 /src/libsyntax/ext | |
| parent | a65d3f5b98cc94f0a759fbf1a08be9aee0f97883 (diff) | |
| download | rust-9fdc0effd292b097ae487ec4d927ca15102c5791.tar.gz rust-9fdc0effd292b097ae487ec4d927ca15102c5791.zip | |
implement for loop desugaring
Diffstat (limited to 'src/libsyntax/ext')
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 96 |
1 files changed, 93 insertions, 3 deletions
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index acf0fe7f6cd..357bd2c17ab 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -225,11 +225,101 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> { fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident)) } + // Desugar ExprForLoop + // From: `[opt_ident]: for <pat> in <head> <body>` ast::ExprForLoop(pat, head, body, opt_ident) => { - let pat = fld.fold_pat(pat); + // to: + // + // match ::std::iter::IntoIterator::into_iter(<head>) { + // mut iter => { + // [opt_ident]: loop { + // match ::std::iter::Iterator::next(&mut iter) { + // ::std::option::Option::Some(<pat>) => <body>, + // ::std::option::Option::None => break + // } + // } + // } + // } + + // expand <head> let head = fld.fold_expr(head); - let (body, opt_ident) = expand_loop_block(body, opt_ident, fld); - fld.cx.expr(span, ast::ExprForLoop(pat, head, body, opt_ident)) + + // create an hygienic ident + let iter = { + let ident = fld.cx.ident_of("iter"); + let new_ident = fresh_name(&ident); + let rename = (ident, new_ident); + let mut rename_list = vec![rename]; + let mut rename_fld = IdentRenamer{ renames: &mut rename_list }; + + rename_fld.fold_ident(ident) + }; + + let pat_span = pat.span; + // `:;std::option::Option::Some(<pat>) => <body>` + let pat_arm = { + let body_expr = fld.cx.expr_block(body); + let some_pat = fld.cx.pat_some(pat_span, pat); + + fld.cx.arm(pat_span, vec![some_pat], body_expr) + }; + + // `::std::option::Option::None => break` + let break_arm = { + let break_expr = fld.cx.expr_break(span); + + fld.cx.arm(span, vec![fld.cx.pat_none(span)], break_expr) + }; + + // `match ::std::iter::Iterator::next(&mut iter) { ... }` + let match_expr = { + let next_path = { + let strs = vec![ + fld.cx.ident_of("std"), + fld.cx.ident_of("iter"), + fld.cx.ident_of("Iterator"), + fld.cx.ident_of("next"), + ]; + + fld.cx.path_global(span, strs) + }; + let ref_mut_iter = fld.cx.expr_mut_addr_of(span, fld.cx.expr_ident(span, iter)); + let next_expr = + fld.cx.expr_call(span, fld.cx.expr_path(next_path), vec![ref_mut_iter]); + let arms = vec![pat_arm, break_arm]; + + // FIXME(japaric) This should use `ForLoopDesugar` as MatchSource + fld.cx.expr_match(pat_span, next_expr, arms) + }; + + // `[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); + let loop_expr = fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident)); + + // `mut iter => { ... }` + let iter_arm = { + let iter_pat = + fld.cx.pat_ident_binding_mode(span, iter, ast::BindByValue(ast::MutMutable)); + fld.cx.arm(span, vec![iter_pat], loop_expr) + }; + + // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }` + let into_iter_expr = { + let into_iter_path = { + let strs = vec![ + fld.cx.ident_of("std"), + fld.cx.ident_of("iter"), + fld.cx.ident_of("IntoIterator"), + fld.cx.ident_of("into_iter"), + ]; + + fld.cx.path_global(span, strs) + }; + + fld.cx.expr_call(span, fld.cx.expr_path(into_iter_path), vec![head]) + }; + fld.cx.expr_match(span, into_iter_expr, vec![iter_arm]) } ast::ExprClosure(capture_clause, opt_kind, fn_decl, block) => { |
