about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-09-08 07:45:57 -0700
committerbors <bors@rust-lang.org>2013-09-08 07:45:57 -0700
commitd36612d65b67e18c7f8d247055f83b28a602e875 (patch)
treeda8753d901a569992bf4ee1a30c016b377221485 /src/libsyntax
parentb609d022c4df307e4d68499b063c81a9ecb1e9cf (diff)
parent14183114e1048097869a5c56ebfa4a6d71e1a492 (diff)
downloadrust-d36612d65b67e18c7f8d247055f83b28a602e875.tar.gz
rust-d36612d65b67e18c7f8d247055f83b28a602e875.zip
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; }
    }
}
```
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs2
-rw-r--r--src/libsyntax/ext/expand.rs170
-rw-r--r--src/libsyntax/fold.rs7
-rw-r--r--src/libsyntax/oldvisit.rs2
-rw-r--r--src/libsyntax/parse/parser.rs15
-rw-r--r--src/libsyntax/print/pprust.rs7
-rw-r--r--src/libsyntax/visit.rs3
7 files changed, 62 insertions, 144 deletions
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<Ident>),
     /* 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..099fa54c0c2 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -14,13 +14,13 @@ use ast::{item_mac, Mrk, Stmt_, StmtDecl, StmtMac, StmtExpr, StmtSemi};
 use ast::{token_tree};
 use ast;
 use ast_util::{mtwt_outer_mark, new_rename, new_mark};
+use ext::build::AstBuilder;
 use attr;
 use attr::AttrMetaMethods;
 use codemap;
-use codemap::{Span, Spanned, spanned, ExpnInfo, NameAndSpan};
+use codemap::{Span, Spanned, ExpnInfo, NameAndSpan};
 use ext::base::*;
 use fold::*;
-use opt_vec;
 use parse;
 use parse::{parse_item_from_source_str};
 use parse::token;
@@ -33,7 +33,7 @@ use std::vec;
 pub fn expand_expr(extsbox: @mut SyntaxEnv,
                    cx: @ExtCtxt,
                    e: &Expr_,
-                   s: Span,
+                   span: Span,
                    fld: @ast_fold,
                    orig: @fn(&Expr_, Span, @ast_fold) -> (Expr_, Span))
                 -> (Expr_, Span) {
@@ -66,7 +66,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
                         }
                         Some(@SE(NormalTT(expandfun, exp_span))) => {
                             cx.bt_push(ExpnInfo {
-                                call_site: s,
+                                call_site: span,
                                 callee: NameAndSpan {
                                     name: extnamestr,
                                     span: exp_span,
@@ -98,7 +98,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
                                 fld.fold_expr(marked_after).node.clone();
                             cx.bt_pop();
 
-                            (fully_expanded, s)
+                            (fully_expanded, span)
                         }
                         _ => {
                             cx.span_fatal(
@@ -112,62 +112,18 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
         }
 
         // Desugar expr_for_loop
-        // From: `for <src_pat> in <src_expr> <src_loop_block>`
-        ast::ExprForLoop(src_pat, src_expr, ref src_loop_block) => {
-            let src_pat = src_pat.clone();
-            let src_expr = src_expr.clone();
-
+        // From: `['<ident>:] for <src_pat> in <src_expr> <src_loop_block>`
+        ast::ExprForLoop(src_pat, src_expr, ref src_loop_block, opt_ident) => {
             // Expand any interior macros etc.
             // NB: we don't fold pats yet. Curious.
-            let src_expr = fld.fold_expr(src_expr).clone();
-            let src_loop_block = fld.fold_block(src_loop_block).clone();
-
-            let span = s;
-            let lo = s.lo;
-            let hi = s.hi;
-
-            pub fn mk_expr(cx: @ExtCtxt, span: Span,
-                           node: Expr_) -> @ast::Expr {
-                @ast::Expr {
-                    id: cx.next_id(),
-                    node: node,
-                    span: span,
-                }
-            }
-
-            fn mk_block(cx: @ExtCtxt,
-                        stmts: &[@ast::Stmt],
-                        expr: Option<@ast::Expr>,
-                        span: Span) -> ast::Block {
-                ast::Block {
-                    view_items: ~[],
-                    stmts: stmts.to_owned(),
-                    expr: expr,
-                    id: cx.next_id(),
-                    rules: ast::DefaultBlock,
-                    span: span,
-                }
-            }
-
-            fn mk_simple_path(ident: ast::Ident, span: Span) -> ast::Path {
-                ast::Path {
-                    span: span,
-                    global: false,
-                    segments: ~[
-                        ast::PathSegment {
-                            identifier: ident,
-                            lifetime: None,
-                            types: opt_vec::Empty,
-                        }
-                    ],
-                }
-            }
+            let src_expr = fld.fold_expr(src_expr);
+            let src_loop_block = fld.fold_block(src_loop_block);
 
             // to:
             //
             // {
             //   let _i = &mut <src_expr>;
-            //   loop {
+            //   ['<ident>:] loop {
             //       match i.next() {
             //           None => break,
             //           Some(<src_pat>) => <src_loop_block>
@@ -176,98 +132,50 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
             // }
 
             let local_ident = token::gensym_ident("i");
-            let some_ident = token::str_to_ident("Some");
-            let none_ident = token::str_to_ident("None");
-            let next_ident = token::str_to_ident("next");
+            let next_ident = cx.ident_of("next");
+            let none_ident = cx.ident_of("None");
 
-            let local_path_1 = mk_simple_path(local_ident, span);
-            let local_path_2 = mk_simple_path(local_ident, span);
-            let some_path = mk_simple_path(some_ident, span);
-            let none_path = mk_simple_path(none_ident, span);
+            let local_path = cx.path_ident(span, local_ident);
+            let some_path = cx.path_ident(span, cx.ident_of("Some"));
 
             // `let i = &mut <src_expr>`
-            let iter_decl_stmt = {
-                let ty = ast::Ty {
-                    id: cx.next_id(),
-                    node: ast::ty_infer,
-                    span: span
-                };
-                let local = @ast::Local {
-                    is_mutbl: false,
-                    ty: ty,
-                    pat: @ast::Pat {
-                        id: cx.next_id(),
-                        node: ast::PatIdent(ast::BindInfer, local_path_1, None),
-                        span: src_expr.span
-                    },
-                    init: Some(mk_expr(cx, src_expr.span,
-                                       ast::ExprAddrOf(ast::MutMutable, src_expr))),
-                    id: cx.next_id(),
-                    span: src_expr.span,
-                };
-                let e = @spanned(src_expr.span.lo,
-                                 src_expr.span.hi,
-                                 ast::DeclLocal(local));
-                @spanned(lo, hi, ast::StmtDecl(e, cx.next_id()))
-            };
+            let iter_decl_stmt = cx.stmt_let(span, false, local_ident,
+                                             cx.expr_mut_addr_of(span, src_expr));
 
-            // `None => break;`
+            // `None => break ['<ident>];`
             let none_arm = {
-                let break_expr = mk_expr(cx, span, ast::ExprBreak(None));
-                let break_stmt = @spanned(lo, hi, ast::StmtExpr(break_expr, cx.next_id()));
-                let none_block = mk_block(cx, [break_stmt], None, span);
-                let none_pat = @ast::Pat {
-                    id: cx.next_id(),
-                    node: ast::PatIdent(ast::BindInfer, none_path, None),
-                    span: span
-                };
-                ast::Arm {
-                    pats: ~[none_pat],
-                    guard: None,
-                    body: none_block
-                }
+                let break_expr = cx.expr(span, ast::ExprBreak(opt_ident));
+                let none_pat = cx.pat_ident(span, none_ident);
+                cx.arm(span, ~[none_pat], break_expr)
             };
 
             // `Some(<src_pat>) => <src_loop_block>`
-            let some_arm = {
-                let pat = @ast::Pat {
-                    id: cx.next_id(),
-                    node: ast::PatEnum(some_path, Some(~[src_pat])),
-                    span: src_pat.span
-                };
-                ast::Arm {
-                    pats: ~[pat],
-                    guard: None,
-                    body: src_loop_block
-                }
-            };
+            let some_arm =
+                cx.arm(span,
+                       ~[cx.pat_enum(span, some_path, ~[src_pat])],
+                       cx.expr_block(src_loop_block));
 
             // `match i.next() { ... }`
-            let match_stmt = {
-                let local_expr = mk_expr(cx, span, ast::ExprPath(local_path_2));
-                let next_call_expr = mk_expr(cx, span,
-                                             ast::ExprMethodCall(cx.next_id(),
-                                                                   local_expr, next_ident,
-                                                                   ~[], ~[], ast::NoSugar));
-                let match_expr = mk_expr(cx, span, ast::ExprMatch(next_call_expr,
-                                                                   ~[none_arm, some_arm]));
-                @spanned(lo, hi, ast::StmtExpr(match_expr, cx.next_id()))
-            };
+            let match_expr = {
+                let next_call_expr =
+                    cx.expr_method_call(span, cx.expr_path(local_path), next_ident, ~[]);
 
-            // `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_stmt = @spanned(lo, hi, ast::StmtExpr(loop_body_expr, cx.next_id()));
-                mk_block(cx, [iter_decl_stmt,
-                              loop_body_stmt],
-                         None, span)
+                cx.expr_match(span, next_call_expr, ~[none_arm, some_arm])
             };
 
-            (ast::ExprBlock(loop_block), span)
+            // ['ident:] loop { ... }
+            let loop_expr = cx.expr(span,
+                                    ast::ExprLoop(cx.block_expr(match_expr), opt_ident));
+
+            // `{ let ... ;  loop { ... } }`
+            let block = cx.block(span,
+                                 ~[iter_decl_stmt],
+                                 Some(loop_expr));
+
+            (ast::ExprBlock(block), span)
         }
 
-        _ => orig(e, s, fld)
+        _ => orig(e, span, fld)
     }
 }
 
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<E:Clone>(ex: @Expr, (e, v): (E, vt<E>)) {
             (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<ast::Ident>) -> @Expr {
         // Parse: `for <src_pat> in <src_expr> <src_loop_block>`
 
         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<E:Clone, V:Visitor<E>>(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)
     }
 }
-