From 378c0087ca7572cd17726c704fe04d57bf4687af Mon Sep 17 00:00:00 2001
From: Brian Anderson <andersrb@gmail.com>
Date: Sun, 30 Jan 2011 17:18:19 -0500
Subject: [PATCH] Parse 'be' statement. Pass tailcall tests. No actual
 tailcalls yet.

---
 src/Makefile              |  3 +++
 src/comp/front/ast.rs     |  1 +
 src/comp/front/parser.rs  |  7 +++++++
 src/comp/middle/fold.rs   | 13 +++++++++++++
 src/comp/middle/trans.rs  |  9 +++++++++
 src/comp/middle/typeck.rs | 15 +++++++++++++++
 6 files changed, 48 insertions(+)

diff --git a/src/Makefile b/src/Makefile
index 02bd8708601..5c3f297f788 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -517,6 +517,9 @@ TEST_XFAILS_RUSTC := $(filter-out \
                         simple-obj.rs \
                         stateful-obj.rs \
                         str-idx.rs \
+                        tail-call-arg-leak.rs \
+                        tail-cps.rs \
+                        tail-direct.rs \
                         type-in-nested-module.rs \
                         type-param.rs \
                         tup.rs \
diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs
index 5f315e58262..756a7ad1e6b 100644
--- a/src/comp/front/ast.rs
+++ b/src/comp/front/ast.rs
@@ -116,6 +116,7 @@ type stmt = spanned[stmt_];
 tag stmt_ {
     stmt_decl(@decl);
     stmt_ret(option.t[@expr]);
+    stmt_be(@expr);
     stmt_log(@expr);
     stmt_check_expr(@expr);
     stmt_fail;
diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs
index 8d1309352bb..a1b519ba7f5 100644
--- a/src/comp/front/parser.rs
+++ b/src/comp/front/parser.rs
@@ -1200,6 +1200,12 @@ impure fn parse_stmt(parser p) -> @ast.stmt {
             }
         }
 
+        case (token.BE) {
+            p.bump();
+            auto e = parse_expr(p);
+            ret @spanned(lo, e.span, ast.stmt_be(e));
+        }
+
         case (token.LET) {
             auto decl = parse_let(p);
             auto hi = p.get_span();
@@ -1340,6 +1346,7 @@ fn stmt_ends_with_semi(@ast.stmt stmt) -> bool {
             }
         }
         case (ast.stmt_ret(_))                  { ret true; }
+        case (ast.stmt_be(_))                   { ret true; }
         case (ast.stmt_log(_))                  { ret true; }
         case (ast.stmt_check_expr(_))           { ret true; }
         case (ast.stmt_fail)                    { ret true; }
diff --git a/src/comp/middle/fold.rs b/src/comp/middle/fold.rs
index 7e5c2d26aef..9194f734bee 100644
--- a/src/comp/middle/fold.rs
+++ b/src/comp/middle/fold.rs
@@ -176,6 +176,9 @@ type ast_fold[ENV] =
      (fn(&ENV e, &span sp,
          &option.t[@expr] rv) -> @stmt)           fold_stmt_ret,
 
+     (fn(&ENV e, &span sp,
+         @expr e) -> @stmt)                       fold_stmt_be,
+
      (fn(&ENV e, &span sp,
          @expr e) -> @stmt)                       fold_stmt_log,
 
@@ -636,6 +639,11 @@ fn fold_stmt[ENV](&ENV env, ast_fold[ENV] fld, &@stmt s) -> @stmt {
             ret fld.fold_stmt_ret(env_, s.span, oee);
         }
 
+        case (ast.stmt_be(?e)) {
+            auto ee = fold_expr(env_, fld, e);
+            ret fld.fold_stmt_be(env_, s.span, ee);
+        }
+
         case (ast.stmt_log(?e)) {
             auto ee = fold_expr(env_, fld, e);
             ret fld.fold_stmt_log(env_, s.span, ee);
@@ -1136,6 +1144,10 @@ fn identity_fold_stmt_ret[ENV](&ENV env, &span sp,
     ret @respan(sp, ast.stmt_ret(rv));
 }
 
+fn identity_fold_stmt_be[ENV](&ENV env, &span sp, @expr x) -> @stmt {
+    ret @respan(sp, ast.stmt_be(x));
+}
+
 fn identity_fold_stmt_log[ENV](&ENV e, &span sp, @expr x) -> @stmt {
     ret @respan(sp, ast.stmt_log(x));
 }
@@ -1366,6 +1378,7 @@ fn new_identity_fold[ENV]() -> ast_fold[ENV] {
 
          fold_stmt_decl   = bind identity_fold_stmt_decl[ENV](_,_,_),
          fold_stmt_ret    = bind identity_fold_stmt_ret[ENV](_,_,_),
+         fold_stmt_be     = bind identity_fold_stmt_be[ENV](_,_,_),
          fold_stmt_log    = bind identity_fold_stmt_log[ENV](_,_,_),
          fold_stmt_check_expr
                           = bind identity_fold_stmt_check_expr[ENV](_,_,_),
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 2a9c32da5e4..499ab027d50 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -3128,6 +3128,11 @@ fn trans_ret(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
     ret res(bcx, C_nil());
 }
 
+fn trans_be(@block_ctxt cx, @ast.expr e) -> result {
+    // FIXME: So this isn't actually a tail call
+    ret trans_ret(cx, some(e));
+}
+
 fn init_local(@block_ctxt cx, @ast.local local) -> result {
 
     // Make a note to drop this slot on the way out.
@@ -3178,6 +3183,10 @@ fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
             bcx = trans_ret(cx, e).bcx;
         }
 
+        case (ast.stmt_be(?e)) {
+            bcx = trans_be(cx, e).bcx;
+        }
+
         case (ast.stmt_expr(?e)) {
             bcx = trans_expr(cx, e).bcx;
         }
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 5b14eea4101..7a2b0616d2b 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -1719,6 +1719,21 @@ fn check_stmt(&@fn_ctxt fcx, &@ast.stmt stmt) -> @ast.stmt {
             }
         }
 
+        case (ast.stmt_be(?expr)) {
+            alt (expr.node) {
+                case (ast.expr_call(_, _, _)) {
+                    auto expr_0 = check_expr(fcx, expr);
+                    auto expr_1 = demand_expr(fcx, fcx.ret_ty, expr_0);
+                    ret @fold.respan[ast.stmt_](stmt.span,
+                                                ast.stmt_be(expr_1));
+                }
+                case (_) {
+                    fcx.ccx.sess.err("Non-call expression in tail call");
+                    fail;
+                }
+            }
+        }
+
         case (ast.stmt_log(?expr)) {
             auto expr_t = check_expr(fcx, expr);
             ret @fold.respan[ast.stmt_](stmt.span, ast.stmt_log(expr_t));