Add 'do' expressions
This commit is contained in:
parent
ee9e5b9d20
commit
1ec5a5c635
18 changed files with 91 additions and 8 deletions
|
@ -318,6 +318,8 @@ enum expr_ {
|
|||
// easily type this (a function returning nil on the inside but bool on
|
||||
// the outside).
|
||||
expr_loop_body(@expr),
|
||||
// Like expr_loop_body but for 'do' blocks
|
||||
expr_do_body(@expr),
|
||||
expr_block(blk),
|
||||
|
||||
/*
|
||||
|
|
|
@ -415,6 +415,7 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
|
|||
}
|
||||
expr_unary(binop, ohs) { expr_unary(binop, fld.fold_expr(ohs)) }
|
||||
expr_loop_body(f) { expr_loop_body(fld.fold_expr(f)) }
|
||||
expr_do_body(f) { expr_do_body(fld.fold_expr(f)) }
|
||||
expr_lit(_) { copy e }
|
||||
expr_cast(expr, ty) { expr_cast(fld.fold_expr(expr), ty) }
|
||||
expr_addr_of(m, ohs) { expr_addr_of(m, fld.fold_expr(ohs)) }
|
||||
|
|
|
@ -772,6 +772,8 @@ class parser {
|
|||
ret pexpr(self.parse_if_expr());
|
||||
} else if self.eat_keyword("for") {
|
||||
ret pexpr(self.parse_for_expr());
|
||||
} else if self.eat_keyword("do") {
|
||||
ret pexpr(self.parse_do_expr());
|
||||
} else if self.eat_keyword("while") {
|
||||
ret pexpr(self.parse_while_expr());
|
||||
} else if self.eat_keyword("loop") {
|
||||
|
@ -1312,6 +1314,23 @@ class parser {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_do_expr() -> @expr {
|
||||
let lo = self.last_span;
|
||||
let call = self.parse_expr_res(RESTRICT_STMT_EXPR);
|
||||
alt call.node {
|
||||
expr_call(f, args, true) {
|
||||
let b_arg = vec::last(args);
|
||||
let last = self.mk_expr(b_arg.span.lo, b_arg.span.hi,
|
||||
expr_do_body(b_arg));
|
||||
@{node: expr_call(f, vec::init(args) + [last], true)
|
||||
with *call}
|
||||
}
|
||||
_ {
|
||||
self.span_fatal(lo, "`do` must be followed by a block call");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_while_expr() -> @expr {
|
||||
let lo = self.last_span.lo;
|
||||
let cond = self.parse_expr();
|
||||
|
|
|
@ -287,7 +287,7 @@ fn restricted_keyword_table() -> hashmap<str, ()> {
|
|||
"assert",
|
||||
"be", "break",
|
||||
"check", "claim", "class", "const", "cont", "copy", "crust",
|
||||
"drop",
|
||||
"do", "drop",
|
||||
"else", "enum", "export",
|
||||
"fail", "false", "fn", "for",
|
||||
"if", "iface", "impl", "import",
|
||||
|
|
|
@ -1048,6 +1048,9 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
|
|||
ast::expr_loop_body(body) {
|
||||
print_expr(s, body);
|
||||
}
|
||||
ast::expr_do_body(body) {
|
||||
print_expr(s, body);
|
||||
}
|
||||
ast::expr_block(blk) {
|
||||
// containing cbox, will be closed by print-block at }
|
||||
cbox(s, indent_unit);
|
||||
|
|
|
@ -382,7 +382,8 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
|
|||
for args.each {|eo| visit_expr_opt(eo, e, v); }
|
||||
}
|
||||
expr_binary(_, a, b) { v.visit_expr(a, e, v); v.visit_expr(b, e, v); }
|
||||
expr_addr_of(_, x) | expr_unary(_, x) | expr_loop_body(x) |
|
||||
expr_addr_of(_, x) | expr_unary(_, x) |
|
||||
expr_loop_body(x) | expr_do_body(x) |
|
||||
expr_check(_, x) | expr_assert(x) {
|
||||
v.visit_expr(x, e, v);
|
||||
}
|
||||
|
|
|
@ -174,7 +174,7 @@ impl public_methods for borrowck_ctxt {
|
|||
ast::expr_swap(*) | ast::expr_move(*) | ast::expr_assign(*) |
|
||||
ast::expr_assign_op(*) | ast::expr_fn(*) | ast::expr_fn_block(*) |
|
||||
ast::expr_assert(*) | ast::expr_check(*) | ast::expr_ret(*) |
|
||||
ast::expr_loop_body(*) | ast::expr_unary(*) |
|
||||
ast::expr_loop_body(*) | ast::expr_do_body(*) | ast::expr_unary(*) |
|
||||
ast::expr_copy(*) | ast::expr_cast(*) | ast::expr_fail(*) |
|
||||
ast::expr_vstore(*) | ast::expr_vec(*) | ast::expr_tup(*) |
|
||||
ast::expr_if_check(*) | ast::expr_if(*) | ast::expr_log(*) |
|
||||
|
|
|
@ -412,7 +412,8 @@ fn visit_expr(expr: @expr, &&self: @ir_maps, vt: vt<@ir_maps>) {
|
|||
expr_vec(*) | expr_rec(*) | expr_call(*) | expr_tup(*) |
|
||||
expr_bind(*) | expr_new(*) | expr_log(*) | expr_binary(*) |
|
||||
expr_assert(*) | expr_check(*) | expr_addr_of(*) | expr_copy(*) |
|
||||
expr_loop_body(*) | expr_cast(*) | expr_unary(*) | expr_fail(*) |
|
||||
expr_loop_body(*) | expr_do_body(*) | expr_cast(*) |
|
||||
expr_unary(*) | expr_fail(*) |
|
||||
expr_break | expr_cont | expr_lit(_) | expr_ret(*) |
|
||||
expr_block(*) | expr_move(*) | expr_assign(*) | expr_swap(*) |
|
||||
expr_assign_op(*) | expr_mac(*) {
|
||||
|
@ -1054,6 +1055,7 @@ class liveness {
|
|||
expr_addr_of(_, e) |
|
||||
expr_copy(e) |
|
||||
expr_loop_body(e) |
|
||||
expr_do_body(e) |
|
||||
expr_cast(e, _) |
|
||||
expr_unary(_, e) {
|
||||
self.propagate_through_expr(e, succ)
|
||||
|
@ -1406,7 +1408,8 @@ fn check_expr(expr: @expr, &&self: @liveness, vt: vt<@liveness>) {
|
|||
expr_vec(*) | expr_rec(*) | expr_tup(*) |
|
||||
expr_bind(*) | expr_new(*) | expr_log(*) | expr_binary(*) |
|
||||
expr_assert(*) | expr_check(*) | expr_copy(*) |
|
||||
expr_loop_body(*) | expr_cast(*) | expr_unary(*) | expr_fail(*) |
|
||||
expr_loop_body(*) | expr_do_body(*) |
|
||||
expr_cast(*) | expr_unary(*) | expr_fail(*) |
|
||||
expr_ret(*) | expr_break | expr_cont | expr_lit(_) |
|
||||
expr_block(*) | expr_swap(*) | expr_mac(*) | expr_addr_of(*) {
|
||||
visit::visit_expr(expr, self, vt);
|
||||
|
|
|
@ -3622,6 +3622,9 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
|
|||
ast::expr_loop_body(blk) {
|
||||
ret trans_loop_body(bcx, e, none, dest);
|
||||
}
|
||||
ast::expr_do_body(blk) {
|
||||
ret trans_expr(bcx, blk, dest);
|
||||
}
|
||||
ast::expr_bind(f, args) {
|
||||
ret closure::trans_bind(
|
||||
bcx, f, args, e.id, dest);
|
||||
|
|
|
@ -223,7 +223,8 @@ fn mark_for_expr(cx: ctx, e: @expr) {
|
|||
expr_while(_, _) | expr_fail(_) | expr_break | expr_cont |
|
||||
expr_unary(_, _) | expr_lit(_) | expr_assert(_) | expr_check(_, _) |
|
||||
expr_if_check(_, _, _) | expr_mac(_) | expr_addr_of(_, _) |
|
||||
expr_ret(_) | expr_loop(_) | expr_bind(_, _) | expr_loop_body(_) {}
|
||||
expr_ret(_) | expr_loop(_) | expr_bind(_, _) |
|
||||
expr_loop_body(_) | expr_do_body(_) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -364,7 +364,7 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) {
|
|||
} else { find_pre_post_exprs(fcx, [l, r], e.id); }
|
||||
}
|
||||
expr_addr_of(_, x) | expr_cast(x, _) | expr_unary(_, x) |
|
||||
expr_loop_body(x) | expr_assert(x) | expr_copy(x) {
|
||||
expr_loop_body(x) | expr_do_body(x) | expr_assert(x) | expr_copy(x) {
|
||||
find_pre_post_expr(fcx, x);
|
||||
copy_pre_post(fcx.ccx, e.id, x);
|
||||
}
|
||||
|
|
|
@ -486,7 +486,8 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool {
|
|||
}
|
||||
ret changed | set_poststate_ann(fcx.ccx, e.id, a_post);
|
||||
}
|
||||
expr_field(x, _, _) | expr_loop_body(x) | expr_unary(_, x) |
|
||||
expr_field(x, _, _) | expr_loop_body(x) | expr_do_body(x) |
|
||||
expr_unary(_, x) |
|
||||
expr_addr_of(_, x) | expr_assert(x) | expr_cast(x, _) |
|
||||
expr_copy(x) {
|
||||
ret find_pre_post_state_sub(fcx, pres, x, e.id, none);
|
||||
|
|
|
@ -1364,6 +1364,32 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
|||
}
|
||||
}
|
||||
}
|
||||
ast::expr_do_body(b) {
|
||||
let expected_sty = unpack_expected(fcx, expected, {|x|some(x)}).get();
|
||||
let (inner_ty, proto) = alt expected_sty {
|
||||
ty::ty_fn(fty) {
|
||||
(ty::mk_fn(tcx, fty), fty.proto)
|
||||
}
|
||||
_ {
|
||||
tcx.sess.span_fatal(expr.span, "a do function's last argument \
|
||||
should be of function type");
|
||||
}
|
||||
};
|
||||
alt check b.node {
|
||||
ast::expr_fn_block(decl, body, cap_clause) {
|
||||
check_expr_fn(fcx, b, proto, decl, body, true, some(inner_ty));
|
||||
demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
|
||||
capture::check_capture_clause(tcx, b.id, cap_clause);
|
||||
}
|
||||
}
|
||||
let block_ty = structurally_resolved_type(
|
||||
fcx, expr.span, fcx.node_ty(b.id));
|
||||
alt check ty::get(block_ty).struct {
|
||||
ty::ty_fn(fty) {
|
||||
fcx.write_ty(expr.id, ty::mk_fn(tcx, fty));
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::expr_block(b) {
|
||||
// If this is an unchecked block, turn off purity-checking
|
||||
bot = check_block(fcx, b);
|
||||
|
|
3
src/test/compile-fail/do1.rs
Normal file
3
src/test/compile-fail/do1.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
let x = do y; //! ERROR: `do` must be followed by a block call
|
||||
}
|
5
src/test/compile-fail/do2.rs
Normal file
5
src/test/compile-fail/do2.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
fn f(f: fn@(int) -> bool) -> bool { f(10) }
|
||||
|
||||
fn main() {
|
||||
assert do f() { |i| i == 10 } == 10; //! ERROR: expected `bool` but found `int`
|
||||
}
|
5
src/test/run-pass/do1.rs
Normal file
5
src/test/run-pass/do1.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
fn f(f: fn@(int)) { f(10) }
|
||||
|
||||
fn main() {
|
||||
do f() { |i| assert i == 10 }
|
||||
}
|
5
src/test/run-pass/do2.rs
Normal file
5
src/test/run-pass/do2.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
fn f(f: fn@(int) -> int) -> int { f(10) }
|
||||
|
||||
fn main() {
|
||||
assert do f() { |i| i } == 10;
|
||||
}
|
5
src/test/run-pass/do3.rs
Normal file
5
src/test/run-pass/do3.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
fn f(f: fn@(int) -> int) -> int { f(10) }
|
||||
|
||||
fn main() {
|
||||
assert do f { |i| i } == 10;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue