Skip to content

Commit d36612d

Browse files
committed
auto merge of #9054 : huonw/rust/labelled-for, r=thestinger
The following parses and works as expected with this change: ```rust 'foo: for i in range(0, 10) { for j in range(0, 10) { if i + j == 15 { break 'foo; } } } ```
2 parents b609d02 + 1418311 commit d36612d

File tree

9 files changed

+69
-145
lines changed

9 files changed

+69
-145
lines changed

src/librustc/middle/trans/debuginfo.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2064,7 +2064,7 @@ fn populate_scope_map(cx: &mut CrateContext,
20642064
}
20652065
}
20662066

2067-
ast::ExprForLoop(_, _, _) => {
2067+
ast::ExprForLoop(_, _, _, _) => {
20682068
cx.sess.span_bug(exp.span, "debuginfo::populate_scope_map() - \
20692069
Found unexpanded for-loop.");
20702070
}

src/libsyntax/ast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ pub enum Expr_ {
528528
ExprCast(@Expr, Ty),
529529
ExprIf(@Expr, Block, Option<@Expr>),
530530
ExprWhile(@Expr, Block),
531-
ExprForLoop(@Pat, @Expr, Block),
531+
ExprForLoop(@Pat, @Expr, Block, Option<Ident>),
532532
/* Conditionless loop (can be exited with break, cont, or ret)
533533
Same semantics as while(true) { body }, but typestate knows that the
534534
(implicit) condition is always true. */

src/libsyntax/ext/expand.rs

Lines changed: 39 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ use ast::{item_mac, Mrk, Stmt_, StmtDecl, StmtMac, StmtExpr, StmtSemi};
1414
use ast::{token_tree};
1515
use ast;
1616
use ast_util::{mtwt_outer_mark, new_rename, new_mark};
17+
use ext::build::AstBuilder;
1718
use attr;
1819
use attr::AttrMetaMethods;
1920
use codemap;
20-
use codemap::{Span, Spanned, spanned, ExpnInfo, NameAndSpan};
21+
use codemap::{Span, Spanned, ExpnInfo, NameAndSpan};
2122
use ext::base::*;
2223
use fold::*;
23-
use opt_vec;
2424
use parse;
2525
use parse::{parse_item_from_source_str};
2626
use parse::token;
@@ -33,7 +33,7 @@ use std::vec;
3333
pub fn expand_expr(extsbox: @mut SyntaxEnv,
3434
cx: @ExtCtxt,
3535
e: &Expr_,
36-
s: Span,
36+
span: Span,
3737
fld: @ast_fold,
3838
orig: @fn(&Expr_, Span, @ast_fold) -> (Expr_, Span))
3939
-> (Expr_, Span) {
@@ -66,7 +66,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
6666
}
6767
Some(@SE(NormalTT(expandfun, exp_span))) => {
6868
cx.bt_push(ExpnInfo {
69-
call_site: s,
69+
call_site: span,
7070
callee: NameAndSpan {
7171
name: extnamestr,
7272
span: exp_span,
@@ -98,7 +98,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
9898
fld.fold_expr(marked_after).node.clone();
9999
cx.bt_pop();
100100

101-
(fully_expanded, s)
101+
(fully_expanded, span)
102102
}
103103
_ => {
104104
cx.span_fatal(
@@ -112,62 +112,18 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
112112
}
113113

114114
// Desugar expr_for_loop
115-
// From: `for <src_pat> in <src_expr> <src_loop_block>`
116-
ast::ExprForLoop(src_pat, src_expr, ref src_loop_block) => {
117-
let src_pat = src_pat.clone();
118-
let src_expr = src_expr.clone();
119-
115+
// From: `['<ident>:] for <src_pat> in <src_expr> <src_loop_block>`
116+
ast::ExprForLoop(src_pat, src_expr, ref src_loop_block, opt_ident) => {
120117
// Expand any interior macros etc.
121118
// NB: we don't fold pats yet. Curious.
122-
let src_expr = fld.fold_expr(src_expr).clone();
123-
let src_loop_block = fld.fold_block(src_loop_block).clone();
124-
125-
let span = s;
126-
let lo = s.lo;
127-
let hi = s.hi;
128-
129-
pub fn mk_expr(cx: @ExtCtxt, span: Span,
130-
node: Expr_) -> @ast::Expr {
131-
@ast::Expr {
132-
id: cx.next_id(),
133-
node: node,
134-
span: span,
135-
}
136-
}
137-
138-
fn mk_block(cx: @ExtCtxt,
139-
stmts: &[@ast::Stmt],
140-
expr: Option<@ast::Expr>,
141-
span: Span) -> ast::Block {
142-
ast::Block {
143-
view_items: ~[],
144-
stmts: stmts.to_owned(),
145-
expr: expr,
146-
id: cx.next_id(),
147-
rules: ast::DefaultBlock,
148-
span: span,
149-
}
150-
}
151-
152-
fn mk_simple_path(ident: ast::Ident, span: Span) -> ast::Path {
153-
ast::Path {
154-
span: span,
155-
global: false,
156-
segments: ~[
157-
ast::PathSegment {
158-
identifier: ident,
159-
lifetime: None,
160-
types: opt_vec::Empty,
161-
}
162-
],
163-
}
164-
}
119+
let src_expr = fld.fold_expr(src_expr);
120+
let src_loop_block = fld.fold_block(src_loop_block);
165121

166122
// to:
167123
//
168124
// {
169125
// let _i = &mut <src_expr>;
170-
// loop {
126+
// ['<ident>:] loop {
171127
// match i.next() {
172128
// None => break,
173129
// Some(<src_pat>) => <src_loop_block>
@@ -176,98 +132,50 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
176132
// }
177133

178134
let local_ident = token::gensym_ident("i");
179-
let some_ident = token::str_to_ident("Some");
180-
let none_ident = token::str_to_ident("None");
181-
let next_ident = token::str_to_ident("next");
135+
let next_ident = cx.ident_of("next");
136+
let none_ident = cx.ident_of("None");
182137

183-
let local_path_1 = mk_simple_path(local_ident, span);
184-
let local_path_2 = mk_simple_path(local_ident, span);
185-
let some_path = mk_simple_path(some_ident, span);
186-
let none_path = mk_simple_path(none_ident, span);
138+
let local_path = cx.path_ident(span, local_ident);
139+
let some_path = cx.path_ident(span, cx.ident_of("Some"));
187140

188141
// `let i = &mut <src_expr>`
189-
let iter_decl_stmt = {
190-
let ty = ast::Ty {
191-
id: cx.next_id(),
192-
node: ast::ty_infer,
193-
span: span
194-
};
195-
let local = @ast::Local {
196-
is_mutbl: false,
197-
ty: ty,
198-
pat: @ast::Pat {
199-
id: cx.next_id(),
200-
node: ast::PatIdent(ast::BindInfer, local_path_1, None),
201-
span: src_expr.span
202-
},
203-
init: Some(mk_expr(cx, src_expr.span,
204-
ast::ExprAddrOf(ast::MutMutable, src_expr))),
205-
id: cx.next_id(),
206-
span: src_expr.span,
207-
};
208-
let e = @spanned(src_expr.span.lo,
209-
src_expr.span.hi,
210-
ast::DeclLocal(local));
211-
@spanned(lo, hi, ast::StmtDecl(e, cx.next_id()))
212-
};
142+
let iter_decl_stmt = cx.stmt_let(span, false, local_ident,
143+
cx.expr_mut_addr_of(span, src_expr));
213144

214-
// `None => break;`
145+
// `None => break ['<ident>];`
215146
let none_arm = {
216-
let break_expr = mk_expr(cx, span, ast::ExprBreak(None));
217-
let break_stmt = @spanned(lo, hi, ast::StmtExpr(break_expr, cx.next_id()));
218-
let none_block = mk_block(cx, [break_stmt], None, span);
219-
let none_pat = @ast::Pat {
220-
id: cx.next_id(),
221-
node: ast::PatIdent(ast::BindInfer, none_path, None),
222-
span: span
223-
};
224-
ast::Arm {
225-
pats: ~[none_pat],
226-
guard: None,
227-
body: none_block
228-
}
147+
let break_expr = cx.expr(span, ast::ExprBreak(opt_ident));
148+
let none_pat = cx.pat_ident(span, none_ident);
149+
cx.arm(span, ~[none_pat], break_expr)
229150
};
230151

231152
// `Some(<src_pat>) => <src_loop_block>`
232-
let some_arm = {
233-
let pat = @ast::Pat {
234-
id: cx.next_id(),
235-
node: ast::PatEnum(some_path, Some(~[src_pat])),
236-
span: src_pat.span
237-
};
238-
ast::Arm {
239-
pats: ~[pat],
240-
guard: None,
241-
body: src_loop_block
242-
}
243-
};
153+
let some_arm =
154+
cx.arm(span,
155+
~[cx.pat_enum(span, some_path, ~[src_pat])],
156+
cx.expr_block(src_loop_block));
244157

245158
// `match i.next() { ... }`
246-
let match_stmt = {
247-
let local_expr = mk_expr(cx, span, ast::ExprPath(local_path_2));
248-
let next_call_expr = mk_expr(cx, span,
249-
ast::ExprMethodCall(cx.next_id(),
250-
local_expr, next_ident,
251-
~[], ~[], ast::NoSugar));
252-
let match_expr = mk_expr(cx, span, ast::ExprMatch(next_call_expr,
253-
~[none_arm, some_arm]));
254-
@spanned(lo, hi, ast::StmtExpr(match_expr, cx.next_id()))
255-
};
159+
let match_expr = {
160+
let next_call_expr =
161+
cx.expr_method_call(span, cx.expr_path(local_path), next_ident, ~[]);
256162

257-
// `loop { ... }`
258-
let loop_block = {
259-
let loop_body_block = mk_block(cx, [match_stmt], None, span);
260-
let loop_body_expr = mk_expr(cx, span, ast::ExprLoop(loop_body_block, None));
261-
let loop_body_stmt = @spanned(lo, hi, ast::StmtExpr(loop_body_expr, cx.next_id()));
262-
mk_block(cx, [iter_decl_stmt,
263-
loop_body_stmt],
264-
None, span)
163+
cx.expr_match(span, next_call_expr, ~[none_arm, some_arm])
265164
};
266165

267-
(ast::ExprBlock(loop_block), span)
166+
// ['ident:] loop { ... }
167+
let loop_expr = cx.expr(span,
168+
ast::ExprLoop(cx.block_expr(match_expr), opt_ident));
169+
170+
// `{ let ... ; loop { ... } }`
171+
let block = cx.block(span,
172+
~[iter_decl_stmt],
173+
Some(loop_expr));
174+
175+
(ast::ExprBlock(block), span)
268176
}
269177

270-
_ => orig(e, s, fld)
178+
_ => orig(e, span, fld)
271179
}
272180
}
273181

src/libsyntax/fold.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -557,10 +557,11 @@ pub fn noop_fold_expr(e: &Expr_, fld: @ast_fold) -> Expr_ {
557557
ExprWhile(cond, ref body) => {
558558
ExprWhile(fld.fold_expr(cond), fld.fold_block(body))
559559
}
560-
ExprForLoop(pat, iter, ref body) => {
560+
ExprForLoop(pat, iter, ref body, opt_ident) => {
561561
ExprForLoop(fld.fold_pat(pat),
562-
fld.fold_expr(iter),
563-
fld.fold_block(body))
562+
fld.fold_expr(iter),
563+
fld.fold_block(body),
564+
opt_ident.map_move(|x| fld.fold_ident(x)))
564565
}
565566
ExprLoop(ref body, opt_ident) => {
566567
ExprLoop(

src/libsyntax/oldvisit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ pub fn visit_expr<E:Clone>(ex: @Expr, (e, v): (E, vt<E>)) {
523523
(v.visit_expr)(x, (e.clone(), v));
524524
(v.visit_block)(b, (e.clone(), v));
525525
}
526-
ExprForLoop(pattern, subexpression, ref block) => {
526+
ExprForLoop(pattern, subexpression, ref block, _) => {
527527
(v.visit_pat)(pattern, (e.clone(), v));
528528
(v.visit_expr)(subexpression, (e.clone(), v));
529529
(v.visit_block)(block, (e.clone(), v))

src/libsyntax/parse/parser.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,7 +1771,7 @@ impl Parser {
17711771
} else if self.eat_keyword(keywords::If) {
17721772
return self.parse_if_expr();
17731773
} else if self.eat_keyword(keywords::For) {
1774-
return self.parse_for_expr();
1774+
return self.parse_for_expr(None);
17751775
} else if self.eat_keyword(keywords::Do) {
17761776
return self.parse_sugary_call_expr(lo, ~"do", DoSugar,
17771777
ExprDoBody);
@@ -1781,8 +1781,13 @@ impl Parser {
17811781
let lifetime = self.get_lifetime(&*self.token);
17821782
self.bump();
17831783
self.expect(&token::COLON);
1784-
self.expect_keyword(keywords::Loop);
1785-
return self.parse_loop_expr(Some(lifetime));
1784+
if self.eat_keyword(keywords::For) {
1785+
return self.parse_for_expr(Some(lifetime))
1786+
} else if self.eat_keyword(keywords::Loop) {
1787+
return self.parse_loop_expr(Some(lifetime))
1788+
} else {
1789+
self.fatal("expected `for` or `loop` after a label")
1790+
}
17861791
} else if self.eat_keyword(keywords::Loop) {
17871792
return self.parse_loop_expr(None);
17881793
} else if self.eat_keyword(keywords::Match) {
@@ -2467,7 +2472,7 @@ impl Parser {
24672472
}
24682473

24692474
// parse a 'for' .. 'in' expression ('for' token already eaten)
2470-
pub fn parse_for_expr(&self) -> @Expr {
2475+
pub fn parse_for_expr(&self, opt_ident: Option<ast::Ident>) -> @Expr {
24712476
// Parse: `for <src_pat> in <src_expr> <src_loop_block>`
24722477

24732478
let lo = self.last_span.lo;
@@ -2477,7 +2482,7 @@ impl Parser {
24772482
let loop_block = self.parse_block();
24782483
let hi = self.span.hi;
24792484

2480-
self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block))
2485+
self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident))
24812486
}
24822487

24832488

src/libsyntax/print/pprust.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1232,7 +1232,12 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
12321232
space(s.s);
12331233
print_block(s, blk);
12341234
}
1235-
ast::ExprForLoop(pat, iter, ref blk) => {
1235+
ast::ExprForLoop(pat, iter, ref blk, opt_ident) => {
1236+
for ident in opt_ident.iter() {
1237+
word(s.s, "'");
1238+
print_ident(s, *ident);
1239+
word_space(s, ":");
1240+
}
12361241
head(s, "for");
12371242
print_pat(s, pat);
12381243
space(s.s);

src/libsyntax/visit.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,7 @@ pub fn walk_expr<E:Clone, V:Visitor<E>>(visitor: &mut V, expression: @Expr, env:
599599
visitor.visit_expr(subexpression, env.clone());
600600
visitor.visit_block(block, env.clone())
601601
}
602-
ExprForLoop(pattern, subexpression, ref block) => {
602+
ExprForLoop(pattern, subexpression, ref block, _) => {
603603
visitor.visit_pat(pattern, env.clone());
604604
visitor.visit_expr(subexpression, env.clone());
605605
visitor.visit_block(block, env.clone())
@@ -812,4 +812,3 @@ impl Visitor<()> for SimpleVisitorVisitor {
812812
walk_struct_field(self, struct_field, env)
813813
}
814814
}
815-

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,10 @@ pub fn main() {
1414
break 'foo;
1515
}
1616
}
17+
18+
'bar: for _ in range(0, 100) {
19+
loop {
20+
break 'bar;
21+
}
22+
}
1723
}

0 commit comments

Comments
 (0)