Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Foreach in sketch #8141

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/librustc/middle/cfg/construct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@ impl CFGBuilder {
expr_exit
}

ast::expr_for_loop(*) => fail!("non-desugared expr_for_loop"),

ast::expr_loop(ref body, _) => {
//
// [pred]
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/middle/dataflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,8 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> {
copy_bits(new_loop_scope.break_bits, in_out);
}

ast::expr_for_loop(*) => fail!("non-desugared expr_for_loop"),

ast::expr_loop(ref blk, _) => {
//
// (expr) <--+
Expand Down
4 changes: 4 additions & 0 deletions src/librustc/middle/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,7 @@ fn visit_expr(expr: @expr, (this, vt): (@mut IrMaps, vt<@mut IrMaps>)) {
this.add_live_node_for_node(expr.id, ExprNode(expr.span));
visit::visit_expr(expr, (this, vt));
}
expr_for_loop(*) => fail!("non-desugared expr_for_loop"),
expr_binary(_, op, _, _) if ast_util::lazy_binop(op) => {
this.add_live_node_for_node(expr.id, ExprNode(expr.span));
visit::visit_expr(expr, (this, vt));
Expand Down Expand Up @@ -1057,6 +1058,8 @@ impl Liveness {
self.propagate_through_loop(expr, Some(cond), blk, succ)
}

expr_for_loop(*) => fail!("non-desugared expr_for_loop"),

// Note that labels have been resolved, so we don't need to look
// at the label ident
expr_loop(ref blk, _) => {
Expand Down Expand Up @@ -1487,6 +1490,7 @@ fn check_expr(expr: @expr, (this, vt): (@Liveness, vt<@Liveness>)) {
expr_paren(*) | expr_fn_block(*) | expr_path(*) | expr_self(*) => {
visit::visit_expr(expr, (this, vt));
}
expr_for_loop(*) => fail!("non-desugared expr_for_loop")
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,8 @@ impl mem_categorization_ctxt {
ast::expr_inline_asm(*) => {
return self.cat_rvalue_node(expr, expr_ty);
}

ast::expr_for_loop(*) => fail!("non-desugared expr_for_loop")
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/librustc/middle/moves.rs
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,8 @@ impl VisitContext {
self.consume_block(blk, visitor);
}

expr_for_loop(*) => fail!("non-desugared expr_for_loop"),

expr_unary(_, _, lhs) => {
if !self.use_overloaded_operator(
expr, lhs, [], visitor)
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/middle/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5016,6 +5016,8 @@ impl Resolver {
}
}

expr_for_loop(*) => fail!("non-desugared expr_for_loop"),

expr_break(Some(label)) | expr_again(Some(label)) => {
match self.search_ribs(self.label_ribs, label, expr.span,
DontAllowCapturingSelf) {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2266,7 +2266,7 @@ pub fn register_fn_fuller(ccx: @mut CrateContext,
sp: span,
sym: ~str,
node_id: ast::NodeId,
node_type: ty::t,
_node_type: ty::t,
cc: lib::llvm::CallConv,
fn_ty: Type)
-> ValueRef {
Expand Down
4 changes: 3 additions & 1 deletion src/librustc/middle/trans/type_use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,9 @@ pub fn mark_for_expr(cx: &Context, e: &expr) {
expr_match(*) | expr_block(_) | expr_if(*) | expr_while(*) |
expr_break(_) | expr_again(_) | expr_unary(*) | expr_lit(_) |
expr_mac(_) | expr_addr_of(*) | expr_ret(_) | expr_loop(*) |
expr_loop_body(_) | expr_do_body(_) => ()
expr_loop_body(_) | expr_do_body(_) => (),

expr_for_loop(*) => fail!("non-desugared expr_for_loop")
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3240,6 +3240,8 @@ pub fn expr_kind(tcx: ctxt,
RvalueStmtExpr
}

ast::expr_for_loop(*) => fail!("non-desugared expr_for_loop"),

ast::expr_lit(_) | // Note: lit_str is carved out above
ast::expr_unary(*) |
ast::expr_addr_of(*) |
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/middle/typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2559,6 +2559,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
fcx.write_nil(id);
}
}
ast::expr_for_loop(*) =>
fail!("non-desugared expr_for_loop"),
ast::expr_loop(ref body, _) => {
check_block_no_value(fcx, (body));
if !may_break(tcx, expr.id, body) {
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/typeck/check/regionck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,7 @@ pub mod guarantor {
rcx.fcx.tcx(), rcx.fcx.inh.method_map, expr));
None
}
ast::expr_for_loop(*) => fail!("non-desugared expr_for_loop"),
}
}

Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ pub enum expr_ {
expr_cast(@expr, Ty),
expr_if(@expr, Block, Option<@expr>),
expr_while(@expr, Block),
expr_for_loop(@pat, @expr, Block),
/* Conditionless loop (can be exited with break, cont, or ret)
Same semantics as while(true) { body }, but typestate knows that the
(implicit) condition is always true. */
Expand Down
156 changes: 155 additions & 1 deletion src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/libsyntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,11 @@ pub fn noop_fold_expr(e: &expr_, fld: @ast_fold) -> expr_ {
expr_while(cond, ref body) => {
expr_while(fld.fold_expr(cond), fld.fold_block(body))
}
expr_for_loop(pat, iter, ref body) => {
expr_for_loop(fld.fold_pat(pat),
fld.fold_expr(iter),
fld.fold_block(body))
}
expr_loop(ref body, opt_ident) => {
expr_loop(
fld.fold_block(body),
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/parse/classify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub fn expr_requires_semi_to_be_stmt(e: @ast::expr) -> bool {
| ast::expr_block(_)
| ast::expr_while(*)
| ast::expr_loop(*)
| ast::expr_for_loop(*)
| ast::expr_call(_, _, ast::DoSugar)
| ast::expr_call(_, _, ast::ForSugar)
| ast::expr_method_call(_, _, _, _, _, ast::DoSugar)
Expand Down
19 changes: 18 additions & 1 deletion src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use ast::{expr_method_call, expr_paren, expr_path, expr_repeat};
use ast::{expr_ret, expr_self, expr_struct, expr_tup, expr_unary};
use ast::{expr_vec, expr_vstore, expr_vstore_mut_box};
use ast::{expr_vstore_slice, expr_vstore_box};
use ast::{expr_vstore_mut_slice, expr_while, extern_fn, Field, fn_decl};
use ast::{expr_vstore_mut_slice, expr_while, expr_for_loop, extern_fn, Field, fn_decl};
use ast::{expr_vstore_uniq, Onceness, Once, Many};
use ast::{foreign_item, foreign_item_static, foreign_item_fn, foreign_mod};
use ast::{ident, impure_fn, inherited, item, item_, item_static};
Expand Down Expand Up @@ -1622,6 +1622,8 @@ impl Parser {
hi = self.span.hi;
} else if self.eat_keyword(keywords::If) {
return self.parse_if_expr();
} else if self.eat_keyword(keywords::ForEach) {
return self.parse_for_expr();
} else if self.eat_keyword(keywords::For) {
return self.parse_sugary_call_expr(lo, ~"for", ForSugar,
expr_loop_body);
Expand Down Expand Up @@ -2323,6 +2325,21 @@ impl Parser {
}
}

// parse a 'foreach' .. 'in' expression ('foreach' token already eaten)
pub fn parse_for_expr(&self) -> @expr {
// Parse: `foreach <src_pat> in <src_expr> <src_loop_block>`

let lo = self.last_span.lo;
let pat = self.parse_pat();
self.expect_keyword(keywords::In);
let expr = self.parse_expr();
let loop_block = self.parse_block();
let hi = self.span.hi;

self.mk_expr(lo, hi, expr_for_loop(pat, expr, loop_block))
}


// parse a 'for' or 'do'.
// the 'for' and 'do' expressions parse as calls, but look like
// function calls followed by a closure expression.
Expand Down
6 changes: 6 additions & 0 deletions src/libsyntax/parse/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,8 @@ fn mk_fresh_ident_interner() -> @ident_interner {
"while", // 64

"be", // 65
"in", // 66
"foreach", // 67
];

@ident_interner {
Expand Down Expand Up @@ -570,8 +572,10 @@ pub mod keywords {
False,
Fn,
For,
ForEach,
If,
Impl,
In,
Let,
__Log,
Loop,
Expand Down Expand Up @@ -612,8 +616,10 @@ pub mod keywords {
False => ident { name: 40, ctxt: 0 },
Fn => ident { name: 41, ctxt: 0 },
For => ident { name: 42, ctxt: 0 },
ForEach => ident { name: 67, ctxt: 0 },
If => ident { name: 43, ctxt: 0 },
Impl => ident { name: 44, ctxt: 0 },
In => ident { name: 66, ctxt: 0 },
Let => ident { name: 45, ctxt: 0 },
__Log => ident { name: 46, ctxt: 0 },
Loop => ident { name: 47, ctxt: 0 },
Expand Down
Loading