提交 1ec5a5c6 编写于 作者: B Brian Anderson

Add 'do' expressions

上级 ee9e5b9d
......@@ -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 fold_field_(field: field, fld: ast_fold) -> field {
}
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 @@ fn parse_bottom_expr() -> pexpr {
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 @@ fn parse_for_expr() -> @expr {
}
}
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_opt(s: ps, expr: option<@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 @@ fn cat_expr(expr: @ast::expr) -> cmt {
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 @@ fn propagate_through_expr(expr: @expr, succ: live_node) -> live_node {
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 unrooted(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_fn(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);
......
fn main() {
let x = do y; //! ERROR: `do` must be followed by a block call
}
fn f(f: fn@(int) -> bool) -> bool { f(10) }
fn main() {
assert do f() { |i| i == 10 } == 10; //! ERROR: expected `bool` but found `int`
}
fn f(f: fn@(int)) { f(10) }
fn main() {
do f() { |i| assert i == 10 }
}
fn f(f: fn@(int) -> int) -> int { f(10) }
fn main() {
assert do f() { |i| i } == 10;
}
fn f(f: fn@(int) -> int) -> int { f(10) }
fn main() {
assert do f { |i| i } == 10;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册