From 07351b44c657225d45e2aa0a302ccd28f96839a8 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Sun, 8 Sep 2013 22:08:01 +1000 Subject: [PATCH] syntax: implement labelled breaks for `for`. `for` desugars to `loop` so it is trivial to just desugar to `loop` while retaining any label. --- src/librustc/middle/trans/debuginfo.rs | 2 +- src/libsyntax/ast.rs | 2 +- src/libsyntax/ext/expand.rs | 4 ++-- src/libsyntax/fold.rs | 7 ++++--- src/libsyntax/oldvisit.rs | 2 +- src/libsyntax/parse/parser.rs | 15 ++++++++++----- src/libsyntax/print/pprust.rs | 7 ++++++- src/libsyntax/visit.rs | 3 +-- src/test/run-pass/labeled-break.rs | 6 ++++++ 9 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 21bde8e388b..b89414a6a53 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -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() - \ Found unexpanded for-loop."); } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index b993f98ec82..6957f9ae351 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -528,7 +528,7 @@ pub enum Expr_ { ExprCast(@Expr, Ty), ExprIf(@Expr, Block, Option<@Expr>), ExprWhile(@Expr, Block), - ExprForLoop(@Pat, @Expr, Block), + ExprForLoop(@Pat, @Expr, Block, Option), /* 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. */ diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index cde418ca991..abade04fedf 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -113,7 +113,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv, // Desugar expr_for_loop // From: `for in ` - 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_expr = src_expr.clone(); @@ -257,7 +257,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv, // `loop { ... }` let loop_block = { 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())); mk_block(cx, [iter_decl_stmt, loop_body_stmt], diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index aad992706fd..11e39163992 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -557,10 +557,11 @@ pub fn noop_fold_expr(e: &Expr_, fld: @ast_fold) -> Expr_ { ExprWhile(cond, ref 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), - fld.fold_expr(iter), - fld.fold_block(body)) + fld.fold_expr(iter), + fld.fold_block(body), + opt_ident.map_move(|x| fld.fold_ident(x))) } ExprLoop(ref body, opt_ident) => { ExprLoop( diff --git a/src/libsyntax/oldvisit.rs b/src/libsyntax/oldvisit.rs index e9d7b5c4a0d..850f73096ed 100644 --- a/src/libsyntax/oldvisit.rs +++ b/src/libsyntax/oldvisit.rs @@ -523,7 +523,7 @@ pub fn visit_expr(ex: @Expr, (e, v): (E, vt)) { (v.visit_expr)(x, (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_expr)(subexpression, (e.clone(), v)); (v.visit_block)(block, (e.clone(), v)) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 8b11a25f13c..b8615352504 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1771,7 +1771,7 @@ impl Parser { } else if self.eat_keyword(keywords::If) { return self.parse_if_expr(); } 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) { return self.parse_sugary_call_expr(lo, ~"do", DoSugar, ExprDoBody); @@ -1781,8 +1781,13 @@ impl Parser { let lifetime = self.get_lifetime(&*self.token); self.bump(); self.expect(&token::COLON); - self.expect_keyword(keywords::Loop); - return self.parse_loop_expr(Some(lifetime)); + if self.eat_keyword(keywords::For) { + 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) { return self.parse_loop_expr(None); } else if self.eat_keyword(keywords::Match) { @@ -2467,7 +2472,7 @@ impl Parser { } // 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) -> @Expr { // Parse: `for in ` let lo = self.last_span.lo; @@ -2477,7 +2482,7 @@ impl Parser { let loop_block = self.parse_block(); 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)) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index f440e0a1771..282b66b2c59 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1232,7 +1232,12 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) { space(s.s); 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"); print_pat(s, pat); space(s.s); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index ae2044cb979..191b4509a80 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -599,7 +599,7 @@ pub fn walk_expr>(visitor: &mut V, expression: @Expr, env: visitor.visit_expr(subexpression, 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_expr(subexpression, env.clone()); visitor.visit_block(block, env.clone()) @@ -812,4 +812,3 @@ impl Visitor<()> for SimpleVisitorVisitor { walk_struct_field(self, struct_field, env) } } - diff --git a/src/test/run-pass/labeled-break.rs b/src/test/run-pass/labeled-break.rs index b6b6e0e1437..d7d210c7524 100644 --- a/src/test/run-pass/labeled-break.rs +++ b/src/test/run-pass/labeled-break.rs @@ -14,4 +14,10 @@ pub fn main() { break 'foo; } } + + 'bar: for _ in range(0, 100) { + loop { + break 'bar; + } + } }