diff options
| author | Graydon Hoare <graydon@mozilla.com> | 2013-07-29 17:25:00 -0700 |
|---|---|---|
| committer | Graydon Hoare <graydon@mozilla.com> | 2013-07-30 18:50:28 -0700 |
| commit | c29e9fb60b46a66bd55643981edbec881c5def82 (patch) | |
| tree | 98eaff9295335b4ca1612f4f28cc7ed23c6fc5b6 /src/libsyntax/ext | |
| parent | 9a2d183d6ae83a0119f5cce1f95e3770ddf5d689 (diff) | |
syntax: implement foreach .. in .. { .. } via desugaring.
Diffstat (limited to 'src/libsyntax/ext')
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 156 |
1 files changed, 155 insertions, 1 deletions
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index af05f726860..72bbc4a96c5 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -16,11 +16,12 @@ use ast_util::{new_rename, new_mark, resolve}; use attr; use attr::AttrMetaMethods; use codemap; -use codemap::{span, ExpnInfo, NameAndSpan}; +use codemap::{span, spanned, ExpnInfo, NameAndSpan}; use ext::base::*; use fold::*; use parse; use parse::{parse_item_from_source_str}; +use parse::token; use parse::token::{ident_to_str, intern}; use visit; use visit::Visitor; @@ -99,6 +100,159 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv, } } } + + // Desugar expr_for_loop + // From: `foreach <src_pat> in <src_expr> <src_loop_block>` + ast::expr_for_loop(src_pat, src_expr, ref src_loop_block) => { + let src_pat = src_pat.clone(); + let src_expr = src_expr.clone(); + + // Expand any interior macros etc. + // NB: we don't fold pats yet. Curious. + let src_expr = fld.fold_expr(src_expr).clone(); + let src_loop_block = fld.fold_block(src_loop_block).clone(); + + let span = s; + let lo = s.lo; + let hi = s.hi; + + pub fn mk_expr(cx: @ExtCtxt, span: span, + node: expr_) -> @ast::expr { + @ast::expr { + id: cx.next_id(), + node: node, + span: span, + } + } + + fn mk_block(cx: @ExtCtxt, + stmts: &[@ast::stmt], + expr: Option<@ast::expr>, + span: span) -> ast::Block { + ast::Block { + view_items: ~[], + stmts: stmts.to_owned(), + expr: expr, + id: cx.next_id(), + rules: ast::DefaultBlock, + span: span, + } + } + + fn mk_simple_path(ident: ast::ident, span: span) -> ast::Path { + ast::Path { + span: span, + global: false, + idents: ~[ident], + rp: None, + types: ~[] + } + } + + // to: + // + // { + // let _i = &mut <src_expr>; + // loop { + // match i.next() { + // None => break, + // Some(<src_pat>) => <src_loop_block> + // } + // } + // } + + let local_ident = token::gensym_ident("i"); + let some_ident = token::str_to_ident("Some"); + let none_ident = token::str_to_ident("None"); + let next_ident = token::str_to_ident("next"); + + let local_path_1 = mk_simple_path(local_ident, span); + let local_path_2 = mk_simple_path(local_ident, span); + let some_path = mk_simple_path(some_ident, span); + let none_path = mk_simple_path(none_ident, span); + + // `let i = &mut <src_expr>` + let iter_decl_stmt = { + let ty = ast::Ty { + id: cx.next_id(), + node: ast::ty_infer, + span: span + }; + let local = @ast::Local { + is_mutbl: false, + ty: ty, + pat: @ast::pat { + id: cx.next_id(), + node: ast::pat_ident(ast::bind_infer, local_path_1, None), + span: src_expr.span + }, + init: Some(mk_expr(cx, src_expr.span, + ast::expr_addr_of(ast::m_mutbl, src_expr))), + id: cx.next_id(), + span: src_expr.span, + }; + let e = @spanned(src_expr.span.lo, + src_expr.span.hi, + ast::decl_local(local)); + @spanned(lo, hi, ast::stmt_decl(e, cx.next_id())) + }; + + // `None => break;` + let none_arm = { + let break_expr = mk_expr(cx, span, ast::expr_break(None)); + let break_stmt = @spanned(lo, hi, ast::stmt_expr(break_expr, cx.next_id())); + let none_block = mk_block(cx, [break_stmt], None, span); + let none_pat = @ast::pat { + id: cx.next_id(), + node: ast::pat_ident(ast::bind_infer, none_path, None), + span: span + }; + ast::arm { + pats: ~[none_pat], + guard: None, + body: none_block + } + }; + + // `Some(<src_pat>) => <src_loop_block>` + let some_arm = { + let pat = @ast::pat { + id: cx.next_id(), + node: ast::pat_enum(some_path, Some(~[src_pat])), + span: src_pat.span + }; + ast::arm { + pats: ~[pat], + guard: None, + body: src_loop_block + } + }; + + // `match i.next() { ... }` + let match_stmt = { + let local_expr = mk_expr(cx, span, ast::expr_path(local_path_2)); + let next_call_expr = mk_expr(cx, span, + ast::expr_method_call(cx.next_id(), + local_expr, next_ident, + ~[], ~[], ast::NoSugar)); + let match_expr = mk_expr(cx, span, ast::expr_match(next_call_expr, + ~[none_arm, some_arm])); + @spanned(lo, hi, ast::stmt_expr(match_expr, cx.next_id())) + }; + + // `loop { ... }` + let loop_block = { + let loop_body_block = mk_block(cx, [match_stmt], None, span); + let loop_body_expr = mk_expr(cx, span, ast::expr_loop(loop_body_block, None)); + let loop_body_stmt = @spanned(lo, hi, ast::stmt_expr(loop_body_expr, cx.next_id())); + mk_block(cx, [iter_decl_stmt, + loop_body_stmt], + None, span) + }; + + (ast::expr_block(loop_block), span) + } + _ => orig(e, s, fld) } } |
