Skip to content

Implement the swap operator #503

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions src/comp/front/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,11 +245,13 @@ tag expr_ {
expr_alt(@expr, vec[arm], ann);
expr_fn(_fn, ann);
expr_block(block, ann);
expr_move(@expr, /* TODO: @expr|is_lval */@expr, ann);
expr_assign(@expr, /* TODO: @expr|is_lval */@expr, ann);
expr_assign_op(binop, @expr, /* TODO: @expr|is_lval */@expr, ann);
expr_send(@expr, /* TODO: @expr|is_lval */@expr, ann);
expr_recv(@expr, /* TODO: @expr|is_lval */@expr, ann);
expr_move(@expr /* TODO: @expr|is_lval */, @expr, ann);
expr_assign(@expr /* TODO: @expr|is_lval */, @expr, ann);
expr_swap(@expr /* TODO: @expr|is_lval */,
@expr /* TODO: @expr|is_lval */, ann);
expr_assign_op(binop, @expr /* TODO: @expr|is_lval */, @expr, ann);
expr_send(@expr /* TODO: @expr|is_lval */, @expr, ann);
expr_recv(@expr /* TODO: @expr|is_lval */, @expr, ann);
expr_field(@expr, ident, ann);
expr_index(@expr, @expr, ann);
expr_path(path, ann);
Expand Down
8 changes: 7 additions & 1 deletion src/comp/front/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,8 +389,14 @@ fn next_token(&reader rdr) -> token::token {
alt (rdr.curr()) {
case ('=') { rdr.bump(); ret token::LE; }
case ('<') { ret binop(rdr, token::LSL); }
case ('-') { rdr.bump(); ret token::LARROW; }
case ('|') { rdr.bump(); ret token::SEND; }
case ('-') {
rdr.bump();
alt (rdr.curr()) {
case ('>') { rdr.bump(); ret token::DARROW; }
case (_) { ret token::LARROW; }
}
}
case (_) { ret token::LT; }
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/comp/front/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1161,6 +1161,12 @@ fn parse_assign_expr(&parser p) -> @ast::expr {
ret @spanned(lo, rhs.span.hi,
ast::expr_recv(rhs, lhs, p.get_ann()));
}
case (token::DARROW) {
p.bump();
auto rhs = parse_expr(p);
ret @spanned(lo, rhs.span.hi,
ast::expr_swap(lhs, rhs, p.get_ann()));
}
case (_) {/* fall through */ }
}
ret lhs;
Expand Down Expand Up @@ -1509,7 +1515,9 @@ fn stmt_ends_with_semi(&ast::stmt stmt) -> bool {
case (ast::expr_alt(_, _, _)) { ret false; }
case (ast::expr_fn(_, _)) { ret false; }
case (ast::expr_block(_, _)) { ret false; }
case (ast::expr_move(_, _, _)) { ret true; }
case (ast::expr_assign(_, _, _)) { ret true; }
case (ast::expr_swap(_, _, _)) { ret true; }
case (ast::expr_assign_op(_, _, _, _)) { ret true; }
case (ast::expr_send(_, _, _)) { ret true; }
case (ast::expr_recv(_, _, _)) { ret true; }
Expand Down
2 changes: 2 additions & 0 deletions src/comp/front/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ tag token {
SEND;
RECV;
LARROW;
DARROW;
LPAREN;
RPAREN;
LBRACKET;
Expand Down Expand Up @@ -124,6 +125,7 @@ fn to_str(lexer::reader r, token t) -> str {
case (SEND) { ret "<|"; }
case (RECV) { ret "<|"; }
case (LARROW) { ret "<-"; }
case (DARROW) { ret "<->"; }
case (LPAREN) { ret "("; }
case (RPAREN) { ret ")"; }
case (LBRACKET) { ret "["; }
Expand Down
22 changes: 20 additions & 2 deletions src/comp/middle/trans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3027,7 +3027,7 @@ fn move_val(@block_ctxt cx, copy_action action, ValueRef dst, ValueRef src,
ty::type_is_native(cx.fcx.lcx.ccx.tcx, t)) {
ret res(cx, cx.build.Store(src, dst));
} else if (ty::type_is_nil(cx.fcx.lcx.ccx.tcx, t) ||
ty::type_is_bot(cx.fcx.lcx.ccx.tcx, t)) {
ty::type_is_bot(cx.fcx.lcx.ccx.tcx, t)) {
ret res(cx, C_nil());
} else if (ty::type_is_boxed(cx.fcx.lcx.ccx.tcx, t)) {
if (action == DROP_EXISTING) {
Expand All @@ -3038,7 +3038,7 @@ fn move_val(@block_ctxt cx, copy_action action, ValueRef dst, ValueRef src,
} else if (ty::type_is_structural(cx.fcx.lcx.ccx.tcx, t) ||
ty::type_has_dynamic_size(cx.fcx.lcx.ccx.tcx, t)) {
if (action == DROP_EXISTING) { cx = drop_ty(cx, dst, t).bcx; }
auto r = memmove_ty(cx, dst, cx.build.Load(src), t);
auto r = memmove_ty(cx, dst, src, t);
ret zero_alloca(r.bcx, src, t);
}
cx.fcx.lcx.ccx.sess.bug("unexpected type in trans::move_val: " +
Expand Down Expand Up @@ -5404,6 +5404,24 @@ fn trans_expr_out(&@block_ctxt cx, &@ast::expr e, out_method output) ->
rhs_res.val, t);
ret res(copy_res.bcx, C_nil());
}
case (ast::expr_swap(?dst, ?src, _)) {
auto lhs_res = trans_lval(cx, dst);
assert (lhs_res.is_mem);
// FIXME Fill in lhs_res.res.bcx.sp

auto rhs_res = trans_lval(lhs_res.res.bcx, src);
auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, src);
auto tmp_res = alloc_ty(rhs_res.res.bcx, t);

// Swap through a temporary.
auto move1_res = memmove_ty(tmp_res.bcx, tmp_res.val,
lhs_res.res.val, t);
auto move2_res = memmove_ty(move1_res.bcx, lhs_res.res.val,
rhs_res.res.val, t);
auto move3_res = memmove_ty(move2_res.bcx, rhs_res.res.val,
tmp_res.val, t);
ret res(move3_res.bcx, C_nil());
}
case (ast::expr_assign_op(?op, ?dst, ?src, _)) {
auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, src);
auto lhs_res = trans_lval(cx, dst);
Expand Down
4 changes: 4 additions & 0 deletions src/comp/middle/tstate/pre_post_conditions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,10 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) {
case (_) { find_pre_post_exprs(fcx, [lhs, rhs], a); }
}
}
case (expr_swap(?lhs, ?rhs, ?a)) {
// Both sides must already be initialized
find_pre_post_exprs(fcx, [lhs, rhs], a);
}
case (expr_assign(?lhs, ?rhs, ?a)) {
alt (lhs.node) {
case (expr_path(?p, ?a_lhs)) {
Expand Down
14 changes: 14 additions & 0 deletions src/comp/middle/tstate/states.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,20 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
}
ret changed;
}
case (expr_swap(?lhs, ?rhs, ?a)) {
/* quite similar to binary -- should abstract this */
changed = extend_prestate_ann(fcx.ccx, a, pres) || changed;
changed = find_pre_post_state_expr(fcx, pres, lhs)
|| changed;
changed =
find_pre_post_state_expr(fcx,
expr_poststate(fcx.ccx, lhs),
rhs) || changed;
changed =
extend_poststate_ann(fcx.ccx, a,
expr_poststate(fcx.ccx, rhs)) || changed;
ret changed;
}
case (expr_recv(?lhs, ?rhs, ?a)) {
extend_prestate_ann(fcx.ccx, a, pres);
alt (lhs.node) {
Expand Down
1 change: 1 addition & 0 deletions src/comp/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1548,6 +1548,7 @@ fn expr_ann(&@ast::expr e) -> ast::ann {
case (ast::expr_block(_, ?a)) { ret a; }
case (ast::expr_move(_, _, ?a)) { ret a; }
case (ast::expr_assign(_, _, ?a)) { ret a; }
case (ast::expr_swap(_,_,?a)) { ret a; }
case (ast::expr_assign_op(_, _, _, ?a)) { ret a; }
case (ast::expr_send(_, _, ?a)) { ret a; }
case (ast::expr_recv(_, _, ?a)) { ret a; }
Expand Down
4 changes: 4 additions & 0 deletions src/comp/middle/typeck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1639,6 +1639,10 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
check_assignment(fcx, expr.span, lhs, rhs, a);
}
case (ast::expr_swap(?lhs, ?rhs, ?a)) {
require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
check_assignment(fcx, expr.span, lhs, rhs, a);
}
case (ast::expr_assign_op(?op, ?lhs, ?rhs, ?a)) {
require_impure(fcx.ccx.tcx.sess, fcx.purity, expr.span);
check_assignment(fcx, expr.span, lhs, rhs, a);
Expand Down
4 changes: 4 additions & 0 deletions src/comp/middle/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,10 @@ fn visit_expr[E](&@expr ex, &E e, &vt[E] v) {
vt(v).visit_expr(b, e, v);
vt(v).visit_expr(a, e, v);
}
case (expr_swap(?a, ?b, _)) {
vt(v).visit_expr(a, e, v);
vt(v).visit_expr(b, e, v);
}
case (expr_assign_op(_, ?a, ?b, _)) {
vt(v).visit_expr(b, e, v);
vt(v).visit_expr(a, e, v);
Expand Down
1 change: 1 addition & 0 deletions src/comp/middle/walk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ fn walk_expr(&ast_visitor v, @ast::expr e) {
walk_expr(v, b);
}
case (ast::expr_move(?a, ?b, _)) { walk_expr(v, a); walk_expr(v, b); }
case (ast::expr_swap(?a, ?b, _)) { walk_expr(v, a); walk_expr(v, b); }
case (ast::expr_assign_op(_, ?a, ?b, _)) {
walk_expr(v, a);
walk_expr(v, b);
Expand Down
6 changes: 6 additions & 0 deletions src/comp/pretty/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,12 @@ fn print_expr(&ps s, &@ast::expr expr) {
word_space(s, "=");
print_expr(s, rhs);
}
case (ast::expr_swap(?lhs, ?rhs, _)) {
print_expr(s, lhs);
space(s.s);
word_space(s, "<->");
print_expr(s, rhs);
}
case (ast::expr_assign_op(?op, ?lhs, ?rhs, _)) {
print_expr(s, lhs);
space(s.s);
Expand Down
7 changes: 7 additions & 0 deletions src/test/compile-fail/swap-uninit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// error-pattern:Unsatisfied precondition

fn main() {
auto x = 3;
auto y;
x <-> y;
}
7 changes: 7 additions & 0 deletions src/test/run-pass/swap-1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
fn main() {
auto x = 3;
auto y = 7;
x <-> y;
assert (x == 7);
assert (y == 3);
}
14 changes: 14 additions & 0 deletions src/test/run-pass/swap-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
fn swap[T](&vec[mutable T] v, int i, int j) {
v.(i) <-> v.(j);
}

fn main() {
let vec[mutable int] a = [mutable 0,1,2,3,4,5,6];
swap(a, 2, 4);
assert(a.(2) == 4);
assert(a.(4) == 2);
auto n = 42;
n <-> a.(0);
assert(a.(0) == 42);
assert(n == 0);
}