Skip to content

Commit

Permalink
Add support for break and cont to rustc
Browse files Browse the repository at this point in the history
  • Loading branch information
marijnh committed Mar 27, 2011
1 parent 9c5affd commit 6ecdc04
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 9 deletions.
2 changes: 2 additions & 0 deletions src/comp/front/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,8 @@ tag expr_ {
expr_path(path, option.t[def], ann);
expr_ext(path, vec[@expr], option.t[@expr], @expr, ann);
expr_fail;
expr_break;
expr_cont;
expr_ret(option.t[@expr]);
expr_put(option.t[@expr]);
expr_be(@expr);
Expand Down
2 changes: 2 additions & 0 deletions src/comp/front/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ impure fn new_reader(io.reader rdr, str filename) -> reader

keywords.insert("for", token.FOR);
keywords.insert("each", token.EACH);
keywords.insert("break", token.BREAK);
keywords.insert("cont", token.CONT);
keywords.insert("put", token.PUT);
keywords.insert("ret", token.RET);
keywords.insert("be", token.BE);
Expand Down
10 changes: 10 additions & 0 deletions src/comp/front/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,16 @@ impure fn parse_bottom_expr(parser p) -> @ast.expr {
}
}

case (token.BREAK) {
p.bump();
ex = ast.expr_break;
}

case (token.CONT) {
p.bump();
ex = ast.expr_cont;
}

case (token.PUT) {
p.bump();
alt (p.peek()) {
Expand Down
6 changes: 6 additions & 0 deletions src/comp/front/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ tag token {
ALT;
CASE;

BREAK;
CONT;

FAIL;
DROP;

Expand Down Expand Up @@ -242,6 +245,9 @@ fn to_str(token t) -> str {
case (ALT) { ret "alt"; }
case (CASE) { ret "case"; }

case (BREAK) { ret "break"; }
case (CONT) { ret "cont"; }

case (FAIL) { ret "fail"; }
case (DROP) { ret "drop"; }

Expand Down
22 changes: 22 additions & 0 deletions src/comp/middle/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ type ast_fold[ENV] =

(fn(&ENV e, &span sp) -> @expr) fold_expr_fail,

(fn(&ENV e, &span sp) -> @expr) fold_expr_break,

(fn(&ENV e, &span sp) -> @expr) fold_expr_cont,

(fn(&ENV e, &span sp,
&option.t[@expr] rv) -> @expr) fold_expr_ret,

Expand Down Expand Up @@ -695,6 +699,14 @@ fn fold_expr[ENV](&ENV env, ast_fold[ENV] fld, &@expr e) -> @expr {
ret fld.fold_expr_fail(env_, e.span);
}

case (ast.expr_break) {
ret fld.fold_expr_break(env_, e.span);
}

case (ast.expr_cont) {
ret fld.fold_expr_cont(env_, e.span);
}

case (ast.expr_ret(?oe)) {
auto oee = none[@expr];
alt (oe) {
Expand Down Expand Up @@ -1266,6 +1278,14 @@ fn identity_fold_expr_fail[ENV](&ENV env, &span sp) -> @expr {
ret @respan(sp, ast.expr_fail);
}

fn identity_fold_expr_break[ENV](&ENV env, &span sp) -> @expr {
ret @respan(sp, ast.expr_break);
}

fn identity_fold_expr_cont[ENV](&ENV env, &span sp) -> @expr {
ret @respan(sp, ast.expr_cont);
}

fn identity_fold_expr_ret[ENV](&ENV env, &span sp,
&option.t[@expr] rv) -> @expr {
ret @respan(sp, ast.expr_ret(rv));
Expand Down Expand Up @@ -1565,6 +1585,8 @@ fn new_identity_fold[ENV]() -> ast_fold[ENV] {
fold_expr_path = bind identity_fold_expr_path[ENV](_,_,_,_,_),
fold_expr_ext = bind identity_fold_expr_ext[ENV](_,_,_,_,_,_,_),
fold_expr_fail = bind identity_fold_expr_fail[ENV](_,_),
fold_expr_break = bind identity_fold_expr_break[ENV](_,_),
fold_expr_cont = bind identity_fold_expr_cont[ENV](_,_),
fold_expr_ret = bind identity_fold_expr_ret[ENV](_,_,_),
fold_expr_put = bind identity_fold_expr_put[ENV](_,_,_),
fold_expr_be = bind identity_fold_expr_be[ENV](_,_,_),
Expand Down
81 changes: 72 additions & 9 deletions src/comp/middle/trans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ tag cleanup {

tag block_kind {
SCOPE_BLOCK;
LOOP_SCOPE_BLOCK(option.t[@block_ctxt], @block_ctxt);
NON_SCOPE_BLOCK;
}

Expand Down Expand Up @@ -990,7 +991,7 @@ fn trans_non_gc_free(@block_ctxt cx, ValueRef v) -> result {
}

fn find_scope_cx(@block_ctxt cx) -> @block_ctxt {
if (cx.kind == SCOPE_BLOCK) {
if (cx.kind != NON_SCOPE_BLOCK) {
ret cx;
}
alt (cx.parent) {
Expand Down Expand Up @@ -3043,13 +3044,15 @@ fn trans_for(@block_ctxt cx,
@ast.decl decl,
@ast.expr seq,
&ast.block body) -> result {

fn inner(@block_ctxt cx,
@ast.local local, ValueRef curr,
@ty.t t, ast.block body) -> result {
@ty.t t, ast.block body,
@block_ctxt outer_next_cx) -> result {

auto scope_cx = new_scope_block_ctxt(cx, "for loop scope");
auto next_cx = new_sub_block_ctxt(cx, "next");
auto scope_cx =
new_loop_scope_block_ctxt(cx, option.some[@block_ctxt](next_cx),
outer_next_cx, "for loop scope");

cx.build.Br(scope_cx.llbb);
auto local_res = alloc_local(scope_cx, local);
Expand All @@ -3069,10 +3072,13 @@ fn trans_for(@block_ctxt cx,
}
}

auto next_cx = new_sub_block_ctxt(cx, "next");
auto seq_ty = ty.expr_ty(seq);
auto seq_res = trans_expr(cx, seq);
ret iter_sequence(seq_res.bcx, seq_res.val, seq_ty,
bind inner(_, local, _, _, body));
auto it = iter_sequence(seq_res.bcx, seq_res.val, seq_ty,
bind inner(_, local, _, _, body, next_cx));
it.bcx.build.Br(next_cx.llbb);
ret res(next_cx, it.val);
}


Expand Down Expand Up @@ -3308,8 +3314,9 @@ fn trans_while(@block_ctxt cx, @ast.expr cond,
&ast.block body) -> result {

auto cond_cx = new_scope_block_ctxt(cx, "while cond");
auto body_cx = new_scope_block_ctxt(cx, "while loop body");
auto next_cx = new_sub_block_ctxt(cx, "next");
auto body_cx = new_loop_scope_block_ctxt(cx, option.none[@block_ctxt],
next_cx, "while loop body");

auto body_res = trans_block(body_cx, body);
auto cond_res = trans_expr(cond_cx, cond);
Expand All @@ -3326,8 +3333,9 @@ fn trans_while(@block_ctxt cx, @ast.expr cond,
fn trans_do_while(@block_ctxt cx, &ast.block body,
@ast.expr cond) -> result {

auto body_cx = new_scope_block_ctxt(cx, "do-while loop body");
auto next_cx = new_sub_block_ctxt(cx, "next");
auto body_cx = new_loop_scope_block_ctxt(cx, option.none[@block_ctxt],
next_cx, "do-while loop body");

auto body_res = trans_block(body_cx, body);
auto cond_res = trans_expr(body_res.bcx, cond);
Expand Down Expand Up @@ -4599,6 +4607,14 @@ fn trans_expr(@block_ctxt cx, @ast.expr e) -> result {
ret trans_check_expr(cx, a);
}

case (ast.expr_break) {
ret trans_break(cx);
}

case (ast.expr_cont) {
ret trans_cont(cx);
}

case (ast.expr_ret(?e)) {
ret trans_ret(cx, e);
}
Expand Down Expand Up @@ -4770,6 +4786,47 @@ fn trans_put(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
ret res(bcx, bcx.build.FastCall(llcallee, llargs));
}

fn trans_break_cont(@block_ctxt cx, bool to_end) -> result {
auto bcx = cx;
// Locate closest loop block, outputting cleanup as we go.
auto cleanup_cx = cx;
while (true) {
bcx = trans_block_cleanups(bcx, cleanup_cx);
alt (cleanup_cx.kind) {
case (LOOP_SCOPE_BLOCK(?_cont, ?_break)) {
if (to_end) {
bcx.build.Br(_break.llbb);
} else {
alt (_cont) {
case (option.some[@block_ctxt](?_cont)) {
bcx.build.Br(_cont.llbb);
}
case (_) {
bcx.build.Br(cleanup_cx.llbb);
}
}
}
ret res(new_sub_block_ctxt(cx, "unreachable"), C_nil());
}
case (_) {
alt (cleanup_cx.parent) {
case (parent_some(?cx)) { cleanup_cx = cx; }
}
}
}
}
ret res(cx, C_nil()); // Never reached. Won't compile otherwise.
}

fn trans_break(@block_ctxt cx) -> result {
ret trans_break_cont(cx, true);
}

fn trans_cont(@block_ctxt cx) -> result {
ret trans_break_cont(cx, false);
}


fn trans_ret(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
auto bcx = cx;
auto val = C_nil();
Expand Down Expand Up @@ -5033,6 +5090,12 @@ fn new_scope_block_ctxt(@block_ctxt bcx, str n) -> @block_ctxt {
ret new_block_ctxt(bcx.fcx, parent_some(bcx), SCOPE_BLOCK, n);
}

fn new_loop_scope_block_ctxt(@block_ctxt bcx, option.t[@block_ctxt] _cont,
@block_ctxt _break, str n) -> @block_ctxt {
ret new_block_ctxt(bcx.fcx, parent_some(bcx),
LOOP_SCOPE_BLOCK(_cont, _break), n);
}

// Use this when you're making a general CFG BB within a scope.
fn new_sub_block_ctxt(@block_ctxt bcx, str n) -> @block_ctxt {
ret new_block_ctxt(bcx.fcx, parent_some(bcx), NON_SCOPE_BLOCK, n);
Expand All @@ -5043,7 +5106,7 @@ fn trans_block_cleanups(@block_ctxt cx,
@block_ctxt cleanup_cx) -> @block_ctxt {
auto bcx = cx;

if (cleanup_cx.kind != SCOPE_BLOCK) {
if (cleanup_cx.kind == NON_SCOPE_BLOCK) {
check (_vec.len[cleanup](cleanup_cx.cleanups) == 0u);
}

Expand Down
10 changes: 10 additions & 0 deletions src/comp/middle/typeck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1413,6 +1413,8 @@ fn demand_expr_full(&@fn_ctxt fcx, @ty.t expected, @ast.expr e,
}
case (ast.expr_fail) { e_1 = e.node; }
case (ast.expr_log(_)) { e_1 = e.node; }
case (ast.expr_break) { e_1 = e.node; }
case (ast.expr_cont) { e_1 = e.node; }
case (ast.expr_ret(_)) { e_1 = e.node; }
case (ast.expr_put(_)) { e_1 = e.node; }
case (ast.expr_be(_)) { e_1 = e.node; }
Expand Down Expand Up @@ -1806,6 +1808,14 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
ret expr;
}

case (ast.expr_break) {
ret expr;
}

case (ast.expr_cont) {
ret expr;
}

case (ast.expr_ret(?expr_opt)) {
alt (expr_opt) {
case (none[@ast.expr]) {
Expand Down
40 changes: 40 additions & 0 deletions src/test/run-pass/break.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// xfail-boot

fn main() {
auto i = 0;
while (i < 20) {
i += 1;
if (i == 10) { break; }
}
check(i == 10);

do {
i += 1;
if (i == 20) { break; }
} while (i < 30);
check(i == 20);

for (int x in vec(1, 2, 3, 4, 5, 6)) {
if (x == 3) { break; }
check(x <= 3);
}

i = 0;
while (i < 10) {
i += 1;
if (i % 2 == 0) { cont; }
check(i % 2 != 0);
}

i = 0;
do {
i += 1;
if (i % 2 == 0) { cont; }
check(i % 2 != 0);
} while (i < 10);

for (int x in vec(1, 2, 3, 4, 5, 6)) {
if (x % 2 == 0) { cont; }
check(x % 2 != 0);
}
}

0 comments on commit 6ecdc04

Please sign in to comment.