rustc: Add ternary operator. Closes #565

The implementation is so simple it might be considered cheating: at almost
every step the expr_ternary is just converted to expr_if.
This commit is contained in:
Brian Anderson 2011-06-23 15:15:50 -07:00
parent 5495ad17d1
commit 05c0216654
9 changed files with 110 additions and 2 deletions

View File

@ -241,6 +241,7 @@ tag expr_ {
expr_lit(@lit);
expr_cast(@expr, @ty);
expr_if(@expr, block, option::t[@expr]);
expr_ternary(@expr, @expr, @expr);
expr_while(@expr, block);
expr_for(@local, @expr, block);
expr_for_each(@local, @expr, block);
@ -550,6 +551,32 @@ fn is_constraint_arg(@expr e) -> bool {
fn eq_ty(&@ty a, &@ty b) -> bool { ret std::box::ptr_eq(a, b); }
fn hash_ty(&@ty t) -> uint { ret t.span.lo << 16u + t.span.hi; }
fn block_from_expr(@expr e) -> block {
let block_ blk_ =
rec(stmts=[],
expr=option::some[@expr](e),
id=e.id);
ret rec(node=blk_, span=e.span);
}
// This is a convenience function to transfor ternary expressions to if
// expressions so that they can be treated the same
fn ternary_to_if(&@expr e) -> @ast::expr {
alt (e.node) {
case (expr_ternary(?cond, ?then, ?els)) {
auto then_blk = block_from_expr(then);
auto els_blk = block_from_expr(els);
auto els_expr = @rec(id=els.id, node=expr_block(els_blk),
span=els.span);
ret @rec(id=e.id,
node=expr_if(cond, then_blk, option::some(els_expr)),
span=e.span);
}
case (_) { fail; }
}
}
//
// Local Variables:
// mode: rust

View File

@ -1071,6 +1071,20 @@ fn parse_prefix_expr(&parser p) -> @ast::expr {
ret mk_expr(p, lo, hi, ex);
}
fn parse_ternary(&parser p) -> @ast::expr {
auto cond_expr = parse_binops(p);
if (p.peek() == token::QUES) {
p.bump();
auto then_expr = parse_expr(p);
expect(p, token::COLON);
auto else_expr = parse_expr(p);
ret mk_expr(p, cond_expr.span.lo, else_expr.span.hi,
ast::expr_ternary(cond_expr, then_expr, else_expr));
} else {
ret cond_expr;
}
}
type op_spec = rec(token::token tok, ast::binop op, int prec);
@ -1128,7 +1142,7 @@ fn parse_more_binops(&parser p, @ast::expr lhs, int min_prec) -> @ast::expr {
fn parse_assign_expr(&parser p) -> @ast::expr {
auto lo = p.get_lo_pos();
auto lhs = parse_binops(p);
auto lhs = parse_ternary(p);
alt (p.peek()) {
case (token::EQ) {
p.bump();

View File

@ -5746,6 +5746,9 @@ fn trans_expr_out(&@block_ctxt cx, &@ast::expr e, out_method output) ->
ret with_out_method(bind trans_if(cx, cond, thn, els, e.id, _),
cx, e.id, output);
}
case (ast::expr_ternary(_, _, _)) {
ret trans_expr_out(cx, ast::ternary_to_if(e), output);
}
case (ast::expr_for(?decl, ?seq, ?body)) {
ret trans_for(cx, decl, seq, body);
}

View File

@ -422,6 +422,9 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) {
case (expr_if(?antec, ?conseq, ?maybe_alt)) {
join_then_else(fcx, antec, conseq, maybe_alt, e.id, plain_if);
}
case (expr_ternary(_, _, _)) {
find_pre_post_expr(fcx, ternary_to_if(e));
}
case (expr_binary(?bop, ?l, ?r)) {
/* *unless* bop is lazy (e.g. and, or)?
FIXME */

View File

@ -489,6 +489,9 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
|| changed;
ret changed;
}
case (expr_ternary(_, _, _)) {
ret find_pre_post_state_expr(fcx, pres, ternary_to_if(e));
}
case (expr_binary(?bop, ?l, ?r)) {
/* FIXME: what if bop is lazy? */

View File

@ -1609,6 +1609,9 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
check_pred_expr(fcx, cond);
check_then_else(fcx, thn, elsopt, id, expr.span);
}
case (ast::expr_ternary(_, _, _)) {
check_expr(fcx, ast::ternary_to_if(expr));
}
case (ast::expr_assert(?e)) {
check_expr(fcx, e);
auto ety = expr_ty(fcx.ccx.tcx, e);

View File

@ -295,6 +295,11 @@ fn visit_expr[E](&@expr ex, &E e, &vt[E] v) {
vt(v).visit_block(b, e, v);
visit_expr_opt(eo, e, v);
}
case (expr_ternary(?c, ?t, ?el)) {
vt(v).visit_expr(c, e, v);
vt(v).visit_expr(t, e, v);
vt(v).visit_expr(el, e, v);
}
case (expr_while(?x, ?b)) {
vt(v).visit_expr(x, e, v);
vt(v).visit_block(b, e, v);

View File

@ -307,7 +307,11 @@ fn walk_expr(&ast_visitor v, @ast::expr e) {
walk_block(v, b);
walk_expr_opt(v, eo);
}
case (ast::expr_ternary(?c, ?t, ?e)) {
walk_expr(v, c);
walk_expr(v, t);
walk_expr(v, e);
}
case (ast::expr_while(?x, ?b)) {
walk_expr(v, x);
walk_block(v, b);

View File

@ -0,0 +1,46 @@
// xfail-stage0
fn test_simple() {
auto x = true ? 10 : 11;
assert (x == 10);
}
fn test_precedence() {
auto x;
x = true == false ? 10 : 11;
assert (x == 11);
x = true ? false ? 10 : 11 : 12;
assert (x == 11);
auto y = false ? 10 : 0xF0 | 0x0F;
assert (y == 0xFF);
}
fn test_associativity() {
// Ternary is right-associative
auto x = false ? 10 : false ? 11 : 12;
assert (x == 12);
}
fn test_lval() {
let @mutable int box1 = @mutable 10;
let @mutable int box2 = @mutable 10;
*(true ? box1 : box2) = 100;
assert (*box1 == 100);
}
fn test_as_stmt() {
auto s;
true ? s = 10 : s = 12;
assert (s == 10);
}
fn main() {
test_simple();
test_precedence();
test_associativity();
test_lval();
test_as_stmt();
}