From 214c32393a9d28436dd782c9ea6e3e32d3baba2e Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 30 Jan 2011 14:15:22 -0500 Subject: [PATCH 1/3] Teach rustc to parse 'else if' --- src/Makefile | 1 + src/comp/front/parser.rs | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Makefile b/src/Makefile index 968f9d6c9a0ea..bd45d2531dfb5 100644 --- a/src/Makefile +++ b/src/Makefile @@ -447,6 +447,7 @@ TEST_XFAILS_RUSTC := $(filter-out \ div-mod.rs \ drop-bind-thunk-args.rs \ drop-on-ret.rs \ + else-if.rs \ fact.rs \ fn-lval.rs \ fun-call-variants.rs \ diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index bef37a3cc7ea4..fbed877fbd88d 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -895,8 +895,7 @@ impure fn parse_if_expr(parser p) -> @ast.expr { hi = thn.span; alt (p.peek()) { case (token.ELSE) { - p.bump(); - auto eblk = parse_block(p); + auto eblk = parse_else_block(p); els = some(eblk); hi = eblk.span; } @@ -905,6 +904,21 @@ impure fn parse_if_expr(parser p) -> @ast.expr { ret @spanned(lo, hi, ast.expr_if(cond, thn, els, ast.ann_none)); } +impure fn parse_else_block(parser p) -> ast.block { + expect(p, token.ELSE); + alt (p.peek()) { + case (token.IF) { + let vec[@ast.stmt] stmts = vec(); + auto ifexpr = parse_if_expr(p); + auto bloc = index_block(stmts, some(ifexpr)); + ret spanned(ifexpr.span, ifexpr.span, bloc); + } + case (_) { + ret parse_block(p); + } + } +} + impure fn parse_head_local(parser p) -> @ast.decl { auto lo = p.get_span(); let @ast.local local; From 3fedb18c0af0bd9fa5e4973936003c0b57e4d3e8 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 31 Jan 2011 23:06:02 -0500 Subject: [PATCH 2/3] Allow the else part of an expr_if to be either expr_if or expr_block --- src/comp/front/ast.rs | 2 +- src/comp/front/parser.rs | 19 +++++++++---------- src/comp/middle/fold.rs | 10 +++++----- src/comp/middle/trans.rs | 17 ++++++++++++++--- src/comp/middle/typeck.rs | 37 ++++++++++++++++++++++++++----------- 5 files changed, 55 insertions(+), 30 deletions(-) diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index 10bcd5c4562f8..fb068dba4aaf3 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, option.t[@expr], 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 fbed877fbd88d..e629683c2f818 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -891,30 +891,29 @@ 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]; + let option.t[@ast.expr] els = none[@ast.expr]; hi = thn.span; alt (p.peek()) { case (token.ELSE) { - auto eblk = parse_else_block(p); - els = some(eblk); - hi = eblk.span; + auto elexpr = parse_else_expr(p); + els = some(elexpr); + hi = elexpr.span; } case (_) { /* fall through */ } } ret @spanned(lo, hi, ast.expr_if(cond, thn, els, ast.ann_none)); } -impure fn parse_else_block(parser p) -> ast.block { +impure fn parse_else_expr(parser p) -> @ast.expr { expect(p, token.ELSE); alt (p.peek()) { case (token.IF) { - let vec[@ast.stmt] stmts = vec(); - auto ifexpr = parse_if_expr(p); - auto bloc = index_block(stmts, some(ifexpr)); - ret spanned(ifexpr.span, ifexpr.span, bloc); + ret parse_if_expr(p); } case (_) { - ret parse_block(p); + auto blk = parse_block(p); + ret @spanned(blk.span, blk.span, + ast.expr_block(blk, ast.ann_none)); } } } diff --git a/src/comp/middle/fold.rs b/src/comp/middle/fold.rs index 67c260140b727..ca10e79fe2d40 100644 --- a/src/comp/middle/fold.rs +++ b/src/comp/middle/fold.rs @@ -100,7 +100,7 @@ type ast_fold[ENV] = (fn(&ENV e, &span sp, @expr cond, &block thn, - &option.t[block] els, + &option.t[@expr] els, ann a) -> @expr) fold_expr_if, (fn(&ENV e, &span sp, @@ -504,10 +504,10 @@ fn fold_expr[ENV](&ENV env, ast_fold[ENV] fld, &@expr e) -> @expr { case (ast.expr_if(?cnd, ?thn, ?els, ?t)) { auto ccnd = fold_expr(env_, fld, cnd); auto tthn = fold_block(env_, fld, thn); - auto eels = none[block]; + auto eels = none[@expr]; alt (els) { - case (some[block](?b)) { - eels = some(fold_block(env_, fld, b)); + case (some[@expr](?e)) { + eels = some(fold_expr(env_, fld, e)); } case (_) { /* fall through */ } } @@ -961,7 +961,7 @@ 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, - &option.t[block] els, ann a) -> @expr { + &option.t[@expr] els, ann a) -> @expr { ret @respan(sp, ast.expr_if(cond, thn, els, a)); } diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 8eb614e5da385..c2b0ae48bbccb 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -1931,7 +1931,7 @@ fn join_results(@block_ctxt parent_cx, } fn trans_if(@block_ctxt cx, @ast.expr cond, - &ast.block thn, &option.t[ast.block] els) -> result { + &ast.block thn, &option.t[@ast.expr] els) -> result { auto cond_res = trans_expr(cx, cond); @@ -1942,8 +1942,19 @@ fn trans_if(@block_ctxt cx, @ast.expr cond, auto else_res = res(else_cx, C_nil()); alt (els) { - case (some[ast.block](?eblk)) { - else_res = trans_block(else_cx, eblk); + case (some[@ast.expr](?elexpr)) { + // FIXME: Shouldn't need to unwrap the block here, + // instead just use 'else_res = trans_expr(else_cx, elexpr)', + // but either a) trans_expr doesn't handle expr_block + // correctly or b) I have no idea what I'm doing... + alt (elexpr.node) { + case (ast.expr_if(_, _, _, _)) { + else_res = trans_expr(else_cx, elexpr); + } + case (ast.expr_block(?b, _)) { + else_res = trans_block(else_cx, b); + } + } } case (_) { /* fall through */ } } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index ea9002aeccbee..d778ffa96d0c0 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -870,10 +870,10 @@ fn demand_expr_full(&@fn_ctxt fcx, @ty.t expected, @ast.expr e, auto then_1 = demand_block(fcx, expected, then_0); auto else_1; alt (else_0) { - case (none[ast.block]) { else_1 = none[ast.block]; } - case (some[ast.block](?b_0)) { - auto b_1 = demand_block(fcx, expected, b_0); - else_1 = some[ast.block](b_1); + case (none[@ast.expr]) { else_1 = none[@ast.expr]; } + case (some[@ast.expr](?e_0)) { + auto e_1 = demand_expr(fcx, expected, e_0); + else_1 = some[@ast.expr](e_1); } } e_1 = ast.expr_if(cond, then_1, else_1, ast.ann_type(t)); @@ -1205,14 +1205,14 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr { auto elsopt_1; auto elsopt_t; alt (elsopt) { - case (some[ast.block](?els)) { - auto els_0 = check_block(fcx, els); - auto els_1 = demand_block(fcx, thn_t, els_0); - elsopt_1 = some[ast.block](els_1); - elsopt_t = block_ty(els_1); + case (some[@ast.expr](?els)) { + auto els_0 = check_expr(fcx, els); + auto els_1 = demand_expr(fcx, thn_t, els_0); + elsopt_1 = some[@ast.expr](els_1); + elsopt_t = expr_ty(els_1); } - case (none[ast.block]) { - elsopt_1 = none[ast.block]; + case (none[@ast.expr]) { + elsopt_1 = none[@ast.expr]; elsopt_t = plain_ty(ty.ty_nil); } } @@ -1308,6 +1308,21 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr { ast.expr_alt(expr_1, arms_1, ann)); } + case (ast.expr_block(?b, _)) { + auto b_0 = check_block(fcx, b); + auto ann; + alt (b_0.node.expr) { + case (some[@ast.expr](?expr)) { + ann = ast.ann_type(expr_ty(expr)); + } + case (none[@ast.expr]) { + ann = ast.ann_type(plain_ty(ty.ty_nil)); + } + } + ret @fold.respan[ast.expr_](expr.span, + ast.expr_block(b_0, ann)); + } + case (ast.expr_bind(?f, ?args, _)) { auto f_0 = check_expr(fcx, f); auto t_0 = expr_ty(f_0); From 2a662944a4d87c6d82299a181996ba14170b2ebb Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 10 Mar 2011 23:39:18 -0500 Subject: [PATCH 3/3] Remove extra blocks from the translation of expr_block Doesn't seem to break anything and allows trans_if to be streamlined --- src/comp/middle/trans.rs | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 728f20dd0eb81..87f01609a3886 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -2683,18 +2683,7 @@ fn trans_if(@block_ctxt cx, @ast.expr cond, alt (els) { case (some[@ast.expr](?elexpr)) { - // FIXME: Shouldn't need to unwrap the block here, - // instead just use 'else_res = trans_expr(else_cx, elexpr)', - // but either a) trans_expr doesn't handle expr_block - // correctly or b) I have no idea what I'm doing... - alt (elexpr.node) { - case (ast.expr_if(_, _, _, _)) { - else_res = trans_expr(else_cx, elexpr); - } - case (ast.expr_block(?b, _)) { - else_res = trans_block(else_cx, b); - } - } + else_res = trans_expr(else_cx, elexpr); } case (_) { /* fall through */ } } @@ -3942,14 +3931,7 @@ fn trans_expr(@block_ctxt cx, @ast.expr e) -> result { } case (ast.expr_block(?blk, _)) { - auto sub_cx = new_scope_block_ctxt(cx, "block-expr body"); - auto next_cx = new_sub_block_ctxt(cx, "next"); - auto sub = trans_block(sub_cx, blk); - - cx.build.Br(sub_cx.llbb); - sub.bcx.build.Br(next_cx.llbb); - - ret res(next_cx, sub.val); + ret trans_block(cx, blk); } case (ast.expr_assign(?dst, ?src, ?ann)) {