Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 6ecdc04

Browse files
committedMar 27, 2011
Add support for break and cont to rustc
Testing proper cleanup is hampered by https://github.com/graydon/rust/issues/293
1 parent 9c5affd commit 6ecdc04

File tree

8 files changed

+164
-9
lines changed

8 files changed

+164
-9
lines changed
 

‎src/comp/front/ast.rs

+2
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,8 @@ tag expr_ {
246246
expr_path(path, option.t[def], ann);
247247
expr_ext(path, vec[@expr], option.t[@expr], @expr, ann);
248248
expr_fail;
249+
expr_break;
250+
expr_cont;
249251
expr_ret(option.t[@expr]);
250252
expr_put(option.t[@expr]);
251253
expr_be(@expr);

‎src/comp/front/lexer.rs

+2
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ impure fn new_reader(io.reader rdr, str filename) -> reader
111111

112112
keywords.insert("for", token.FOR);
113113
keywords.insert("each", token.EACH);
114+
keywords.insert("break", token.BREAK);
115+
keywords.insert("cont", token.CONT);
114116
keywords.insert("put", token.PUT);
115117
keywords.insert("ret", token.RET);
116118
keywords.insert("be", token.BE);

‎src/comp/front/parser.rs

+10
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,16 @@ impure fn parse_bottom_expr(parser p) -> @ast.expr {
829829
}
830830
}
831831

832+
case (token.BREAK) {
833+
p.bump();
834+
ex = ast.expr_break;
835+
}
836+
837+
case (token.CONT) {
838+
p.bump();
839+
ex = ast.expr_cont;
840+
}
841+
832842
case (token.PUT) {
833843
p.bump();
834844
alt (p.peek()) {

‎src/comp/front/token.rs

+6
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ tag token {
7474
ALT;
7575
CASE;
7676

77+
BREAK;
78+
CONT;
79+
7780
FAIL;
7881
DROP;
7982

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

248+
case (BREAK) { ret "break"; }
249+
case (CONT) { ret "cont"; }
250+
245251
case (FAIL) { ret "fail"; }
246252
case (DROP) { ret "drop"; }
247253

‎src/comp/middle/fold.rs

+22
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,10 @@ type ast_fold[ENV] =
170170

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

173+
(fn(&ENV e, &span sp) -> @expr) fold_expr_break,
174+
175+
(fn(&ENV e, &span sp) -> @expr) fold_expr_cont,
176+
173177
(fn(&ENV e, &span sp,
174178
&option.t[@expr] rv) -> @expr) fold_expr_ret,
175179

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

702+
case (ast.expr_break) {
703+
ret fld.fold_expr_break(env_, e.span);
704+
}
705+
706+
case (ast.expr_cont) {
707+
ret fld.fold_expr_cont(env_, e.span);
708+
}
709+
698710
case (ast.expr_ret(?oe)) {
699711
auto oee = none[@expr];
700712
alt (oe) {
@@ -1266,6 +1278,14 @@ fn identity_fold_expr_fail[ENV](&ENV env, &span sp) -> @expr {
12661278
ret @respan(sp, ast.expr_fail);
12671279
}
12681280

1281+
fn identity_fold_expr_break[ENV](&ENV env, &span sp) -> @expr {
1282+
ret @respan(sp, ast.expr_break);
1283+
}
1284+
1285+
fn identity_fold_expr_cont[ENV](&ENV env, &span sp) -> @expr {
1286+
ret @respan(sp, ast.expr_cont);
1287+
}
1288+
12691289
fn identity_fold_expr_ret[ENV](&ENV env, &span sp,
12701290
&option.t[@expr] rv) -> @expr {
12711291
ret @respan(sp, ast.expr_ret(rv));
@@ -1565,6 +1585,8 @@ fn new_identity_fold[ENV]() -> ast_fold[ENV] {
15651585
fold_expr_path = bind identity_fold_expr_path[ENV](_,_,_,_,_),
15661586
fold_expr_ext = bind identity_fold_expr_ext[ENV](_,_,_,_,_,_,_),
15671587
fold_expr_fail = bind identity_fold_expr_fail[ENV](_,_),
1588+
fold_expr_break = bind identity_fold_expr_break[ENV](_,_),
1589+
fold_expr_cont = bind identity_fold_expr_cont[ENV](_,_),
15681590
fold_expr_ret = bind identity_fold_expr_ret[ENV](_,_,_),
15691591
fold_expr_put = bind identity_fold_expr_put[ENV](_,_,_),
15701592
fold_expr_be = bind identity_fold_expr_be[ENV](_,_,_),

‎src/comp/middle/trans.rs

+72-9
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ tag cleanup {
130130

131131
tag block_kind {
132132
SCOPE_BLOCK;
133+
LOOP_SCOPE_BLOCK(option.t[@block_ctxt], @block_ctxt);
133134
NON_SCOPE_BLOCK;
134135
}
135136

@@ -990,7 +991,7 @@ fn trans_non_gc_free(@block_ctxt cx, ValueRef v) -> result {
990991
}
991992

992993
fn find_scope_cx(@block_ctxt cx) -> @block_ctxt {
993-
if (cx.kind == SCOPE_BLOCK) {
994+
if (cx.kind != NON_SCOPE_BLOCK) {
994995
ret cx;
995996
}
996997
alt (cx.parent) {
@@ -3043,13 +3044,15 @@ fn trans_for(@block_ctxt cx,
30433044
@ast.decl decl,
30443045
@ast.expr seq,
30453046
&ast.block body) -> result {
3046-
30473047
fn inner(@block_ctxt cx,
30483048
@ast.local local, ValueRef curr,
3049-
@ty.t t, ast.block body) -> result {
3049+
@ty.t t, ast.block body,
3050+
@block_ctxt outer_next_cx) -> result {
30503051

3051-
auto scope_cx = new_scope_block_ctxt(cx, "for loop scope");
30523052
auto next_cx = new_sub_block_ctxt(cx, "next");
3053+
auto scope_cx =
3054+
new_loop_scope_block_ctxt(cx, option.some[@block_ctxt](next_cx),
3055+
outer_next_cx, "for loop scope");
30533056

30543057
cx.build.Br(scope_cx.llbb);
30553058
auto local_res = alloc_local(scope_cx, local);
@@ -3069,10 +3072,13 @@ fn trans_for(@block_ctxt cx,
30693072
}
30703073
}
30713074

3075+
auto next_cx = new_sub_block_ctxt(cx, "next");
30723076
auto seq_ty = ty.expr_ty(seq);
30733077
auto seq_res = trans_expr(cx, seq);
3074-
ret iter_sequence(seq_res.bcx, seq_res.val, seq_ty,
3075-
bind inner(_, local, _, _, body));
3078+
auto it = iter_sequence(seq_res.bcx, seq_res.val, seq_ty,
3079+
bind inner(_, local, _, _, body, next_cx));
3080+
it.bcx.build.Br(next_cx.llbb);
3081+
ret res(next_cx, it.val);
30763082
}
30773083

30783084

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

33103316
auto cond_cx = new_scope_block_ctxt(cx, "while cond");
3311-
auto body_cx = new_scope_block_ctxt(cx, "while loop body");
33123317
auto next_cx = new_sub_block_ctxt(cx, "next");
3318+
auto body_cx = new_loop_scope_block_ctxt(cx, option.none[@block_ctxt],
3319+
next_cx, "while loop body");
33133320

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

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

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

4610+
case (ast.expr_break) {
4611+
ret trans_break(cx);
4612+
}
4613+
4614+
case (ast.expr_cont) {
4615+
ret trans_cont(cx);
4616+
}
4617+
46024618
case (ast.expr_ret(?e)) {
46034619
ret trans_ret(cx, e);
46044620
}
@@ -4770,6 +4786,47 @@ fn trans_put(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
47704786
ret res(bcx, bcx.build.FastCall(llcallee, llargs));
47714787
}
47724788

4789+
fn trans_break_cont(@block_ctxt cx, bool to_end) -> result {
4790+
auto bcx = cx;
4791+
// Locate closest loop block, outputting cleanup as we go.
4792+
auto cleanup_cx = cx;
4793+
while (true) {
4794+
bcx = trans_block_cleanups(bcx, cleanup_cx);
4795+
alt (cleanup_cx.kind) {
4796+
case (LOOP_SCOPE_BLOCK(?_cont, ?_break)) {
4797+
if (to_end) {
4798+
bcx.build.Br(_break.llbb);
4799+
} else {
4800+
alt (_cont) {
4801+
case (option.some[@block_ctxt](?_cont)) {
4802+
bcx.build.Br(_cont.llbb);
4803+
}
4804+
case (_) {
4805+
bcx.build.Br(cleanup_cx.llbb);
4806+
}
4807+
}
4808+
}
4809+
ret res(new_sub_block_ctxt(cx, "unreachable"), C_nil());
4810+
}
4811+
case (_) {
4812+
alt (cleanup_cx.parent) {
4813+
case (parent_some(?cx)) { cleanup_cx = cx; }
4814+
}
4815+
}
4816+
}
4817+
}
4818+
ret res(cx, C_nil()); // Never reached. Won't compile otherwise.
4819+
}
4820+
4821+
fn trans_break(@block_ctxt cx) -> result {
4822+
ret trans_break_cont(cx, true);
4823+
}
4824+
4825+
fn trans_cont(@block_ctxt cx) -> result {
4826+
ret trans_break_cont(cx, false);
4827+
}
4828+
4829+
47734830
fn trans_ret(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
47744831
auto bcx = cx;
47754832
auto val = C_nil();
@@ -5033,6 +5090,12 @@ fn new_scope_block_ctxt(@block_ctxt bcx, str n) -> @block_ctxt {
50335090
ret new_block_ctxt(bcx.fcx, parent_some(bcx), SCOPE_BLOCK, n);
50345091
}
50355092

5093+
fn new_loop_scope_block_ctxt(@block_ctxt bcx, option.t[@block_ctxt] _cont,
5094+
@block_ctxt _break, str n) -> @block_ctxt {
5095+
ret new_block_ctxt(bcx.fcx, parent_some(bcx),
5096+
LOOP_SCOPE_BLOCK(_cont, _break), n);
5097+
}
5098+
50365099
// Use this when you're making a general CFG BB within a scope.
50375100
fn new_sub_block_ctxt(@block_ctxt bcx, str n) -> @block_ctxt {
50385101
ret new_block_ctxt(bcx.fcx, parent_some(bcx), NON_SCOPE_BLOCK, n);
@@ -5043,7 +5106,7 @@ fn trans_block_cleanups(@block_ctxt cx,
50435106
@block_ctxt cleanup_cx) -> @block_ctxt {
50445107
auto bcx = cx;
50455108

5046-
if (cleanup_cx.kind != SCOPE_BLOCK) {
5109+
if (cleanup_cx.kind == NON_SCOPE_BLOCK) {
50475110
check (_vec.len[cleanup](cleanup_cx.cleanups) == 0u);
50485111
}
50495112

‎src/comp/middle/typeck.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1413,6 +1413,8 @@ fn demand_expr_full(&@fn_ctxt fcx, @ty.t expected, @ast.expr e,
14131413
}
14141414
case (ast.expr_fail) { e_1 = e.node; }
14151415
case (ast.expr_log(_)) { e_1 = e.node; }
1416+
case (ast.expr_break) { e_1 = e.node; }
1417+
case (ast.expr_cont) { e_1 = e.node; }
14161418
case (ast.expr_ret(_)) { e_1 = e.node; }
14171419
case (ast.expr_put(_)) { e_1 = e.node; }
14181420
case (ast.expr_be(_)) { e_1 = e.node; }
@@ -1806,6 +1808,14 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
18061808
ret expr;
18071809
}
18081810

1811+
case (ast.expr_break) {
1812+
ret expr;
1813+
}
1814+
1815+
case (ast.expr_cont) {
1816+
ret expr;
1817+
}
1818+
18091819
case (ast.expr_ret(?expr_opt)) {
18101820
alt (expr_opt) {
18111821
case (none[@ast.expr]) {

‎src/test/run-pass/break.rs

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// xfail-boot
2+
3+
fn main() {
4+
auto i = 0;
5+
while (i < 20) {
6+
i += 1;
7+
if (i == 10) { break; }
8+
}
9+
check(i == 10);
10+
11+
do {
12+
i += 1;
13+
if (i == 20) { break; }
14+
} while (i < 30);
15+
check(i == 20);
16+
17+
for (int x in vec(1, 2, 3, 4, 5, 6)) {
18+
if (x == 3) { break; }
19+
check(x <= 3);
20+
}
21+
22+
i = 0;
23+
while (i < 10) {
24+
i += 1;
25+
if (i % 2 == 0) { cont; }
26+
check(i % 2 != 0);
27+
}
28+
29+
i = 0;
30+
do {
31+
i += 1;
32+
if (i % 2 == 0) { cont; }
33+
check(i % 2 != 0);
34+
} while (i < 10);
35+
36+
for (int x in vec(1, 2, 3, 4, 5, 6)) {
37+
if (x % 2 == 0) { cont; }
38+
check(x % 2 != 0);
39+
}
40+
}

0 commit comments

Comments
 (0)
Please sign in to comment.