From 9fdc0effd292b097ae487ec4d927ca15102c5791 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 8 Jan 2015 18:04:26 -0500 Subject: implement for loop desugaring --- src/libsyntax/ext/expand.rs | 96 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 3 deletions(-) (limited to 'src/libsyntax') 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, fld: &mut MacroExpander) -> P { fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident)) } + // Desugar ExprForLoop + // From: `[opt_ident]: for in ` ast::ExprForLoop(pat, head, body, opt_ident) => { - let pat = fld.fold_pat(pat); + // to: + // + // match ::std::iter::IntoIterator::into_iter() { + // mut iter => { + // [opt_ident]: loop { + // match ::std::iter::Iterator::next(&mut iter) { + // ::std::option::Option::Some() => , + // ::std::option::Option::None => break + // } + // } + // } + // } + + // expand 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() => ` + 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() { ... }` + 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) => { -- cgit 1.4.1-3-g733a5