about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2011-02-01 16:23:48 -0800
committerGraydon Hoare <graydon@mozilla.com>2011-02-01 16:23:48 -0800
commit70bf54bcac587c0bc8a3a593bda75115e4c23aa8 (patch)
treefc04fe2f7bc4fa1dd902689e4db20e193bec9097 /src/comp
parenteb16942c1de42c2f30f7e0eb0ff69371a167f7bd (diff)
downloadrust-70bf54bcac587c0bc8a3a593bda75115e4c23aa8.tar.gz
rust-70bf54bcac587c0bc8a3a593bda75115e4c23aa8.zip
Implement 'else if'
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/front/ast.rs2
-rw-r--r--src/comp/front/parser.rs42
-rw-r--r--src/comp/middle/fold.rs21
-rw-r--r--src/comp/middle/trans.rs31
-rw-r--r--src/comp/middle/ty.rs2
-rw-r--r--src/comp/middle/typeck.rs33
6 files changed, 103 insertions, 28 deletions
diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs
index 9fddb66f397..be47615a502 100644
--- a/src/comp/front/ast.rs
+++ b/src/comp/front/ast.rs
@@ -149,7 +149,7 @@ tag expr_ {
     expr_unary(unop, @expr, ann);
     expr_lit(@lit, ann);
     expr_cast(@expr, @ty, ann);
-    expr_if(@expr, block, option.t[block], ann);
+    expr_if(@expr, block, vec[tup(@expr, block)], option.t[block], ann);
     expr_while(@expr, block, ann);
     expr_for(@decl, @expr, block, ann);
     expr_do_while(block, @expr, ann);
diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs
index bef37a3cc7e..0c90df5c783 100644
--- a/src/comp/front/parser.rs
+++ b/src/comp/front/parser.rs
@@ -891,18 +891,40 @@ impure fn parse_if_expr(parser p) -> @ast.expr {
     auto cond = parse_expr(p);
     expect(p, token.RPAREN);
     auto thn = parse_block(p);
-    let option.t[ast.block] els = none[ast.block];
     hi = thn.span;
-    alt (p.peek()) {
-        case (token.ELSE) {
-            p.bump();
-            auto eblk = parse_block(p);
-            els = some(eblk);
-            hi = eblk.span;
+
+    let vec[tup(@ast.expr, ast.block)] elifs = vec();
+    let option.t[ast.block] els = none[ast.block];
+    let bool parsing_elses = true;
+    while (parsing_elses) {
+        alt (p.peek()) {
+            case (token.ELSE) {
+                expect(p, token.ELSE);
+                alt (p.peek()) {
+                    case (token.IF) {
+                        expect(p, token.IF);
+                        expect(p, token.LPAREN);
+                        auto elifcond = parse_expr(p);
+                        expect(p, token.RPAREN);
+                        auto elifthn = parse_block(p);
+                        elifs += tup(elifcond, elifthn);
+                        hi = elifthn.span;
+                    }
+                    case (_) {
+                        auto eblk = parse_block(p);
+                        els = some(eblk);
+                        hi = eblk.span;
+                        parsing_elses = false;
+                    }
+                }
+            }
+            case (_) {
+                parsing_elses = false;
+            }
         }
-        case (_) { /* fall through */ }
     }
-    ret @spanned(lo, hi, ast.expr_if(cond, thn, els, ast.ann_none));
+
+    ret @spanned(lo, hi, ast.expr_if(cond, thn, elifs, els, ast.ann_none));
 }
 
 impure fn parse_head_local(parser p) -> @ast.decl {
@@ -1331,7 +1353,7 @@ fn stmt_ends_with_semi(@ast.stmt stmt) -> bool {
                 case (ast.expr_unary(_,_,_))    { ret true; }
                 case (ast.expr_lit(_,_))        { ret true; }
                 case (ast.expr_cast(_,_,_))     { ret true; }
-                case (ast.expr_if(_,_,_,_))     { ret false; }
+                case (ast.expr_if(_,_,_,_,_))   { ret false; }
                 case (ast.expr_for(_,_,_,_))    { ret false; }
                 case (ast.expr_while(_,_,_))    { ret false; }
                 case (ast.expr_do_while(_,_,_)) { ret false; }
diff --git a/src/comp/middle/fold.rs b/src/comp/middle/fold.rs
index 67c260140b7..7e6839a831e 100644
--- a/src/comp/middle/fold.rs
+++ b/src/comp/middle/fold.rs
@@ -28,6 +28,7 @@ import front.ast.def;
 import front.ast.def_id;
 import front.ast.ann;
 
+import std._uint;
 import std._vec;
 
 type ast_fold[ENV] =
@@ -100,6 +101,7 @@ type ast_fold[ENV] =
 
      (fn(&ENV e, &span sp,
          @expr cond, &block thn,
+         &vec[tup(@expr, block)] elifs,
          &option.t[block] els,
          ann a) -> @expr)                         fold_expr_if,
 
@@ -501,9 +503,19 @@ fn fold_expr[ENV](&ENV env, ast_fold[ENV] fld, &@expr e) -> @expr {
             ret fld.fold_expr_cast(env_, e.span, ee, tt, at);
         }
 
-        case (ast.expr_if(?cnd, ?thn, ?els, ?t)) {
+        case (ast.expr_if(?cnd, ?thn, ?elifs, ?els, ?t)) {
             auto ccnd = fold_expr(env_, fld, cnd);
             auto tthn = fold_block(env_, fld, thn);
+
+            let vec[tup(@ast.expr, ast.block)] eelifs = vec();
+            for (tup(@expr, block) elif in elifs) {
+                auto elifcnd = elif._0;
+                auto elifthn = elif._1;
+                auto elifccnd = fold_expr(env_, fld, elifcnd);
+                auto eliftthn = fold_block(env_, fld, elifthn);
+                eelifs += tup(elifccnd, eliftthn);
+            }
+
             auto eels = none[block];
             alt (els) {
                 case (some[block](?b)) {
@@ -511,7 +523,7 @@ fn fold_expr[ENV](&ENV env, ast_fold[ENV] fld, &@expr e) -> @expr {
                 }
                 case (_) { /* fall through */  }
             }
-            ret fld.fold_expr_if(env_, e.span, ccnd, tthn, eels, t);
+            ret fld.fold_expr_if(env_, e.span, ccnd, tthn, eelifs, eels, t);
         }
 
         case (ast.expr_for(?decl, ?seq, ?body, ?t)) {
@@ -961,8 +973,9 @@ fn identity_fold_expr_cast[ENV](&ENV env, &span sp, @ast.expr e,
 
 fn identity_fold_expr_if[ENV](&ENV env, &span sp,
                               @expr cond, &block thn,
+                              &vec[tup(@expr, block)] elifs,
                               &option.t[block] els, ann a) -> @expr {
-    ret @respan(sp, ast.expr_if(cond, thn, els, a));
+    ret @respan(sp, ast.expr_if(cond, thn, elifs, els, a));
 }
 
 fn identity_fold_expr_for[ENV](&ENV env, &span sp,
@@ -1237,7 +1250,7 @@ fn new_identity_fold[ENV]() -> ast_fold[ENV] {
          fold_expr_unary  = bind identity_fold_expr_unary[ENV](_,_,_,_,_),
          fold_expr_lit    = bind identity_fold_expr_lit[ENV](_,_,_,_),
          fold_expr_cast   = bind identity_fold_expr_cast[ENV](_,_,_,_,_),
-         fold_expr_if     = bind identity_fold_expr_if[ENV](_,_,_,_,_,_),
+         fold_expr_if     = bind identity_fold_expr_if[ENV](_,_,_,_,_,_,_),
          fold_expr_for    = bind identity_fold_expr_for[ENV](_,_,_,_,_,_),
          fold_expr_while  = bind identity_fold_expr_while[ENV](_,_,_,_,_),
          fold_expr_do_while
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 446b4f10f08..c08147fec5a 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -1957,8 +1957,9 @@ fn join_results(@block_ctxt parent_cx,
     ret res(join_cx, phi);
 }
 
-fn trans_if(@block_ctxt cx, @ast.expr cond,
-            &ast.block thn, &option.t[ast.block] els) -> result {
+fn trans_if(@block_ctxt cx, @ast.expr cond, &ast.block thn,
+            &vec[tup(@ast.expr, ast.block)] elifs,
+            &option.t[ast.block] els) -> result {
 
     auto cond_res = trans_expr(cx, cond);
 
@@ -1968,11 +1969,25 @@ fn trans_if(@block_ctxt cx, @ast.expr cond,
     auto else_cx = new_scope_block_ctxt(cx, "else");
     auto else_res = res(else_cx, C_nil());
 
-    alt (els) {
-        case (some[ast.block](?eblk)) {
-            else_res = trans_block(else_cx, eblk);
+    auto num_elifs = _vec.len[tup(@ast.expr, ast.block)](elifs);
+    if (num_elifs > 0u) {
+        auto next_elif = elifs.(0u);
+        auto next_elifthn = next_elif._0;
+        auto next_elifcnd = next_elif._1;
+        auto rest_elifs = _vec.shift[tup(@ast.expr, ast.block)](elifs);
+        else_res = trans_if(else_cx, next_elifthn, next_elifcnd,
+                            rest_elifs, els);
+    }
+
+    /* else: FIXME: rustboot has a problem here
+       with preconditions inside an else block */
+    if (num_elifs == 0u)  {
+        alt (els) {
+            case (some[ast.block](?eblk)) {
+                else_res = trans_block(else_cx, eblk);
+            }
+            case (_) { /* fall through */ }
         }
-        case (_) { /* fall through */ }
     }
 
     cond_res.bcx.build.CondBr(cond_res.val,
@@ -2901,8 +2916,8 @@ fn trans_expr(@block_ctxt cx, @ast.expr e) -> result {
             ret trans_binary(cx, op, x, y);
         }
 
-        case (ast.expr_if(?cond, ?thn, ?els, _)) {
-            ret trans_if(cx, cond, thn, els);
+        case (ast.expr_if(?cond, ?thn, ?elifs, ?els, _)) {
+            ret trans_if(cx, cond, thn, elifs, els);
         }
 
         case (ast.expr_for(?decl, ?seq, ?body, _)) {
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index b840be91384..2f14aae6259 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -653,7 +653,7 @@ fn expr_ty(@ast.expr expr) -> @t {
         case (ast.expr_unary(_, _, ?ann))     { ret ann_to_type(ann); }
         case (ast.expr_lit(_, ?ann))          { ret ann_to_type(ann); }
         case (ast.expr_cast(_, _, ?ann))      { ret ann_to_type(ann); }
-        case (ast.expr_if(_, _, _, ?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_while(_, _, ?ann))     { ret ann_to_type(ann); }
         case (ast.expr_do_while(_, _, ?ann))  { ret ann_to_type(ann); }
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index ea9002aeccb..7112e982743 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -864,10 +864,19 @@ 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_cast(sube, ast_ty, ast.ann_type(t));
         }
-        case (ast.expr_if(?cond, ?then_0, ?else_0, ?ann)) {
+        case (ast.expr_if(?cond, ?then_0, ?elifs_0, ?else_0, ?ann)) {
             auto t = demand_full(fcx, e.span, expected,
                                  ann_to_type(ann), adk);
             auto then_1 = demand_block(fcx, expected, then_0);
+
+            let vec[tup(@ast.expr, ast.block)] elifs_1 = vec();
+            for (tup(@ast.expr, ast.block) elif in elifs_0) {
+                auto elifcond = elif._0;
+                auto elifthn_0 = elif._1;
+                auto elifthn_1 = demand_block(fcx, expected, elifthn_0);
+                elifs_1 += tup(elifcond, elifthn_1);
+            }
+
             auto else_1;
             alt (else_0) {
                 case (none[ast.block]) { else_1 = none[ast.block]; }
@@ -876,7 +885,7 @@ fn demand_expr_full(&@fn_ctxt fcx, @ty.t expected, @ast.expr e,
                     else_1 = some[ast.block](b_1);
                 }
             }
-            e_1 = ast.expr_if(cond, then_1, else_1, ast.ann_type(t));
+            e_1 = ast.expr_if(cond, then_1, elifs_1, else_1, ast.ann_type(t));
         }
         case (ast.expr_for(?decl, ?seq, ?bloc, ?ann)) {
             auto t = demand(fcx, e.span, expected, ann_to_type(ann));
@@ -1195,13 +1204,28 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
                                                            ann));
         }
 
-        case (ast.expr_if(?cond, ?thn, ?elsopt, _)) {
+        case (ast.expr_if(?cond, ?thn, ?elifs, ?elsopt, _)) {
             auto cond_0 = check_expr(fcx, cond);
             auto cond_1 = demand_expr(fcx, plain_ty(ty.ty_bool), cond_0);
 
             auto thn_0 = check_block(fcx, thn);
             auto thn_t = block_ty(thn_0);
 
+            auto num_elifs = _vec.len[tup(@ast.expr, ast.block)](elifs);
+            let vec[tup(@ast.expr, ast.block)] elifs_1 = vec();
+            for each (uint i in _uint.range(0u, num_elifs)) {
+                auto elif = elifs.(i);
+                auto elifcond = elif._0;
+                auto elifcond_0 = check_expr(fcx, cond);
+                auto elifcond_1 = demand_expr(fcx,
+                                              plain_ty(ty.ty_bool),
+                                              elifcond_0);
+                auto elifthn = elif._1;
+                auto elifthn_0 = check_block(fcx, elifthn);
+                auto elifthn_1 = demand_block(fcx, thn_t, elifthn_0);
+                elifs_1 += tup(elifcond_1, elifthn_1);
+            }
+
             auto elsopt_1;
             auto elsopt_t;
             alt (elsopt) {
@@ -1220,7 +1244,8 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr {
             auto thn_1 = demand_block(fcx, elsopt_t, thn_0);
 
             ret @fold.respan[ast.expr_](expr.span,
-                                        ast.expr_if(cond_1, thn_1, elsopt_1,
+                                        ast.expr_if(cond_1, thn_1,
+                                                    elifs_1, elsopt_1,
                                                     ast.ann_type(elsopt_t)));
         }