1
Fork 0

syntax: implement labelled breaks for for.

`for` desugars to `loop` so it is trivial to just desugar to `loop` while
retaining any label.
This commit is contained in:
Huon Wilson 2013-09-08 22:08:01 +10:00
parent b609d022c4
commit 07351b44c6
9 changed files with 32 additions and 16 deletions

View file

@ -2064,7 +2064,7 @@ fn populate_scope_map(cx: &mut CrateContext,
} }
} }
ast::ExprForLoop(_, _, _) => { ast::ExprForLoop(_, _, _, _) => {
cx.sess.span_bug(exp.span, "debuginfo::populate_scope_map() - \ cx.sess.span_bug(exp.span, "debuginfo::populate_scope_map() - \
Found unexpanded for-loop."); Found unexpanded for-loop.");
} }

View file

@ -528,7 +528,7 @@ pub enum Expr_ {
ExprCast(@Expr, Ty), ExprCast(@Expr, Ty),
ExprIf(@Expr, Block, Option<@Expr>), ExprIf(@Expr, Block, Option<@Expr>),
ExprWhile(@Expr, Block), ExprWhile(@Expr, Block),
ExprForLoop(@Pat, @Expr, Block), ExprForLoop(@Pat, @Expr, Block, Option<Ident>),
/* Conditionless loop (can be exited with break, cont, or ret) /* Conditionless loop (can be exited with break, cont, or ret)
Same semantics as while(true) { body }, but typestate knows that the Same semantics as while(true) { body }, but typestate knows that the
(implicit) condition is always true. */ (implicit) condition is always true. */

View file

@ -113,7 +113,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
// Desugar expr_for_loop // Desugar expr_for_loop
// From: `for <src_pat> in <src_expr> <src_loop_block>` // From: `for <src_pat> in <src_expr> <src_loop_block>`
ast::ExprForLoop(src_pat, src_expr, ref src_loop_block) => { ast::ExprForLoop(src_pat, src_expr, ref src_loop_block, opt_ident) => {
let src_pat = src_pat.clone(); let src_pat = src_pat.clone();
let src_expr = src_expr.clone(); let src_expr = src_expr.clone();
@ -257,7 +257,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
// `loop { ... }` // `loop { ... }`
let loop_block = { let loop_block = {
let loop_body_block = mk_block(cx, [match_stmt], None, span); let loop_body_block = mk_block(cx, [match_stmt], None, span);
let loop_body_expr = mk_expr(cx, span, ast::ExprLoop(loop_body_block, None)); let loop_body_expr = mk_expr(cx, span, ast::ExprLoop(loop_body_block, opt_ident));
let loop_body_stmt = @spanned(lo, hi, ast::StmtExpr(loop_body_expr, cx.next_id())); let loop_body_stmt = @spanned(lo, hi, ast::StmtExpr(loop_body_expr, cx.next_id()));
mk_block(cx, [iter_decl_stmt, mk_block(cx, [iter_decl_stmt,
loop_body_stmt], loop_body_stmt],

View file

@ -557,10 +557,11 @@ pub fn noop_fold_expr(e: &Expr_, fld: @ast_fold) -> Expr_ {
ExprWhile(cond, ref body) => { ExprWhile(cond, ref body) => {
ExprWhile(fld.fold_expr(cond), fld.fold_block(body)) ExprWhile(fld.fold_expr(cond), fld.fold_block(body))
} }
ExprForLoop(pat, iter, ref body) => { ExprForLoop(pat, iter, ref body, opt_ident) => {
ExprForLoop(fld.fold_pat(pat), ExprForLoop(fld.fold_pat(pat),
fld.fold_expr(iter), fld.fold_expr(iter),
fld.fold_block(body)) fld.fold_block(body),
opt_ident.map_move(|x| fld.fold_ident(x)))
} }
ExprLoop(ref body, opt_ident) => { ExprLoop(ref body, opt_ident) => {
ExprLoop( ExprLoop(

View file

@ -523,7 +523,7 @@ pub fn visit_expr<E:Clone>(ex: @Expr, (e, v): (E, vt<E>)) {
(v.visit_expr)(x, (e.clone(), v)); (v.visit_expr)(x, (e.clone(), v));
(v.visit_block)(b, (e.clone(), v)); (v.visit_block)(b, (e.clone(), v));
} }
ExprForLoop(pattern, subexpression, ref block) => { ExprForLoop(pattern, subexpression, ref block, _) => {
(v.visit_pat)(pattern, (e.clone(), v)); (v.visit_pat)(pattern, (e.clone(), v));
(v.visit_expr)(subexpression, (e.clone(), v)); (v.visit_expr)(subexpression, (e.clone(), v));
(v.visit_block)(block, (e.clone(), v)) (v.visit_block)(block, (e.clone(), v))

View file

@ -1771,7 +1771,7 @@ impl Parser {
} else if self.eat_keyword(keywords::If) { } else if self.eat_keyword(keywords::If) {
return self.parse_if_expr(); return self.parse_if_expr();
} else if self.eat_keyword(keywords::For) { } else if self.eat_keyword(keywords::For) {
return self.parse_for_expr(); return self.parse_for_expr(None);
} else if self.eat_keyword(keywords::Do) { } else if self.eat_keyword(keywords::Do) {
return self.parse_sugary_call_expr(lo, ~"do", DoSugar, return self.parse_sugary_call_expr(lo, ~"do", DoSugar,
ExprDoBody); ExprDoBody);
@ -1781,8 +1781,13 @@ impl Parser {
let lifetime = self.get_lifetime(&*self.token); let lifetime = self.get_lifetime(&*self.token);
self.bump(); self.bump();
self.expect(&token::COLON); self.expect(&token::COLON);
self.expect_keyword(keywords::Loop); if self.eat_keyword(keywords::For) {
return self.parse_loop_expr(Some(lifetime)); return self.parse_for_expr(Some(lifetime))
} else if self.eat_keyword(keywords::Loop) {
return self.parse_loop_expr(Some(lifetime))
} else {
self.fatal("expected `for` or `loop` after a label")
}
} else if self.eat_keyword(keywords::Loop) { } else if self.eat_keyword(keywords::Loop) {
return self.parse_loop_expr(None); return self.parse_loop_expr(None);
} else if self.eat_keyword(keywords::Match) { } else if self.eat_keyword(keywords::Match) {
@ -2467,7 +2472,7 @@ impl Parser {
} }
// parse a 'for' .. 'in' expression ('for' token already eaten) // parse a 'for' .. 'in' expression ('for' token already eaten)
pub fn parse_for_expr(&self) -> @Expr { pub fn parse_for_expr(&self, opt_ident: Option<ast::Ident>) -> @Expr {
// Parse: `for <src_pat> in <src_expr> <src_loop_block>` // Parse: `for <src_pat> in <src_expr> <src_loop_block>`
let lo = self.last_span.lo; let lo = self.last_span.lo;
@ -2477,7 +2482,7 @@ impl Parser {
let loop_block = self.parse_block(); let loop_block = self.parse_block();
let hi = self.span.hi; let hi = self.span.hi;
self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block)) self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident))
} }

View file

@ -1232,7 +1232,12 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
space(s.s); space(s.s);
print_block(s, blk); print_block(s, blk);
} }
ast::ExprForLoop(pat, iter, ref blk) => { ast::ExprForLoop(pat, iter, ref blk, opt_ident) => {
for ident in opt_ident.iter() {
word(s.s, "'");
print_ident(s, *ident);
word_space(s, ":");
}
head(s, "for"); head(s, "for");
print_pat(s, pat); print_pat(s, pat);
space(s.s); space(s.s);

View file

@ -599,7 +599,7 @@ pub fn walk_expr<E:Clone, V:Visitor<E>>(visitor: &mut V, expression: @Expr, env:
visitor.visit_expr(subexpression, env.clone()); visitor.visit_expr(subexpression, env.clone());
visitor.visit_block(block, env.clone()) visitor.visit_block(block, env.clone())
} }
ExprForLoop(pattern, subexpression, ref block) => { ExprForLoop(pattern, subexpression, ref block, _) => {
visitor.visit_pat(pattern, env.clone()); visitor.visit_pat(pattern, env.clone());
visitor.visit_expr(subexpression, env.clone()); visitor.visit_expr(subexpression, env.clone());
visitor.visit_block(block, env.clone()) visitor.visit_block(block, env.clone())
@ -812,4 +812,3 @@ impl Visitor<()> for SimpleVisitorVisitor {
walk_struct_field(self, struct_field, env) walk_struct_field(self, struct_field, env)
} }
} }

View file

@ -14,4 +14,10 @@ pub fn main() {
break 'foo; break 'foo;
} }
} }
'bar: for _ in range(0, 100) {
loop {
break 'bar;
}
}
} }