From 4a72a23171d87fb5a0f9b7ad039944856b93bf0f Mon Sep 17 00:00:00 2001
From: Graydon Hoare <graydon@mozilla.com>
Date: Mon, 14 Feb 2011 18:17:31 -0800
Subject: [PATCH] Add basic front-end support for 'for each' loops.

---
 src/comp/front/ast.rs      |  1 +
 src/comp/front/parser.rs   | 17 ++++++++++++++++-
 src/comp/middle/fold.rs    | 19 +++++++++++++++++++
 src/comp/middle/resolve.rs |  3 +++
 src/comp/middle/trans.rs   | 13 +++++++++++++
 src/comp/middle/ty.rs      |  2 ++
 src/comp/middle/typeck.rs  | 15 +++++++++++++++
 7 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs
index cb2df2a5a3e..9e43d3496b4 100644
--- a/src/comp/front/ast.rs
+++ b/src/comp/front/ast.rs
@@ -151,6 +151,7 @@ tag expr_ {
     expr_if(@expr, block, vec[tup(@expr, block)], option.t[block], ann);
     expr_while(@expr, block, ann);
     expr_for(@decl, @expr, block, ann);
+    expr_for_each(@decl, @expr, block, ann);
     expr_do_while(block, @expr, ann);
     expr_alt(@expr, vec[arm], ann);
     expr_block(block, ann);
diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs
index a779d0133cd..ddadc789764 100644
--- a/src/comp/front/parser.rs
+++ b/src/comp/front/parser.rs
@@ -1049,8 +1049,14 @@ impure fn parse_head_local(parser p) -> @ast.decl {
 impure fn parse_for_expr(parser p) -> @ast.expr {
     auto lo = p.get_span();
     auto hi = lo;
+    auto is_each = false;
 
     expect(p, token.FOR);
+    if (p.peek() == token.EACH) {
+        is_each = true;
+        p.bump();
+    }
+
     expect (p, token.LPAREN);
 
     auto decl = parse_head_local(p);
@@ -1060,9 +1066,16 @@ impure fn parse_for_expr(parser p) -> @ast.expr {
     expect(p, token.RPAREN);
     auto body = parse_block(p);
     hi = body.span;
-    ret @spanned(lo, hi, ast.expr_for(decl, seq, body, ast.ann_none));
+    if (is_each) {
+        ret @spanned(lo, hi, ast.expr_for_each(decl, seq, body,
+                                               ast.ann_none));
+    } else {
+        ret @spanned(lo, hi, ast.expr_for(decl, seq, body,
+                                          ast.ann_none));
+    }
 }
 
+
 impure fn parse_while_expr(parser p) -> @ast.expr {
     auto lo = p.get_span();
     auto hi = lo;
@@ -1422,6 +1435,8 @@ fn stmt_ends_with_semi(@ast.stmt stmt) -> bool {
                 case (ast.expr_cast(_,_,_))     { ret true; }
                 case (ast.expr_if(_,_,_,_,_))   { ret false; }
                 case (ast.expr_for(_,_,_,_))    { ret false; }
+                case (ast.expr_for_each(_,_,_,_))
+                                                { ret false; }
                 case (ast.expr_while(_,_,_))    { ret false; }
                 case (ast.expr_do_while(_,_,_)) { ret false; }
                 case (ast.expr_alt(_,_,_))      { ret false; }
diff --git a/src/comp/middle/fold.rs b/src/comp/middle/fold.rs
index 4d3c2e2d149..3cafa9610b6 100644
--- a/src/comp/middle/fold.rs
+++ b/src/comp/middle/fold.rs
@@ -112,6 +112,10 @@ type ast_fold[ENV] =
          @decl decl, @expr seq, &block body,
          ann a) -> @expr)                         fold_expr_for,
 
+     (fn(&ENV e, &span sp,
+         @decl decl, @expr seq, &block body,
+         ann a) -> @expr)                         fold_expr_for_each,
+
      (fn(&ENV e, &span sp,
          @expr cond, &block body,
          ann a) -> @expr)                         fold_expr_while,
@@ -574,6 +578,13 @@ fn fold_expr[ENV](&ENV env, ast_fold[ENV] fld, &@expr e) -> @expr {
             ret fld.fold_expr_for(env_, e.span, ddecl, sseq, bbody, t);
         }
 
+        case (ast.expr_for_each(?decl, ?seq, ?body, ?t)) {
+            auto ddecl = fold_decl(env_, fld, decl);
+            auto sseq = fold_expr(env_, fld, seq);
+            auto bbody = fold_block(env_, fld, body);
+            ret fld.fold_expr_for_each(env_, e.span, ddecl, sseq, bbody, t);
+        }
+
         case (ast.expr_while(?cnd, ?body, ?t)) {
             auto ccnd = fold_expr(env_, fld, cnd);
             auto bbody = fold_block(env_, fld, body);
@@ -1087,6 +1098,12 @@ fn identity_fold_expr_for[ENV](&ENV env, &span sp,
     ret @respan(sp, ast.expr_for(d, seq, body, a));
 }
 
+fn identity_fold_expr_for_each[ENV](&ENV env, &span sp,
+                                    @decl d, @expr seq,
+                                    &block body, ann a) -> @expr {
+    ret @respan(sp, ast.expr_for_each(d, seq, body, a));
+}
+
 fn identity_fold_expr_while[ENV](&ENV env, &span sp,
                                  @expr cond, &block body, ann a) -> @expr {
     ret @respan(sp, ast.expr_while(cond, body, a));
@@ -1402,6 +1419,8 @@ fn new_identity_fold[ENV]() -> ast_fold[ENV] {
          fold_expr_cast   = bind identity_fold_expr_cast[ENV](_,_,_,_,_),
          fold_expr_if     = bind identity_fold_expr_if[ENV](_,_,_,_,_,_,_),
          fold_expr_for    = bind identity_fold_expr_for[ENV](_,_,_,_,_,_),
+         fold_expr_for_each
+             = bind identity_fold_expr_for_each[ENV](_,_,_,_,_,_),
          fold_expr_while  = bind identity_fold_expr_while[ENV](_,_,_,_,_),
          fold_expr_do_while
                           = bind identity_fold_expr_do_while[ENV](_,_,_,_,_),
diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs
index 96be838c7c8..d4ad907e32a 100644
--- a/src/comp/middle/resolve.rs
+++ b/src/comp/middle/resolve.rs
@@ -565,6 +565,9 @@ fn update_env_for_expr(&env e, @ast.expr x) -> env {
         case (ast.expr_for(?d, _, _, _)) {
             ret rec(scopes = cons[scope](scope_loop(d), @e.scopes) with e);
         }
+        case (ast.expr_for_each(?d, _, _, _)) {
+            ret rec(scopes = cons[scope](scope_loop(d), @e.scopes) with e);
+        }
         case (_) { }
     }
     ret e;
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index c8f21dff513..c4e5c9c4f33 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -2116,6 +2116,15 @@ fn trans_for(@block_ctxt cx,
                       bind inner(_, local, _, _, body));
 }
 
+fn trans_for_each(@block_ctxt cx,
+                  @ast.decl decl,
+                  @ast.expr seq,
+                  &ast.block body) -> result {
+    cx.fcx.ccx.sess.unimpl("for each loop");
+    fail;
+}
+
+
 fn trans_while(@block_ctxt cx, @ast.expr cond,
                &ast.block body) -> result {
 
@@ -3035,6 +3044,10 @@ fn trans_expr(@block_ctxt cx, @ast.expr e) -> result {
             ret trans_for(cx, decl, seq, body);
         }
 
+        case (ast.expr_for_each(?decl, ?seq, ?body, _)) {
+            ret trans_for_each(cx, decl, seq, body);
+        }
+
         case (ast.expr_while(?cond, ?body, _)) {
             ret trans_while(cx, cond, body);
         }
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index f9b2bd9d000..499ed74d8a9 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -676,6 +676,8 @@ fn expr_ty(@ast.expr expr) -> @t {
         case (ast.expr_cast(_, _, ?ann))      { ret ann_to_type(ann); }
         case (ast.expr_if(_, _, _, _, ?ann))  { ret ann_to_type(ann); }
         case (ast.expr_for(_, _, _, ?ann))    { ret ann_to_type(ann); }
+        case (ast.expr_for_each(_, _, _, ?ann))
+                                              { ret ann_to_type(ann); }
         case (ast.expr_while(_, _, ?ann))     { ret ann_to_type(ann); }
         case (ast.expr_do_while(_, _, ?ann))  { ret ann_to_type(ann); }
         case (ast.expr_alt(_, _, ?ann))       { ret ann_to_type(ann); }
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 5109adb2a43..a062f79d4d0 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -995,6 +995,10 @@ fn demand_expr_full(&@fn_ctxt fcx, @ty.t expected, @ast.expr e,
             auto t = demand(fcx, e.span, expected, ann_to_type(ann));
             e_1 = ast.expr_for(decl, seq, bloc, ast.ann_type(t));
         }
+        case (ast.expr_for_each(?decl, ?seq, ?bloc, ?ann)) {
+            auto t = demand(fcx, e.span, expected, ann_to_type(ann));
+            e_1 = ast.expr_for_each(decl, seq, bloc, ast.ann_type(t));
+        }
         case (ast.expr_while(?cond, ?bloc, ?ann)) {
             auto t = demand(fcx, e.span, expected, ann_to_type(ann));
             e_1 = ast.expr_while(cond, bloc, ast.ann_type(t));
@@ -1448,6 +1452,17 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
                                                      body_1, ann));
         }
 
+        case (ast.expr_for_each(?decl, ?seq, ?body, _)) {
+            auto decl_1 = check_decl_local(fcx, decl);
+            auto seq_1 = check_expr(fcx, seq);
+            auto body_1 = check_block(fcx, body);
+
+            auto ann = ast.ann_type(plain_ty(ty.ty_nil));
+            ret @fold.respan[ast.expr_](expr.span,
+                                        ast.expr_for_each(decl_1, seq_1,
+                                                          body_1, ann));
+        }
+
         case (ast.expr_while(?cond, ?body, _)) {
             auto cond_0 = check_expr(fcx, cond);
             auto cond_1 = demand_expr(fcx, plain_ty(ty.ty_bool), cond_0);