Skip to content

Commit 05c0216

Browse files
committed
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.
1 parent 5495ad1 commit 05c0216

File tree

9 files changed

+110
-2
lines changed

9 files changed

+110
-2
lines changed

src/comp/front/ast.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ tag expr_ {
241241
expr_lit(@lit);
242242
expr_cast(@expr, @ty);
243243
expr_if(@expr, block, option::t[@expr]);
244+
expr_ternary(@expr, @expr, @expr);
244245
expr_while(@expr, block);
245246
expr_for(@local, @expr, block);
246247
expr_for_each(@local, @expr, block);
@@ -550,6 +551,32 @@ fn is_constraint_arg(@expr e) -> bool {
550551
fn eq_ty(&@ty a, &@ty b) -> bool { ret std::box::ptr_eq(a, b); }
551552

552553
fn hash_ty(&@ty t) -> uint { ret t.span.lo << 16u + t.span.hi; }
554+
555+
fn block_from_expr(@expr e) -> block {
556+
let block_ blk_ =
557+
rec(stmts=[],
558+
expr=option::some[@expr](e),
559+
id=e.id);
560+
ret rec(node=blk_, span=e.span);
561+
}
562+
563+
// This is a convenience function to transfor ternary expressions to if
564+
// expressions so that they can be treated the same
565+
fn ternary_to_if(&@expr e) -> @ast::expr {
566+
alt (e.node) {
567+
case (expr_ternary(?cond, ?then, ?els)) {
568+
auto then_blk = block_from_expr(then);
569+
auto els_blk = block_from_expr(els);
570+
auto els_expr = @rec(id=els.id, node=expr_block(els_blk),
571+
span=els.span);
572+
ret @rec(id=e.id,
573+
node=expr_if(cond, then_blk, option::some(els_expr)),
574+
span=e.span);
575+
}
576+
case (_) { fail; }
577+
}
578+
}
579+
553580
//
554581
// Local Variables:
555582
// mode: rust

src/comp/front/parser.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,20 @@ fn parse_prefix_expr(&parser p) -> @ast::expr {
10711071
ret mk_expr(p, lo, hi, ex);
10721072
}
10731073

1074+
fn parse_ternary(&parser p) -> @ast::expr {
1075+
auto cond_expr = parse_binops(p);
1076+
if (p.peek() == token::QUES) {
1077+
p.bump();
1078+
auto then_expr = parse_expr(p);
1079+
expect(p, token::COLON);
1080+
auto else_expr = parse_expr(p);
1081+
ret mk_expr(p, cond_expr.span.lo, else_expr.span.hi,
1082+
ast::expr_ternary(cond_expr, then_expr, else_expr));
1083+
} else {
1084+
ret cond_expr;
1085+
}
1086+
}
1087+
10741088
type op_spec = rec(token::token tok, ast::binop op, int prec);
10751089

10761090

@@ -1128,7 +1142,7 @@ fn parse_more_binops(&parser p, @ast::expr lhs, int min_prec) -> @ast::expr {
11281142

11291143
fn parse_assign_expr(&parser p) -> @ast::expr {
11301144
auto lo = p.get_lo_pos();
1131-
auto lhs = parse_binops(p);
1145+
auto lhs = parse_ternary(p);
11321146
alt (p.peek()) {
11331147
case (token::EQ) {
11341148
p.bump();

src/comp/middle/trans.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5746,6 +5746,9 @@ fn trans_expr_out(&@block_ctxt cx, &@ast::expr e, out_method output) ->
57465746
ret with_out_method(bind trans_if(cx, cond, thn, els, e.id, _),
57475747
cx, e.id, output);
57485748
}
5749+
case (ast::expr_ternary(_, _, _)) {
5750+
ret trans_expr_out(cx, ast::ternary_to_if(e), output);
5751+
}
57495752
case (ast::expr_for(?decl, ?seq, ?body)) {
57505753
ret trans_for(cx, decl, seq, body);
57515754
}

src/comp/middle/tstate/pre_post_conditions.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,9 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) {
422422
case (expr_if(?antec, ?conseq, ?maybe_alt)) {
423423
join_then_else(fcx, antec, conseq, maybe_alt, e.id, plain_if);
424424
}
425+
case (expr_ternary(_, _, _)) {
426+
find_pre_post_expr(fcx, ternary_to_if(e));
427+
}
425428
case (expr_binary(?bop, ?l, ?r)) {
426429
/* *unless* bop is lazy (e.g. and, or)?
427430
FIXME */

src/comp/middle/tstate/states.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,9 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
489489
|| changed;
490490
ret changed;
491491
}
492+
case (expr_ternary(_, _, _)) {
493+
ret find_pre_post_state_expr(fcx, pres, ternary_to_if(e));
494+
}
492495
case (expr_binary(?bop, ?l, ?r)) {
493496
/* FIXME: what if bop is lazy? */
494497

src/comp/middle/typeck.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,6 +1609,9 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
16091609
check_pred_expr(fcx, cond);
16101610
check_then_else(fcx, thn, elsopt, id, expr.span);
16111611
}
1612+
case (ast::expr_ternary(_, _, _)) {
1613+
check_expr(fcx, ast::ternary_to_if(expr));
1614+
}
16121615
case (ast::expr_assert(?e)) {
16131616
check_expr(fcx, e);
16141617
auto ety = expr_ty(fcx.ccx.tcx, e);

src/comp/middle/visit.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,11 @@ fn visit_expr[E](&@expr ex, &E e, &vt[E] v) {
295295
vt(v).visit_block(b, e, v);
296296
visit_expr_opt(eo, e, v);
297297
}
298+
case (expr_ternary(?c, ?t, ?el)) {
299+
vt(v).visit_expr(c, e, v);
300+
vt(v).visit_expr(t, e, v);
301+
vt(v).visit_expr(el, e, v);
302+
}
298303
case (expr_while(?x, ?b)) {
299304
vt(v).visit_expr(x, e, v);
300305
vt(v).visit_block(b, e, v);

src/comp/middle/walk.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,11 @@ fn walk_expr(&ast_visitor v, @ast::expr e) {
307307
walk_block(v, b);
308308
walk_expr_opt(v, eo);
309309
}
310-
310+
case (ast::expr_ternary(?c, ?t, ?e)) {
311+
walk_expr(v, c);
312+
walk_expr(v, t);
313+
walk_expr(v, e);
314+
}
311315
case (ast::expr_while(?x, ?b)) {
312316
walk_expr(v, x);
313317
walk_block(v, b);

src/test/run-pass/ternary.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// xfail-stage0
2+
3+
fn test_simple() {
4+
auto x = true ? 10 : 11;
5+
assert (x == 10);
6+
}
7+
8+
fn test_precedence() {
9+
auto x;
10+
11+
x = true == false ? 10 : 11;
12+
assert (x == 11);
13+
14+
x = true ? false ? 10 : 11 : 12;
15+
assert (x == 11);
16+
17+
auto y = false ? 10 : 0xF0 | 0x0F;
18+
assert (y == 0xFF);
19+
}
20+
21+
fn test_associativity() {
22+
// Ternary is right-associative
23+
auto x = false ? 10 : false ? 11 : 12;
24+
assert (x == 12);
25+
}
26+
27+
fn test_lval() {
28+
let @mutable int box1 = @mutable 10;
29+
let @mutable int box2 = @mutable 10;
30+
*(true ? box1 : box2) = 100;
31+
assert (*box1 == 100);
32+
}
33+
34+
fn test_as_stmt() {
35+
auto s;
36+
true ? s = 10 : s = 12;
37+
assert (s == 10);
38+
}
39+
40+
fn main() {
41+
test_simple();
42+
test_precedence();
43+
test_associativity();
44+
test_lval();
45+
test_as_stmt();
46+
}

0 commit comments

Comments
 (0)